Ok,..
Windows registers Device-Removed-Event here:
https://github.com/julianstorer/JUCE/blob/master/modules/juce_events/native/juce_win32_HiddenMessageWindow.h#L123
-> line 105:
void triggerAsyncDeviceChangeCallback()
{
// We'll pause before sending a message, because on device removal, the OS hasn't always updated
// its device lists correctly at this point. This also helps avoid repeated callbacks.
startTimer (500); // <-- trying 1500 doesn't fix
}
-> line 133
-> https://github.com/julianstorer/JUCE/blob/master/modules/juce_audio_devices/native/juce_win32_DirectSound.cpp#L1256
void systemDeviceChanged() override
{
DSoundDeviceList newList;
newList.scan();
if (newList != deviceList)
{
deviceList = newList;
for (auto s : newList.outputDeviceNames) // <-- I add this...
DBG(s);
callDeviceChangeListeners();
}
}
output:
Primary Sound Driver
Speakers (Cirrus Logic CS4206B (AB 06))
Digital Audio (S/PDIF) (Cirrus Logic CS4206B (AB 06))
I don't know what Primary Sound Driver entails... anyway -- onwards:
Only one listener, here: https://github.com/julianstorer/JUCE/blob/master/modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.cpp#L79
-> line 195:
void AudioDeviceManager::audioDeviceListChanged()
{
if (currentAudioDevice != nullptr)
{
DBG(currentAudioDevice->getName()); // <-- "Headphones (Cirrus Logic CS4206B (AB 06))"
currentSetup.sampleRate = currentAudioDevice->getCurrentSampleRate();
currentSetup.bufferSize = currentAudioDevice->getCurrentBufferSizeSamples();
currentSetup.inputChannels = currentAudioDevice->getActiveInputChannels();
currentSetup.outputChannels = currentAudioDevice->getActiveOutputChannels();
}
sendChangeMessage();
}
Should currentAudioDevice still be referencing the just-removed-device?
Moving on...
-> https://github.com/julianstorer/JUCE/blob/master/modules/juce_events/broadcasters/juce_ChangeBroadcaster.cpp#L61
-> https://github.com/julianstorer/JUCE/blob/master/modules/juce_events/broadcasters/juce_AsyncUpdater.cpp#L61
... which emits a Windows message
... which gets picked up again in juce_ChangeBroadcaster.cpp#L92
... which eventually triggers my callback:
class MainContentComponent : public AudioAppComponent, ChangeListener
{
public:
MainContentComponent() {
setSize(800, 600);
setAudioChannels(0, 2);
deviceManager.addChangeListener(this);
}
void changeListenerCallback(ChangeBroadcaster*) override {
static int i=0; DBG("\nchangeListenerCallback:" + String(i++));
StringArray newDeviceNames = deviceManager.getCurrentDeviceTypeObject()->getDeviceNames();
for (auto s : newDeviceNames)
DBG(s);
}
Aaaaaaaaaaaaaaah!
This gets hit twice!
changeListenerCallback:0
Headphones (Cirrus Logic CS4206B (AB 06))
Digital Audio (S/PDIF) (Cirrus Logic CS4206B (AB 06))
Speakers (Cirrus Logic CS4206B (AB 06))
changeListenerCallback:1
Speakers (Cirrus Logic CS4206B (AB 06))
Digital Audio (S/PDIF) (Cirrus Logic CS4206B (AB 06))
Inserting the headphones gives another pair of hits!
My code was diffing the output with the prev-output, and first run was generating an empty string.
Wow.
Well, that was a fun run through the innards of JUCE audio.
https://youtu.be/IjarLbD9r30?t=38s
:]
Why is it hitting twice, out of curiosity?
π