#include "device.h" #include #include #include #include "hooks/audio/audio_private.h" #include "hooks/audio/backends/mmdevice/audio_endpoint_volume.h" #include "hooks/audio/backends/wasapi/audio_client.h" #define PRINT_FAILED_RESULT(name, ret) \ do { \ if (AUDIO_LOG_HRESULT) { \ log_warning("audio::mmdevice", "{} failed, hr={}", name, FMT_HRESULT(ret)); \ } \ } while (0) #define CHECK_RESULT(x) \ do { \ HRESULT __ret = (x); \ if (FAILED(__ret)) { \ PRINT_FAILED_RESULT(__FUNCTION__, __ret); \ } \ return __ret; \ } while (0) #ifdef _MSC_VER DEFINE_GUID(IID_IMMDevice, 0xd666063f, 0x1587, 0x4e43, 0x81, 0xf1, 0xb9, 0x48, 0xe8, 0x07, 0x36, 0x3f); #endif HRESULT STDMETHODCALLTYPE WrappedIMMDevice::QueryInterface(REFIID riid, void **ppvObj) { if (ppvObj == nullptr) { return E_POINTER; } if (riid == IID_WrappedIMMDevice || riid == IID_IMMDevice) { this->AddRef(); *ppvObj = this; return S_OK; } return pReal->QueryInterface(riid, ppvObj); } ULONG STDMETHODCALLTYPE WrappedIMMDevice::AddRef() { return pReal->AddRef(); } ULONG STDMETHODCALLTYPE WrappedIMMDevice::Release() { // get reference count of underlying interface ULONG refs = pReal != nullptr ? pReal->Release() : 0; if (refs == 0) { delete this; } return refs; } // IMMDevice HRESULT STDMETHODCALLTYPE WrappedIMMDevice::Activate( REFIID iid, DWORD dwClsCtx, PROPVARIANT *pActivationParams, void **ppInterface) { log_misc("audio::mmdevice", "WrappedIMMDevice::Activate"); // call original HRESULT ret = pReal->Activate(iid, dwClsCtx, pActivationParams, ppInterface); // check for failure if (FAILED(ret)) { PRINT_FAILED_RESULT("IMMDevice::Activate", ret); return ret; } if (iid == IID_IAudioClient) { // prevent initialization recursion when using some ASIO backends that proxy to DirectSound, WASAPI, or WDM // like ASIO4All or FlexASIO if (!hooks::audio::INITIALIZE_LOCK.try_lock()) { log_warning("audio::mmdevice", "ignoring wrap request while backend is initializing, possible recursion"); return ret; } std::lock_guard initialize_guard(hooks::audio::INITIALIZE_LOCK, std::adopt_lock); auto client = reinterpret_cast(*ppInterface); // release old audio client if initialized if (hooks::audio::CLIENT) { hooks::audio::CLIENT->Release(); } /* ret = wrap_audio_client(pReal, dwClsCtx, pActivationParams, &client); if (FAILED(ret)) { return ret; } */ client = wrap_audio_client(client); *ppInterface = client; // persist the audio client hooks::audio::CLIENT = client; hooks::audio::CLIENT->AddRef(); } else if (iid == __uuidof(IAudioEndpointVolume) && hooks::audio::VOLUME_HOOK_ENABLED) { *ppInterface = new WrappedIAudioEndpointVolume(reinterpret_cast(*ppInterface)); } return ret; } HRESULT STDMETHODCALLTYPE WrappedIMMDevice::OpenPropertyStore(DWORD stgmAccess, IPropertyStore **ppProperties) { CHECK_RESULT(pReal->OpenPropertyStore(stgmAccess, ppProperties)); } HRESULT STDMETHODCALLTYPE WrappedIMMDevice::GetId(LPWSTR *ppstrId) { CHECK_RESULT(pReal->GetId(ppstrId)); } HRESULT STDMETHODCALLTYPE WrappedIMMDevice::GetState(DWORD *pdwState) { CHECK_RESULT(pReal->GetState(pdwState)); }