Change audio device dynamically

Hi,
Is there a way to dynamically change the active audio device via blueprint or c++ ?
I tried GEngine->GetAudioDeviceManager()->SetActiveDevice(iIndex) but that just silenced my current device and i was not able to restart it.

It is for an ingame audio settings menu, where you can choose in a list of available devices.

You’d need to write some code to initialize the audio backend to the device you want. Presumably this would only be for desktop. All the backends presume the default device defined in the OS.

The code you’re looking at with the audio device manager is NOT intended for this feature. The device manager handles different FAudioDevice instances for use with multiple PIE. It was an accident of history that the object, FAudioDevice, is called that. It should be called FAudioSystem or FAudioEngine and doesn’t necessarily mean the actual low-level audio hardware device. The code that handles that is in the XAudio2 module (on PC) , the CoreAudio module (on Mac), or the OpenAL module (for linux).

If you’re using the new audio mixer (which presumably you are not since you are on 4.14), you’d have to check out simpler backends used in the audio mixer.

On PC, in the old audio engine backend (again, XAudio2 module), there is some code already that lets you define which physical output device you want to use. Check out the intiailization function. You should be able to change that code to be setable by some other method. However, if you want to support changing the output device while the game is running without requiring a restart, you’ll need to shutdown the entire audio engine (i.e. flush, etc), then restart it with the new device. It’s not trivial in the old audio engine. In the new audio mixer there is support for dynamic hot-load/swapping of audio devices and there is a function which migrates all audio rendering to new output devices so it’d be a bit easier to pull off (and is on my list of features to support).

1 Like

I am also looking for a solution for this. You mentioned that the new audio system has support for dynamic hot-swapping of audio devices, is there some documentation on how to do this or some example code?

Did you manage to figure this out? I’m looking to do the same thing as well

2020 still no built in support for hot swapping audio output device?

Hey Jaytheway. Yes it’s 2020 and it’s supported.

1 Like

Could you possibly describe how to do that? This would be a game changer. I’m trying to figure this out for a long time. I’m trying to use

MoveAudioStreamToNewAudioDevice()

from AudioPlatformMixer, which I get from the Mixer Device, which I obtain with a world context object.
I give it a valid device ID, but when this function is called audio stream cuts off and resumes on the same default device.
Maybe I’m missing something. Do I have to manually teardown and reinitialize hardware to move audio stream to a new device, or something like that?
In fact I tried that, but got stuck on re-initialization of submixes.

So first, we only support swapping to the default device in windows currently. It should be easy to add support for swapping to any device – we just haven’t done that yet.

The primary problem with audio device hot swap on PC was a bug in XAudio2_7 which would periodically cause a hang with other windows API calls (MMDeviceNotification). Matters are more complicated because in XAudio2_8 microsoft decided to distribute XAudio2 with Windows – i.e. games suddenly depend on which OS you have. Which isn’t a great scenario. Lots of games complained and eventually MS released XAudio2_9redist last fall, which allowed us to distribute the lib w/o windows (i.e. you can run with it on windows 7, etc).

So in 4.24 we upgraded to use an XAudio2_9redist library. This allows us to do the audio device hot swap without crashing. It SHOULD just automatically happen.

Basically play the game with an audio device, then change the OS to use a different device for default and it should swap to that new device. It also swaps when the current one becomes invalid, etc.

The final piece to this was supporting the case properly where NO audio devices are available – you’ve disabled all of them and now what. So in that case, it swaps to a “null audio renderer” automatically which continues rendering audio and keeping all audio engine state but throws away the rendered audio buffers (or feeds them to some server in the case of something like audio rendering in the cloud for cloud gaming). Then when a device becomes available, it smoothly swaps audio to feed to the new available audio device.

The notifications code is hooked up in AudioMixerPlatformWindows.cpp.

