audio: WASAPI Force Shared Mode option (#745)

## 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
This commit is contained in:
bicarus
2026-06-10 00:20:59 -07:00
committed by GitHub
parent ccb3bac48c
commit 6bcadccf09
11 changed files with 234 additions and 65 deletions
+1
View File
@@ -510,6 +510,7 @@ set(SOURCE_FILES ${SOURCE_FILES}
hooks/audio/backends/wasapi/audio_render_client.cpp hooks/audio/backends/wasapi/audio_render_client.cpp
hooks/audio/backends/wasapi/downmix.cpp hooks/audio/backends/wasapi/downmix.cpp
hooks/audio/backends/wasapi/resample.cpp hooks/audio/backends/wasapi/resample.cpp
hooks/audio/backends/wasapi/shared.cpp
hooks/audio/backends/wasapi/dummy_audio_client.cpp hooks/audio/backends/wasapi/dummy_audio_client.cpp
hooks/audio/backends/wasapi/dummy_audio_clock.cpp hooks/audio/backends/wasapi/dummy_audio_clock.cpp
hooks/audio/backends/wasapi/dummy_audio_render_client.cpp hooks/audio/backends/wasapi/dummy_audio_render_client.cpp
+1
View File
@@ -44,6 +44,7 @@ namespace hooks::audio {
float VOLUME_BOOST = 1.0f; float VOLUME_BOOST = 1.0f;
std::optional<uint32_t> RESAMPLE_RATE = std::nullopt; std::optional<uint32_t> RESAMPLE_RATE = std::nullopt;
std::optional<uint32_t> EXCLUSIVE_BUFFER_MS = std::nullopt; std::optional<uint32_t> EXCLUSIVE_BUFFER_MS = std::nullopt;
bool WASAPI_COMPATIBILITY_MODE = false;
bool USE_DUMMY = false; bool USE_DUMMY = false;
WAVEFORMATEXTENSIBLE FORMAT {}; WAVEFORMATEXTENSIBLE FORMAT {};
std::optional<Backend> BACKEND = std::nullopt; std::optional<Backend> BACKEND = std::nullopt;
+6
View File
@@ -37,6 +37,12 @@ namespace hooks::audio {
// minimum WASAPI exclusive buffer duration (milliseconds), if set. enlarges the device buffer // minimum WASAPI exclusive buffer duration (milliseconds), if set. enlarges the device buffer
// to avoid underrun crackle on endpoints that cannot service a tiny buffer in time. // to avoid underrun crackle on endpoints that cannot service a tiny buffer in time.
extern std::optional<uint32_t> EXCLUSIVE_BUFFER_MS; extern std::optional<uint32_t> EXCLUSIVE_BUFFER_MS;
// when true, WASAPI compatibility mode is active: exclusive-mode streams are redirected to
// shared mode. the Windows audio engine performs any required sample-rate / channel / bit-depth
// conversion, so the game's format is passed through unchanged and other applications can play
// audio simultaneously.
extern bool WASAPI_COMPATIBILITY_MODE;
extern bool USE_DUMMY; extern bool USE_DUMMY;
extern WAVEFORMATEXTENSIBLE FORMAT; extern WAVEFORMATEXTENSIBLE FORMAT;
extern std::optional<Backend> BACKEND; extern std::optional<Backend> BACKEND;
@@ -167,11 +167,26 @@ HRESULT STDMETHODCALLTYPE WrappedIAudioClient::Initialize(
fix_rec_format(const_cast<WAVEFORMATEX *>(pFormat)); fix_rec_format(const_cast<WAVEFORMATEX *>(pFormat));
} }
// when downmixing, open the real device as stereo while the game keeps writing its native // apply the -wasapishared option: redirect an exclusive request to shared mode. once redirected,
// multi-channel format into the scratch buffer. // spice's own downmix/resample paths below are skipped (gated on redirected_from_exclusive) and
// the shared engine handles any format conversion via AUTOCONVERTPCM (PCM / float only).
if (hooks::audio::SharedRedirect::wants(ShareMode, pFormat)) {
this->shared.apply(&ShareMode, &StreamFlags, &hnsPeriodicity);
} else if (hooks::audio::WASAPI_COMPATIBILITY_MODE && ShareMode == AUDCLNT_SHAREMODE_SHARED) {
log_warning(
"audio::wasapi",
"-wasapishared is enabled but the game is already opening a shared-mode stream; "
"the option has no effect");
}
WAVEFORMATEXTENSIBLE stereo_storage = {}; WAVEFORMATEXTENSIBLE stereo_storage = {};
WAVEFORMATEXTENSIBLE resample_storage = {};
const WAVEFORMATEX *device_format = pFormat; const WAVEFORMATEX *device_format = pFormat;
if (!this->shared.redirected_from_exclusive) {
// when downmixing, open the real device as stereo while the game keeps writing its native
// multi-channel format into the scratch buffer.
if (auto algorithm = resolve_downmix(pFormat)) { if (auto algorithm = resolve_downmix(pFormat)) {
this->downmix.setup(pFormat, &stereo_storage, *algorithm); this->downmix.setup(pFormat, &stereo_storage, *algorithm);
device_format = reinterpret_cast<const WAVEFORMATEX *>(&stereo_storage); device_format = reinterpret_cast<const WAVEFORMATEX *>(&stereo_storage);
@@ -185,7 +200,6 @@ HRESULT STDMETHODCALLTYPE WrappedIAudioClient::Initialize(
// native-rate audio into the scratch buffer. this runs on whatever device_format is now: the // native-rate audio into the scratch buffer. this runs on whatever device_format is now: the
// game's native format, or the stereo format produced above when downmix is also active, so // game's native format, or the stereo format produced above when downmix is also active, so
// the two stages chain as multi-channel -> stereo -> resampled stereo. // the two stages chain as multi-channel -> stereo -> resampled stereo.
WAVEFORMATEXTENSIBLE resample_storage = {};
if (auto target_rate = hooks::audio::Resampler::resolve(device_format)) { if (auto target_rate = hooks::audio::Resampler::resolve(device_format)) {
const uint32_t src_rate = device_format->nSamplesPerSec; const uint32_t src_rate = device_format->nSamplesPerSec;
this->resample.setup(device_format, &resample_storage, *target_rate); this->resample.setup(device_format, &resample_storage, *target_rate);
@@ -193,6 +207,7 @@ HRESULT STDMETHODCALLTYPE WrappedIAudioClient::Initialize(
log_info("audio::wasapi", "resample enabled: {} Hz -> {} Hz{}", log_info("audio::wasapi", "resample enabled: {} Hz -> {} Hz{}",
src_rate, *target_rate, this->downmix.enabled ? " (after downmix)" : ""); src_rate, *target_rate, this->downmix.enabled ? " (after downmix)" : "");
} }
}
// verbose output // verbose output
log_info("audio::wasapi", "IAudioClient::Initialize hook hit"); log_info("audio::wasapi", "IAudioClient::Initialize hook hit");
@@ -308,6 +323,12 @@ HRESULT STDMETHODCALLTYPE WrappedIAudioClient::GetBufferSize(UINT32 *pNumBufferF
*pNumBufferFrames = this->resample.frames_device_to_game(*pNumBufferFrames); *pNumBufferFrames = this->resample.frames_device_to_game(*pNumBufferFrames);
} }
// redirected to shared mode: clamp the reported buffer to one device period (see SharedRedirect).
if (SUCCEEDED(ret) && this->shared.redirected_from_exclusive && pNumBufferFrames) {
*pNumBufferFrames = this->shared.clamp_buffer_size(
pReal, this->device_format.Format.nSamplesPerSec, *pNumBufferFrames);
}
CHECK_RESULT(ret); CHECK_RESULT(ret);
} }
HRESULT STDMETHODCALLTYPE WrappedIAudioClient::GetStreamLatency(REFERENCE_TIME *phnsLatency) { HRESULT STDMETHODCALLTYPE WrappedIAudioClient::GetStreamLatency(REFERENCE_TIME *phnsLatency) {
@@ -380,6 +401,16 @@ HRESULT STDMETHODCALLTYPE WrappedIAudioClient::IsFormatSupported(
log_info("audio::wasapi", "IAudioClient::IsFormatSupported hook hit"); log_info("audio::wasapi", "IAudioClient::IsFormatSupported hook hit");
print_format(ShareMode, pFormat); print_format(ShareMode, pFormat);
// under the exclusive->shared redirect, report the exclusive format as supported so the game
// doesn't fall back before reaching Initialize.
if (hooks::audio::SharedRedirect::wants(ShareMode, pFormat)) {
log_info("audio::wasapi", "... reporting supported (will redirect to shared mode)");
if (ppClosestMatch) {
*ppClosestMatch = nullptr;
}
return S_OK;
}
// when downmixing, the real device is opened as stereo, so check whether the equivalent // when downmixing, the real device is opened as stereo, so check whether the equivalent
// stereo format is supported instead of the multi-channel one. when resampling is also active // stereo format is supported instead of the multi-channel one. when resampling is also active
// it chains onto that stereo format, so check the resampled stereo format. // it chains onto that stereo format, so check the resampled stereo format.
@@ -10,6 +10,7 @@
#include "downmix.h" #include "downmix.h"
#include "resample.h" #include "resample.h"
#include "shared.h"
#include "audio_render_client.h" #include "audio_render_client.h"
// {1FBC8530-AF3E-4128-B418-115DE72F76B6} // {1FBC8530-AF3E-4128-B418-115DE72F76B6}
@@ -94,6 +95,10 @@ struct WrappedIAudioClient : IAudioClient3 {
IAudioClient3 *const pReal3; IAudioClient3 *const pReal3;
AudioBackend *const backend; AudioBackend *const backend;
bool exclusive_mode = false; 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; int frame_size = 0;
// the format the real device was opened with (after any downmix). used to scale the final // the format the real device was opened with (after any downmix). used to scale the final
@@ -0,0 +1,78 @@
#include "shared.h"
#include <audioclient.h>
#include "hooks/audio/audio.h"
#include "util/logging.h"
#include "defs.h"
namespace hooks::audio {
// whether the engine's PCM converter can handle this format. PCM / float only; non-PCM
// bitstream (AC-3 / DTS passthrough) must be left alone.
static bool is_pcm_or_float(const WAVEFORMATEX *format) {
if (format == nullptr) {
return false;
}
switch (format->wFormatTag) {
case WAVE_FORMAT_PCM:
case WAVE_FORMAT_IEEE_FLOAT:
return true;
case WAVE_FORMAT_EXTENSIBLE: {
// SubFormat is only valid when the extra-bytes block is large enough
if (format->cbSize < sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)) {
return false;
}
const auto *ext = reinterpret_cast<const WAVEFORMATEXTENSIBLE *>(format);
return ext->SubFormat == GUID_KSDATAFORMAT_SUBTYPE_PCM
|| ext->SubFormat == GUID_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
}
default:
return false;
}
}
bool SharedRedirect::wants(AUDCLNT_SHAREMODE share_mode, const WAVEFORMATEX *format) {
// only redirect PCM / float exclusive streams: the engine converter (AUTOCONVERTPCM) can
// handle those, but non-PCM bitstream (AC-3 / DTS passthrough) would fail in shared mode,
// so leave it in exclusive untouched.
return hooks::audio::WASAPI_COMPATIBILITY_MODE
&& share_mode == AUDCLNT_SHAREMODE_EXCLUSIVE
&& is_pcm_or_float(format);
}
void SharedRedirect::apply(AUDCLNT_SHAREMODE *share_mode, DWORD *stream_flags,
REFERENCE_TIME *periodicity) {
// shared mode requires periodicity == 0; AUTOCONVERTPCM lets the engine accept the game's
// native format (else shared Initialize returns AUDCLNT_E_UNSUPPORTED_FORMAT).
log_info("audio::wasapi", "redirecting exclusive WASAPI to shared mode");
*share_mode = AUDCLNT_SHAREMODE_SHARED;
*periodicity = 0;
*stream_flags |= AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM | AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY;
this->redirected_from_exclusive = true;
}
UINT32 SharedRedirect::clamp_buffer_size(IAudioClient *real, uint32_t sample_rate,
UINT32 device_frames) const {
if (!this->redirected_from_exclusive || real == nullptr || sample_rate == 0 || device_frames == 0) {
return device_frames;
}
// GetDevicePeriod returns REFERENCE_TIME units (100 ns), 10^7 per second, so
// period_frames = period * sample_rate / 10^7.
REFERENCE_TIME period = 0;
if (SUCCEEDED(real->GetDevicePeriod(&period, nullptr)) && period > 0) {
const UINT32 period_frames = (UINT32) ((period * sample_rate) / 10000000);
if (period_frames > 0 && period_frames < device_frames) {
return period_frames;
}
}
return device_frames;
}
}
@@ -0,0 +1,31 @@
#pragma once
#include <cstdint>
#include <windows.h>
#include <audioclient.h>
namespace hooks::audio {
// The -wasapishared option redirects an exclusive WASAPI stream to shared mode. lets other apps
// play sound and works on devices that can't open the exclusive format, at the cost of some
// latency. Only PCM / float is converted; bitstream (AC-3 / DTS) is left alone.
struct SharedRedirect {
// true once apply() has redirected an exclusive request. gates the buffer clamp; stays false
// for a natively-shared stream (it paces itself, so must not be clamped).
bool redirected_from_exclusive = false;
// whether an exclusive-mode request should be redirected, given the -wasapishared option.
// only PCM / float is eligible; bitstream (AC-3 / DTS) is left in exclusive mode.
static bool wants(AUDCLNT_SHAREMODE share_mode, const WAVEFORMATEX *format);
// redirect an exclusive request to shared mode. caller must have checked wants() first.
void apply(AUDCLNT_SHAREMODE *share_mode, DWORD *stream_flags, REFERENCE_TIME *periodicity);
// clamp a reported buffer size to one device period. some games write the whole buffer per
// event, which overflows shared-mode buffering (AUDCLNT_E_BUFFER_TOO_LARGE -> stutter); one
// period always fits. a no-op unless an exclusive request was redirected.
UINT32 clamp_buffer_size(IAudioClient *real, uint32_t sample_rate, UINT32 device_frames) const;
};
}
+3
View File
@@ -1132,6 +1132,9 @@ int main_implementation(int argc, char *argv[]) {
hooks::audio::EXCLUSIVE_BUFFER_MS = ms; hooks::audio::EXCLUSIVE_BUFFER_MS = ms;
} }
} }
if (options[launcher::Options::AudioShared].value_bool()) {
hooks::audio::WASAPI_COMPATIBILITY_MODE = true;
}
if (options[launcher::Options::AudioBackend].is_active()) { if (options[launcher::Options::AudioBackend].is_active()) {
auto &name = options[launcher::Options::AudioBackend].value_text(); auto &name = options[launcher::Options::AudioBackend].value_text();
+51 -39
View File
@@ -28,6 +28,7 @@ static const std::vector<std::string> CATEGORY_ORDER_BASIC = {
"Graphics (Full Screen)", "Graphics (Full Screen)",
"Graphics (Windowed)", "Graphics (Windowed)",
"Audio", "Audio",
"Audio (Conversion)",
}; };
static const std::vector<std::string> CATEGORY_ORDER_ADVANCED = { static const std::vector<std::string> CATEGORY_ORDER_ADVANCED = {
@@ -1933,6 +1934,30 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
.type = OptionType::Bool, .type = OptionType::Bool,
.category = "Audio (Hacks)", .category = "Audio (Hacks)",
}, },
{
// AudioShared
.title = "WASAPI Force Shared Mode",
.name = "wasapishared",
.desc = "This option converts all WASAPI exclusive mode requests to shared mode.\n\n"
"Many games have patches that turn on shared mode, but this option is better! "
"This will automatically perform sample rate conversion - "
"you do not need to manually set the sample rate of your audio device before launching the game.",
.type = OptionType::Bool,
.category = "Audio",
},
{
// spice2x_LowLatencySharedAudio
.title = "Low Latency Shared Audio",
.name = "sp2x-lowlatencysharedaudio",
.display_name = "lowlatencysharedaudio",
.aliases= "lowlatencysharedaudio",
.desc = "Force the usage of smallest buffer size supported by the device when shared mode audio is used. "
"Works for games using DirectSound or shared WASAPI; no effect for exclusive WASAPI and ASIO. "
"For best results (under 10ms), use the default Windows inbox audio driver instead of manufacturer supplied driver. "
"Requires Windows 10 and above.",
.type = OptionType::Bool,
.category = "Audio",
},
{ {
// AudioBackend // AudioBackend
.title = "Spice Audio Hook Backend (DEPRECATED - use -asioconvert instead)", .title = "Spice Audio Hook Backend (DEPRECATED - use -asioconvert instead)",
@@ -1941,7 +1966,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
"Does nothing for games that do not output to exclusive WASAPI.", "Does nothing for games that do not output to exclusive WASAPI.",
.type = OptionType::Enum, .type = OptionType::Enum,
.hidden = true, .hidden = true,
.category = "Audio", .category = "Audio (Conversion)",
.elements = { .elements = {
{"asio", "ASIO"}, {"asio", "ASIO"},
{"waveout", "broken, do not use"} {"waveout", "broken, do not use"}
@@ -1954,7 +1979,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
.desc = "Selects the ASIO driver id to use when Spice Audio Backend is set to ASIO.", .desc = "Selects the ASIO driver id to use when Spice Audio Backend is set to ASIO.",
.type = OptionType::Integer, .type = OptionType::Integer,
.hidden = true, .hidden = true,
.category = "Audio", .category = "Audio (Conversion)",
}, },
{ {
// AsioDriverName // AsioDriverName
@@ -1965,7 +1990,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
"This should only be used as last resort if your audio device does not support WASAPI Exclusive.\n\n" "This should only be used as last resort if your audio device does not support WASAPI Exclusive.\n\n"
"Does nothing for games that do not output to exclusive WASAPI.", "Does nothing for games that do not output to exclusive WASAPI.",
.type = OptionType::Text, .type = OptionType::Text,
.category = "Audio", .category = "Audio (Conversion)",
.picker = OptionPickerType::AsioDriver, .picker = OptionPickerType::AsioDriver,
}, },
{ {
@@ -1990,7 +2015,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
"rear: rear channels only.\n\n" "rear: rear channels only.\n\n"
"side: side channels only.", "side: side channels only.",
.type = OptionType::Enum, .type = OptionType::Enum,
.category = "Audio", .category = "Audio (Conversion)",
.elements = { .elements = {
{"ac4", "AC-4 downmix"}, {"ac4", "AC-4 downmix"},
{"normalize", "All channels"}, {"normalize", "All channels"},
@@ -1999,26 +2024,6 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
{"side", "Side channels only"}, {"side", "Side channels only"},
}, },
}, },
{
// AsioDownmixToStereo
.title = "ASIO 7.1 to Stereo Downmix",
.name = "asiodownmix",
.desc = "Extracts a single stereo channel pair from a multi-channel ASIO output, "
"mapping the selected pair to the device's first two channels.\n\n"
"Channel pairs assume a standard 7.1 ASIO layout (0-indexed):\n\n"
"front: channels 0/1 (front left/right).\n\n"
"center: channel 2 (front center, duplicated to both outputs).\n\n"
"rear: channels 4/5 (rear left/right).\n\n"
"side: channels 6/7 (side left/right).",
.type = OptionType::Enum,
.category = "Audio",
.elements = {
{"front", "Front channels (0/1)"},
{"center", "Center channel (2)"},
{"rear", "Rear channels (4/5)"},
{"side", "Side channels (6/7)"},
},
},
{ {
// VolumeBoost // VolumeBoost
.title = "WASAPI/ASIO Boost Audio Volume", .title = "WASAPI/ASIO Boost Audio Volume",
@@ -2050,7 +2055,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
"Select the TARGET sample rate (one that your audio card supports).\n\n" "Select the TARGET sample rate (one that your audio card supports).\n\n"
"Will result in couple milliseconds of latency and increased CPU usage when active.", "Will result in couple milliseconds of latency and increased CPU usage when active.",
.type = OptionType::Enum, .type = OptionType::Enum,
.category = "Audio", .category = "Audio (Conversion)",
.elements = { .elements = {
{"44100", "44.1 kHz"}, {"44100", "44.1 kHz"},
{"48000", "48 kHz"}, {"48000", "48 kHz"},
@@ -2069,7 +2074,27 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
"(at the cost of slightly increased latency).", "(at the cost of slightly increased latency).",
.type = OptionType::Integer, .type = OptionType::Integer,
.setting_name = "16", .setting_name = "16",
.category = "Audio", .category = "Audio (Conversion)",
},
{
// AsioDownmixToStereo
.title = "ASIO 7.1 to Stereo Downmix",
.name = "asiodownmix",
.desc = "Extracts a single stereo channel pair from a multi-channel ASIO output, "
"mapping the selected pair to the device's first two channels.\n\n"
"Channel pairs assume a standard 7.1 ASIO layout (0-indexed):\n\n"
"front: channels 0/1 (front left/right).\n\n"
"center: channel 2 (front center, duplicated to both outputs).\n\n"
"rear: channels 4/5 (rear left/right).\n\n"
"side: channels 6/7 (side left/right).",
.type = OptionType::Enum,
.category = "Audio (Conversion)",
.elements = {
{"front", "Front (ch 0/1)"},
{"center", "Center (ch 2)"},
{"rear", "Rear (ch 4/5)"},
{"side", "Side (ch 6/7)"},
},
}, },
{ {
// DelayBy5Seconds // DelayBy5Seconds
@@ -2740,19 +2765,6 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
{"both", ""}, {"both", ""},
}, },
}, },
{
// spice2x_LowLatencySharedAudio
.title = "Low Latency Shared Audio",
.name = "sp2x-lowlatencysharedaudio",
.display_name = "lowlatencysharedaudio",
.aliases= "lowlatencysharedaudio",
.desc = "Force the usage of smallest buffer size supported by the device when shared mode audio is used. "
"Works for games using DirectSound or shared WASAPI; no effect for exclusive WASAPI and ASIO. "
"For best results (under 10ms), use the default Windows inbox audio driver instead of manufacturer supplied driver. "
"Requires Windows 10 and above.",
.type = OptionType::Bool,
.category = "Audio",
},
{ {
// spice2x_TapeLedAlgorithm // spice2x_TapeLedAlgorithm
.title = "Tape LED Avg Algorithm", .title = "Tape LED Avg Algorithm",
+3 -2
View File
@@ -198,15 +198,17 @@ namespace launcher {
spice2x_NvapiProfile, spice2x_NvapiProfile,
DisableAudioHooks, DisableAudioHooks,
spice2x_DisableVolumeHook, spice2x_DisableVolumeHook,
AudioShared,
spice2x_LowLatencySharedAudio,
AudioBackend, AudioBackend,
AsioDriverId, AsioDriverId,
AsioDriverName, AsioDriverName,
AudioDummy, AudioDummy,
DownmixAudioToStereo, DownmixAudioToStereo,
AsioDownmixToStereo,
VolumeBoost, VolumeBoost,
AudioResample, AudioResample,
AudioExclusiveBuffer, AudioExclusiveBuffer,
AsioDownmixToStereo,
DelayBy5Seconds, DelayBy5Seconds,
spice2x_DelayByNSeconds, spice2x_DelayByNSeconds,
LoadStubs, LoadStubs,
@@ -272,7 +274,6 @@ namespace launcher {
IIDXSubMonitorOverride, IIDXSubMonitorOverride,
spice2x_IIDXEmulateSubscreenKeypadTouch, spice2x_IIDXEmulateSubscreenKeypadTouch,
spice2x_AutoCard, spice2x_AutoCard,
spice2x_LowLatencySharedAudio,
spice2x_TapeLedAlgorithm, spice2x_TapeLedAlgorithm,
spice2x_NoNVAPI, spice2x_NoNVAPI,
spice2x_NoD3D9DeviceHook, spice2x_NoD3D9DeviceHook,
+2 -2
View File
@@ -8,10 +8,10 @@
namespace deferredlogs { namespace deferredlogs {
const std::initializer_list<std::string> SUPERSTEP_SOUND_ERROR_MESSAGE = { const std::initializer_list<std::string> SUPERSTEP_SOUND_ERROR_MESSAGE = {
"audio initialization error was previously detected during boot!", "audio initialization error was detected during boot!",
" this crash is most likely related to audio init failure", " this crash is most likely related to audio init failure",
" * try enabling WASAPI Force Shared Mode (-wasapishared)",
" * check if the default audio device has changed", " * check if the default audio device has changed",
" * fix your audio device settings (e.g., sample rate)",
" * double check your spice audio options and patches", " * double check your spice audio options and patches",
" * ensure no other application is using the device in exclusive mode" " * ensure no other application is using the device in exclusive mode"
}; };