(I first hit this with JUCE 5.4.7, but I’ve read through the latest code in the repo and there’s nothing different in the AudioDeviceManager class that would lead me to believe things have changed in 6.0.8 or later.)
When it needs to default the current audio device, in the absence of any other configuration the AudioDeviceManager will fall back to choosing the first device for the first available device type.
That’s somewhat unfortunate if you happen to find yourself in the admittedly-unusual situation where the first audio device type contains NO devices at all, since AudioDeviceManager will nevertheless set the first type in availableDeviceTypes as current, whenever any code wants to createDeviceTypesIfNeeded():
juce_AudioDeviceManager.cpp@100:115
void AudioDeviceManager::createDeviceTypesIfNeeded()
{
if (availableDeviceTypes.size() == 0)
{
OwnedArray<AudioIODeviceType> types;
createAudioDeviceTypes (types);
for (auto* t : types)
addAudioDeviceType (std::unique_ptr<AudioIODeviceType> (t));
types.clear (false);
if (auto* first = availableDeviceTypes.getFirst())
currentDeviceType = first->getTypeName();
}
}
And code that sets the default device tends to query the currentDeviceType for a list of devices to choose from.
I ran into this building a command-line tool under MinGW on Win10 — because the executable isn’t compiled as a WIN32 application, it won’t detect any WASAPI devices, but the type is still created as the first one in the list — it simply contains zero devices. Whereas the DirectSound type does contain a working and usable device, but it’ll be ignored unless explicitly requested.
For that particular tool I worked around this in the supported manner: by subclassing the AudioDeviceManager, overriding createAudioDeviceTypes(), and removing the WASAPI type instantiations because I know that code will never be able to see WASAPI devices. The API is, as always, well-designed and conducive to such needs.
From reading the code it seems I could’ve also worked around it by passing "*" as the preferredDefaultDeviceName argument to AudioDeviceManager::initialise(), instead of omitting it and passing the default empty string, since having a non-empty preferredDefaultDeviceName will cause initialiseDefault() to walk the entire list of availableDeviceTypes looking for matching devices.
But it strikes me that the AudioDeviceManager should be able to notice any AudioIODeviceType* types that return an empty list for type->getDeviceNames(), and do any of the following in response:
- Skip over that type when defaulting the
currentDeviceType, if there are more types in theavailableDeviceTypeslist. - Sort the 0-device
AudioIODeviceType*s to the end of theavailableDeviceTypeslist, instead of preserving the original configuration order, so that any types with detected devices are given priority. - Remove the “empty” types from
availableDeviceTypesentirely. (I’m not so sure about this one, could there be some types that come up with no devices initially, but are later populated in response to some sort of device activation/initialization? I assume probably yes.)

:threadEntryPoint())