| @@ -388,65 +388,84 @@ public: | |||||
| return 0; | 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; | AudioObjectPropertyAddress pa; | ||||
| pa.mScope = kAudioObjectPropertyScopeWildcard; | pa.mScope = kAudioObjectPropertyScopeWildcard; | ||||
| pa.mElement = kAudioObjectPropertyElementMaster; | pa.mElement = kAudioObjectPropertyElementMaster; | ||||
| pa.mSelector = kAudioDevicePropertyDeviceIsAlive; | |||||
| UInt32 isAlive; | |||||
| UInt32 isAlive = 0; | |||||
| UInt32 size = sizeof (isAlive); | 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; | Array<CallbackDetailsForChannel> newInChans, newOutChans; | ||||
| StringArray newInNames (getChannelInfo (true, newInChans)); | StringArray newInNames (getChannelInfo (true, newInChans)); | ||||
| StringArray newOutNames (getChannelInfo (false, newOutChans)); | 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(); | stopTimer(); | ||||
| const double oldSampleRate = sampleRate; | const double oldSampleRate = sampleRate; | ||||
| const int oldBufferSize = bufferSize; | const int oldBufferSize = bufferSize; | ||||
| updateDetailsFromDevice(); | |||||
| if (oldBufferSize != bufferSize || oldSampleRate != sampleRate) | |||||
| if (! updateDetailsFromDevice()) | |||||
| owner.stop(); | |||||
| else if (oldBufferSize != bufferSize || oldSampleRate != sampleRate) | |||||
| owner.restart(); | owner.restart(); | ||||
| } | } | ||||