Browse Source

libobs: Make scenes mix audio of sub-sources

Mark scenes as composite sources and use audio_render to mix and output
the audio of their sub-sources.
jp9000 10 years ago
parent
commit
247a42c2a1
1 changed files with 77 additions and 1 deletions
  1. 77 1
      libobs/obs-scene.c

+ 77 - 1
libobs/obs-scene.c

@@ -482,15 +482,91 @@ static uint32_t scene_getheight(void *data)
 	return obs->video.base_height;
 }
 
+static inline void mix_audio(float *p_out, float *p_in,
+		size_t pos, size_t count)
+{
+	register float *out = p_out;
+	register float *in = p_in + pos;
+	register float *end = in + count;
+
+	while (in < end)
+		*(out++) += *(in++);
+}
+
+static bool scene_audio_render(void *data, uint64_t *ts_out,
+		struct obs_source_audio_mix *audio_output, uint32_t mixers,
+		size_t channels, size_t sample_rate)
+{
+	uint64_t timestamp = 0;
+	struct obs_source_audio_mix child_audio;
+	struct obs_scene *scene = data;
+	struct obs_scene_item *item;
+
+	audio_lock(scene);
+
+	item = scene->first_item;
+	while (item) {
+		if (!obs_source_audio_pending(item->source)) {
+			uint64_t source_ts =
+				obs_source_get_audio_timestamp(item->source);
+
+			if (!timestamp || source_ts < timestamp)
+				timestamp = source_ts;
+		}
+
+		item = item->next;
+	}
+
+	if (!timestamp) {
+		audio_unlock(scene);
+		return false;
+	}
+
+	item = scene->first_item;
+	while (item) {
+		uint64_t source_ts;
+		size_t pos, count;
+
+		if (obs_source_audio_pending(item->source)) {
+			item = item->next;
+			continue;
+		}
+
+		source_ts = obs_source_get_audio_timestamp(item->source);
+		pos = (size_t)ns_to_audio_frames(sample_rate,
+				source_ts - timestamp);
+		count = AUDIO_OUTPUT_FRAMES - pos;
+
+		obs_source_get_audio_mix(item->source, &child_audio);
+		for (size_t mix = 0; mix < MAX_AUDIO_MIXES; mix++) {
+			for (size_t ch = 0; ch < channels; ch++) {
+				float *out = audio_output->output[mix].data[ch];
+				float *in = child_audio.output[mix].data[ch];
+
+				mix_audio(out, in, pos, count);
+			}
+		}
+
+		item = item->next;
+	}
+
+	*ts_out = timestamp;
+	audio_unlock(scene);
+	return true;
+}
+
 const struct obs_source_info scene_info =
 {
 	.id            = "scene",
 	.type          = OBS_SOURCE_TYPE_INPUT,
-	.output_flags  = OBS_SOURCE_VIDEO | OBS_SOURCE_CUSTOM_DRAW,
+	.output_flags  = OBS_SOURCE_VIDEO |
+	                 OBS_SOURCE_CUSTOM_DRAW |
+	                 OBS_SOURCE_COMPOSITE,
 	.get_name      = scene_getname,
 	.create        = scene_create,
 	.destroy       = scene_destroy,
 	.video_render  = scene_video_render,
+	.audio_render  = scene_audio_render,
 	.get_width     = scene_getwidth,
 	.get_height    = scene_getheight,
 	.load          = scene_load,