(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* type
s 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 theavailableDeviceTypes
list. - Sort the 0-device
AudioIODeviceType*
s to the end of theavailableDeviceTypes
list, instead of preserving the original configuration order, so that any types with detected devices are given priority. - Remove the “empty” types from
availableDeviceTypes
entirely. (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.)