mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2026-03-08 05:34:03 -04:00
module-vban: derive write position from frame counter
Instead of writing packets sequentially and losing sync on any frame gap, compute the write position from the VBAN header's n_frames field. Out-of-order packets land at the correct ringbuffer offset, matching how module-rtp handles this. Only advance the writeindex when a packet extends the frontier so that late arrivals fill gaps without moving the pointer backwards. Fixes: https://gitlab.freedesktop.org/pipewire/pipewire/-/issues/5145
This commit is contained in:
parent
354ec08b9b
commit
8ceb671cc8
2 changed files with 25 additions and 15 deletions
|
|
@ -98,38 +98,43 @@ static int vban_audio_receive(struct impl *impl, uint8_t *buffer, ssize_t len)
|
||||||
samples = SPA_MIN(hdr->format_nbs+1, plen / stride);
|
samples = SPA_MIN(hdr->format_nbs+1, plen / stride);
|
||||||
|
|
||||||
n_frames = hdr->n_frames;
|
n_frames = hdr->n_frames;
|
||||||
if (impl->have_sync && impl->n_frames != n_frames) {
|
|
||||||
pw_log_info("unexpected frame (%d != %d)",
|
if (impl->samples_per_frame == 0) {
|
||||||
n_frames, impl->n_frames);
|
impl->samples_per_frame = samples;
|
||||||
|
} else if (samples != impl->samples_per_frame) {
|
||||||
|
pw_log_warn("samples_per_frame changed (%u != %u)",
|
||||||
|
samples, impl->samples_per_frame);
|
||||||
|
impl->samples_per_frame = samples;
|
||||||
impl->have_sync = false;
|
impl->have_sync = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (impl->have_sync && impl->n_frames != n_frames) {
|
||||||
|
pw_log_info("unexpected frame (%u != %u)",
|
||||||
|
n_frames, impl->n_frames);
|
||||||
|
}
|
||||||
impl->n_frames = n_frames + 1;
|
impl->n_frames = n_frames + 1;
|
||||||
|
|
||||||
timestamp = impl->timestamp;
|
/* derive write position from frame counter, like module-rtp */
|
||||||
impl->timestamp += samples;
|
timestamp = n_frames * impl->samples_per_frame;
|
||||||
|
write = timestamp + impl->target_buffer;
|
||||||
|
|
||||||
filled = spa_ringbuffer_get_write_index(&impl->ring, &expected_write);
|
filled = spa_ringbuffer_get_write_index(&impl->ring, &expected_write);
|
||||||
|
|
||||||
/* we always write to timestamp + delay */
|
|
||||||
write = timestamp + impl->target_buffer;
|
|
||||||
|
|
||||||
if (!impl->have_sync) {
|
if (!impl->have_sync) {
|
||||||
pw_log_info("sync to timestamp:%u target:%u",
|
pw_log_info("sync to n_frames:%u timestamp:%u target:%u",
|
||||||
timestamp, impl->target_buffer);
|
n_frames, timestamp, impl->target_buffer);
|
||||||
|
|
||||||
/* we read from timestamp, keeping target_buffer of data
|
/* we read from timestamp, keeping target_buffer of data
|
||||||
* in the ringbuffer. */
|
* in the ringbuffer. */
|
||||||
impl->ring.readindex = timestamp;
|
impl->ring.readindex = timestamp;
|
||||||
impl->ring.writeindex = write;
|
impl->ring.writeindex = write;
|
||||||
filled = impl->target_buffer;
|
filled = impl->target_buffer;
|
||||||
|
expected_write = write;
|
||||||
|
|
||||||
spa_dll_init(&impl->dll);
|
spa_dll_init(&impl->dll);
|
||||||
spa_dll_set_bw(&impl->dll, SPA_DLL_BW_MAX, 128, impl->rate);
|
spa_dll_set_bw(&impl->dll, SPA_DLL_BW_MAX, 128, impl->rate);
|
||||||
memset(impl->buffer, 0, BUFFER_SIZE);
|
memset(impl->buffer, 0, BUFFER_SIZE);
|
||||||
impl->have_sync = true;
|
impl->have_sync = true;
|
||||||
} else if (expected_write != write) {
|
|
||||||
pw_log_debug("unexpected write (%u != %u)",
|
|
||||||
write, expected_write);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filled + samples > BUFFER_SIZE / stride) {
|
if (filled + samples > BUFFER_SIZE / stride) {
|
||||||
|
|
@ -137,14 +142,17 @@ static int vban_audio_receive(struct impl *impl, uint8_t *buffer, ssize_t len)
|
||||||
BUFFER_SIZE / stride);
|
BUFFER_SIZE / stride);
|
||||||
impl->have_sync = false;
|
impl->have_sync = false;
|
||||||
} else {
|
} else {
|
||||||
pw_log_trace("got samples:%u", samples);
|
pw_log_trace("got n_frames:%u samples:%u", n_frames, samples);
|
||||||
spa_ringbuffer_write_data(&impl->ring,
|
spa_ringbuffer_write_data(&impl->ring,
|
||||||
impl->buffer,
|
impl->buffer,
|
||||||
BUFFER_SIZE,
|
BUFFER_SIZE,
|
||||||
(write * stride) & BUFFER_MASK,
|
(write * stride) & BUFFER_MASK,
|
||||||
&buffer[hlen], (samples * stride));
|
&buffer[hlen], (samples * stride));
|
||||||
|
|
||||||
|
/* only advance writeindex if this extends the frontier */
|
||||||
write += samples;
|
write += samples;
|
||||||
spa_ringbuffer_write_update(&impl->ring, write);
|
if ((int32_t)(write - expected_write) > 0)
|
||||||
|
spa_ringbuffer_write_update(&impl->ring, write);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -262,5 +270,6 @@ static int vban_audio_init(struct impl *impl, enum spa_direction direction)
|
||||||
else
|
else
|
||||||
impl->stream_events.process = vban_audio_process_playback;
|
impl->stream_events.process = vban_audio_process_playback;
|
||||||
impl->receive_vban = vban_audio_receive;
|
impl->receive_vban = vban_audio_receive;
|
||||||
|
impl->samples_per_frame = 0;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -61,6 +61,7 @@ struct impl {
|
||||||
struct vban_header header;
|
struct vban_header header;
|
||||||
uint32_t timestamp;
|
uint32_t timestamp;
|
||||||
uint32_t n_frames;
|
uint32_t n_frames;
|
||||||
|
uint32_t samples_per_frame;
|
||||||
|
|
||||||
struct spa_ringbuffer ring;
|
struct spa_ringbuffer ring;
|
||||||
uint8_t buffer[BUFFER_SIZE];
|
uint8_t buffer[BUFFER_SIZE];
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue