diff --git a/drivers/wasapi/audio_driver_wasapi.cpp b/drivers/wasapi/audio_driver_wasapi.cpp index 68f7e3fa374..c725bc733c8 100644 --- a/drivers/wasapi/audio_driver_wasapi.cpp +++ b/drivers/wasapi/audio_driver_wasapi.cpp @@ -39,6 +39,69 @@ const IID IID_IMMDeviceEnumerator = __uuidof(IMMDeviceEnumerator); const IID IID_IAudioClient = __uuidof(IAudioClient); const IID IID_IAudioRenderClient = __uuidof(IAudioRenderClient); +static bool default_device_changed = false; + +class CMMNotificationClient : public IMMNotificationClient { + LONG _cRef; + IMMDeviceEnumerator *_pEnumerator; + +public: + CMMNotificationClient() : _cRef(1), _pEnumerator(NULL) { } + ~CMMNotificationClient() { if ((_pEnumerator) != NULL) { (_pEnumerator)->Release(); (_pEnumerator) = NULL; } } + + ULONG STDMETHODCALLTYPE AddRef() { + return InterlockedIncrement(&_cRef); + } + + ULONG STDMETHODCALLTYPE Release() { + ULONG ulRef = InterlockedDecrement(&_cRef); + if (0 == ulRef) { + delete this; + } + return ulRef; + } + + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, VOID **ppvInterface) { + if (IID_IUnknown == riid) { + AddRef(); + *ppvInterface = (IUnknown*)this; + } else if (__uuidof(IMMNotificationClient) == riid) { + AddRef(); + *ppvInterface = (IMMNotificationClient*)this; + } else { + *ppvInterface = NULL; + return E_NOINTERFACE; + } + return S_OK; + } + + HRESULT STDMETHODCALLTYPE OnDeviceAdded(LPCWSTR pwstrDeviceId) { + return S_OK; + }; + + HRESULT STDMETHODCALLTYPE OnDeviceRemoved(LPCWSTR pwstrDeviceId) { + return S_OK; + } + + HRESULT STDMETHODCALLTYPE OnDeviceStateChanged(LPCWSTR pwstrDeviceId, DWORD dwNewState) { + return S_OK; + } + + HRESULT STDMETHODCALLTYPE OnDefaultDeviceChanged(EDataFlow flow, ERole role, LPCWSTR pwstrDeviceId) { + if (flow == eRender && role == eConsole) { + default_device_changed = true; + } + + return S_OK; + } + + HRESULT STDMETHODCALLTYPE OnPropertyValueChanged(LPCWSTR pwstrDeviceId, const PROPERTYKEY key) { + return S_OK; + } +}; + +static CMMNotificationClient notif_client; + Error AudioDriverWASAPI::init_device(bool reinit) { WAVEFORMATEX *pwfex; @@ -53,7 +116,7 @@ Error AudioDriverWASAPI::init_device(bool reinit) { hr = enumerator->GetDefaultAudioEndpoint(eRender, eConsole, &device); if (reinit) { // In case we're trying to re-initialize the device prevent throwing this error on the console, - // otherwise if there is currently no devie available this will spam the console. + // otherwise if there is currently no device available this will spam the console. if (hr != S_OK) { return ERR_CANT_OPEN; } @@ -61,6 +124,11 @@ Error AudioDriverWASAPI::init_device(bool reinit) { ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN); } + hr = enumerator->RegisterEndpointNotificationCallback(¬if_client); + if (hr != S_OK) { + ERR_PRINT("WASAPI: RegisterEndpointNotificationCallback error"); + } + hr = device->Activate(IID_IAudioClient, CLSCTX_ALL, NULL, (void **)&audio_client); if (reinit) { if (hr != S_OK) { @@ -87,7 +155,7 @@ Error AudioDriverWASAPI::init_device(bool reinit) { break; default: - ERR_PRINTS("WASAPI: Unsupported number of channels (" + itos(wasapi_channels) + ")"); + WARN_PRINTS("WASAPI: Unsupported number of channels (" + itos(wasapi_channels) + ")"); channels = 2; } @@ -144,6 +212,8 @@ Error AudioDriverWASAPI::finish_device() { if (audio_client) { if (active) { audio_client->Stop(); + audio_client->Release(); + audio_client = NULL; active = false; } } @@ -319,6 +389,15 @@ void AudioDriverWASAPI::thread_func(void *p_udata) { } } + if (default_device_changed) { + Error err = ad->finish_device(); + if (err != OK) { + ERR_PRINT("WASAPI: finish_device error"); + } + + default_device_changed = false; + } + if (!ad->audio_client) { Error err = ad->init_device(true); if (err == OK) {