Skip to content

Conversation

@acid-chicken
Copy link

@acid-chicken acid-chicken commented Aug 26, 2025

Working on #705

This PR changes the audio management system to use a more modular approach. The main changes include:

  • Deprecating the old osu.Framework.Audio.AudioManager class, which was a monolithic audio manager.
  • Introducing a new osu.Framework.Audio.Manager.IAudioManager interface and a new osu.Framework.Audio.Manager.AudioManager abstract class, which are no longer dependent on BASS, will allow for easier work on other audio backends in the future (cc: Implement SDL3 Audio backend #6002).
  • Introducing a new osu.Framework.Audio.Manager.Bass.BassAudioManager abstract class, which will contain BASS-specific audio management logic.
  • Introducing a new osu.Framework.Audio.Manager.Bass.BassPrimitiveAudioManager class, which is a concrete implementation of audio management using BASS, so it can be used as a drop-in replacement for the old osu.Framework.Audio.AudioManager class. WASAPI support is completely removed in this class.
  • Introducing a new osu.Framework.Audio.Manager.Bass.BassWasapiAudioManager class, which is a concrete implementation of audio management using BASS with WASAPI support.

And the following tweaks:

  • Removed BASS-specific logics from osu.Framework.Threading.AudioThread and moved them to BassPrimitiveAudioManager and BassWasapiAudioManager.
  • The audio backend and/or device can now be configured via environment variables OSU_AUDIO_BACKEND and OSU_AUDIO_DEVICE.

Notable breaking changes

  • The old osu.Framework.Audio.AudioManager class is no longer available, and new audio manager classes have some design differences.
    • The new audio manager identifies audio devices by their identifiers provided by concrete implementations, instead of using their names.
    • The new audio manager does not require resource stores in the constructor and instead provides a SetStore method to set the resource store after construction.
    • The new audio manager does not have the global mixer handle at abstract levels. Instead, concrete implementations which need a global mixer implement osu.Framework.Audio.Manager.IGlobalMixerProvide interface to provide the global mixer handle.

Known issues

  • Switching devices later using WASAPI causes the sound to stop playing. I've probably made a design mistake regarding global mixer handling.
  • When a debugger breakpoint occurs while using WASAPI, buffer updates stall, causing the last data in the buffer to loop indefinitely. This may surprise or frustrate you.

Copy link
Member

@peppy peppy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

very quick pass


if (wasapiSupported)
{
// Give preference to WASAPI if available.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Except as touched on, the offsets are wrong with WASAPI and need further consideration.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems to be an inaccurate comment. Apologies for the confusion.

Suggested change
// Give preference to WASAPI if available.
// Candidate WASAPI if available.

private Scheduler eventScheduler => EventScheduler ?? Scheduler;

// Mutated by multiple threads, must be thread safe.
private ImmutableList<DeviceInfo> audioDevices = [];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This kind of thing is beyond dodge. The private here should be a backing for the public version, not a separate field which is used to store "old" and "new" in a local method (do that local to the method instead).

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The main purpose of this field is to reverse lookup from device ID to index. BASS uses indexes to refer to devices, but since this class provides device IDs as a public interface, a way to get the index from the ID is needed. Also, BASS's indexes are for the list of all devices, including those that are not available, while this class provides a filtered list of only available devices as a public interface.

Perhaps the name of this field can be changed to make it clearer.

Comment on lines -190 to -194
// WASAPI device indices don't match normal BASS devices.
// Each device is listed multiple times with each supported channel/frequency pair.
//
// Working backwards to find the correct device is how bass does things internally (see BassWasapi.GetBassDevice).
if (Bass.CurrentDevice > 0)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How is this handled in the new code? It doesn't look to be present.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This section is no longer needed.

In the previous code, the framework always referred to BASS's device list as the one to provide. Since BASS and BASS add-ons each have their own device lists, the traditional WASAPI support needed to re-match what was requested in BASS's device list to WASAPI's device list. This is what this section was doing. While this worked out by chance for WASAPI, at least ASIO provides a completely different unit of list.

In the new code, due to the abstraction, the device list is provided directly according to the add-on actually being used, so such matching is unnecessary.

@peppy
Copy link
Member

peppy commented Aug 28, 2025

I haven't considered the new code splitting, structure, DI usage or anything. That's going to take hours / days of consideration.

Hard to say if any of this abstraction is required when wasapi was already working with the old structure.

@acid-chicken
Copy link
Author

  • Switching devices later using WASAPI causes the sound to stop playing. I've probably made a design mistake regarding global mixer handling.

This problem is fixed @ 1d0f324.

@acid-chicken acid-chicken marked this pull request as ready for review August 31, 2025 11:44
@acid-chicken
Copy link
Author

When a debugger breakpoint occurs while using WASAPI, buffer updates stall, causing the last data in the buffer to loop indefinitely. This may surprise or frustrate you.

This problem is also fixed @ 07b4727.

acid-chicken added a commit to acid-chicken/lazer that referenced this pull request Sep 9, 2025
acid-chicken added a commit to acid-chicken/lazer that referenced this pull request Sep 9, 2025
acid-chicken added a commit to acid-chicken/lazer that referenced this pull request Sep 9, 2025
acid-chicken added a commit to acid-chicken/lazer that referenced this pull request Sep 9, 2025
acid-chicken added a commit to acid-chicken/lazer that referenced this pull request Sep 9, 2025
acid-chicken added a commit to acid-chicken/lazer that referenced this pull request Sep 9, 2025
acid-chicken added a commit to acid-chicken/lazer that referenced this pull request Sep 9, 2025
acid-chicken added a commit to acid-chicken/lazer that referenced this pull request Sep 9, 2025
acid-chicken added a commit to acid-chicken/lazer that referenced this pull request Sep 9, 2025
acid-chicken added a commit to acid-chicken/lazer that referenced this pull request Sep 9, 2025
acid-chicken added a commit to acid-chicken/lazer that referenced this pull request Sep 9, 2025
acid-chicken added a commit to acid-chicken/lazer that referenced this pull request Sep 10, 2025
acid-chicken added a commit to acid-chicken/lazer that referenced this pull request Sep 10, 2025
acid-chicken added a commit to acid-chicken/lazer that referenced this pull request Sep 10, 2025
acid-chicken added a commit to acid-chicken/lazer that referenced this pull request Sep 14, 2025
acid-chicken added a commit to acid-chicken/lazer that referenced this pull request Sep 14, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants