mirror of
https://github.com/spice2x/spice2x.github.io.git
synced 2026-08-01 22:30:42 -07:00
6bcadccf09
## Link to GitHub Issue or related Pull Request, if one exists n/a ## Description of change This new option, `-wasapishared`, detects when the game opens WASAPI Exclusive stream and forcibly opens a shared mode stream instead on the real device. #### Benefits of this: 1. No need for `force wasapi shared` patches 2. No need to change sample rate of audio devices before starting up games 3. Adds ability to boot in shared mode even for games that do not have shared wasapi changes (old GITADORA, popn HC) As a result, this option is strictly better than `shared wasapi` patches available for many games. #### Downsides: 1. OS resampling will add a small latency, but not big enough to be noticeable. 2. Using shared mode instead of exclusive mode adds latency, of course. (If you cared about latency, you would use the low latency option, or use exclusive or asio) Basically it's the "make things work" button for audio that should work for almost all games that we support. The option has no effect if the game opens in shared mode. ## Testing SDVX7 - ok GITADORA GW - ok popn HC - ok IIDX - ok
117 lines
4.6 KiB
C
117 lines
4.6 KiB
C
#pragma once
|
|
|
|
#include <initguid.h>
|
|
#include <audioclient.h>
|
|
#include <mmdeviceapi.h>
|
|
|
|
#include "hooks/audio/implementations/backend.h"
|
|
#include "hooks/audio/audio_private.h"
|
|
#include "util/logging.h"
|
|
|
|
#include "downmix.h"
|
|
#include "resample.h"
|
|
#include "shared.h"
|
|
|
|
#include "audio_render_client.h"
|
|
// {1FBC8530-AF3E-4128-B418-115DE72F76B6}
|
|
static const GUID IID_WrappedIAudioClient = {
|
|
0x1fbc8530, 0xaf3e, 0x4128, { 0xb4, 0x18, 0x11, 0x5d, 0xe7, 0x2f, 0x76, 0xb6 }
|
|
};
|
|
|
|
IAudioClient *wrap_audio_client(IAudioClient *client);
|
|
IAudioClient3 *wrap_audio_client3(IAudioClient3 *client);
|
|
|
|
struct WrappedIAudioClient : IAudioClient3 {
|
|
|
|
explicit WrappedIAudioClient(IAudioClient3 *orig3, AudioBackend *backend) :
|
|
pReal(orig3), pReal3(orig3), backend(backend) {
|
|
}
|
|
|
|
explicit WrappedIAudioClient(IAudioClient *orig, AudioBackend *backend) :
|
|
pReal(orig), pReal3(nullptr), backend(backend) {
|
|
}
|
|
|
|
WrappedIAudioClient(const WrappedIAudioClient &) = delete;
|
|
WrappedIAudioClient &operator=(const WrappedIAudioClient &) = delete;
|
|
|
|
virtual ~WrappedIAudioClient() = default;
|
|
|
|
#pragma region IUnknown
|
|
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObj) override;
|
|
ULONG STDMETHODCALLTYPE AddRef() override;
|
|
ULONG STDMETHODCALLTYPE Release() override;
|
|
#pragma endregion
|
|
|
|
#pragma region IAudioClient
|
|
HRESULT STDMETHODCALLTYPE Initialize(AUDCLNT_SHAREMODE ShareMode, DWORD StreamFlags, REFERENCE_TIME hnsBufferDuration, REFERENCE_TIME hnsPeriodicity, const WAVEFORMATEX *pFormat, LPCGUID AudioSessionGuid) override;
|
|
HRESULT STDMETHODCALLTYPE GetBufferSize(UINT32 *pNumBufferFrames) override;
|
|
HRESULT STDMETHODCALLTYPE GetStreamLatency(REFERENCE_TIME *phnsLatency) override;
|
|
HRESULT STDMETHODCALLTYPE GetCurrentPadding(UINT32 *pNumPaddingFrames) override;
|
|
HRESULT STDMETHODCALLTYPE IsFormatSupported(AUDCLNT_SHAREMODE ShareMode, const WAVEFORMATEX *pFormat, WAVEFORMATEX **ppClosestMatch) override;
|
|
HRESULT STDMETHODCALLTYPE GetMixFormat(WAVEFORMATEX **ppDeviceFormat) override;
|
|
HRESULT STDMETHODCALLTYPE GetDevicePeriod(REFERENCE_TIME *phnsDefaultDevicePeriod, REFERENCE_TIME *phnsMinimumDevicePeriod) override;
|
|
HRESULT STDMETHODCALLTYPE Start() override;
|
|
HRESULT STDMETHODCALLTYPE Stop() override;
|
|
HRESULT STDMETHODCALLTYPE Reset() override;
|
|
HRESULT STDMETHODCALLTYPE SetEventHandle(HANDLE eventHandle) override;
|
|
HRESULT STDMETHODCALLTYPE GetService(REFIID riid, void **ppv) override;
|
|
#pragma endregion
|
|
|
|
#pragma region IAudioClient2
|
|
HRESULT STDMETHODCALLTYPE IsOffloadCapable(
|
|
AUDIO_STREAM_CATEGORY Category,
|
|
BOOL *pbOffloadCapable) override;
|
|
|
|
HRESULT STDMETHODCALLTYPE SetClientProperties(
|
|
const AudioClientProperties *pProperties) override;
|
|
|
|
HRESULT STDMETHODCALLTYPE GetBufferSizeLimits(
|
|
const WAVEFORMATEX *pFormat,
|
|
BOOL bEventDriven,
|
|
REFERENCE_TIME *phnsMinBufferDuration,
|
|
REFERENCE_TIME *phnsMaxBufferDuration) override;
|
|
#pragma endregion
|
|
|
|
#pragma region IAudioClient3
|
|
HRESULT STDMETHODCALLTYPE GetSharedModeEnginePeriod(
|
|
const WAVEFORMATEX *pFormat,
|
|
UINT32 *pDefaultPeriodInFrames,
|
|
UINT32 *pFundamentalPeriodInFrames,
|
|
UINT32 *pMinPeriodInFrames,
|
|
UINT32 *pMaxPeriodInFrames) override;
|
|
|
|
HRESULT STDMETHODCALLTYPE GetCurrentSharedModeEnginePeriod(
|
|
WAVEFORMATEX **ppFormat,
|
|
UINT32 *pCurrentPeriodInFrames) override;
|
|
|
|
HRESULT STDMETHODCALLTYPE InitializeSharedAudioStream(
|
|
DWORD StreamFlags,
|
|
UINT32 PeriodInFrames,
|
|
const WAVEFORMATEX *pFormat,
|
|
LPCGUID AudioSessionGuid) override;
|
|
#pragma endregion
|
|
|
|
IAudioClient *const pReal;
|
|
IAudioClient3 *const pReal3;
|
|
AudioBackend *const backend;
|
|
bool exclusive_mode = false;
|
|
|
|
// -wasapishared redirect state: when an exclusive request was redirected to shared mode, the
|
|
// engine converts the native format and the reported buffer size is clamped (see SharedRedirect).
|
|
hooks::audio::SharedRedirect shared;
|
|
int frame_size = 0;
|
|
|
|
// the format the real device was opened with (after any downmix). used to scale the final
|
|
// output buffer for the volume boost.
|
|
WAVEFORMATEXTENSIBLE device_format = {};
|
|
|
|
// surround -> stereo downmix. the real device is opened as stereo while the game keeps
|
|
// writing multi-channel audio into a scratch buffer that we downmix in the render client.
|
|
hooks::audio::Downmix downmix;
|
|
|
|
// native-rate -> target-rate sample-rate conversion. the real device is opened at the target
|
|
// rate while the game keeps writing its native-rate audio into a scratch buffer that we
|
|
// resample in the render client.
|
|
hooks::audio::Resampler resample;
|
|
};
|