fix: MXL_ERR_FLOW_INVALID reconnect, nullptr→"" options, null guards

Readers (ndiout, fakesink) now handle MXL_ERR_FLOW_INVALID by releasing
and recreating the flow reader, then realigning the index to current time.
This lets consumer nodes survive a producer restart without exiting.

All mxlCreateInstance/FlowWriter/FlowReader options args changed from
nullptr to "" to match MXL reference implementation style.

mxlReleaseFlowReader calls guarded with null checks so cleanup is safe
when a mid-run reconnect attempt fails.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
JohannesItten
2026-07-03 10:28:30 +03:00
parent 21a8ee4ba0
commit f2515b7ce2
6 changed files with 45 additions and 13 deletions
+12 -2
View File
@@ -23,7 +23,7 @@ class FakeSinkNode : public dmf::NodeBase {
log("flow active — starting read");
mxlFlowReader reader{};
mxlStatus st = mxlCreateFlowReader(instance(), flow_id.c_str(), nullptr, &reader);
mxlStatus st = mxlCreateFlowReader(instance(), flow_id.c_str(), "", &reader);
if (st != MXL_STATUS_OK) {
log("mxlCreateFlowReader failed (%s)", dmf::mxl_status_str(st));
return;
@@ -59,6 +59,16 @@ class FakeSinkNode : public dmf::NodeBase {
mxlFlowReaderGetRuntimeInfo(reader, &ri);
index = ri.headIndex;
} else if (st == MXL_ERR_FLOW_INVALID) {
log("flow invalidated — reconnecting...");
if (reader) mxlReleaseFlowReader(instance(), reader);
reader = nullptr;
mxlSleepForNs(100'000'000);
if (mxlCreateFlowReader(instance(), flow_id.c_str(), "", &reader) == MXL_STATUS_OK) {
log("flow reconnected");
index = mxlGetCurrentIndex(&rate);
}
} else {
log("unexpected status (%s) on index=%llu", dmf::mxl_status_str(st), index);
break;
@@ -77,7 +87,7 @@ class FakeSinkNode : public dmf::NodeBase {
log("stopped — total frames=%llu invalid=%llu late=%llu",
frame_count, invalid_count, late_count);
mxlReleaseFlowReader(instance(), reader);
if (reader) mxlReleaseFlowReader(instance(), reader);
}
};