Browse Source

libobs: Add ability to queue audio task

This is mostly framework for allowing the ability to wait for certain
threads
jp9000 3 years ago
parent
commit
cf492ca271
4 changed files with 55 additions and 2 deletions
  1. 19 0
      libobs/obs-audio.c
  2. 3 0
      libobs/obs-internal.h
  3. 32 2
      libobs/obs.c
  4. 1 0
      libobs/obs.h

+ 19 - 0
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;
 }

+ 3 - 0
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 */

+ 32 - 2
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);
 		}
 	}
 }

+ 1 - 0
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,