From 81a0f36f274b0a403419635de87fe38abfbb59ab Mon Sep 17 00:00:00 2001 From: Richard Fuchs Date: Fri, 17 Feb 2023 09:43:43 -0500 Subject: [PATCH] MT#56471 mix_buffer: support initial write-delay This is to compensate for inter-packet arrival jitter. Change-Id: I5cdfb4bbda8e90b82f5abe410f48329070d7005b --- lib/mix_buffer.c | 27 ++++++++++++++++++++++++--- lib/mix_buffer.h | 4 +++- t/test-mix-buffer.c | 40 ++++++++++++++++++++++++++++++++++++++-- 3 files changed, 65 insertions(+), 6 deletions(-) diff --git a/lib/mix_buffer.c b/lib/mix_buffer.c index 6845624d8..37654a80b 100644 --- a/lib/mix_buffer.c +++ b/lib/mix_buffer.c @@ -189,11 +189,31 @@ static bool mix_buffer_write_slow(struct mix_buffer *mb, struct mix_buffer_ssrc_ } +static void mix_buffer_src_add_delay(struct mix_buffer *mb, struct mix_buffer_ssrc_source *src, + unsigned int samples) +{ + if (!samples) + return; + // shift new write pos into the future + src->write_pos += samples; + if (src->write_pos >= mb->size) { + src->write_pos -= mb->size; + src->loops++; + } + // fill up buffer if needed + if (src->loops == mb->loops && src->write_pos > mb->head_write_pos) + fill_up_to(mb, mb->fill + src->write_pos - mb->head_write_pos); + else if (src->loops == mb->loops + 1 && src->write_pos < mb->head_write_pos) + fill_up_to(mb, mb->fill + src->write_pos + mb->size - mb->head_write_pos); +} + + static void mix_buffer_src_init_pos(struct mix_buffer *mb, struct mix_buffer_ssrc_source *src) { src->write_pos = mb->read_pos; src->loops = mb->loops; if (mb->head_write_pos < src->write_pos) src->loops--; + mix_buffer_src_add_delay(mb, src, mb->delay); } @@ -230,7 +250,6 @@ bool mix_buffer_write(struct mix_buffer *mb, uint32_t ssrc, const void *buf, uns // we fell behind. reset write position to current read pos and try again mix_buffer_src_init_pos(mb, src); - // TODO: add offset to correct for jitter/delay } } @@ -245,7 +264,7 @@ static struct ssrc_entry *mix_buffer_ssrc_new(void *p) { // struct must be zeroed already bool mix_buffer_init(struct mix_buffer *mb, enum AVSampleFormat fmt, unsigned int clockrate, - unsigned int channels, unsigned int size_ms) + unsigned int channels, unsigned int size_ms, unsigned int delay_ms) { switch (fmt) { case AV_SAMPLE_FMT_S16: @@ -256,6 +275,7 @@ bool mix_buffer_init(struct mix_buffer *mb, enum AVSampleFormat fmt, unsigned in } unsigned int size = clockrate * size_ms / 1000; // in samples + unsigned int delay = clockrate * delay_ms / 1000; // in samples mutex_init(&mb->lock); mb->sample_size_channels = channels * mb->impl->sample_size; @@ -263,8 +283,9 @@ bool mix_buffer_init(struct mix_buffer *mb, enum AVSampleFormat fmt, unsigned in mb->size = size; mb->clockrate = clockrate; mb->channels = channels; + mb->delay = delay; - mb->ssrc_hash = create_ssrc_hash_full(mix_buffer_ssrc_new, mb); + mb->ssrc_hash = create_ssrc_hash_full_fast(mix_buffer_ssrc_new, mb); return true; } diff --git a/lib/mix_buffer.h b/lib/mix_buffer.h index c576b6f69..769dc221c 100644 --- a/lib/mix_buffer.h +++ b/lib/mix_buffer.h @@ -47,6 +47,8 @@ struct mix_buffer { unsigned int read_pos; // current read (output) position unsigned int head_write_pos; // furthest ahead write (input) position unsigned int fill; // difference between read and write position + unsigned int delay; // initial write delay for new inputs/sources + unsigned int loops; // how many times the write pos has circled around // implementation details @@ -57,7 +59,7 @@ struct mix_buffer { bool mix_buffer_init(struct mix_buffer *, enum AVSampleFormat, unsigned int clockrate, - unsigned int channels, unsigned int size_ms); + unsigned int channels, unsigned int size_ms, unsigned int delay_ms); void mix_buffer_destroy(struct mix_buffer *); void *mix_buffer_read_fast(struct mix_buffer *, unsigned int samples, unsigned int *size); diff --git a/t/test-mix-buffer.c b/t/test-mix-buffer.c index fd17d8d06..0d14bfa94 100644 --- a/t/test-mix-buffer.c +++ b/t/test-mix-buffer.c @@ -24,7 +24,7 @@ int main(void) { struct mix_buffer mb; memset(&mb, 0, sizeof(mb)); - bool ret = mix_buffer_init(&mb, AV_SAMPLE_FMT_S16, 500, 1, 100); + bool ret = mix_buffer_init(&mb, AV_SAMPLE_FMT_S16, 500, 1, 100, 0); assert(ret == true); // pre-fill with zeroes @@ -235,7 +235,7 @@ int main(void) { // 2-channel memset(&mb, 0, sizeof(mb)); - ret = mix_buffer_init(&mb, AV_SAMPLE_FMT_S16, 500, 2, 100); + ret = mix_buffer_init(&mb, AV_SAMPLE_FMT_S16, 500, 2, 100, 0); assert(ret == true); // pre-fill with zeroes @@ -417,5 +417,41 @@ int main(void) { mix_buffer_destroy(&mb); + + + // initial delay + + memset(&mb, 0, sizeof(mb)); + ret = mix_buffer_init(&mb, AV_SAMPLE_FMT_S16, 500, 1, 100, 10); // 5 samples delay + assert(ret == true); + + // write-in and read-out + + ret = mix_buffer_write(&mb, 0x1234, "1122334455", 5); + assert(ret == true); + + p = mix_buffer_read_fast(&mb, 15, &size); + assert(p != NULL); + assert(size == 30); + assert(memcmp(p, "\0\0\0\0\0\0\0\0\0\0" "1122334455" "\0\0\0\0\0\0\0\0\0\0", size) == 0); + + ret = mix_buffer_write(&mb, 0x1234, "1122334455", 5); + assert(ret == true); + + p = mix_buffer_read_fast(&mb, 10, &size); + assert(p != NULL); + assert(size == 20); + assert(memcmp(p, "\0\0\0\0\0\0\0\0\0\0" "1122334455", size) == 0); + + ret = mix_buffer_write(&mb, 0x1234, "1122334455", 5); + assert(ret == true); + + p = mix_buffer_read_fast(&mb, 10, &size); + assert(p != NULL); + assert(size == 20); + assert(memcmp(p, "1122334455" "\0\0\0\0\0\0\0\0\0\0", size) == 0); + + mix_buffer_destroy(&mb); + return 0; }