129 lines
3.6 KiB
C++
129 lines
3.6 KiB
C++
|
#include "device.h"
|
||
|
|
||
|
#include <mutex>
|
||
|
|
||
|
#include <audioclient.h>
|
||
|
#include <endpointvolume.h>
|
||
|
|
||
|
#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<IAudioClient *>(*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<IAudioEndpointVolume *>(*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));
|
||
|
}
|