diff --git a/lib/mix_buffer.c b/lib/mix_buffer.c index 37654a80b..51778e92e 100644 --- a/lib/mix_buffer.c +++ b/lib/mix_buffer.c @@ -217,12 +217,33 @@ static void mix_buffer_src_init_pos(struct mix_buffer *mb, struct mix_buffer_ssr } -bool mix_buffer_write(struct mix_buffer *mb, uint32_t ssrc, const void *buf, unsigned int samples) { +static void mix_buff_src_shift_delay(struct mix_buffer *mb, struct mix_buffer_ssrc_source *src, + const struct timeval *last, const struct timeval *now) +{ + if (!last || !now) + return; + long long diff_us = timeval_diff(now, last); + if (diff_us <= 0) + return; + unsigned int samples = mb->clockrate * diff_us / 1000000; + mix_buffer_src_add_delay(mb, src, samples); +} + + +// takes the difference between two time stamps into account, scaled to the given clock rate, +// to add an additional write-delay for a newly created source +bool mix_buffer_write_delay(struct mix_buffer *mb, uint32_t ssrc, const void *buf, unsigned int samples, + const struct timeval *last, const struct timeval *now) +{ LOCK(&mb->lock); - AUTO_CLEANUP(struct mix_buffer_ssrc_source *src, mix_ssrc_put) = get_ssrc(ssrc, mb->ssrc_hash); + bool created; + AUTO_CLEANUP(struct mix_buffer_ssrc_source *src, mix_ssrc_put) + = get_ssrc_full(ssrc, mb->ssrc_hash, &created); if (!src) return false; + if (created) + mix_buff_src_shift_delay(mb, src, last, now); // loop twice at the most to re-run logic after a reset while (true) { diff --git a/lib/mix_buffer.h b/lib/mix_buffer.h index 769dc221c..8b422ab4a 100644 --- a/lib/mix_buffer.h +++ b/lib/mix_buffer.h @@ -64,7 +64,12 @@ void mix_buffer_destroy(struct mix_buffer *); void *mix_buffer_read_fast(struct mix_buffer *, unsigned int samples, unsigned int *size); void mix_buffer_read_slow(struct mix_buffer *, void *outbuf, unsigned int samples); -bool mix_buffer_write(struct mix_buffer *, uint32_t ssrc, const void *buf, unsigned int samples); +bool mix_buffer_write_delay(struct mix_buffer *, uint32_t ssrc, const void *buf, unsigned int samples, + const struct timeval *, const struct timeval *); + +INLINE bool mix_buffer_write(struct mix_buffer *mb, uint32_t ssrc, const void *buf, unsigned int samples) { + return mix_buffer_write_delay(mb, ssrc, buf, samples, NULL, NULL); +} #endif diff --git a/t/test-mix-buffer.c b/t/test-mix-buffer.c index 0d14bfa94..7ee2e42e6 100644 --- a/t/test-mix-buffer.c +++ b/t/test-mix-buffer.c @@ -451,6 +451,56 @@ int main(void) { assert(size == 20); assert(memcmp(p, "1122334455" "\0\0\0\0\0\0\0\0\0\0", size) == 0); + // src now fallen behind, catch up with reader + + ret = mix_buffer_write(&mb, 0x1234, "xxxxxxxxxx", 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" "xxxxxxxxxx", size) == 0); + + // mix two sources + + ret = mix_buffer_write(&mb, 0x1234, "1122334455", 5); + assert(ret == true); + + // add new source + + ret = mix_buffer_write(&mb, 0x6543, "9988776655", 5); + assert(ret == true); + ret = mix_buffer_write(&mb, 0x1234, "3344556677", 5); + assert(ret == true); + + // output partially mixed, new source delayed + + p = mix_buffer_read_fast(&mb, 10, &size); + assert(p == NULL); + assert(size == 20); + mix_buffer_read_slow(&mb, buf, 10); + assert(memcmp(buf, "1122334455llllllllll" , size) == 0); + + // caught up now. add new source with extra delay: + // 10 ms constant, 15 ms extra = 25 ms total = 12.5 sampes (12) + + struct timeval last = { 100, 200 }; + struct timeval now = { 100, 15200 }; + + ret = mix_buffer_write_delay(&mb, 0x3333, "0011223344", 5, &last, &now); + assert(ret == true); + + // mix-in previous source + + ret = mix_buffer_write(&mb, 0x6543, "3322114455998866334422339988776655443322", 20); + assert(ret == true); + + // read mixed output + + p = mix_buffer_read_fast(&mb, 20, &size); + assert(p != NULL); + assert(size == 40); + assert(memcmp(p, "332211445599886633442233iiiiiiiiii443322", size) == 0); + mix_buffer_destroy(&mb); return 0;