From e3bdb4ca7bf01aead1ab8b71422dd371bb9425ae Mon Sep 17 00:00:00 2001 From: jp9000 Date: Sun, 24 Apr 2022 07:50:28 -0700 Subject: [PATCH] libobs: Add ability to use fixed audio buffering This is in anticipation to adding low audio latency mode, will cause audio buffering to be fixed rather than dynamically increasing. Having fixed audio buffering means that audio latency always stays the same rather than dynamically increasing. --- libobs/obs-audio.c | 72 ++++++++++++++++++++++++++++++++++++++++--- libobs/obs-internal.h | 1 + 2 files changed, 69 insertions(+), 4 deletions(-) diff --git a/libobs/obs-audio.c b/libobs/obs-audio.c index e6b107b2b..68a933a67 100644 --- a/libobs/obs-audio.c +++ b/libobs/obs-audio.c @@ -292,6 +292,65 @@ static inline void discard_audio(struct obs_core_audio *audio, source->audio_ts = ts->end; } +static inline bool audio_buffering_maxed(struct obs_core_audio *audio) +{ + return audio->total_buffering_ticks == MAX_BUFFERING_TICKS; +} + +static void set_fixed_audio_buffering(struct obs_core_audio *audio, + size_t sample_rate, struct ts_info *ts) +{ + struct ts_info new_ts; + size_t total_ms; + size_t ms; + int ticks; + + if (audio_buffering_maxed(audio)) + return; + + if (!audio->buffering_wait_ticks) + audio->buffered_ts = ts->start; + + ticks = MAX_BUFFERING_TICKS - audio->total_buffering_ticks; + audio->total_buffering_ticks += ticks; + + ms = ticks * AUDIO_OUTPUT_FRAMES * 1000 / sample_rate; + total_ms = audio->total_buffering_ticks * AUDIO_OUTPUT_FRAMES * 1000 / + sample_rate; + + blog(LOG_INFO, + "\n" + "enabling fixed audio buffering, total " + "audio buffering is now %d milliseconds" + "\n", + (int)total_ms); + + new_ts.start = + audio->buffered_ts - + audio_frames_to_ns(sample_rate, audio->buffering_wait_ticks * + AUDIO_OUTPUT_FRAMES); + + while (ticks--) { + const uint64_t cur_ticks = ++audio->buffering_wait_ticks; + + new_ts.end = new_ts.start; + new_ts.start = + audio->buffered_ts - + audio_frames_to_ns(sample_rate, + cur_ticks * AUDIO_OUTPUT_FRAMES); + +#if DEBUG_AUDIO == 1 + blog(LOG_DEBUG, "add buffered ts: %" PRIu64 "-%" PRIu64, + new_ts.start, new_ts.end); +#endif + + circlebuf_push_front(&audio->buffered_timestamps, &new_ts, + sizeof(new_ts)); + } + + *ts = new_ts; +} + static void add_audio_buffering(struct obs_core_audio *audio, size_t sample_rate, struct ts_info *ts, uint64_t min_ts, const char *buffering_name) @@ -303,7 +362,7 @@ static void add_audio_buffering(struct obs_core_audio *audio, size_t ms; int ticks; - if (audio->total_buffering_ticks == MAX_BUFFERING_TICKS) + if (audio_buffering_maxed(audio)) return; if (!audio->buffering_wait_ticks) @@ -518,7 +577,7 @@ bool audio_callback(void *param, uint64_t start_ts_in, uint64_t end_ts_in, /* if a source has gone backward in time and we can no * longer buffer, drop some or all of its audio */ - if (audio->total_buffering_ticks == MAX_BUFFERING_TICKS && + if (audio_buffering_maxed(audio) && source->audio_ts < ts.start) { if (source->info.audio_render) { blog(LOG_DEBUG, @@ -556,10 +615,15 @@ bool audio_callback(void *param, uint64_t start_ts_in, uint64_t end_ts_in, pthread_mutex_unlock(&data->audio_sources_mutex); /* ------------------------------------------------ */ - /* if a source has gone backward in time, buffer */ - if (min_ts < ts.start) + /* if a source has gone backward in time, buffer */ + if (audio->fixed_buffer) { + if (!audio_buffering_maxed(audio)) { + set_fixed_audio_buffering(audio, sample_rate, &ts); + } + } else if (min_ts < ts.start) { add_audio_buffering(audio, sample_rate, &ts, min_ts, buffering_name); + } /* ------------------------------------------------ */ /* mix audio */ diff --git a/libobs/obs-internal.h b/libobs/obs-internal.h index 1ced6fe1c..271bbe599 100644 --- a/libobs/obs-internal.h +++ b/libobs/obs-internal.h @@ -344,6 +344,7 @@ struct obs_core_audio { struct circlebuf buffered_timestamps; uint64_t buffering_wait_ticks; int total_buffering_ticks; + bool fixed_buffer; float user_volume;