Browse Source

Improved WASAPI driver so that it always uses the default audio device

Marcelo Fernandez 7 years ago
parent
commit
d5afcf7ab1
1 changed files with 87 additions and 1 deletions
  1. 87 1
      drivers/wasapi/audio_driver_wasapi.cpp

+ 87 - 1
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) {