Hello everyone !
I think I’ve encountered a bug if FMOD.System when changing the default device on Windows when setCallback is used to handle FMOD.SYSTEM_CALLBACK_TYPE.DEVICELISTCHANGED.
Our setup in Unity lets users choose on which device they want the sound to be output to.
Let’s say they chose “system default” which means the device we want to output to will always be the first one in the drivers list.
The drivers list initially looks like this:
- 0: DEVICE A
- 1: DEVICE B
- 2: DEVICE C
The user then changes the default device from DEVICE A to DEVICE C through the Windows OS UI.
Once the system callback is called with type=DEVICELISTCHANGED, the drivers list now looks like this.
- 0: DEVICE C
- 1: DEVICE A
- 2: DEVICE B
After the callback is called, I enumerate the drivers with getNumDrivers and getDriverInfo and the list is as expected: the first driver is the new default device (DEVICE C).
FMOD still outputs sounds on the previous device (DEVICE A) which is expected since I didn’t do anything to change the output device yet.
But getDriver doesn’t return the new index of DEVICE A (which should be 1 in this example), it continues to return 0.
The only way I could find to have getDriver return the correct value is to call setOutput(None) and setOutput(whatever the previous value was). But this is not ideal since it cuts off the sound every time something happens with the device configuration.
I hope someone can have a look at this and check if it is indeed a bug or if I’m missing something regarding custom device handling.
Thanks in advance.
PS: we’re using version 2.01.10
System::getDriver is supposed to reflect System::setDriver rather than the currently used output device. Ie. The default for
setDriver is zero which represents the default OS device. Calling
getDriver will return zero which means you are using the default output device for the OS, instead of specifying a particular output.
FMOD will normally use the same output as the OS when using the default, the exception is when you override the
Using FMOD_SYSTEM_CALLBACK_DEVICELISTCHANGED (Windows only) will disable any automated device ejection/insertion handling. Use this callback to control the behavior yourself.
Thank you for your answer.
As a follow-up, is there any way to ask the FMOD system which device or driver is currently used as an output? Or must it be tracked by our own code?
You should be able to use
getDriverInfo with the index from
getDriver as long as you aren’t overriding the device list changed callback.
I just ran into the same issue…
In my case I am using the
FMOD_SYSTEM_CALLBACK_DEVICELISTCHANGED override and had previously called SetDriver, so my initial configuration is:
- 0: Device A = System
- 1: Device B
- 2: Device C = Output
A call to System::getDriver yields 2.
Next, I switch the system device from A to C, so the new configuration is:
- 0: Device C = System, Output
- 1: Device A
- 2: Device B
A call to System::getDriver STILL yields 2, so it is incorrect under any interpretation.
WORKAROUND: Do not use getDriver.
According to the specification, the output driver switches with the system driver IFF a callback is NOT registered for FMOD_SYSTEM_CALLBACK_DEVICELISTCHANGED. So, register the callback, cache the driver GUID, and check each device to see if the previously active device is still connected.
WARNING: When I tried to enumerate connected devices in the callback I caused Unity to deadlock. Instead, use the callback to flag that an update is needed, then update on Unity’s main thread. See: BUG: Unity Editor hangs when handling DEVICELISTCHANGED callback - #2 by Reification
This behavior is a result of registering for the
FMOD_SYSTEM_CALLBACK_DEVICELISTCHANGED callback, which overrides the default behavior.
The value returned from
System::getDriver is only updated when calling
System::setDriver and by overriding the
FMOD_SYSTEM_CALLBACK_DEVICELISTCHANGED callback, FMOD no longer does this automatically, you will need to handle this in your callback.