From 076896d33be81e11b0c918486a419cd36aef8cf3 Mon Sep 17 00:00:00 2001 From: jules Date: Wed, 3 Feb 2016 09:57:42 +0000 Subject: [PATCH] Improved CoreAudio handling of USB audio devices being unplugged --- .../native/juce_mac_CoreAudio.cpp | 96 +++++++++++-------- 1 file changed, 58 insertions(+), 38 deletions(-) diff --git a/modules/juce_audio_devices/native/juce_mac_CoreAudio.cpp b/modules/juce_audio_devices/native/juce_mac_CoreAudio.cpp index e3ec6cea46..7a0dbf30af 100644 --- a/modules/juce_audio_devices/native/juce_mac_CoreAudio.cpp +++ b/modules/juce_audio_devices/native/juce_mac_CoreAudio.cpp @@ -388,65 +388,84 @@ public: return 0; } - void updateDetailsFromDevice() + int getFrameSizeFromDevice() const { - stopTimer(); + AudioObjectPropertyAddress pa; + pa.mScope = kAudioObjectPropertyScopeWildcard; + pa.mElement = kAudioObjectPropertyElementMaster; + pa.mSelector = kAudioDevicePropertyBufferFrameSize; - if (deviceID == 0) - return; + UInt32 framesPerBuf = (UInt32) bufferSize; + UInt32 size = sizeof (framesPerBuf); + AudioObjectGetPropertyData (deviceID, &pa, 0, nullptr, &size, &framesPerBuf); + return (int) framesPerBuf; + } - // this collects all the new details from the device without any locking, then - // locks + swaps them afterwards. + bool isDeviceAlive() const + { AudioObjectPropertyAddress pa; pa.mScope = kAudioObjectPropertyScopeWildcard; pa.mElement = kAudioObjectPropertyElementMaster; + pa.mSelector = kAudioDevicePropertyDeviceIsAlive; - UInt32 isAlive; + UInt32 isAlive = 0; UInt32 size = sizeof (isAlive); - pa.mSelector = kAudioDevicePropertyDeviceIsAlive; - if (OK (AudioObjectGetPropertyData (deviceID, &pa, 0, nullptr, &size, &isAlive)) && isAlive == 0) - return; + return deviceID != 0 + && OK (AudioObjectGetPropertyData (deviceID, &pa, 0, nullptr, &size, &isAlive)) + && isAlive != 0; + } + + bool updateDetailsFromDevice() + { + stopTimer(); - const double currentRate = getNominalSampleRate(); - if (currentRate > 0) - sampleRate = currentRate; + if (! isDeviceAlive()) + return false; - UInt32 framesPerBuf = (UInt32) bufferSize; - size = sizeof (framesPerBuf); - pa.mSelector = kAudioDevicePropertyBufferFrameSize; - AudioObjectGetPropertyData (deviceID, &pa, 0, nullptr, &size, &framesPerBuf); + // this collects all the new details from the device without any locking, then + // locks + swaps them afterwards. - Array newBufferSizes (getBufferSizesFromDevice()); - Array newSampleRates (getSampleRatesFromDevice()); + const double newSampleRate = getNominalSampleRate(); + const int newBufferSize = getFrameSizeFromDevice(); - inputLatency = getLatencyFromDevice (kAudioDevicePropertyScopeInput); - outputLatency = getLatencyFromDevice (kAudioDevicePropertyScopeOutput); + Array newBufferSizes = getBufferSizesFromDevice(); + Array newSampleRates = getSampleRatesFromDevice(); + + const int newInputLatency = getLatencyFromDevice (kAudioDevicePropertyScopeInput); + const int newOutputLatency = getLatencyFromDevice (kAudioDevicePropertyScopeOutput); Array newInChans, newOutChans; StringArray newInNames (getChannelInfo (true, newInChans)); StringArray newOutNames (getChannelInfo (false, newOutChans)); - const int inputBitDepth = getBitDepthFromDevice (kAudioDevicePropertyScopeInput); - const int outputBitDepth = getBitDepthFromDevice (kAudioDevicePropertyScopeOutput); + const int newBitDepth = jmax (getBitDepthFromDevice (kAudioDevicePropertyScopeInput), + getBitDepthFromDevice (kAudioDevicePropertyScopeOutput)); + + { + const ScopedLock sl (callbackLock); - bitDepth = jmax (inputBitDepth, outputBitDepth); - if (bitDepth <= 0) - bitDepth = 32; + bitDepth = newBitDepth > 0 ? newBitDepth : 32; - // after getting the new values, lock + apply them - const ScopedLock sl (callbackLock); + if (newSampleRate > 0) + sampleRate = newSampleRate; - bufferSize = (int) framesPerBuf; - allocateTempBuffers(); + inputLatency = newInputLatency; + outputLatency = newOutputLatency; + bufferSize = newBufferSize; - sampleRates.swapWith (newSampleRates); - bufferSizes.swapWith (newBufferSizes); + sampleRates.swapWith (newSampleRates); + bufferSizes.swapWith (newBufferSizes); - inChanNames.swapWith (newInNames); - outChanNames.swapWith (newOutNames); + inChanNames.swapWith (newInNames); + outChanNames.swapWith (newOutNames); - inputChannelInfo.swapWith (newInChans); - outputChannelInfo.swapWith (newOutChans); + inputChannelInfo.swapWith (newInChans); + outputChannelInfo.swapWith (newOutChans); + + allocateTempBuffers(); + } + + return true; } //============================================================================== @@ -769,9 +788,10 @@ public: stopTimer(); const double oldSampleRate = sampleRate; const int oldBufferSize = bufferSize; - updateDetailsFromDevice(); - if (oldBufferSize != bufferSize || oldSampleRate != sampleRate) + if (! updateDetailsFromDevice()) + owner.stop(); + else if (oldBufferSize != bufferSize || oldSampleRate != sampleRate) owner.restart(); }