summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/wasapi/audio_driver_wasapi.cpp88
1 files changed, 87 insertions, 1 deletions
diff --git a/drivers/wasapi/audio_driver_wasapi.cpp b/drivers/wasapi/audio_driver_wasapi.cpp
index 4c80e70a95..36acfb10d1 100644
--- a/drivers/wasapi/audio_driver_wasapi.cpp
+++ b/drivers/wasapi/audio_driver_wasapi.cpp
@@ -40,6 +40,76 @@ 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;
@@ -54,7 +124,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;
}
@@ -62,6 +132,11 @@ Error AudioDriverWASAPI::init_device(bool reinit) {
ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN);
}
+ hr = enumerator->RegisterEndpointNotificationCallback(&notif_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) {
@@ -148,6 +223,8 @@ Error AudioDriverWASAPI::finish_device() {
if (audio_client) {
if (active) {
audio_client->Stop();
+ audio_client->Release();
+ audio_client = NULL;
active = false;
}
}
@@ -323,6 +400,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) {