From 7af886581d99c230c52c3fc7dc97608798ea8da0 Mon Sep 17 00:00:00 2001 From: jpark37 Date: Fri, 1 Oct 2021 21:41:50 -0700 Subject: [PATCH] libobs/audio-monitoring: Add WASAPI init helper audio_monitor_init_wasapi will be used for reconnect logic. --- libobs/audio-monitoring/win32/wasapi-output.c | 238 +++++++++--------- 1 file changed, 122 insertions(+), 116 deletions(-) diff --git a/libobs/audio-monitoring/win32/wasapi-output.c b/libobs/audio-monitoring/win32/wasapi-output.c index 55c17d79e..1f8adaff0 100644 --- a/libobs/audio-monitoring/win32/wasapi-output.c +++ b/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)