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

(cherry picked from commit d5afcf7ab1)
This commit is contained in:
Marcelo Fernandez 2018-01-19 17:55:20 -03:00 committed by Hein-Pieter van Braam
parent 801b544ee1
commit 906cf28dae
1 changed files with 87 additions and 1 deletions

View File

@ -40,6 +40,76 @@ const IID IID_IMMDeviceEnumerator = __uuidof(IMMDeviceEnumerator);
const IID IID_IAudioClient = __uuidof(IAudioClient); const IID IID_IAudioClient = __uuidof(IAudioClient);
const IID IID_IAudioRenderClient = __uuidof(IAudioRenderClient); 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) { Error AudioDriverWASAPI::init_device(bool reinit) {
WAVEFORMATEX *pwfex; WAVEFORMATEX *pwfex;
@ -54,7 +124,7 @@ Error AudioDriverWASAPI::init_device(bool reinit) {
hr = enumerator->GetDefaultAudioEndpoint(eRender, eConsole, &device); hr = enumerator->GetDefaultAudioEndpoint(eRender, eConsole, &device);
if (reinit) { if (reinit) {
// In case we're trying to re-initialize the device prevent throwing this error on the console, // 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) { if (hr != S_OK) {
return ERR_CANT_OPEN; return ERR_CANT_OPEN;
} }
@ -62,6 +132,11 @@ Error AudioDriverWASAPI::init_device(bool reinit) {
ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN); 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); hr = device->Activate(IID_IAudioClient, CLSCTX_ALL, NULL, (void **)&audio_client);
if (reinit) { if (reinit) {
if (hr != S_OK) { if (hr != S_OK) {
@ -148,6 +223,8 @@ Error AudioDriverWASAPI::finish_device() {
if (audio_client) { if (audio_client) {
if (active) { if (active) {
audio_client->Stop(); audio_client->Stop();
audio_client->Release();
audio_client = NULL;
active = false; 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) { if (!ad->audio_client) {
Error err = ad->init_device(true); Error err = ad->init_device(true);
if (err == OK) { if (err == OK) {