libsdl-org / SDL

Simple Directmedia Layer
https://libsdl.org
zlib License
10.24k stars 1.87k forks source link

Failed to open audio recording device [name]. SDL Error: CoreAudio error (AudioQueueStart): -66681 [MacOS] #10432

Open mail2mhossain opened 4 months ago

mail2mhossain commented 4 months ago

When using our app, if an audio input or output device is unplugged, I can switch to another available device on all platforms (Windows, MacOS, Linux). However, after plugging the device back in, the app can only switch back to it on Windows.

On MacOS, I encounter the following error: "Failed to open audio recording device [name]. SDL Error: CoreAudio error (AudioQueueStart): -66681".

This indicates that the unplugged device is still in use or blocked by SDL2 or MacOS. I have tried the following code in the "InitRecordingDevice" method after calling "CloseAudio()", but it still does not work:

SDL_QuitSubSystem(SDL_INIT_AUDIO); SDL_InitSubSystem(SDL_INIT_AUDIO);

I have also added "SDL_ClearQueuedAudio(dev)" in the "CloseAudio" method before calling "CloseAudioRecordingDevice", but this has not resolved the issue either.

Are there any solutions for this problem?

icculus commented 4 months ago

Are there any solutions for this problem?

This sounds like a bug in SDL; I'll try to reproduce it here tomorrow morning.

icculus commented 4 months ago

This reproduces for me with testaudiohotplug on both SDL2 and SDL3 (just unplug USB headphones and plug them back in while the test program is running). Digging deeper.

icculus commented 4 months ago

Looks like (in SDL3, at least) device->currently_opened is zero when DeviceAliveNotification is fired...so when we tell SDL that the device is disconnected, it doesn't try to close it, so all sorts of stuff is still dangling.

Not sure why yet, looking into it still.

icculus commented 4 months ago

Wait, no, that was the recording half of the USB headset. But I'm also noticing the testaudiohotplug doesn't close the device at all, so I bet that's what's happening.

icculus commented 4 months ago

Nope, that didn't fix it.

I'm starting to believe this is a macOS bug; the internet (since Mac OS X 10.5, apparently) has been asking "why does this error pop up some times?" and no one seems to know.

Notably, it seems to hang all the other playing devices too, for several seconds, when replugging the USB headset. If I start the device as unplugged and plug it in after everything else, it picks it up fine and works (but then, an unplug/replug after will still cause failure).

I added a 5 second delay to see if it just needed a little time to get itself together on hotplug; didn't fix it.

Feels like the CoreAudio framework is holding some state from the previous device connection that confuses it on replugging. I could be wrong. I'll ask our Apple contact.

icculus commented 4 months ago

Okay, I've moved the SDL coreaudio code out to a standalone program that still reproduces the issue, which is to say this could still be our bug, since it's still our code, but now I can hand this to Apple as a ~500 line Objective-C program without any external dependencies, including SDL itself:

https://gist.github.com/icculus/b021a110eb1bcdfa72f169a620e2d46e

Stay tuned!

mail2mhossain commented 2 months ago

Any Update

icculus commented 2 months ago

I never got a reply from Apple. :(

icculus commented 1 month ago

I filed this with Apple, outside of the usual contact.

rdar://15576779

icculus commented 1 month ago

Moving to 3.x, but if Apple moves on the bug report, we can revisit.

darbyjohnston commented 1 month ago

Hi, I am also seeing a crash that I believe is related to this. If I try to re-open the default device after seeing the first -66681 error message, I get this crash with the following trace:

frame #0: 0x0000000101385430 tlplay`SDL_AtomicSet_REAL(a=0x000000000000006c, v=1) at SDL_atomic.c:194:12
    frame #1: 0x000000010148d330 tlplay`default_device_changed(inObjectID=1, inNumberAddresses=1, inAddresses=0x000060000000ded0, inUserData=0x000060000332d9a0) at SDL_coreaudio.m:675:5
    frame #2: 0x000000018fd17a04 CoreAudio`HALObject::PropertiesChanged(unsigned int, AudioObjectPropertyAddress const*) + 1564
    frame #3: 0x000000018fb9c228 CoreAudio`HALSystem::PropertiesChanged(unsigned int, AudioObjectPropertyAddress const*) + 412
    frame #4: 0x000000018fc6bce8 CoreAudio`HALC_ShellPlugIn::ProxyObject_PropertiesChanged(unsigned int, unsigned int, AudioObjectPropertyAddress const*) + 1060
    frame #5: 0x000000018fcc31cc CoreAudio`HALC_ProxyNotifications::CallListener_f(void*) + 92
    frame #6: 0x000000018d81c400 libdispatch.dylib`_dispatch_client_callout + 20
    frame #7: 0x000000018d823a88 libdispatch.dylib`_dispatch_lane_serial_drain + 668
    frame #8: 0x000000018d82462c libdispatch.dylib`_dispatch_lane_invoke + 436
    frame #9: 0x000000018d8258e8 libdispatch.dylib`_dispatch_workloop_invoke + 1764
    frame #10: 0x000000018d82f244 libdispatch.dylib`_dispatch_workloop_worker_thread + 648
    frame #11: 0x000000018d9c8074 libsystem_pthread.dylib`_pthread_wqthread + 288

In default_device_changed() it looks like this->hidden is null. If I change the code to add a check for null the crash seems to be fixed, does this seem like a reasonable change?

    if (this->hidden)
    {
        SDL_AtomicSet(&this->hidden->device_change_flag, 1); /* let the audioqueue thread pick up on this when safe to do so. */
    }

This is on macOS 13.7 with SDL2 2.30.9. I am triggering the error by turning on/off a bluetooth headset.

I am also seeing these errors in lldb when turning on/off the bluetooth headset:

2024-11-04 14:15:58.569647-0800 tlplay[29868:35257908]   HALC_ProxyObjectMap.cpp:153    HALC_ProxyObjectMap::_CopyObjectByObjectID: failed to create the local object
2024-11-04 14:15:58.569670-0800 tlplay[29868:35257908]      HALC_ShellDevice.cpp:2606   HALC_ShellDevice::RebuildControlList: couldn't find the control object
2024-11-04 14:15:58.632811-0800 tlplay[29868:35258610] AudioHardware-mac-imp.cpp:660    AudioObjectGetPropertyData: no object with given ID 0
2024-11-04 14:15:58.772863-0800 tlplay[29868:35258812] [aqsrv]              AQServer.cpp:80    Exception caught in AudioQueueInternalNotifyRunning - error -66671
2024-11-04 14:15:58.796104-0800 tlplay[29868:35258812] [aqsrv]              AQServer.cpp:80    Exception caught in AudioQueueInternalNotifyRunning - error -66671
2024-11-04 14:15:59.016756-0800 tlplay[29868:35258812] [aqsrv]              AQServer.cpp:80    Exception caught in AudioQueueInternalStop_Sync - error -66671
2024-11-04 14:15:59.039934-0800 tlplay[29868:35257955] [aqsrv]              AQServer.cpp:80    Exception caught in AudioQueueInternalStop_Sync - error -66671