瀏覽代碼

libobs/audio-monitoring: Add WASAPI init helper

audio_monitor_init_wasapi will be used for reconnect logic.
jpark37 4 年之前
父節點
當前提交
7af886581d
共有 1 個文件被更改,包括 122 次插入116 次删除
  1. 122 116
      libobs/audio-monitoring/win32/wasapi-output.c

+ 122 - 116
libobs/audio-monitoring/win32/wasapi-output.c

@@ -139,95 +139,6 @@ static bool process_audio_delay(struct audio_monitor *monitor, float **data,
 	return false;
 }
 
-static void on_audio_playback(void *param, obs_source_t *source,
-			      const struct audio_data *audio_data, bool muted)
-{
-	struct audio_monitor *monitor = param;
-	IAudioRenderClient *render = monitor->render;
-	uint8_t *resample_data[MAX_AV_PLANES];
-	float vol = source->user_volume;
-	uint32_t resample_frames;
-	uint64_t ts_offset;
-	bool success;
-	BYTE *output;
-
-	if (!TryAcquireSRWLockExclusive(&monitor->playback_mutex)) {
-		return;
-	}
-	if (os_atomic_load_long(&source->activate_refs) == 0) {
-		goto unlock;
-	}
-
-	success = audio_resampler_resample(
-		monitor->resampler, resample_data, &resample_frames, &ts_offset,
-		(const uint8_t *const *)audio_data->data,
-		(uint32_t)audio_data->frames);
-	if (!success) {
-		goto unlock;
-	}
-
-	UINT32 pad = 0;
-	monitor->client->lpVtbl->GetCurrentPadding(monitor->client, &pad);
-
-	bool decouple_audio = source->async_unbuffered &&
-			      source->async_decoupled;
-
-	if (monitor->source_has_video && !decouple_audio) {
-		uint64_t ts = audio_data->timestamp - ts_offset;
-
-		if (!process_audio_delay(monitor, (float **)(&resample_data[0]),
-					 &resample_frames, ts, pad)) {
-			goto unlock;
-		}
-	}
-
-	HRESULT hr =
-		render->lpVtbl->GetBuffer(render, resample_frames, &output);
-	if (FAILED(hr)) {
-		goto unlock;
-	}
-
-	if (!muted) {
-		/* apply volume */
-		if (!close_float(vol, 1.0f, EPSILON)) {
-			register float *cur = (float *)resample_data[0];
-			register float *end =
-				cur + resample_frames * monitor->channels;
-
-			while (cur < end)
-				*(cur++) *= vol;
-		}
-		memcpy(output, resample_data[0],
-		       resample_frames * monitor->channels * sizeof(float));
-	}
-
-	render->lpVtbl->ReleaseBuffer(render, resample_frames,
-				      muted ? AUDCLNT_BUFFERFLAGS_SILENT : 0);
-
-unlock:
-	ReleaseSRWLockExclusive(&monitor->playback_mutex);
-}
-
-static inline void audio_monitor_free(struct audio_monitor *monitor)
-{
-	if (monitor->ignore)
-		return;
-
-	if (monitor->source) {
-		obs_source_remove_audio_capture_callback(
-			monitor->source, on_audio_playback, monitor);
-	}
-
-	if (monitor->client)
-		monitor->client->lpVtbl->Stop(monitor->client);
-
-	safe_release(monitor->client);
-	safe_release(monitor->render);
-	audio_resampler_destroy(monitor->resampler);
-	circlebuf_free(&monitor->delay_buffer);
-	da_free(monitor->buf);
-}
-
 static enum speaker_layout convert_speaker_layout(DWORD layout, WORD channels)
 {
 	switch (layout) {
@@ -246,37 +157,14 @@ static enum speaker_layout convert_speaker_layout(DWORD layout, WORD channels)
 	return (enum speaker_layout)channels;
 }
 
-extern bool devices_match(const char *id1, const char *id2);
-
-static bool audio_monitor_init(struct audio_monitor *monitor,
-			       obs_source_t *source)
+static bool audio_monitor_init_wasapi(struct audio_monitor *monitor)
 {
+	bool success = false;
 	IMMDeviceEnumerator *immde = NULL;
 	WAVEFORMATEX *wfex = NULL;
-	bool success = false;
 	UINT32 frames;
 	HRESULT hr;
 
-	monitor->source = source;
-
-	const char *id = obs->audio.monitoring_device_id;
-	if (!id) {
-		warn("%s: No device ID set", __FUNCTION__);
-		return false;
-	}
-
-	if (source->info.output_flags & OBS_SOURCE_DO_NOT_SELF_MONITOR) {
-		obs_data_t *s = obs_source_get_settings(source);
-		const char *s_dev_id = obs_data_get_string(s, "device_id");
-		bool match = devices_match(s_dev_id, id);
-		obs_data_release(s);
-
-		if (match) {
-			monitor->ignore = true;
-			return true;
-		}
-	}
-
 	/* ------------------------------------------ *
 	 * Init device                                */
 
@@ -289,6 +177,7 @@ static bool audio_monitor_init(struct audio_monitor *monitor,
 	}
 
 	IMMDevice *device = NULL;
+	const char *const id = obs->audio.monitoring_device_id;
 	if (strcmp(id, "default") == 0) {
 		hr = immde->lpVtbl->GetDefaultAudioEndpoint(immde, eRender,
 							    eConsole, &device);
@@ -378,8 +267,6 @@ static bool audio_monitor_init(struct audio_monitor *monitor,
 		goto fail;
 	}
 
-	InitializeSRWLock(&monitor->playback_mutex);
-
 	success = true;
 
 fail:
@@ -389,6 +276,125 @@ fail:
 	return success;
 }
 
+static void on_audio_playback(void *param, obs_source_t *source,
+			      const struct audio_data *audio_data, bool muted)
+{
+	struct audio_monitor *monitor = param;
+	IAudioRenderClient *render = monitor->render;
+	uint8_t *resample_data[MAX_AV_PLANES];
+	float vol = source->user_volume;
+	uint32_t resample_frames;
+	uint64_t ts_offset;
+	bool success;
+	BYTE *output;
+
+	if (!TryAcquireSRWLockExclusive(&monitor->playback_mutex)) {
+		return;
+	}
+	if (os_atomic_load_long(&source->activate_refs) == 0) {
+		goto unlock;
+	}
+
+	success = audio_resampler_resample(
+		monitor->resampler, resample_data, &resample_frames, &ts_offset,
+		(const uint8_t *const *)audio_data->data,
+		(uint32_t)audio_data->frames);
+	if (!success) {
+		goto unlock;
+	}
+
+	UINT32 pad = 0;
+	monitor->client->lpVtbl->GetCurrentPadding(monitor->client, &pad);
+
+	bool decouple_audio = source->async_unbuffered &&
+			      source->async_decoupled;
+
+	if (monitor->source_has_video && !decouple_audio) {
+		uint64_t ts = audio_data->timestamp - ts_offset;
+
+		if (!process_audio_delay(monitor, (float **)(&resample_data[0]),
+					 &resample_frames, ts, pad)) {
+			goto unlock;
+		}
+	}
+
+	HRESULT hr =
+		render->lpVtbl->GetBuffer(render, resample_frames, &output);
+	if (FAILED(hr)) {
+		goto unlock;
+	}
+
+	if (!muted) {
+		/* apply volume */
+		if (!close_float(vol, 1.0f, EPSILON)) {
+			register float *cur = (float *)resample_data[0];
+			register float *end =
+				cur + resample_frames * monitor->channels;
+
+			while (cur < end)
+				*(cur++) *= vol;
+		}
+		memcpy(output, resample_data[0],
+		       resample_frames * monitor->channels * sizeof(float));
+	}
+
+	render->lpVtbl->ReleaseBuffer(render, resample_frames,
+				      muted ? AUDCLNT_BUFFERFLAGS_SILENT : 0);
+
+unlock:
+	ReleaseSRWLockExclusive(&monitor->playback_mutex);
+}
+
+static inline void audio_monitor_free(struct audio_monitor *monitor)
+{
+	if (monitor->ignore)
+		return;
+
+	if (monitor->source) {
+		obs_source_remove_audio_capture_callback(
+			monitor->source, on_audio_playback, monitor);
+	}
+
+	if (monitor->client)
+		monitor->client->lpVtbl->Stop(monitor->client);
+
+	safe_release(monitor->client);
+	safe_release(monitor->render);
+	audio_resampler_destroy(monitor->resampler);
+	circlebuf_free(&monitor->delay_buffer);
+	da_free(monitor->buf);
+}
+
+extern bool devices_match(const char *id1, const char *id2);
+
+static bool audio_monitor_init(struct audio_monitor *monitor,
+			       obs_source_t *source)
+{
+	monitor->source = source;
+
+	const char *id = obs->audio.monitoring_device_id;
+	if (!id) {
+		warn("%s: No device ID set", __FUNCTION__);
+		return false;
+	}
+
+	if (source->info.output_flags & OBS_SOURCE_DO_NOT_SELF_MONITOR) {
+		obs_data_t *s = obs_source_get_settings(source);
+		const char *s_dev_id = obs_data_get_string(s, "device_id");
+		bool match = devices_match(s_dev_id, id);
+		obs_data_release(s);
+
+		if (match) {
+			monitor->ignore = true;
+			return true;
+		}
+	}
+
+	InitializeSRWLock(&monitor->playback_mutex);
+
+	return audio_monitor_init_wasapi(monitor);
+}
+
 static void audio_monitor_init_final(struct audio_monitor *monitor)
 {
 	if (monitor->ignore)