Device insertion/removal detection

I’ve just checked in some code that adds support for detecting audio devices being added and removed.

It works for CoreAudio, and I’ve implemented it for WASAPI too, but I can’t get my damned Windows VM to actually add or remove any audio devices to test it! So if anyone fancies giving it a spin in WASAPI to see if it works, that’d be appreciated! It’s easy to test: in the juce demo audio page, the drop-down list of devices should now update itself when you plug a device in… Thanks!

Is this implemented into the prebuilt demo or do we have to download the latest tip and compile juce + the demo ?

No, I don’t keep the prebuilt demo up to date, you’d need to build it.

OK.

So far, I tested using the demo.
Environment :

  • Windows 7, 64 bit
  • EDIROL FA66
  • Korg PadKontrol
  • Juce demo build in debug x32, with

#define JUCE_ASIO 1 #define JUCE_WASAPI 1 #define JUCE_DIRECTSOUND 1 in AppConfig.h

WASAPI :

Pluging or unpluging both the midi device (pad kontrol) and the sound card seems to work BUT I hava to switch the demo page to have it taken into account.
For example : in audio page I can see the padkontrol. I physically unplug it. It’s still in the available midi devices. I go to graphics demo, then back to audio demo : it’s not there (as expected)
Same for the sound card

ASIO

The padkontrol reacts exactly as in WASAPI.
The sound card removal isn’t detected even when switching pages. If I select the soundcard while unplugged I get an error message.

This was just a quick test. If you need someone to debug more in depth and/or run some tests, I’m ok to spend some time on it.

Thanks! ASIO wasn’t supposed to work - like I said, this is just WASAPI at the moment.

But it should update without switching pages - that’s the whole point, really!

Could you perhaps catch it inside the WASAPIAudioIODeviceType::deviceChangeEventCallback() and WASAPIAudioIODeviceType::handleDeviceChange() and see what happens there? It should re-scan the device list and send a notification if it has changed, but maybe something isn’t working…

OK I put a conditional breakpoint on the first “if” in the following code.

[code] static LRESULT CALLBACK deviceChangeEventCallback (HWND h, const UINT message,
const WPARAM wParam, const LPARAM lParam)
{
if (message == WM_DEVICECHANGE
&& (wParam == 0x8000 /DBT_DEVICEARRIVAL/
|| wParam == 0x8004 /DBT_DEVICEREMOVECOMPLETE/))
{
((WASAPIAudioIODeviceType*) GetWindowLongPtr (h, GWLP_USERDATA))->handleDeviceChange();
}

    return DefWindowProc (h, message, wParam, lParam);
}[/code]

My conditional breakpoint stops if “message == WM_DEVICECHANGE” is true (otherwise, it breaks on every single message so it’s impossible to debug :wink: )
What I found is that, when a device is plugged or unplugged (both the sound card or the midi controller), wParam==0x0007

According to Windows API docs this corresponds to DBT_DEVNODES_CHANGED - A device has been added to or removed from the system.

Basically the test is never true and handleDeviceChange is never called.

So I went further and replaced

if (message == WM_DEVICECHANGE && (wParam == 0x8000 /*DBT_DEVICEARRIVAL*/ || wParam == 0x8004 /*DBT_DEVICEREMOVECOMPLETE*/))

by

if (message == WM_DEVICECHANGE && (wParam == 0x8000 /*DBT_DEVICEARRIVAL*/ || wParam == 0x8004 /*DBT_DEVICEREMOVECOMPLETE*/ || wParam==0x0007))

And this time, obviously handleDeviceChange is called and … it works ! :smiley:

However the following test :

if (newOutNames != outputDeviceNames || newInNames != inputDeviceNames || newOutIds != outputDeviceIds || newInIds != inputDeviceIds)

apparently just tests for the sound card’s IO, not the other MIDI controlers IO.
In other words, if I remove the padControl, y handleDeviceChange is called but the “if” evaluates to false.

That would be really nice if it worked for midi controlers as well

Now about ASIO, I noticed that “handleDeviceChange” is also called in ASIO mode, however all the names/id are empty (numUsed==0) .

HTH !

Thanks very much! I’ll add that DBT_DEVNODES_CHANGED value.

Midi detection is obviously a completely separate code area, so doesn’t belong in here, but I’ll think about adding a detector for it at some point.

Hey this looks really good!

Yep, about the DBT_ stuff, that would be cool that other windows 7/vista users test it. The difference (from the docs) between all those DBT_ isn’t really clear

Absolutely. And that’s also true for ASIO.

However, please forgive my noobness about the Windows API, but how come "WASAPIAudioIODeviceType::deviceChangeEventCallback() " is called even for non-WASAPI related events ?
I would have thought that you had a switch statement somewhere which would dispatch the events to the according callback instead of the callback being called all the time, and then, have a test inside the callback to see if the message was relevant.

But then again, it might be completely off-topic, as I said, I don’t know anything about Windows API and message loop itself …

Welcome to the messy, archaic world of win32 programming! Those messages seem to be the only callbacks that win32 provides about device removal, and it doesn’t tell you anything specific about the type of device that’s involved, so checking the WASAPI list was the only method I could find to detect a relevant change.