diff --git a/libobs/obs-audio.c b/libobs/obs-audio.c index 4a40e331a..e6b107b2b 100644 --- a/libobs/obs-audio.c +++ b/libobs/obs-audio.c @@ -442,6 +442,23 @@ static inline void release_audio_sources(struct obs_core_audio *audio) obs_source_release(audio->render_order.array[i]); } +static inline void execute_audio_tasks(void) +{ + struct obs_core_audio *audio = &obs->audio; + bool tasks_remaining = true; + + while (tasks_remaining) { + pthread_mutex_lock(&audio->task_mutex); + if (audio->tasks.size) { + struct obs_task_info info; + circlebuf_pop_front(&audio->tasks, &info, sizeof(info)); + info.task(info.param); + } + tasks_remaining = !!audio->tasks.size; + pthread_mutex_unlock(&audio->task_mutex); + } +} + bool audio_callback(void *param, uint64_t start_ts_in, uint64_t end_ts_in, uint64_t *out_ts, uint32_t mixers, struct audio_output_data *mixes) @@ -591,6 +608,8 @@ bool audio_callback(void *param, uint64_t start_ts_in, uint64_t end_ts_in, return false; } + execute_audio_tasks(); + UNUSED_PARAMETER(param); return true; } diff --git a/libobs/obs-internal.h b/libobs/obs-internal.h index 13e8c7ed1..db6723cdf 100644 --- a/libobs/obs-internal.h +++ b/libobs/obs-internal.h @@ -339,6 +339,9 @@ struct obs_core_audio { DARRAY(struct audio_monitor *) monitors; char *monitoring_device_name; char *monitoring_device_id; + + pthread_mutex_t task_mutex; + struct circlebuf tasks; }; /* user sources, output channels, and displays */ diff --git a/libobs/obs.c b/libobs/obs.c index 2a8fbc7e1..39dfaa83b 100644 --- a/libobs/obs.c +++ b/libobs/obs.c @@ -560,6 +560,8 @@ static void obs_free_graphics(void) } } +static void set_audio_thread(void *unused); + static bool obs_init_audio(struct audio_output_info *ai) { struct obs_core_audio *audio = &obs->audio; @@ -569,6 +571,11 @@ static bool obs_init_audio(struct audio_output_info *ai) if (pthread_mutex_init_recursive(&audio->monitoring_mutex) != 0) return false; + if (pthread_mutex_init(&audio->task_mutex, NULL) != 0) + return false; + + struct obs_task_info audio_init = {.task = set_audio_thread}; + circlebuf_push_back(&audio->tasks, &audio_init, sizeof(audio_init)); audio->user_volume = 1.0f; @@ -609,6 +616,8 @@ static void obs_free_audio(void) da_free(audio->monitors); bfree(audio->monitoring_device_name); bfree(audio->monitoring_device_id); + circlebuf_free(&audio->tasks); + pthread_mutex_destroy(&audio->task_mutex); pthread_mutex_destroy(&audio->monitoring_mutex); memset(audio, 0, sizeof(struct obs_core_audio)); @@ -838,6 +847,7 @@ static bool obs_init(const char *locale, const char *module_config_path, obs = bzalloc(sizeof(struct obs_core)); pthread_mutex_init_value(&obs->audio.monitoring_mutex); + pthread_mutex_init_value(&obs->audio.task_mutex); pthread_mutex_init_value(&obs->video.gpu_encoder_mutex); pthread_mutex_init_value(&obs->video.task_mutex); @@ -2511,11 +2521,19 @@ struct task_wait_info { static void task_wait_callback(void *param) { struct task_wait_info *info = param; - info->task(info->param); + if (info->task) + info->task(info->param); os_event_signal(info->event); } THREAD_LOCAL bool is_graphics_thread = false; +THREAD_LOCAL bool is_audio_thread = false; + +static void set_audio_thread(void *unused) +{ + is_audio_thread = true; + UNUSED_PARAMETER(unused); +} static bool in_task_thread(enum obs_task_type type) { @@ -2523,6 +2541,8 @@ static bool in_task_thread(enum obs_task_type type) if (type == OBS_TASK_GRAPHICS) return is_graphics_thread; + else if (type == OBS_TASK_AUDIO) + return is_audio_thread; assert(false); return false; @@ -2541,6 +2561,7 @@ void obs_queue_task(enum obs_task_type type, obs_task_t task, void *param, } else { if (in_task_thread(type)) { task(param); + } else if (wait) { struct task_wait_info info = { .task = task, @@ -2551,13 +2572,22 @@ void obs_queue_task(enum obs_task_type type, obs_task_t task, void *param, obs_queue_task(type, task_wait_callback, &info, false); os_event_wait(info.event); os_event_destroy(info.event); - } else { + + } else if (type == OBS_TASK_GRAPHICS) { struct obs_core_video *video = &obs->video; struct obs_task_info info = {task, param}; pthread_mutex_lock(&video->task_mutex); circlebuf_push_back(&video->tasks, &info, sizeof(info)); pthread_mutex_unlock(&video->task_mutex); + + } else if (type == OBS_TASK_AUDIO) { + struct obs_core_audio *audio = &obs->audio; + struct obs_task_info info = {task, param}; + + pthread_mutex_lock(&audio->task_mutex); + circlebuf_push_back(&audio->tasks, &info, sizeof(info)); + pthread_mutex_unlock(&audio->task_mutex); } } } diff --git a/libobs/obs.h b/libobs/obs.h index bc45ab79f..fa0d12e87 100644 --- a/libobs/obs.h +++ b/libobs/obs.h @@ -796,6 +796,7 @@ typedef void (*obs_task_t)(void *param); enum obs_task_type { OBS_TASK_UI, OBS_TASK_GRAPHICS, + OBS_TASK_AUDIO, }; EXPORT void obs_queue_task(enum obs_task_type type, obs_task_t task,