MT#56471 mix_buffer: support initial write-delay

This is to compensate for inter-packet arrival jitter.

Change-Id: I5cdfb4bbda8e90b82f5abe410f48329070d7005b
pull/1627/head
Richard Fuchs 2 years ago
parent 61f41522e0
commit 81a0f36f27

@ -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;
}

@ -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);

@ -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;
}

Loading…
Cancel
Save