mirror of
https://github.com/spice2x/spice2x.github.io.git
synced 2026-08-02 06:40:42 -07:00
a6f29d6a5a
## Link to GitHub Issue, if one exists Fixes #509 ## Description of change Implement `WrappedIAudioClient3`. For now, we have only seen SDVX use it (EG final) and only when the shared mode patch is enabled. Exclusive still goes through version 1. This means that for V3 we can forego implementing backend conversion logic (for now). Only significant addition is `InitializeSharedAudioStream` and this IS called by SDVX when shared mode patch is enabled. ## Testing Tested EG final, tested year 1 data, also IIDX shared/exclusive wasapi.
129 lines
3.9 KiB
C++
129 lines
3.9 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"
|
|
#include "util/utils.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) {
|
|
log_misc("audio::mmdevice", "WrappedIMMDevice::Release");
|
|
delete this;
|
|
}
|
|
|
|
return refs;
|
|
}
|
|
|
|
// IMMDevice
|
|
HRESULT STDMETHODCALLTYPE WrappedIMMDevice::Activate(
|
|
REFIID iid,
|
|
DWORD dwClsCtx,
|
|
PROPVARIANT *pActivationParams,
|
|
void **ppInterface)
|
|
{
|
|
log_misc("audio::mmdevice", "WrappedIMMDevice::Activate {}", guid2s(iid));
|
|
|
|
// call original
|
|
HRESULT ret = pReal->Activate(iid, dwClsCtx, pActivationParams, ppInterface);
|
|
|
|
// check for failure
|
|
if (FAILED(ret)) {
|
|
PRINT_FAILED_RESULT("IMMDevice::Activate", ret);
|
|
return ret;
|
|
}
|
|
|
|
// almost all games request IAudioClient
|
|
// so far we have not seen any games request IAudioClient2
|
|
// SDVX EG Final uses IID_IAudioClient3, but only when shared mode patch is on
|
|
if (iid == IID_IAudioClient || iid == IID_IAudioClient3) {
|
|
|
|
// 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);
|
|
|
|
// release old audio client if initialized
|
|
if (hooks::audio::CLIENT) {
|
|
hooks::audio::CLIENT->Release();
|
|
}
|
|
|
|
IAudioClient *client = nullptr;
|
|
if (iid == IID_IAudioClient) {
|
|
client = wrap_audio_client(reinterpret_cast<IAudioClient *>(*ppInterface));
|
|
} else { // IID_IAudioClient3
|
|
client = wrap_audio_client3(reinterpret_cast<IAudioClient3 *>(*ppInterface));
|
|
}
|
|
*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));
|
|
}
|