libobs: Add ability to configure audio buffering latency
Allows a frontend the ability to set the maximum audio buffering latency, and specify whether that audio buffering is either fixed (to the maximum audio buffering latency), or dynamically increasing from 0. This will be useful if the user wishes to output audio to devices or through a virtual audio device at a guaranteed minimal latency.master
parent
090613851e
commit
f482111791
|
@ -144,6 +144,36 @@ Initialization, Shutdown, and Information
|
|||
|
||||
---------------------
|
||||
|
||||
.. function:: bool obs_reset_audio2(const struct obs_audio_info2 *oai)
|
||||
|
||||
Sets base audio output format/channels/samples/etc. Also allows the
|
||||
ability to set the maximum audio latency of OBS, and set whether the
|
||||
audio buffering is fixed or dynamically increasing.
|
||||
|
||||
When using fixed audio buffering, OBS will automatically buffer to
|
||||
the maximum audio latency on startup.
|
||||
|
||||
Maximum audio latency will clamp to the closest multiple of the audio
|
||||
output frames (which is typically 1024 audio frames).
|
||||
|
||||
Note: Cannot reset base audio if an output is currently active.
|
||||
|
||||
:return: *true* if successful, *false* otherwise
|
||||
|
||||
Relevant data types used with this function:
|
||||
|
||||
.. code:: cpp
|
||||
|
||||
struct obs_audio_info2 {
|
||||
uint32_t samples_per_sec;
|
||||
enum speaker_layout speakers;
|
||||
|
||||
uint32_t max_buffering_ms;
|
||||
bool fixed_buffering;
|
||||
};
|
||||
|
||||
---------------------
|
||||
|
||||
.. function:: bool obs_get_video_info(struct obs_video_info *ovi)
|
||||
|
||||
Gets the current video settings.
|
||||
|
|
|
@ -26,7 +26,6 @@ struct ts_info {
|
|||
|
||||
#define DEBUG_AUDIO 0
|
||||
#define DEBUG_LAGGED_AUDIO 0
|
||||
#define MAX_BUFFERING_TICKS 45
|
||||
|
||||
static void push_audio_tree(obs_source_t *parent, obs_source_t *source, void *p)
|
||||
{
|
||||
|
@ -241,7 +240,8 @@ static inline void discard_audio(struct obs_core_audio *audio,
|
|||
|
||||
/* ignore_audio should have already run and marked this source
|
||||
* pending, unless we *just* added buffering */
|
||||
assert(audio->total_buffering_ticks < MAX_BUFFERING_TICKS ||
|
||||
assert(audio->total_buffering_ticks <
|
||||
audio->max_buffering_ticks ||
|
||||
source->audio_pending || !source->audio_ts ||
|
||||
audio->buffering_wait_ticks);
|
||||
#endif
|
||||
|
@ -294,7 +294,7 @@ static inline void discard_audio(struct obs_core_audio *audio,
|
|||
|
||||
static inline bool audio_buffering_maxed(struct obs_core_audio *audio)
|
||||
{
|
||||
return audio->total_buffering_ticks == MAX_BUFFERING_TICKS;
|
||||
return audio->total_buffering_ticks == audio->max_buffering_ticks;
|
||||
}
|
||||
|
||||
static void set_fixed_audio_buffering(struct obs_core_audio *audio,
|
||||
|
@ -311,7 +311,7 @@ static void set_fixed_audio_buffering(struct obs_core_audio *audio,
|
|||
if (!audio->buffering_wait_ticks)
|
||||
audio->buffered_ts = ts->start;
|
||||
|
||||
ticks = MAX_BUFFERING_TICKS - audio->total_buffering_ticks;
|
||||
ticks = audio->max_buffering_ticks - audio->total_buffering_ticks;
|
||||
audio->total_buffering_ticks += ticks;
|
||||
|
||||
ms = ticks * AUDIO_OUTPUT_FRAMES * 1000 / sample_rate;
|
||||
|
@ -374,9 +374,10 @@ static void add_audio_buffering(struct obs_core_audio *audio,
|
|||
|
||||
audio->total_buffering_ticks += ticks;
|
||||
|
||||
if (audio->total_buffering_ticks >= MAX_BUFFERING_TICKS) {
|
||||
ticks -= audio->total_buffering_ticks - MAX_BUFFERING_TICKS;
|
||||
audio->total_buffering_ticks = MAX_BUFFERING_TICKS;
|
||||
if (audio->total_buffering_ticks >= audio->max_buffering_ticks) {
|
||||
ticks -= audio->total_buffering_ticks -
|
||||
audio->max_buffering_ticks;
|
||||
audio->total_buffering_ticks = audio->max_buffering_ticks;
|
||||
blog(LOG_WARNING, "Max audio buffering reached!");
|
||||
}
|
||||
|
||||
|
|
|
@ -344,6 +344,7 @@ struct obs_core_audio {
|
|||
struct circlebuf buffered_timestamps;
|
||||
uint64_t buffering_wait_ticks;
|
||||
int total_buffering_ticks;
|
||||
int max_buffering_ticks;
|
||||
bool fixed_buffer;
|
||||
|
||||
float user_volume;
|
||||
|
|
40
libobs/obs.c
40
libobs/obs.c
|
@ -1395,18 +1395,37 @@ int obs_reset_video(struct obs_video_info *ovi)
|
|||
return obs_init_video(ovi);
|
||||
}
|
||||
|
||||
bool obs_reset_audio(const struct obs_audio_info *oai)
|
||||
#ifndef SEC_TO_MSEC
|
||||
#define SEC_TO_MSEC 1000
|
||||
#endif
|
||||
|
||||
bool obs_reset_audio2(const struct obs_audio_info2 *oai)
|
||||
{
|
||||
struct obs_core_audio *audio = &obs->audio;
|
||||
struct audio_output_info ai;
|
||||
|
||||
/* don't allow changing of audio settings if active. */
|
||||
if (obs->audio.audio && audio_output_active(obs->audio.audio))
|
||||
if (!obs || (audio->audio && audio_output_active(audio->audio)))
|
||||
return false;
|
||||
|
||||
obs_free_audio();
|
||||
if (!oai)
|
||||
return true;
|
||||
|
||||
if (oai->max_buffering_ms) {
|
||||
uint32_t max_frames = oai->max_buffering_ms *
|
||||
oai->samples_per_sec / SEC_TO_MSEC;
|
||||
max_frames += (AUDIO_OUTPUT_FRAMES - 1);
|
||||
audio->max_buffering_ticks = max_frames / AUDIO_OUTPUT_FRAMES;
|
||||
} else {
|
||||
audio->max_buffering_ticks = 45;
|
||||
}
|
||||
audio->fixed_buffer = oai->fixed_buffering;
|
||||
|
||||
int max_buffering_ms = audio->max_buffering_ticks *
|
||||
AUDIO_OUTPUT_FRAMES * SEC_TO_MSEC /
|
||||
(int)oai->samples_per_sec;
|
||||
|
||||
ai.name = "Audio";
|
||||
ai.samples_per_sec = oai->samples_per_sec;
|
||||
ai.format = AUDIO_FORMAT_FLOAT_PLANAR;
|
||||
|
@ -1417,12 +1436,25 @@ bool obs_reset_audio(const struct obs_audio_info *oai)
|
|||
blog(LOG_INFO,
|
||||
"audio settings reset:\n"
|
||||
"\tsamples per sec: %d\n"
|
||||
"\tspeakers: %d",
|
||||
(int)ai.samples_per_sec, (int)ai.speakers);
|
||||
"\tspeakers: %d\n"
|
||||
"\tmax buffering: %d milliseconds\n"
|
||||
"\tbuffering type: %s",
|
||||
(int)ai.samples_per_sec, (int)ai.speakers, max_buffering_ms,
|
||||
oai->fixed_buffering ? "fixed" : "dynamically increasing");
|
||||
|
||||
return obs_init_audio(&ai);
|
||||
}
|
||||
|
||||
bool obs_reset_audio(const struct obs_audio_info *oai)
|
||||
{
|
||||
struct obs_audio_info2 oai2 = {
|
||||
.samples_per_sec = oai->samples_per_sec,
|
||||
.speakers = oai->speakers,
|
||||
};
|
||||
|
||||
return obs_reset_audio2(&oai2);
|
||||
}
|
||||
|
||||
bool obs_get_video_info(struct obs_video_info *ovi)
|
||||
{
|
||||
struct obs_core_video *video = &obs->video;
|
||||
|
|
|
@ -206,6 +206,14 @@ struct obs_audio_info {
|
|||
enum speaker_layout speakers;
|
||||
};
|
||||
|
||||
struct obs_audio_info2 {
|
||||
uint32_t samples_per_sec;
|
||||
enum speaker_layout speakers;
|
||||
|
||||
uint32_t max_buffering_ms;
|
||||
bool fixed_buffering;
|
||||
};
|
||||
|
||||
/**
|
||||
* Sent to source filters via the filter_audio callback to allow filtering of
|
||||
* audio data
|
||||
|
@ -413,6 +421,7 @@ EXPORT int obs_reset_video(struct obs_video_info *ovi);
|
|||
* @note Cannot reset base audio if an output is currently active.
|
||||
*/
|
||||
EXPORT bool obs_reset_audio(const struct obs_audio_info *oai);
|
||||
EXPORT bool obs_reset_audio2(const struct obs_audio_info2 *oai);
|
||||
|
||||
/** Gets the current video settings, returns false if no video */
|
||||
EXPORT bool obs_get_video_info(struct obs_video_info *ovi);
|
||||
|
|
Loading…
Reference in New Issue