fix: use continuous sample API for audio flow in ndiin
Audio flows in MXL use mxlFlowWriterOpenSamples/CommitSamples, not the grain API (mxlFlowWriterOpenGrain is for discrete video flows). Using the grain API silently did nothing — hence "last published index: 0". MXL audio is float32 planar: each channel occupies its own ring buffer region accessed at base.fragments[*].pointer + c * slice.stride. Two fragments handle ring buffer wraparound. No int32 conversion needed. Also log continuous.channelCount/bufferLength instead of the discrete sliceSizes field (wrong union member for audio). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+19
-16
@@ -1,4 +1,3 @@
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
@@ -75,7 +74,8 @@ class NDIInNode : public dmf::NodeBase {
|
||||
log("audio mxlCreateFlowWriter failed (status=%d) — continuing without audio", ast);
|
||||
has_audio = false;
|
||||
} else {
|
||||
log("audio grain=%u B", audio_cfg.discrete.sliceSizes[0]);
|
||||
log("audio channels=%u buffer=%u samples",
|
||||
audio_cfg.continuous.channelCount, audio_cfg.continuous.bufferLength);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,22 +104,25 @@ class NDIInNode : public dmf::NodeBase {
|
||||
if (kind == dmf::NDIReceiver::FrameKind::Video) {
|
||||
have_video = true;
|
||||
} else if (kind == dmf::NDIReceiver::FrameKind::Audio && has_audio) {
|
||||
mxlGrainInfo grain{};
|
||||
uint8_t* buf = nullptr;
|
||||
if (mxlFlowWriterOpenGrain(audio_writer, audio_index, &grain, &buf) == MXL_STATUS_OK) {
|
||||
// Convert float32 planar → int32 interleaved PCM
|
||||
const int audio_grain_size = audio_cfg.discrete.sliceSizes[0];
|
||||
const int capacity = audio_grain_size / (channels * static_cast<int>(sizeof(int32_t)));
|
||||
const int to_write = std::min(audio_info.samples, capacity);
|
||||
auto* out = reinterpret_cast<int32_t*>(buf);
|
||||
for (int s = 0; s < to_write; ++s)
|
||||
mxlMutableWrappedMultiBufferSlice slice{};
|
||||
if (mxlFlowWriterOpenSamples(audio_writer, audio_index,
|
||||
static_cast<size_t>(audio_info.samples), &slice) == MXL_STATUS_OK) {
|
||||
// MXL audio is float32 planar: each channel occupies its own ring buffer
|
||||
// region, accessed at base + c * stride. Fragments handle ring wraparound.
|
||||
const size_t frag0 = slice.base.fragments[0].size / sizeof(float);
|
||||
const size_t frag1 = slice.base.fragments[1].size / sizeof(float);
|
||||
for (int c = 0; c < audio_info.channels; ++c) {
|
||||
float f = audio_buf[c * audio_info.channel_stride + s];
|
||||
f = std::max(-1.0f, std::min(1.0f, f));
|
||||
*out++ = static_cast<int32_t>(f * 2147483647.0f);
|
||||
const float* src = &audio_buf[c * audio_info.channel_stride];
|
||||
auto* dst0 = reinterpret_cast<float*>(
|
||||
static_cast<uint8_t*>(slice.base.fragments[0].pointer) + c * slice.stride);
|
||||
std::memcpy(dst0, src, frag0 * sizeof(float));
|
||||
if (frag1 > 0) {
|
||||
auto* dst1 = reinterpret_cast<float*>(
|
||||
static_cast<uint8_t*>(slice.base.fragments[1].pointer) + c * slice.stride);
|
||||
std::memcpy(dst1, src + frag0, frag1 * sizeof(float));
|
||||
}
|
||||
grain.validSlices = grain.totalSlices;
|
||||
mxlFlowWriterCommitGrain(audio_writer, &grain);
|
||||
}
|
||||
mxlFlowWriterCommitSamples(audio_writer);
|
||||
}
|
||||
audio_index += audio_info.samples;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user