13 Commits

Author SHA1 Message Date
JohannesItten d2095d14d3 Read info about source from source/flow_def 2026-07-09 12:43:10 +03:00
JohannesItten 370cbd89a2 fixes + cmake fixes for macos 2026-07-07 19:33:55 +03:00
itten 0b5b113d4e fixed ndiout flow_id -> video_flow_id 2026-07-03 18:51:10 +03:00
JohannesItten f2515b7ce2 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>
2026-07-03 10:28:30 +03:00
JohannesItten 21a8ee4ba0 feat: garbage collection on startup, readable status strings, audio/float32
studio-manager: call mxlGarbageCollectFlows before launching nodes to
clean up stale flow directories left by previous crashed runs.

shared/NodeBase.hpp: add mxl_status_str(mxlStatus) — converts error
codes to readable names (e.g. MXL_ERR_OUT_OF_RANGE_TOO_LATE). All
nodes now log these names instead of raw integers.

shared/FlowDef.hpp: use "audio/float32" as media_type for 32-bit audio
flows, matching the MXL SDK examples. audio/L{n} kept for other depths.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 10:20:53 +03:00
JohannesItten 5504b8983e feat: ndiout supports audio-only mode (video optional)
flow_id is now optional (config().contains). When absent: skip the
MXL reader, active-wait, and NDI video path entirely. Video buffers
and NDI video frames are heap-allocated only when has_video.

Loop pacing: video branch sleeps 1ms on TOO_EARLY as before; audio-only
path sleeps 1ms when no chunk was available (audio_advanced == false)
to avoid busy-spinning.

NDI sender name changed from the video flow UUID to node_id(), which
is stable and human-readable for both video and audio-only modes.

To use audio-only: wire only audio_flow_id in build_graph, omit flow_id.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 10:11:06 +03:00
JohannesItten 9fd41b0312 fix: samples_per_frame must multiply fps_den for fractional framerates
sample_rate / fps_num gave 48000/30000 = 1 for 29.97 fps, producing
silence. Correct formula is sample_rate * fps_den / fps_num, matching
the calculation already used in testpattern.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 10:06:43 +03:00
JohannesItten 2b11411423 fix: set p216_frame FourCC; scope audio_rate to has_audio branch
ndiout: p216_frame.FourCC was zero-initialized — NDI needs it explicitly
set to NDIlib_FourCC_video_type_P216 to send the correct format.

All three nodes: audio_rate = {sample_rate, 1} was always declared even
when has_audio is false (sample_rate = 0 in ndiout). Scoped into the
has_audio block so the bad rate can never be passed to mxlGetCurrentIndex.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 10:01:39 +03:00
JohannesItten b7fb54e2bc refactor: clean up ndiout — fix hardcoded 1920, consistent naming
Fix: c * 1920 → c * samples_per_frame (broke non-25fps or non-48kHz).
Fix: audio channel loop now iterates `channels` not `audio_slices.count`.

Rename: mxl_stride → video_stride, no_samples → samples_per_frame,
ndi_frame_10bit/16bit → v210_frame/p216_frame, ndi_audio_frame → ndi_audio.
Scope `ast` locally to its use block.
Drop unused #include "V210.hpp" and #include "FlowDef.hpp".
ndi_audio struct zero-initialized then filled only when has_audio.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 09:58:06 +03:00
itten ba3c2994ee ndi out before refactoring 2026-07-03 09:52:29 +03:00
JohannesItten e6d72ab431 fix: ndiout — RAII for NDI lifecycle, vectors instead of malloc
- NDIContext struct handles NDIlib_initialize/send_create/send_destroy/destroy
  so NDIlib_destroy() is guaranteed even if send_create fails (was leaked before)
- malloc/free for 10-bit and 16-bit frame buffers → std::vector<uint8_t>
- NDI frame structs point into vector data, no manual lifetime management
- static_cast for FourCC instead of C-style cast
- Tidy: ndi_frame_count replaces ndi_frame_counter, ++prefix form

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-01 12:15:44 +03:00
JohannesItten 7a32fa20af fix: NDI node correctness and robustness fixes
NDIHelper:
- find_sources: check g_running each attempt to avoid 50s block on shutdown
- getV210_video_frame: fix P216 branch (fall-through + local pointer reassignment bug)
- getV210_video_frame: status_change re-queries source info instead of throwing
- select_source: fix typo "recieve" → "receive"

ndiout:
- set frame_rate_N/frame_rate_D on the NDI send frame (was 0/0)
- add per-second stats logging (matching fakesink pattern)
- add missing <chrono> include
- fix typo "reciever" → "receiver"

ndiin:
- read source_num from NODE_CONFIG (key: "source_num", default 0)
- wrap hot-loop NDI call in try/catch so source-lost terminates cleanly
- pass source_num through to getV210_video_frame

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-01 12:07:45 +03:00
itten 51a1b1b2c8 looks like i forgot about commits 2026-06-25 12:43:53 +03:00