To do manual device selection, you’ll need to add some code to FMixerPlatformXAudio2::OpenAudioStream to pass in an option to select a specific device ID. Probably best do it with GUID but you could try to do it with a device index. Windows changed their device enumeration code to use GUIDs though so i’d stick with that. Don’t use “friendly names” since windows lets users name their audio devices and you can get collisions.

You’ll need to write a bunch of Gameplay/BP code to expose all that to somebody so they can do it dynamically. Like “GetAvailableAudioDevices()” or something, which calls down eventually into the GetOutputDeviceInfo code and GetNumOutputDevices, etc. Then you’d write some BP types to present that info to users.

Then an API to feed that to some code which forces the swap dynamically to use the new device, assuming you want to do that without forcing a restart.

It’s complicated but doable and on our list of things to add support for. It just hasn’t yet been a priority over all the other things we’re trying to do.

If I were you I’d just keep it at using the default device unless you had a very compelling reason not to. I’ve worked on games that let users pick specific audio devices and it’s usually not a great idea.

Then an API to feed that to some code which forces the swap dynamically to use the new device, assuming you want to do that without forcing a restart.

If you mean something like this:

Audio::IAudioMixerPlatformInterface* PlatformMixer = MixerDevice->GetAudioMixerPlatform();

PlatformMixer->OpenAudioStream(OpenStreamParams)

I’ve done that, with the same result. Audio cuts off then resumes on the same default device. I tried that with some combinations of CloseAudioStream() TeardownHardware() PostInitializeHardware() StartAudioStream().

I’m not sure what the proper procedure with all those steps should be and which ones are or aren’t necessary.

I have all of that except for “FMixerPlatformXAudio2::OpenAudioStream” part. I’m retrieving names and GUIDs using Windows API and exposing that to Blueprints.

From what I understood form your comment, I would have to change engine’s code (FMixerPlatformXAudio2) to be able to implement device swapping.

If that’s the case, I’d have to wait until you guys can implement it. Hopefully before UE v.5 :wink:

My compelling reason is that my application relies on being able to transmit audio to listeners outside of it. E.g. to other applications, over the internet etc. Therefore it needs a different output device from system’s default one. For now the workaround is to use Windows “App volume and device preferences” to change default device per application. Which is not very convenient for the end user.

Thank you for the explanation. This was helpful to narrow down the issue and possible solution, or rather a lack of thereof, for right now.

Ah if that’s what you need, the easiest path would probably to make a submix effect and do the output device management that you apparently are able to do there. I suspect doing it with the code you are using, which wasn’t intended to be done by code outside of the audio engine, is causing it to conflict with other logic its doing.

Doing it as a submix effect would be 1) something you could do in a plugin and not modify engine source and 2) give you total control how you want to route it.

Submix effects can also mute their output so you can intercept audio on the master submix and capture all your game audio.

In 4.25 we have the concept of an “endpoint submix” which is where we are going to implement this, hopefully in 4.26, as a fundamental feature of submixes. However, you can do it today as a submix effect and drop it on any submix you want.

Yeah, I think it’s conflicting with its own internal logic trying to keep it on the OS default device.

Okay, I’ll wait for the update with this functionality implemented. Thanks!

Hi. I created plugin System Audio Volume. It can change default audio device in runtime from UE4 project. Hope this helps.

Did you ever manage to get this working? It’s now 2021 and it still seems next to impossible.
I have no problem getting audio device names and DeviceIDs, but MoveAudioStreamToNewAudioDevice() and OpenAudioStream() still don’t actual change the output device (the system seems to think it does as the main device name and ID change, but the sound is still coming out of the default speakers)

Hi Andrew, I’ve actually got your plugin (well done and thanks) but it only works on windows and I need this to be multiplatform.

Hi. I created plugin System Audio Volume. It can change default audio device in runtime from UE4 project. Hope this helps.

Oh, Nice!
Multiplatform…

For iOS and Android maybe problem with permissions but if root.

Maybe help VirtualBox and emulators for tests, hm…

Just let me know more. My discord Andrew Bindraw #9014