mirror of
https://github.com/obsproject/obs-studio.git
synced 2024-07-14 23:34:08 +00:00
libobs: Store circular audio buffer on source itself (skip)
(Note: This commit breaks libobs compilation. Skip if bisecting) Removes audio lines and stores the circular buffer for the audio on the source itself.
This commit is contained in:
parent
f73bbe6746
commit
bc0b85cb79
|
@ -492,6 +492,7 @@ struct obs_source {
|
|||
volatile bool timing_set;
|
||||
volatile uint64_t timing_adjust;
|
||||
uint64_t next_audio_ts_min;
|
||||
uint64_t next_audio_sys_ts_min;
|
||||
uint64_t last_frame_ts;
|
||||
uint64_t last_sys_timestamp;
|
||||
bool async_rendered;
|
||||
|
@ -501,9 +502,12 @@ struct obs_source {
|
|||
bool muted;
|
||||
struct obs_source *next_audio_source;
|
||||
struct obs_source **prev_next_audio_source;
|
||||
uint64_t audio_ts;
|
||||
struct circlebuf audio_input_buf[MAX_AUDIO_CHANNELS];
|
||||
float *audio_output_buf[MAX_AUDIO_MIXES][MAX_AUDIO_CHANNELS];
|
||||
struct resample_info sample_info;
|
||||
audio_resampler_t *resampler;
|
||||
audio_line_t *audio_line;
|
||||
pthread_mutex_t audio_buf_mutex;
|
||||
pthread_mutex_t audio_mutex;
|
||||
struct obs_audio_data audio_data;
|
||||
size_t audio_storage_size;
|
||||
|
|
|
@ -116,6 +116,22 @@ const char *obs_source_get_display_name(enum obs_source_type type,
|
|||
return (info != NULL) ? info->get_name(info->type_data) : NULL;
|
||||
}
|
||||
|
||||
static void allocate_audio_output_buffer(struct obs_source *source)
|
||||
{
|
||||
size_t size = sizeof(float) *
|
||||
AUDIO_OUTPUT_FRAMES * MAX_AUDIO_CHANNELS * MAX_AUDIO_MIXES;
|
||||
float *ptr = bzalloc(size);
|
||||
|
||||
for (size_t mix = 0; mix < MAX_AUDIO_MIXES; mix++) {
|
||||
size_t mix_pos = mix * AUDIO_OUTPUT_FRAMES * MAX_AUDIO_CHANNELS;
|
||||
|
||||
for (size_t i = 0; i < MAX_AUDIO_CHANNELS; i++) {
|
||||
source->audio_output_buf[mix][i] =
|
||||
ptr + mix_pos + AUDIO_OUTPUT_FRAMES * i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* internal initialization */
|
||||
bool obs_source_init(struct obs_source *source,
|
||||
const struct obs_source_info *info)
|
||||
|
@ -129,6 +145,7 @@ bool obs_source_init(struct obs_source *source,
|
|||
pthread_mutex_init_value(&source->filter_mutex);
|
||||
pthread_mutex_init_value(&source->async_mutex);
|
||||
pthread_mutex_init_value(&source->audio_mutex);
|
||||
pthread_mutex_init_value(&source->audio_buf_mutex);
|
||||
|
||||
if (pthread_mutexattr_init(&attr) != 0)
|
||||
return false;
|
||||
|
@ -136,19 +153,15 @@ bool obs_source_init(struct obs_source *source,
|
|||
return false;
|
||||
if (pthread_mutex_init(&source->filter_mutex, &attr) != 0)
|
||||
return false;
|
||||
if (pthread_mutex_init(&source->audio_buf_mutex, NULL) != 0)
|
||||
return false;
|
||||
if (pthread_mutex_init(&source->audio_mutex, NULL) != 0)
|
||||
return false;
|
||||
if (pthread_mutex_init(&source->async_mutex, NULL) != 0)
|
||||
return false;
|
||||
|
||||
if (info && info->output_flags & OBS_SOURCE_AUDIO) {
|
||||
source->audio_line = audio_output_create_line(obs->audio.audio,
|
||||
source->context.name, 0xF);
|
||||
if (!source->audio_line) {
|
||||
blog(LOG_ERROR, "Failed to create audio line for "
|
||||
"source '%s'", source->context.name);
|
||||
return false;
|
||||
}
|
||||
allocate_audio_output_buffer(source);
|
||||
|
||||
pthread_mutex_lock(&obs->data.audio_sources_mutex);
|
||||
|
||||
|
@ -397,14 +410,16 @@ void obs_source_destroy(struct obs_source *source)
|
|||
|
||||
for (i = 0; i < MAX_AV_PLANES; i++)
|
||||
bfree(source->audio_data.data[i]);
|
||||
|
||||
audio_line_destroy(source->audio_line);
|
||||
for (i = 0; i < MAX_AUDIO_CHANNELS; i++)
|
||||
circlebuf_free(&source->audio_input_buf[i]);
|
||||
audio_resampler_destroy(source->resampler);
|
||||
bfree(source->audio_output_buf[0][0]);
|
||||
|
||||
da_free(source->async_cache);
|
||||
da_free(source->async_frames);
|
||||
da_free(source->filters);
|
||||
pthread_mutex_destroy(&source->filter_mutex);
|
||||
pthread_mutex_destroy(&source->audio_buf_mutex);
|
||||
pthread_mutex_destroy(&source->audio_mutex);
|
||||
pthread_mutex_destroy(&source->async_mutex);
|
||||
obs_context_data_free(&source->context);
|
||||
|
@ -861,14 +876,27 @@ static inline void reset_audio_timing(obs_source_t *source, uint64_t timestamp,
|
|||
source->timing_adjust = os_time - timestamp;
|
||||
}
|
||||
|
||||
static inline void handle_ts_jump(obs_source_t *source, uint64_t expected,
|
||||
static void reset_audio_data(obs_source_t *source, uint64_t os_time)
|
||||
{
|
||||
for (size_t i = 0; i < MAX_AUDIO_CHANNELS; i++) {
|
||||
if (source->audio_input_buf[i].size)
|
||||
circlebuf_pop_front(&source->audio_input_buf[i], NULL,
|
||||
source->audio_input_buf[i].size);
|
||||
}
|
||||
|
||||
source->audio_ts = os_time;
|
||||
}
|
||||
|
||||
static void handle_ts_jump(obs_source_t *source, uint64_t expected,
|
||||
uint64_t ts, uint64_t diff, uint64_t os_time)
|
||||
{
|
||||
blog(LOG_DEBUG, "Timestamp for source '%s' jumped by '%"PRIu64"', "
|
||||
"expected value %"PRIu64", input value %"PRIu64,
|
||||
source->context.name, diff, expected, ts);
|
||||
|
||||
pthread_mutex_lock(&source->audio_buf_mutex);
|
||||
reset_audio_timing(source, ts, os_time);
|
||||
pthread_mutex_unlock(&source->audio_buf_mutex);
|
||||
}
|
||||
|
||||
static void source_signal_audio_data(obs_source_t *source,
|
||||
|
@ -892,28 +920,77 @@ static inline uint64_t uint64_diff(uint64_t ts1, uint64_t ts2)
|
|||
return (ts1 < ts2) ? (ts2 - ts1) : (ts1 - ts2);
|
||||
}
|
||||
|
||||
static void source_output_audio_line(obs_source_t *source,
|
||||
static inline size_t get_buf_placement(audio_t *audio, uint64_t offset)
|
||||
{
|
||||
uint32_t sample_rate = audio_output_get_sample_rate(audio);
|
||||
return (size_t)(offset * (uint64_t)sample_rate / 1000000000ULL);
|
||||
}
|
||||
|
||||
static void source_output_audio_place(obs_source_t *source,
|
||||
const struct audio_data *in)
|
||||
{
|
||||
audio_t *audio = obs->audio.audio;
|
||||
size_t buf_placement;
|
||||
size_t channels = audio_output_get_channels(audio);
|
||||
size_t size = in->frames * sizeof(float);
|
||||
|
||||
if (!source->audio_ts || in->timestamp < source->audio_ts)
|
||||
reset_audio_data(source, in->timestamp);
|
||||
|
||||
buf_placement = get_buf_placement(audio,
|
||||
in->timestamp - source->audio_ts) * sizeof(float);
|
||||
|
||||
#if DEBUG_AUDIO == 1
|
||||
blog(LOG_DEBUG, "frames: %lu, size: %lu, placement: %lu, base_ts: %llu, ts: %llu",
|
||||
(unsigned long)in->frames,
|
||||
(unsigned long)source->audio_input_buf[0].size,
|
||||
(unsigned long)buf_placement,
|
||||
source->audio_ts,
|
||||
in->timestamp);
|
||||
#endif
|
||||
|
||||
for (size_t i = 0; i < channels; i++)
|
||||
circlebuf_place(&source->audio_input_buf[i], buf_placement,
|
||||
in->data[i], size);
|
||||
}
|
||||
|
||||
static inline void source_output_audio_push_back(obs_source_t *source,
|
||||
const struct audio_data *in)
|
||||
{
|
||||
audio_t *audio = obs->audio.audio;
|
||||
size_t channels = audio_output_get_channels(audio);
|
||||
|
||||
for (size_t i = 0; i < channels; i++)
|
||||
circlebuf_push_back(&source->audio_input_buf[i],
|
||||
in->data[i], in->frames * sizeof(float));
|
||||
}
|
||||
|
||||
static void source_output_audio_data(obs_source_t *source,
|
||||
const struct audio_data *data)
|
||||
{
|
||||
size_t sample_rate = audio_output_get_sample_rate(obs->audio.audio);
|
||||
struct audio_data in = *data;
|
||||
uint64_t diff;
|
||||
uint64_t os_time = os_gettime_ns();
|
||||
bool using_direct_ts = false;
|
||||
bool push_back = false;
|
||||
|
||||
/* detects 'directly' set timestamps as long as they're within
|
||||
* a certain threshold */
|
||||
if (uint64_diff(in.timestamp, os_time) < MAX_TS_VAR) {
|
||||
source->timing_adjust = 0;
|
||||
source->timing_set = true;
|
||||
using_direct_ts = true;
|
||||
}
|
||||
|
||||
} else if (!source->timing_set) {
|
||||
if (!source->timing_set) {
|
||||
reset_audio_timing(source, in.timestamp, os_time);
|
||||
|
||||
} else if (source->next_audio_ts_min != 0) {
|
||||
diff = uint64_diff(source->next_audio_ts_min, in.timestamp);
|
||||
|
||||
/* smooth audio if within threshold */
|
||||
if (diff > MAX_TS_VAR)
|
||||
if (diff > MAX_TS_VAR && !using_direct_ts)
|
||||
handle_ts_jump(source, source->next_audio_ts_min,
|
||||
in.timestamp, diff, os_time);
|
||||
else if (diff < TS_SMOOTHING_THRESHOLD)
|
||||
|
@ -928,6 +1005,11 @@ static void source_output_audio_line(obs_source_t *source,
|
|||
source->present_volume * obs->audio.user_volume *
|
||||
obs->audio.present_volume;
|
||||
|
||||
if (source->next_audio_sys_ts_min == in.timestamp)
|
||||
push_back = true;
|
||||
source->next_audio_sys_ts_min = source->next_audio_ts_min +
|
||||
source->timing_adjust + source->sync_offset;
|
||||
|
||||
if (source->push_to_mute_enabled && source->push_to_mute_pressed)
|
||||
source->push_to_mute_stop_time = os_time +
|
||||
source->push_to_mute_delay * 1000000;
|
||||
|
@ -948,7 +1030,15 @@ static void source_output_audio_line(obs_source_t *source,
|
|||
if (muted)
|
||||
in.volume = 0.0f;
|
||||
|
||||
audio_line_output(source->audio_line, &in);
|
||||
pthread_mutex_lock(&source->audio_buf_mutex);
|
||||
|
||||
if (push_back)
|
||||
source_output_audio_push_back(source, &in);
|
||||
else
|
||||
source_output_audio_place(source, &in);
|
||||
|
||||
pthread_mutex_unlock(&source->audio_buf_mutex);
|
||||
|
||||
source_signal_audio_data(source, &in, muted);
|
||||
}
|
||||
|
||||
|
@ -2126,7 +2216,7 @@ void obs_source_output_audio(obs_source_t *source,
|
|||
data.timestamp = output->timestamp;
|
||||
|
||||
pthread_mutex_lock(&source->audio_mutex);
|
||||
source_output_audio_line(source, &data);
|
||||
source_output_audio_data(source, &data);
|
||||
pthread_mutex_unlock(&source->audio_mutex);
|
||||
}
|
||||
|
||||
|
@ -3192,3 +3282,25 @@ void *obs_source_get_type_data(obs_source_t *source)
|
|||
return obs_source_valid(source, "obs_source_get_type_data")
|
||||
? source->info.type_data : NULL;
|
||||
}
|
||||
|
||||
uint64_t obs_source_get_audio_timestamp(const obs_source_t *source)
|
||||
{
|
||||
return obs_source_valid(source, "obs_source_get_audio_timestamp") ?
|
||||
source->audio_ts : 0;
|
||||
}
|
||||
|
||||
void obs_source_get_audio_mix(const obs_source_t *source,
|
||||
struct obs_source_audio_mix *audio)
|
||||
{
|
||||
if (!obs_source_valid(source, "obs_source_get_audio_mix"))
|
||||
return;
|
||||
if (!obs_ptr_valid(audio, "audio"))
|
||||
return;
|
||||
|
||||
for (size_t mix = 0; mix < MAX_AUDIO_MIXES; mix++) {
|
||||
for (size_t ch = 0; ch < MAX_AUDIO_CHANNELS; ch++) {
|
||||
audio->output[mix].data[ch] =
|
||||
source->audio_output_buf[mix][ch];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -108,6 +108,10 @@ enum obs_source_type {
|
|||
typedef void (*obs_source_enum_proc_t)(obs_source_t *parent,
|
||||
obs_source_t *child, void *param);
|
||||
|
||||
struct obs_source_audio_mix {
|
||||
struct audio_output_data output[MAX_AUDIO_MIXES];
|
||||
};
|
||||
|
||||
/**
|
||||
* Source definition structure
|
||||
*/
|
||||
|
|
|
@ -986,6 +986,10 @@ EXPORT uint32_t obs_source_get_base_width(obs_source_t *source);
|
|||
/** Gets the base height for a source (not taking in to account filtering) */
|
||||
EXPORT uint32_t obs_source_get_base_height(obs_source_t *source);
|
||||
|
||||
EXPORT uint64_t obs_source_get_audio_timestamp(const obs_source_t *source);
|
||||
EXPORT void obs_source_get_audio_mix(const obs_source_t *source,
|
||||
struct obs_source_audio_mix *audio);
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* Scenes */
|
||||
|
|
Loading…
Reference in a new issue