Try / Tempest

API abstraction layer for 3D graphics, UI and sound. Written in C++17 with Vulkan, DX12 and Metal support.
MIT License
83 stars 24 forks source link

Default audio device is not respected #61

Open MadShadow- opened 2 months ago

MadShadow- commented 2 months ago

The issue

When I start the game with my speakers as default audio device, music will play on the speakers. If I switch from speakers to headphones, the music of the game will continue to play on the speakers.

Proposed solution (Only for Windows)

Windows can notify an application of audio endpoint changes by implementing a class of the IMMNotificationClient interface. I added a class to the windowsAPI backend. The SystemAPI class allows to have a callback set, called by the NotificationClient and set by the AudioDevice of Tempest.

The proposed solution is inside a pull request, provided below: https://github.com/Try/Tempest/pull/62

Points for discussion

Try commented 2 months ago

Hi, @MadShadow- !

Let's split discussion into 2 topics:

  1. Implementation wise, there is a portable solution with alEventCallbackSOFT, that enables to detect device-lost event. I already tested it locally - works quite will on my windows machine. And it also fine grained - callback reported per-context.

  2. Physical to Logical device relations. This is more conceptual question (and a main reason why I didn't touch this area yet). In application side we can have multiple logical devices. In OpenGothic one for game-world, one for music, one for dialogs and all 3 are mapped to default physical device.

Today game has no control over device, as there is no engine api. In graphics side - there is control: application can list physical gpus, select desirable one and will receive exception, if device is removed. But, in case of sound throwing exception is not the great way to do it.

Try commented 2 months ago

Proposed api:

Query all devices static Prop SoundDevice::devices()

Device creation SoundDevice(const Prop&), SoundDevice(std::string_view name = "")

Query active physical device const Prop& SoundDevice::physicalDevice() const

Callback SoundDevice::setEventHandler

struct SoundDevice::Prop { // device description
  char name[128] = {};
  // maybe more data in future
  }

PS If it feel like I'm over complicating this - it's OK I'm fine to implement it by myself :)

MadShadow- commented 2 months ago

If it feel like I'm over complicating this - it's OK I'm fine to implement it by myself :)

When it comes to logical to physical mapping, I think its okay for the system to map all logical outputs to the same physical end device, because I don't see a reason why you would want to split those. Also I don't think the engine and the game need to expose a physical sound device selection. At least in windows I never changed the audio output in an application. Instead if I really want to change something I either use the sound mixer or directly switch output devices there, for all applications at once. So if you don't plan to work with active sound devices, the only one you need is the default one.

The only app I can think of that allows sound device selection is discord - and even there, they'll notify you if you changed the default device and if you fail to click it, well nice then your sound keeps running on the headphones you no longer wear. :D

Implementation wise, there is a portable solution with alEventCallbackSOFT

🗡️ (Cool dagger) Oh alright, if OpenAL got something, thats amazing, so we can rely on them! I am happy if you implement it :)

Try commented 1 month ago

updating on openal experiments:

for unknown to me reason device goes into seemingly unrecoverable state after receiving AL_EVENT_TYPE_DISCONNECTED_SOFT