Skip to content

Commit a6692e6

Browse files
authored
Merge pull request #6659 from peppy/experimental-wasapi-user-toggle
Expose experimental WASAPI support as a user config toggle
2 parents 496247f + d97d051 commit a6692e6

File tree

5 files changed

+28
-15
lines changed

5 files changed

+28
-15
lines changed

osu.Framework/Audio/AudioManager.cs

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,13 @@ public class AudioManager : AudioCollectionManager<AudioComponent>
9696
/// </summary>
9797
public readonly Bindable<string> AudioDevice = new Bindable<string>();
9898

99+
/// <summary>
100+
/// Whether to use experimental WASAPI initialisation on windows.
101+
/// This generally results in lower audio latency, but also changes the audio synchronisation from
102+
/// historical expectations, meaning users / application will have to account for different offsets.
103+
/// </summary>
104+
public readonly BindableBool UseExperimentalWasapi = new BindableBool();
105+
99106
/// <summary>
100107
/// Volume of all samples played game-wide.
101108
/// </summary>
@@ -176,6 +183,7 @@ public AudioManager(AudioThread audioThread, ResourceStore<byte[]> trackStore, R
176183
thread.RegisterManager(this);
177184

178185
AudioDevice.ValueChanged += _ => onDeviceChanged();
186+
UseExperimentalWasapi.ValueChanged += _ => onDeviceChanged();
179187
GlobalMixerHandle.ValueChanged += handle =>
180188
{
181189
onDeviceChanged();
@@ -430,10 +438,16 @@ protected virtual bool InitBass(int device)
430438
// See https://www.un4seen.com/forum/?topic=19601 for more information.
431439
Bass.Configure((ManagedBass.Configuration)70, false);
432440

433-
if (!thread.InitDevice(device))
434-
return false;
441+
if (UseExperimentalWasapi.Value)
442+
{
443+
if (thread.InitDevice(device, true))
444+
return true;
435445

436-
return true;
446+
Logger.Log($"BASS device {device} failed to initialise with experimental WASAPI, disabling", level: LogLevel.Error);
447+
UseExperimentalWasapi.Value = false;
448+
}
449+
450+
return thread.InitDevice(device, false);
437451
}
438452

439453
private void syncAudioDevices()

osu.Framework/Configuration/FrameworkConfigManager.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ protected override void InitialiseDefaults()
3232
SetDefault(FrameworkSetting.WindowedPositionY, 0.5, -0.5, 1.5);
3333
SetDefault(FrameworkSetting.LastDisplayDevice, DisplayIndex.Default);
3434
SetDefault(FrameworkSetting.AudioDevice, string.Empty);
35+
SetDefault(FrameworkSetting.AudioUseExperimentalWasapi, false);
3536
SetDefault(FrameworkSetting.VolumeUniversal, 1.0, 0.0, 1.0, 0.01);
3637
SetDefault(FrameworkSetting.VolumeMusic, 1.0, 0.0, 1.0, 0.01);
3738
SetDefault(FrameworkSetting.VolumeEffect, 1.0, 0.0, 1.0, 0.01);
@@ -79,6 +80,7 @@ public enum FrameworkSetting
7980
ShowLogOverlay,
8081

8182
AudioDevice,
83+
AudioUseExperimentalWasapi,
8284
VolumeUniversal,
8385
VolumeEffect,
8486
VolumeMusic,

osu.Framework/FrameworkEnvironment.cs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ public static class FrameworkEnvironment
2121
public static bool NoStructuredBuffers { get; }
2222
public static string? DeferredRendererEventsOutputPath { get; }
2323
public static bool UseSDL3 { get; }
24-
public static bool UseWasapi { get; }
2524

2625
/// <summary>
2726
/// Whether non-SSL requests should be allowed. Debug only. Defaults to disabled.
@@ -56,8 +55,6 @@ static FrameworkEnvironment()
5655

5756
// Desktop has many issues, see https://github.com/ppy/osu-framework/issues/6540.
5857
UseSDL3 = RuntimeInfo.IsMobile || (parseBool(Environment.GetEnvironmentVariable("OSU_SDL3")) ?? false);
59-
60-
UseWasapi = parseBool(Environment.GetEnvironmentVariable("OSU_AUDIO_WASAPI_EXPERIMENTAL")) ?? false;
6158
}
6259

