mirror of
https://github.com/spice2x/spice2x.github.io.git
synced 2026-08-02 14:50:41 -07:00
21f469b260
## Link to GitHub Issue, if one exists #477 ## Description of change Arena cab has two sound cards and it uses `WrappedIMMDeviceCollection` to set the volume to 100% on boot on both, instead of the typical `GetDefaultAudioEndpoint`. ## Testing Testing Delta, testing other games as well as they are affected.
121 lines
3.5 KiB
C++
121 lines
3.5 KiB
C++
#include "device_enumerator.h"
|
|
#include "device_collection.h"
|
|
#include "device.h"
|
|
#include "util/utils.h"
|
|
|
|
#ifdef _MSC_VER
|
|
DEFINE_GUID(IID_IMMDeviceEnumerator,
|
|
0xa95664d2, 0x9614, 0x4f35,
|
|
0xa7, 0x46, 0xde, 0x8d, 0xb6, 0x36, 0x17, 0xe6);
|
|
#endif
|
|
|
|
HRESULT STDMETHODCALLTYPE WrappedIMMDeviceEnumerator::QueryInterface(REFIID riid, void **ppvObj) {
|
|
if (ppvObj == nullptr) {
|
|
return E_POINTER;
|
|
}
|
|
|
|
if (riid == IID_IMMDeviceEnumerator) {
|
|
this->AddRef();
|
|
*ppvObj = this;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
return pReal->QueryInterface(riid, ppvObj);
|
|
}
|
|
ULONG STDMETHODCALLTYPE WrappedIMMDeviceEnumerator::AddRef() {
|
|
return pReal->AddRef();
|
|
}
|
|
ULONG STDMETHODCALLTYPE WrappedIMMDeviceEnumerator::Release() {
|
|
|
|
// get reference count of underlying interface
|
|
ULONG refs = pReal != nullptr ? pReal->Release() : 0;
|
|
|
|
if (refs == 0) {
|
|
delete this;
|
|
}
|
|
|
|
return refs;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE WrappedIMMDeviceEnumerator::EnumAudioEndpoints(
|
|
EDataFlow dataFlow,
|
|
DWORD dwStateMask,
|
|
IMMDeviceCollection **ppDevices)
|
|
{
|
|
const auto hr = pReal->EnumAudioEndpoints(dataFlow, dwStateMask, ppDevices);
|
|
if (SUCCEEDED(hr) && (ppDevices != nullptr) && (*ppDevices != nullptr)) {
|
|
*ppDevices = new WrappedIMMDeviceCollection(*ppDevices);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE WrappedIMMDeviceEnumerator::GetDefaultAudioEndpoint(
|
|
EDataFlow dataFlow,
|
|
ERole role,
|
|
IMMDevice **ppEndpoint)
|
|
{
|
|
// call orignal
|
|
HRESULT ret = this->pReal->GetDefaultAudioEndpoint(dataFlow, role, ppEndpoint);
|
|
|
|
// check for failure
|
|
if (FAILED(ret)) {
|
|
log_warning("audio", "IMMDeviceEnumerator::GetDefaultAudioEndpoint failed, hr={}", FMT_HRESULT(ret));
|
|
return ret;
|
|
}
|
|
|
|
// dump friendly name of audio endpoint
|
|
// https://learn.microsoft.com/en-us/windows/win32/coreaudio/device-properties?redirectedfrom=MSDN
|
|
{
|
|
IPropertyStore *pProps = nullptr;
|
|
HRESULT hr;
|
|
|
|
hr = (*ppEndpoint)->OpenPropertyStore(STGM_READ, &pProps);
|
|
if (SUCCEEDED(hr)) {
|
|
PROPVARIANT varName;
|
|
|
|
// instead of including giant windows headers, hardcoding the GUID here
|
|
PROPERTYKEY key;
|
|
GUID IDevice_FriendlyName = { 0xa45c254e, 0xdf1c, 0x4efd, { 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0 } };
|
|
key.pid = 14;
|
|
key.fmtid = IDevice_FriendlyName;
|
|
|
|
// get friendly name
|
|
PropVariantInit(&varName);
|
|
hr = pProps->GetValue(key, &varName);
|
|
if (SUCCEEDED(hr) && varName.vt != VT_EMPTY) {
|
|
log_info("audio", "IMMDeviceEnumerator::GetDefaultAudioEndpoint: using {}", ws2s(varName.pwszVal));
|
|
}
|
|
|
|
// cleanup
|
|
PropVariantClear(&varName);
|
|
}
|
|
if (pProps) {
|
|
pProps->Release();
|
|
pProps = nullptr;
|
|
}
|
|
}
|
|
|
|
// wrap interface
|
|
*ppEndpoint = new WrappedIMMDevice(*ppEndpoint);
|
|
|
|
// return original result
|
|
return ret;
|
|
}
|
|
HRESULT STDMETHODCALLTYPE WrappedIMMDeviceEnumerator::GetDevice(
|
|
LPCWSTR pwstrId,
|
|
IMMDevice **ppDevice)
|
|
{
|
|
return pReal->GetDevice(pwstrId, ppDevice);
|
|
}
|
|
HRESULT STDMETHODCALLTYPE WrappedIMMDeviceEnumerator::RegisterEndpointNotificationCallback(
|
|
IMMNotificationClient *pClient)
|
|
{
|
|
return pReal->RegisterEndpointNotificationCallback(pClient);
|
|
}
|
|
HRESULT STDMETHODCALLTYPE WrappedIMMDeviceEnumerator::UnregisterEndpointNotificationCallback(
|
|
IMMNotificationClient *pClient)
|
|
{
|
|
return pReal->UnregisterEndpointNotificationCallback(pClient);
|
|
}
|