getNumDrivers returns "NoDevice" after re-plugging last device

Hi,

I’m working on hot swapping Audio output devices. Everything wokrs nice and smoothly until i re-plug the last remaining device in the system. When it’s remove i get this error:

[FMOD] OutputWASAPI::mixerThread : GetCurrentPadding returned 0x88890004.  Device was unplugged!

After pluging it back, the DEVICE LIST CHANGED callback kicks in, but iterating through list of devices shows only one entry and it’s “no device” . Fmod never recovers and i can;t hear audio at all.

Same thing happens when i start the game with all devices unplugged.

Hi,

Thanks for bringing this to our attention. What version of the FMOD integration are you using? Please could I get the code you are using to detect the output devices?

FMOD integration Version: 2.01.19

This is the code i use for the callback:

List<string> GetOutputDevices()
{
    List<string> devices = new();
    RuntimeManager.CoreSystem.getNumDrivers(out var drivers);

    for (int i = 0; i < drivers; i++)
    {
        RuntimeManager.CoreSystem.getDriverInfo(i, out var name, 120, out Guid g, out int sample, out var speakerMode, out int a);
        Debug.Log($"{i}: {name}");
        if (g == Guid.Empty)
            continue;
        devices.Add(name);
    }

    return devices;
}


[AOT.MonoPInvokeCallback(typeof(FMOD.SYSTEM_CALLBACK))]
static FMOD.RESULT DeviceChangedCallback(IntPtr system, FMOD.SYSTEM_CALLBACK_TYPE type, IntPtr commanddata1, IntPtr commanddata2, IntPtr userdata)
{
    Debug.Log("output device list changed");
    foreach (var instance in instances)
    {

        if (instance.GetOutputDevices().Count > 0)
            instance.Setting.SetChoices(instance.GetOutputDevices());
        else
            instance.Setting.SetChoices(new List<string>());
    }
    return FMOD.RESULT.OK;
}

Thank you for the script.

Unfortunately, 2.01 is no longer supported. Can I confirm your integration version:
image
image

We have documentation for migrating major versions for Studio here: FMOD Studio | Advanced Topics - Migration FMOD Studio Projects.
Migrating Unity versions will be aided by the Unity Integration | Tools - Event Reference Updater.

A few improvements to the device list changed callback since 2.01 may solve the issue.

Hi,
That’s exactly how i checked the version.
Sadly upgrading is out of scope with current project now.
I guess we’ll have to scrap the feature.

Thanks for the information.

1 Like

Hey @Connor_FMOD , we have experienced this issue on version 2.02.22 as well. Could you verify that it’s also broken on your end and also perhaps give an idea about a possible timeline for a fix?

Hi,

How are you detecting the device changes? Could I grab any code and reproduction steps?

With the following settings enabled:

image

Could I grab the full editor logs when experiencing the issues?

image

Our code to get the changes looks like this:

[AOT.MonoPInvokeCallback(typeof(SYSTEM_CALLBACK))]
private static RESULT OnFmodSystemCallback(IntPtr systemPtr, SYSTEM_CALLBACK_TYPE type, IntPtr commandData1, IntPtr commandData2, IntPtr userData)
{
    if (type == SYSTEM_CALLBACK_TYPE.DEVICELISTCHANGED)
    {
        MarkOutputDeviceChanged();
        OnDeviceListChanged.Invoke();
    }
    return RESULT.OK;
}

OnDeviceListChanged triggers:

        {
            await Awaitable.MainThreadAsync();
            if (TryConsumeDeviceChange())
            {
                SetOutputDevicesOptions();  //Sets our UI
                SetInputDevicesOptions();  //Sets our UI
            }
        }

Related methods:

private static void MarkOutputDeviceChanged()
{
    Interlocked.Exchange(ref outputDeviceChanged, 1);
}        

private static bool TryConsumeDeviceChange()
{
    return Interlocked.Exchange(ref outputDeviceChanged, 0) == 1;
}

after disabling the last output device, when enabling it again we get only this driver: (NoSound Driver)
image

With the logs enabled there is an Error log that pops only when disabling the last device:

[FMOD] OutputWASAPI::mixerThread : GetCurrentPadding returned 0x88890004.  Device was unplugged!

UnityEngine.Debug:LogError (object)
FMODUnity.RuntimeUtils:DebugLogError (string) (at Assets/Plugins/FMOD/src/RuntimeUtils.cs:580)
FMODUnity.RuntimeManager:DEBUG_CALLBACK (FMOD.DEBUG_FLAGS,intptr,int,intptr,intptr) (at Assets/Plugins/FMOD/src/RuntimeManager.cs:104)
1 Like

Hi,

Thanks for sharing the code and logs.

Since Connor is away, I will continue with this support case.

I was able to reproduce this locally with a minimal Unity test. When the DEVICELISTCHANGED callback is registered, FMOD reports NoSound Driver after the last device is disabled, and it does not automatically switch back when the device becomes available again.

This matches the behavior described in the documentation:
https://www.fmod.com/docs/2.02/api/troubleshooting.html#my-audio-device-does-not-change-automatically

In this case the application needs to handle the device change itself (for example by selecting a driver again or reinitializing the system). If the callback is not registered, FMOD will normally handle device switching automatically.

There is also a related discussion here about handling device changes on Windows:

Hope this helps!

Hey! Thanks for the reply. Unfortunately, I don’t think that encompasses the entire situation here.

The problem is not about it not detecting driver changes or swapping to the most recently connected device automatically. That we already handle as the documentation says.

The problem is the method RuntimeManager.CoreSystem.getNumDrivers(out numDrivers); always returns 1 and the RuntimeManager.CoreSystem.getDriverInfo for that driver always returns the Guid.Empty driver.
And this keeps going on regardless of how many devices you connect after disconnecting the last.
This methods return the expected values when disconnecting or connecting devices as long as you don’t disconnect the last one.

In this case the application needs to handle the device change itself (for example by selecting a driver again or reinitializing the system)

What exactly do you mean by we should reinitialize the system ourselves?
Like, reinitialize the FMOD plugin entirely? or like the have to restart the app?
We can’t select a driver because FMOD detects none

A nasty workaround we ended up with was having to check every 5 seconds if there are other drivers returned that don’t have GUID.Empty, then we can fall back on using the DEVICELISTCHANGED callback.

But to be perfectly honest, it all just seems like a bug.
If I subscribe to a callback that says “DEVICELISTCHANGED” then when the device list changes, I should be able to query the device list and get something other than “EMPTY”

Thank you for sharing the extra information!

getNumDrivers returns the number of actual drivers the output plugin found, excluding nosound. However, if the last device is unplugged FMOD changes its output plugin to FMOD_OUTPUTTYPE_NOSOUND, which will always report a device count of 1 with a device called NoSound Driver.

You should be able to attempt switching to a new audio device in the DEVICELISTCHANGED callback using System::setOutput.

Sorry for the confusion earlier. When I mentioned “reinitializing the system”, I meant recreating the FMOD system instance via System::close and System::init. I was just exploring whether there might be another possible solution, but that may not be the best fit for your project.

Thanks for the feedback. I will pass this along to the dev team for further review and investigation.