6360
private static bool? parseBool(string? value)

osu.Framework/Game.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,7 @@ private void load(FrameworkConfigManager config)
196196

197197
// attach our bindables to the audio subsystem.
198198
config.BindWith(FrameworkSetting.AudioDevice, Audio.AudioDevice);
199+
config.BindWith(FrameworkSetting.AudioUseExperimentalWasapi, Audio.UseExperimentalWasapi);
199200
config.BindWith(FrameworkSetting.VolumeUniversal, Audio.Volume);
200201
config.BindWith(FrameworkSetting.VolumeEffect, Audio.VolumeSample);
201202
config.BindWith(FrameworkSetting.VolumeMusic, Audio.VolumeTrack);

osu.Framework/Threading/AudioThread.cs

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ protected override void OnExit()
130130
/// </summary>
131131
private readonly Bindable<int?> globalMixerHandle = new Bindable<int?>();
132132

133-
internal bool InitDevice(int deviceId)
133+
internal bool InitDevice(int deviceId, bool useExperimentalWasapi)
134134
{
135135
Debug.Assert(ThreadSafety.IsAudioThread);
136136
Trace.Assert(deviceId != -1); // The real device ID should always be used, as the -1 device has special cases which are hard to work with.
@@ -139,9 +139,7 @@ internal bool InitDevice(int deviceId)
139139
if (!Bass.Init(deviceId, Flags: (DeviceInitFlags)128)) // 128 == BASS_DEVICE_REINIT
140140
return false;
141141

142-
// That this has not been mass-tested since https://github.com/ppy/osu-framework/pull/6651 and probably needs to be.
143-
// Currently envvar gated for users to test at their own discretion.
144-
if (FrameworkEnvironment.UseWasapi)
142+
if (useExperimentalWasapi)
145143
attemptWasapiInitialisation();
146144

147145
initialised_devices.Add(deviceId);
@@ -182,10 +180,10 @@ internal static void PreloadBass()
182180
}
183181
}
184182

185-
private void attemptWasapiInitialisation()
183+
private bool attemptWasapiInitialisation()
186184
{
187185
if (RuntimeInfo.OS != RuntimeInfo.Platform.Windows)
188-
return;
186+
return false;
189187

190188
Logger.Log("Attempting local BassWasapi initialisation");
191189

@@ -219,10 +217,10 @@ private void attemptWasapiInitialisation()
219217

220218
// To keep things in a sane state let's only keep one device initialised via wasapi.
221219
freeWasapi();
222-
initWasapi(wasapiDevice);
220+
return initWasapi(wasapiDevice);
223221
}
224222

225-
private void initWasapi(int wasapiDevice)
223+
private bool initWasapi(int wasapiDevice)
226224
{
227225
// This is intentionally initialised inline and stored to a field.
228226
// If we don't do this, it gets GC'd away.
@@ -246,13 +244,14 @@ private void initWasapi(int wasapiDevice)
246244
Logger.Log($"Initialising BassWasapi for device {wasapiDevice}...{(initialised ? "success!" : "FAILED")}");
247245

248246
if (!initialised)
249-
return;
247+
return false;
250248

251249
BassWasapi.GetInfo(out var wasapiInfo);
252250
globalMixerHandle.Value = BassMix.CreateMixerStream(wasapiInfo.Frequency, wasapiInfo.Channels, BassFlags.MixerNonStop | BassFlags.Decode | BassFlags.Float);
253251
BassWasapi.Start();
254252

255253
BassWasapi.SetNotify(wasapiNotifyProcedure);
254+
return true;
256255
}
257256

258257
private void freeWasapi()

0 commit comments

Comments
 (0)