JUCE lockup on start/buffer change, CoreAudio

For the StandaloneApp audio settings, sometimes the app freezes when the buffer size is changed. I suspect it might be related to stopping and immediately restarting audio.

I tracked it to an infinite contention on callbackLock inside juce_mac_CoreAudio.cpp:

if (OK (AudioDeviceStart (deviceID, audioProcID)))

This sometimes can lock forever because it’s done inside a scoped lock for callbackLoop, and CoreAudio HAL can already invoke and wait for audioCallback to complete inside AudioDeviceStart. The callback freezes on attempting to lock the same critical section from a different thread, and AudioDeviceStart never returns, as it waits (through a set of its own pthread primitives) for the callback to complete.

I solved it in my source base by adding a scoped unlock before the AudioDeviceStart call:

+ const ScopedUnlock sul (callbackLock); // prevent lockup, as AudioDeviceStart may invoke callback
  if (OK (AudioDeviceStart (deviceID, audioProcID)))

I don’t know if it has any implications or side effects to this. Maybe refactoring this way would do?

started = true;
const ScopedUnlock sul (callbackLock); // prevent lockup, as AudioDeviceStart may invoke callback
if (!OK (AudioDeviceStart (deviceID, audioProcID)))
{
    started = false;
    OK (AudioDeviceDestroyIOProcID (deviceID, audioProcID));
    audioProcID = {};
}

This sounds like an issue that was recently fixed on the develop branch. If you’re not using the latest version from the develop branch, please update and test again.