mirror of
https://github.com/spice2x/spice2x.github.io.git
synced 2026-08-02 06:40:42 -07:00
61a0220c1a
## Link to GitHub Issue or related Pull Request, if one exists Fixes #782 ## Description of change This addresses an issue only seen on Linux + WINE. Defer retaining WASAPI clients until `Initialize` succeeds. Before this PR, temporary clients created during DirectShow device capability probing were retained as active audio clients, causing Wine/Linux crashes in DDR and popn. Also covers IAudioClient3, dummy, ASIO, WaveOut, and null-device initialization paths, for consistency. ## Testing WIP
121 lines
3.7 KiB
C++
121 lines
3.7 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);
|
|
|
|
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;
|
|
|
|
} 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));
|
|
}
|