diff --git a/nodes/fakesink/main.cpp b/nodes/fakesink/main.cpp index 6717204..0990bd7 100644 --- a/nodes/fakesink/main.cpp +++ b/nodes/fakesink/main.cpp @@ -25,7 +25,7 @@ class FakeSinkNode : public dmf::NodeBase { mxlFlowReader reader{}; mxlStatus st = mxlCreateFlowReader(instance(), flow_id.c_str(), nullptr, &reader); if (st != MXL_STATUS_OK) { - log("mxlCreateFlowReader failed (status=%d)", st); + log("mxlCreateFlowReader failed (%s)", dmf::mxl_status_str(st)); return; } @@ -60,7 +60,7 @@ class FakeSinkNode : public dmf::NodeBase { index = ri.headIndex; } else { - log("unexpected status=%d on index=%llu", st, index); + log("unexpected status (%s) on index=%llu", dmf::mxl_status_str(st), index); break; } diff --git a/nodes/ndiin/main.cpp b/nodes/ndiin/main.cpp index 4241d68..bf35a8d 100644 --- a/nodes/ndiin/main.cpp +++ b/nodes/ndiin/main.cpp @@ -42,7 +42,7 @@ class NDIInNode : public dmf::NodeBase { instance(), dmf::make_video_flow_def(video_flow_id, node_id(), width, height, fps_num, fps_den).c_str(), nullptr, &video_writer, &video_cfg, &created); - if (st != MXL_STATUS_OK) { log("video mxlCreateFlowWriter failed (status=%d)", st); return; } + if (st != MXL_STATUS_OK) { log("video mxlCreateFlowWriter failed (%s)", dmf::mxl_status_str(st)); return; } const uint32_t video_stride = video_cfg.discrete.sliceSizes[0]; log("video stride=%u B/line grain=%u B ring=%u grains", @@ -71,7 +71,7 @@ class NDIInNode : public dmf::NodeBase { fps_num, fps_den).c_str(), nullptr, &audio_writer, &audio_cfg, &created); if (ast != MXL_STATUS_OK) { - log("audio mxlCreateFlowWriter failed (status=%d) — continuing without audio", ast); + log("audio mxlCreateFlowWriter failed (%s) — continuing without audio", dmf::mxl_status_str(ast)); has_audio = false; } else { log("audio channels=%u buffer=%u samples", @@ -146,7 +146,7 @@ class NDIInNode : public dmf::NodeBase { grain.validSlices = grain.totalSlices; mxlFlowWriterCommitGrain(video_writer, &grain); } else { - log("video OpenGrain failed (status=%d) at index=%llu", st, video_index); + log("video OpenGrain failed (%s) at index=%llu", dmf::mxl_status_str(st), video_index); } video_index = current + 1; } diff --git a/nodes/ndiout/main.cpp b/nodes/ndiout/main.cpp index 4f40596..66f4a37 100644 --- a/nodes/ndiout/main.cpp +++ b/nodes/ndiout/main.cpp @@ -65,7 +65,7 @@ class NDIOutNode : public dmf::NodeBase { mxlFlowConfigInfo video_cfg{}; mxlStatus vst = mxlCreateFlowReader(instance(), flow_id.c_str(), nullptr, &video_reader); - if (vst != MXL_STATUS_OK) { log("video mxlCreateFlowReader failed (status=%d)", vst); return; } + if (vst != MXL_STATUS_OK) { log("video mxlCreateFlowReader failed (%s)", dmf::mxl_status_str(vst)); return; } mxlFlowReaderGetConfigInfo(video_reader, &video_cfg); video_stride = video_cfg.discrete.sliceSizes[0]; } @@ -90,7 +90,7 @@ class NDIOutNode : public dmf::NodeBase { mxlStatus ast = mxlCreateFlowReader(instance(), audio_flow_id.c_str(), nullptr, &audio_reader); if (ast != MXL_STATUS_OK) { - log("audio mxlCreateFlowReader failed (status=%d) — continuing without audio", ast); + log("audio mxlCreateFlowReader failed (%s) — continuing without audio", dmf::mxl_status_str(ast)); has_audio = false; } else { mxlFlowReaderGetConfigInfo(audio_reader, &audio_cfg); @@ -224,7 +224,7 @@ class NDIOutNode : public dmf::NodeBase { video_index = ri.headIndex; } else { - log("unexpected video status=%d on index=%llu", vst, video_index); + log("unexpected video status (%s) on index=%llu", dmf::mxl_status_str(vst), video_index); break; } diff --git a/nodes/testpattern/main.cpp b/nodes/testpattern/main.cpp index 982d5f6..93ca4fe 100644 --- a/nodes/testpattern/main.cpp +++ b/nodes/testpattern/main.cpp @@ -28,7 +28,7 @@ class TestPatternNode : public dmf::NodeBase { instance(), dmf::make_video_flow_def(flow_id, node_id(), width, height, fps_num, fps_den).c_str(), nullptr, &video_writer, &video_cfg, &created); - if (vst != MXL_STATUS_OK) { log("video mxlCreateFlowWriter failed (status=%d)", vst); return; } + if (vst != MXL_STATUS_OK) { log("video mxlCreateFlowWriter failed (%s)", dmf::mxl_status_str(vst)); return; } const uint32_t video_stride = video_cfg.discrete.sliceSizes[0]; log("video stride=%u B/line grain=%u B ring=%u grains", @@ -55,7 +55,7 @@ class TestPatternNode : public dmf::NodeBase { fps_num, fps_den).c_str(), nullptr, &audio_writer, &audio_cfg, &created); if (ast != MXL_STATUS_OK) { - log("audio mxlCreateFlowWriter failed (status=%d) — continuing without audio", ast); + log("audio mxlCreateFlowWriter failed (%s) — continuing without audio", dmf::mxl_status_str(ast)); has_audio = false; } else { log("audio channels=%u buffer=%u samples", @@ -85,7 +85,7 @@ class TestPatternNode : public dmf::NodeBase { uint8_t* video_buf = nullptr; vst = mxlFlowWriterOpenGrain(video_writer, video_index, &video_grain, &video_buf); if (vst != MXL_STATUS_OK) { - log("OpenGrain failed (status=%d), skipping index=%llu", vst, video_index); + log("OpenGrain failed (%s) at index=%llu", dmf::mxl_status_str(vst), video_index); video_index++; continue; } diff --git a/shared/FlowDef.hpp b/shared/FlowDef.hpp index cf42119..ef1538c 100644 --- a/shared/FlowDef.hpp +++ b/shared/FlowDef.hpp @@ -59,7 +59,7 @@ inline std::string make_audio_flow_def( {"format", "urn:x-nmos:format:audio"}, {"label", label}, {"description", label + " MXL Audio Flow"}, - {"media_type", "audio/L" + std::to_string(bit_depth)}, + {"media_type", bit_depth == 32 ? "audio/float32" : "audio/L" + std::to_string(bit_depth)}, {"parents", json::array()}, {"grain_rate", {{"numerator", grain_rate_num}, {"denominator", grain_rate_den}}}, {"sample_rate", {{"numerator", sample_rate}, {"denominator", 1}}}, diff --git a/shared/NodeBase.hpp b/shared/NodeBase.hpp index 9605542..481fd0a 100644 --- a/shared/NodeBase.hpp +++ b/shared/NodeBase.hpp @@ -10,6 +10,35 @@ namespace dmf { +inline const char* mxl_status_str(mxlStatus s) noexcept { + switch (s) { + case MXL_STATUS_OK: return "MXL_STATUS_OK"; + case MXL_ERR_UNKNOWN: return "MXL_ERR_UNKNOWN"; + case MXL_ERR_FLOW_NOT_FOUND: return "MXL_ERR_FLOW_NOT_FOUND"; + case MXL_ERR_OUT_OF_RANGE_TOO_LATE: return "MXL_ERR_OUT_OF_RANGE_TOO_LATE"; + case MXL_ERR_OUT_OF_RANGE_TOO_EARLY: return "MXL_ERR_OUT_OF_RANGE_TOO_EARLY"; + case MXL_ERR_INVALID_FLOW_READER: return "MXL_ERR_INVALID_FLOW_READER"; + case MXL_ERR_INVALID_FLOW_WRITER: return "MXL_ERR_INVALID_FLOW_WRITER"; + case MXL_ERR_TIMEOUT: return "MXL_ERR_TIMEOUT"; + case MXL_ERR_INVALID_ARG: return "MXL_ERR_INVALID_ARG"; + case MXL_ERR_CONFLICT: return "MXL_ERR_CONFLICT"; + case MXL_ERR_PERMISSION_DENIED: return "MXL_ERR_PERMISSION_DENIED"; + case MXL_ERR_FLOW_INVALID: return "MXL_ERR_FLOW_INVALID"; + case MXL_ERR_STRLEN: return "MXL_ERR_STRLEN"; + case MXL_ERR_INTERRUPTED: return "MXL_ERR_INTERRUPTED"; + case MXL_ERR_NO_FABRIC: return "MXL_ERR_NO_FABRIC"; + case MXL_ERR_INVALID_STATE: return "MXL_ERR_INVALID_STATE"; + case MXL_ERR_INTERNAL: return "MXL_ERR_INTERNAL"; + case MXL_ERR_NOT_READY: return "MXL_ERR_NOT_READY"; + case MXL_ERR_NOT_FOUND: return "MXL_ERR_NOT_FOUND"; + case MXL_ERR_EXISTS: return "MXL_ERR_EXISTS"; + case MXL_ERR_UNSUPPORTED_OPERATION: return "MXL_ERR_UNSUPPORTED_OPERATION"; + default: return "MXL_ERR_UNRECOGNIZED"; + } +} + + + // Base class for all DMF node binaries. // // Handles the boilerplate every node needs: diff --git a/studio-manager/main.cpp b/studio-manager/main.cpp index bf240bb..3e0c4b0 100644 --- a/studio-manager/main.cpp +++ b/studio-manager/main.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include "Signal.hpp" #include "FlowGraph.hpp" @@ -152,6 +153,16 @@ int main(int argc, char* argv[]) { } fprintf(stderr, "[studio-manager] domain: %s\n", domain.c_str()); + // Clean up stale flow directories left by any previous crashed run + { + mxlInstance gc = mxlCreateInstance(domain.c_str(), nullptr); + if (gc) { + mxlGarbageCollectFlows(gc); + mxlDestroyInstance(gc); + fprintf(stderr, "[studio-manager] garbage collected stale flows\n"); + } + } + // --- Build and launch the pipeline graph --- const dmf::FlowGraph graph = build_graph();