Update to spice2x-25-04-25 (pre-apply)
> broken commit
This commit is contained in:
@@ -0,0 +1,112 @@
|
||||
#include "audio_endpoint_volume.h"
|
||||
#include "util/logging.h"
|
||||
|
||||
HRESULT STDMETHODCALLTYPE WrappedIAudioEndpointVolume::QueryInterface(REFIID riid, void **ppvObj) {
|
||||
if (ppvObj == nullptr) {
|
||||
return E_POINTER;
|
||||
}
|
||||
|
||||
if (riid == __uuidof(IAudioEndpointVolume)) {
|
||||
this->AddRef();
|
||||
*ppvObj = this;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
return pReal->QueryInterface(riid, ppvObj);
|
||||
}
|
||||
|
||||
ULONG STDMETHODCALLTYPE WrappedIAudioEndpointVolume::AddRef() {
|
||||
return pReal->AddRef();
|
||||
}
|
||||
|
||||
ULONG STDMETHODCALLTYPE WrappedIAudioEndpointVolume::Release() {
|
||||
|
||||
// get reference count of underlying interface
|
||||
ULONG refs = pReal != nullptr ? pReal->Release() : 0;
|
||||
|
||||
if (refs == 0) {
|
||||
delete this;
|
||||
}
|
||||
|
||||
return refs;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE WrappedIAudioEndpointVolume::SetMasterVolumeLevelScalar(float fLevel, LPCGUID pguidEventContext) {
|
||||
log_misc("audio", "WrappedIAudioEndpointVolume::SetMasterVolumeLevelScalar called; ignoring volume change");
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE WrappedIAudioEndpointVolume::RegisterControlChangeNotify(IAudioEndpointVolumeCallback *pNotify) {
|
||||
return pReal->RegisterControlChangeNotify(pNotify);
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE WrappedIAudioEndpointVolume::UnregisterControlChangeNotify(IAudioEndpointVolumeCallback *pNotify) {
|
||||
return pReal->UnregisterControlChangeNotify(pNotify);
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE WrappedIAudioEndpointVolume::GetChannelCount(uint32_t *pnChannelCount) {
|
||||
return pReal->GetChannelCount(pnChannelCount);
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE WrappedIAudioEndpointVolume::SetMasterVolumeLevel(float fLevelDB, LPCGUID pguidEventContext) {
|
||||
log_misc("audio", "WrappedIAudioEndpointVolume::SetMasterVolumeLevel called; ignoring volume change");
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE WrappedIAudioEndpointVolume::GetMasterVolumeLevel(float *fLevelDB) {
|
||||
return pReal->GetMasterVolumeLevel(fLevelDB);
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE WrappedIAudioEndpointVolume::GetMasterVolumeLevelScalar(float *fLevel) {
|
||||
return pReal->GetMasterVolumeLevelScalar(fLevel);
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE WrappedIAudioEndpointVolume::SetChannelVolumeLevel(uint32_t nChannel, float fLevelDB, LPCGUID pguidEventContext) {
|
||||
log_misc("audio", "WrappedIAudioEndpointVolume::SetChannelVolumeLevel called; ignoring volume change");
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE WrappedIAudioEndpointVolume::SetChannelVolumeLevelScalar(uint32_t nChannel, float fLevel, LPCGUID pguidEventContext) {
|
||||
log_misc("audio", "WrappedIAudioEndpointVolume::SetChannelVolumeLevelScalar called; ignoring volume change");
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE WrappedIAudioEndpointVolume::GetChannelVolumeLevel(uint32_t nChannel, float *fLevelDB) {
|
||||
return pReal->GetChannelVolumeLevel(nChannel, fLevelDB);
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE WrappedIAudioEndpointVolume::GetChannelVolumeLevelScalar(uint32_t nChannel, float *fLevel) {
|
||||
return pReal->GetChannelVolumeLevelScalar(nChannel, fLevel);
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE WrappedIAudioEndpointVolume::SetMute(WINBOOL bMute, LPCGUID pguidEventContext) {
|
||||
log_misc("audio", "WrappedIAudioEndpointVolume::SetMute called; ignoring volume change");
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE WrappedIAudioEndpointVolume::GetMute(WINBOOL *bMute) {
|
||||
return pReal->GetMute(bMute);
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE WrappedIAudioEndpointVolume::GetVolumeStepInfo(uint32_t *pnStep, uint32_t *pnStepCount) {
|
||||
return pReal->GetVolumeStepInfo(pnStep, pnStepCount);
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE WrappedIAudioEndpointVolume::VolumeStepUp(LPCGUID pguidEventContext) {
|
||||
log_misc("audio", "WrappedIAudioEndpointVolume::VolumeStepUp called; ignoring volume change");
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE WrappedIAudioEndpointVolume::VolumeStepDown(LPCGUID pguidEventContext) {
|
||||
log_misc("audio", "WrappedIAudioEndpointVolume::VolumeStepDown called; ignoring volume change");
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE WrappedIAudioEndpointVolume::QueryHardwareSupport(DWORD *pdwHardwareSupportMask) {
|
||||
return pReal->QueryHardwareSupport(pdwHardwareSupportMask);
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE WrappedIAudioEndpointVolume::GetVolumeRange(float *pflVolumeMindB, float *pflVolumeMaxdB, float *pflVolumeIncrementdB) {
|
||||
return pReal->GetVolumeRange(pflVolumeMindB, pflVolumeMaxdB, pflVolumeIncrementdB);
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <endpointvolume.h>
|
||||
|
||||
struct WrappedIAudioEndpointVolume : IAudioEndpointVolume {
|
||||
explicit WrappedIAudioEndpointVolume(IAudioEndpointVolume *orig) : pReal(orig) {}
|
||||
|
||||
WrappedIAudioEndpointVolume(const WrappedIAudioEndpointVolume &) = delete;
|
||||
WrappedIAudioEndpointVolume &operator=(const WrappedIAudioEndpointVolume &) = delete;
|
||||
|
||||
virtual ~WrappedIAudioEndpointVolume() = default;
|
||||
|
||||
#pragma region IUnknown
|
||||
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObj) override;
|
||||
ULONG STDMETHODCALLTYPE AddRef() override;
|
||||
ULONG STDMETHODCALLTYPE Release() override;
|
||||
#pragma endregion
|
||||
|
||||
#pragma region IAudioEndpointVolume
|
||||
HRESULT STDMETHODCALLTYPE RegisterControlChangeNotify(IAudioEndpointVolumeCallback *pNotify) override;
|
||||
HRESULT STDMETHODCALLTYPE UnregisterControlChangeNotify(IAudioEndpointVolumeCallback *pNotify) override;
|
||||
HRESULT STDMETHODCALLTYPE GetChannelCount(uint32_t *pnChannelCount) override;
|
||||
HRESULT STDMETHODCALLTYPE SetMasterVolumeLevel(float fLevelDB, LPCGUID pguidEventContext) override;
|
||||
HRESULT STDMETHODCALLTYPE SetMasterVolumeLevelScalar(float fLevel, LPCGUID pguidEventContext) override;
|
||||
HRESULT STDMETHODCALLTYPE GetMasterVolumeLevel(float *fLevelDB) override;
|
||||
HRESULT STDMETHODCALLTYPE GetMasterVolumeLevelScalar(float *fLevel) override;
|
||||
HRESULT STDMETHODCALLTYPE SetChannelVolumeLevel(uint32_t nChannel, float fLevelDB, LPCGUID pguidEventContext) override;
|
||||
HRESULT STDMETHODCALLTYPE SetChannelVolumeLevelScalar(uint32_t nChannel, float fLevel, LPCGUID pguidEventContext) override;
|
||||
HRESULT STDMETHODCALLTYPE GetChannelVolumeLevel(uint32_t nChannel, float *fLevelDB) override;
|
||||
HRESULT STDMETHODCALLTYPE GetChannelVolumeLevelScalar(uint32_t nChannel, float *fLevel) override;
|
||||
HRESULT STDMETHODCALLTYPE SetMute(WINBOOL bMute, LPCGUID pguidEventContext) override;
|
||||
HRESULT STDMETHODCALLTYPE GetMute(WINBOOL *bMute) override;
|
||||
HRESULT STDMETHODCALLTYPE GetVolumeStepInfo(uint32_t *pnStep, uint32_t *pnStepCount) override;
|
||||
HRESULT STDMETHODCALLTYPE VolumeStepUp(LPCGUID pguidEventContext) override;
|
||||
HRESULT STDMETHODCALLTYPE VolumeStepDown(LPCGUID pguidEventContext) override;
|
||||
HRESULT STDMETHODCALLTYPE QueryHardwareSupport(DWORD *pdwHardwareSupportMask) override;
|
||||
HRESULT STDMETHODCALLTYPE GetVolumeRange(float *pflVolumeMindB, float *pflVolumeMaxdB, float *pflVolumeIncrementdB) override;
|
||||
#pragma endregion
|
||||
|
||||
private:
|
||||
IAudioEndpointVolume *const pReal;
|
||||
};
|
||||
@@ -3,8 +3,10 @@
|
||||
#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) \
|
||||
@@ -108,6 +110,9 @@ HRESULT STDMETHODCALLTYPE WrappedIMMDevice::Activate(
|
||||
// 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;
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
#include "device_enumerator.h"
|
||||
|
||||
#include "util/logging.h"
|
||||
|
||||
#include "device.h"
|
||||
#include "util/utils.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
DEFINE_GUID(IID_IMMDeviceEnumerator,
|
||||
@@ -61,6 +59,38 @@ HRESULT STDMETHODCALLTYPE WrappedIMMDeviceEnumerator::GetDefaultAudioEndpoint(
|
||||
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);
|
||||
|
||||
|
||||
@@ -0,0 +1,153 @@
|
||||
#include "low_latency_client.h"
|
||||
#include "util/logging.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
DEFINE_GUID(CLSID_MMDeviceEnumerator,
|
||||
0xBCDE0395, 0xE52F, 0x467C,
|
||||
0x8E, 0x3D, 0xC4, 0x57, 0x92, 0x91, 0x69, 0x2E);
|
||||
#endif
|
||||
|
||||
#define PRINT_FAILED_RESULT(name, ret) \
|
||||
log_warning("audio::lowlatency", "{} failed, hr={}", name, FMT_HRESULT(ret))
|
||||
|
||||
namespace hooks::audio {
|
||||
bool LOW_LATENCY_SHARED_WASAPI = false;
|
||||
static bool COM_INITIALIZED = false;
|
||||
static LowLatencyAudioClient *LOW_LATENCY_CLIENT = nullptr;
|
||||
|
||||
void init_low_latency() {
|
||||
if (!LOW_LATENCY_SHARED_WASAPI) {
|
||||
return;
|
||||
}
|
||||
log_info("audio::lowlatency", "initializing");
|
||||
|
||||
HRESULT hr;
|
||||
|
||||
// initialize COM
|
||||
COM_INITIALIZED = true;
|
||||
hr = CoInitialize(NULL);
|
||||
if (FAILED(hr)) {
|
||||
PRINT_FAILED_RESULT("CoInitialize", hr);
|
||||
return;
|
||||
}
|
||||
|
||||
// initialize device enumerator
|
||||
IMMDeviceEnumerator* enumerator;
|
||||
hr = CoCreateInstance(
|
||||
CLSID_MMDeviceEnumerator,
|
||||
NULL,
|
||||
CLSCTX_ALL,
|
||||
IID_IMMDeviceEnumerator,
|
||||
reinterpret_cast<void**>(&enumerator));
|
||||
if (FAILED(hr)) {
|
||||
PRINT_FAILED_RESULT("CoCreateInstance(CLSID_MMDeviceEnumerator)", hr);
|
||||
return;
|
||||
}
|
||||
|
||||
// get default audio endpoint from enumerator
|
||||
IMMDevice* device;
|
||||
hr = enumerator->GetDefaultAudioEndpoint(eRender, eConsole, &device);
|
||||
if (FAILED(hr)) {
|
||||
PRINT_FAILED_RESULT("GetDefaultAudioEndpoint", hr);
|
||||
return;
|
||||
}
|
||||
enumerator->Release();
|
||||
|
||||
// start the client using the default audio endpoint
|
||||
LOW_LATENCY_CLIENT = hooks::audio::LowLatencyAudioClient::Create(device);
|
||||
log_info("audio::lowlatency", "initialized");
|
||||
}
|
||||
|
||||
void stop_low_latency() {
|
||||
if (!LOW_LATENCY_SHARED_WASAPI) {
|
||||
return;
|
||||
}
|
||||
log_info("audio::lowlatency", "stopping");
|
||||
if (LOW_LATENCY_CLIENT) {
|
||||
delete LOW_LATENCY_CLIENT;
|
||||
LOW_LATENCY_CLIENT = nullptr;
|
||||
}
|
||||
if (COM_INITIALIZED) {
|
||||
COM_INITIALIZED = false;
|
||||
CoUninitialize();
|
||||
}
|
||||
log_info("audio::lowlatency", "stopped");
|
||||
}
|
||||
}
|
||||
|
||||
using namespace hooks::audio;
|
||||
|
||||
LowLatencyAudioClient::LowLatencyAudioClient(IAudioClient3* audioClient) : audioClient(audioClient) {}
|
||||
|
||||
LowLatencyAudioClient::~LowLatencyAudioClient() {
|
||||
if (this->audioClient) {
|
||||
HRESULT ret;
|
||||
ret = this->audioClient->Stop();
|
||||
if (FAILED(ret)) {
|
||||
PRINT_FAILED_RESULT("IAudioClient3::Stop", ret);
|
||||
}
|
||||
this->audioClient->Release();
|
||||
this->audioClient = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
LowLatencyAudioClient *LowLatencyAudioClient::Create(IMMDevice *device) {
|
||||
HRESULT ret;
|
||||
UINT32 minPeriod;
|
||||
UINT32 defaultPeriod;
|
||||
UINT32 fundamentalPeriod;
|
||||
UINT32 maxPeriod;
|
||||
PWAVEFORMATEX pFormat;
|
||||
IAudioClient3* audioClient;
|
||||
|
||||
ret = device->Activate(__uuidof(IAudioClient3), CLSCTX_ALL, NULL, reinterpret_cast<void**>(&audioClient));
|
||||
device->Release();
|
||||
if (FAILED(ret)) {
|
||||
PRINT_FAILED_RESULT("IMMDevice::Activate(IID_IAudioClient3...)", ret);
|
||||
log_warning("audio::lowlatency", "note that only Windows 10 and above supports IAudioClient3");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ret = audioClient->GetMixFormat(&pFormat);
|
||||
if (FAILED(ret)) {
|
||||
PRINT_FAILED_RESULT("IAudioClient3::GetMixFormat", ret);
|
||||
audioClient->Release();
|
||||
audioClient = nullptr;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ret = audioClient->GetSharedModeEnginePeriod(pFormat, &defaultPeriod, &fundamentalPeriod, &minPeriod, &maxPeriod);
|
||||
if (FAILED(ret)) {
|
||||
PRINT_FAILED_RESULT("IAudioClient3::GetSharedModeEnginePeriod", ret);
|
||||
audioClient->Release();
|
||||
audioClient = nullptr;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ret = audioClient->InitializeSharedAudioStream(0, minPeriod, pFormat, NULL);
|
||||
if (FAILED(ret)) {
|
||||
PRINT_FAILED_RESULT("IAudioClient3::InitializeSharedAudioStream", ret);
|
||||
audioClient->Release();
|
||||
audioClient = nullptr;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ret = audioClient->Start();
|
||||
if (FAILED(ret)) {
|
||||
PRINT_FAILED_RESULT("IAudioClient3::Start", ret);
|
||||
audioClient->Release();
|
||||
audioClient = nullptr;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
log_info("audio::lowlatency", "low latency shared mode audio client initialized successfully.");
|
||||
log_info("audio::lowlatency", "this is NOT used to output sound...");
|
||||
log_info("audio::lowlatency", "but rather to reduce buffer sizes when the game requests an audio client at a later point");
|
||||
log_info("audio::lowlatency", "has no effect if the game uses exclusive WASAPI or ASIO!");
|
||||
log_info("audio::lowlatency", "... sample rate : {} Hz", pFormat->nSamplesPerSec);
|
||||
log_info("audio::lowlatency", "... min buffer size : {} samples ({} ms)", minPeriod, 1000.0f * minPeriod / pFormat->nSamplesPerSec);
|
||||
log_info("audio::lowlatency", "... max buffer size : {} samples ({} ms)", maxPeriod, 1000.0f * maxPeriod / pFormat->nSamplesPerSec);
|
||||
log_info("audio::lowlatency", "... default buffer size : {} samples ({} ms)", defaultPeriod, 1000.0f * defaultPeriod / pFormat->nSamplesPerSec);
|
||||
log_info("audio::lowlatency", "... Windows will use minimum buffer size (instead of default) for shared mode audio clients from now on");
|
||||
return new LowLatencyAudioClient(audioClient);
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
#include <initguid.h>
|
||||
#include <audioclient.h>
|
||||
#include <mmdeviceapi.h>
|
||||
|
||||
#include "hooks/audio/audio.h"
|
||||
|
||||
namespace hooks::audio {
|
||||
void init_low_latency();
|
||||
void stop_low_latency();
|
||||
|
||||
class LowLatencyAudioClient {
|
||||
public:
|
||||
static LowLatencyAudioClient *Create(IMMDevice *device);
|
||||
~LowLatencyAudioClient();
|
||||
|
||||
private:
|
||||
LowLatencyAudioClient(IAudioClient3* audioClient);
|
||||
IAudioClient3* audioClient;
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user