Skip to content

Commit b82df26

Browse files
committed
Fix audio desync issue by throwing away old samples instead of new ones incase of buffer overflow
1 parent c1ea0e6 commit b82df26

File tree

2 files changed

+21
-18
lines changed

2 files changed

+21
-18
lines changed

src/video_stream_playback_ndi.cpp

+20-18
Original file line numberDiff line numberDiff line change
@@ -57,10 +57,13 @@ void VideoStreamPlaybackNDI::_set_audio_track(int32_t p_idx) {}
5757

5858
int32_t VideoStreamPlaybackNDI::_get_channels() const {
5959
return 2;
60+
// As far as i know this is only querried once by the video player.
61+
// Might get updated afer stop/play
62+
// Hardcoded for now :/
6063
}
6164

6265
int32_t VideoStreamPlaybackNDI::_get_mix_rate() const {
63-
return ProjectSettings::get_singleton()->get_setting("audio/driver/mix_rate", 41400);
66+
return ProjectSettings::get_singleton()->get_setting("audio/driver/mix_rate", 44100);
6467
}
6568

6669
Ref<Texture2D> VideoStreamPlaybackNDI::_get_texture() const {
@@ -121,53 +124,48 @@ void VideoStreamPlaybackNDI::stop_syncing() {
121124
}
122125

123126
void VideoStreamPlaybackNDI::render_first_frame() {
124-
for (size_t i = 0; i < 200; i++) {
127+
for (size_t i = 0; i < 500; i++) {
125128
ndi->framesync_capture_video(sync, &video_frame, NDIlib_frame_format_type_progressive);
126129
if (video_frame.xres != 0 && video_frame.yres != 0) {
127-
// UtilityFunctions::print("Found after ", i, "ms");
128130
texture->set_image(Image::create_empty(video_frame.xres, video_frame.yres, false, Image::FORMAT_RGBA8));
129131
ndi->framesync_free_video(sync, &video_frame);
130132
return;
131133
}
132134
ndi->framesync_free_video(sync, &video_frame);
133-
OS::get_singleton()->delay_msec(1);
135+
OS::get_singleton()->delay_msec(10);
134136
}
135137

136138
// Fallback resolution
137139
texture->set_image(Image::create_empty(100, 100, false, Image::FORMAT_RGBA8));
138-
UtilityFunctions::push_warning("NDI Source not found at playback start. Will play once found.");
140+
ERR_FAIL_MSG("NDI Source not found at playback start. Will play once found.");
139141
}
140142

141143
void VideoStreamPlaybackNDI::render_video() {
144+
if (img.is_valid()) {
145+
texture->set_image(img);
146+
}
147+
142148
ndi->framesync_capture_video(sync, &video_frame, NDIlib_frame_format_type_progressive);
143149

144150
if (video_frame.p_data != NULL && (video_frame.FourCC == NDIlib_FourCC_type_RGBA || video_frame.FourCC == NDIlib_FourCC_type_RGBX)) {
145151
video_buffer.resize(video_frame.line_stride_in_bytes * video_frame.yres);
146152
memcpy(video_buffer.ptrw(), video_frame.p_data, video_buffer.size());
147153

148-
Ref<Image> img = Image::create_from_data(video_frame.xres, video_frame.yres, false, Image::Format::FORMAT_RGBA8, video_buffer);
149-
texture->set_image(img);
150-
img.unref();
154+
img = Image::create_from_data(video_frame.xres, video_frame.yres, false, Image::Format::FORMAT_RGBA8, video_buffer);
151155
}
152156

153157
ndi->framesync_free_video(sync, &video_frame);
154158
}
155159

156160
void VideoStreamPlaybackNDI::render_audio(double p_delta) {
157-
// This is clipped in an attempt to fix issue #3.
158-
// FIXME: Should be clipping no_samples to buffer size because that's what causes the error.
159-
// But no clue what buffer is meant. The one from Project Settings or the one of VideoStreamPlayer (Buffer msec)?
160-
161-
p_delta = UtilityFunctions::min(p_delta, 0.5);
162-
163-
int no_samples = (double)_get_mix_rate() * p_delta;
164-
ndi->framesync_capture_audio_v2(sync, &audio_frame, _get_mix_rate(), _get_channels(), no_samples);
161+
int requested_samples = Math::min((double)_get_mix_rate() * p_delta, (double)ndi->framesync_audio_queue_depth(sync));
162+
ndi->framesync_capture_audio_v2(sync, &audio_frame, _get_mix_rate(), _get_channels(), requested_samples);
165163

166164
if (audio_frame.p_data != NULL) {
167165
audio_buffer_planar.resize(audio_frame.no_channels * audio_frame.no_samples);
168166
audio_buffer_interleaved.resize(audio_buffer_planar.size());
169167

170-
memcpy(audio_buffer_planar.ptrw(), audio_frame.p_data, audio_buffer_planar.size() * 4);
168+
memcpy((uint8_t *)audio_buffer_planar.ptrw(), audio_frame.p_data, audio_buffer_planar.size() * 4);
171169

172170
for (int64_t i = 0; i < audio_buffer_interleaved.size(); i++) {
173171
int channel = i % audio_frame.no_channels;
@@ -177,7 +175,11 @@ void VideoStreamPlaybackNDI::render_audio(double p_delta) {
177175
audio_buffer_interleaved.set(i, audio_buffer_planar[stride_index + stride_offset]);
178176
}
179177

180-
mix_audio(audio_frame.no_samples, audio_buffer_interleaved, 0);
178+
int processed_samples = Math::min(audio_frame.no_samples, 4096); // FIXME: dont hardcode this
179+
int skipped_samples = audio_frame.no_samples - processed_samples;
180+
181+
// Skip the older samples by playing the last ones in the array
182+
mix_audio(processed_samples, audio_buffer_interleaved, skipped_samples * _get_channels());
181183
}
182184

183185
ndi->framesync_free_audio_v2(sync, &audio_frame);

src/video_stream_playback_ndi.hpp

+1
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ class VideoStreamPlaybackNDI : public VideoStreamPlayback {
6060
void stop_syncing();
6161

6262
Ref<ImageTexture> texture;
63+
Ref<Image> img;
6364
NDIlib_video_frame_v2_t video_frame;
6465
PackedByteArray video_buffer;
6566
void render_first_frame();

0 commit comments

Comments
 (0)