| @@ -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<int> newBufferSizes (getBufferSizesFromDevice()); | |||
| Array<double> newSampleRates (getSampleRatesFromDevice()); | |||
| const double newSampleRate = getNominalSampleRate(); | |||
| const int newBufferSize = getFrameSizeFromDevice(); | |||
| inputLatency = getLatencyFromDevice (kAudioDevicePropertyScopeInput); | |||
| outputLatency = getLatencyFromDevice (kAudioDevicePropertyScopeOutput); | |||
| Array<int> newBufferSizes = getBufferSizesFromDevice(); | |||
| Array<double> newSampleRates = getSampleRatesFromDevice(); | |||
| const int newInputLatency = getLatencyFromDevice (kAudioDevicePropertyScopeInput); | |||
| const int newOutputLatency = getLatencyFromDevice (kAudioDevicePropertyScopeOutput); | |||
| Array<CallbackDetailsForChannel> 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(); | |||
| } | |||