| @@ -357,7 +357,8 @@ public: | |||
| actualBufferSize (0), | |||
| bytesPerSample (0), | |||
| bytesPerFrame (0), | |||
| sampleRateHasChanged (false) | |||
| sampleRateHasChanged (false), | |||
| shouldClose (false) | |||
| { | |||
| clientEvent = CreateEvent (nullptr, false, false, nullptr); | |||
| @@ -468,6 +469,11 @@ public: | |||
| sampleRateHasChanged = true; | |||
| } | |||
| void deviceBecameInactive() | |||
| { | |||
| shouldClose = true; | |||
| } | |||
| //============================================================================== | |||
| ComSmartPtr<IMMDevice> device; | |||
| ComSmartPtr<IAudioClient> client; | |||
| @@ -482,7 +488,7 @@ public: | |||
| Array<int> channelMaps; | |||
| UINT32 actualBufferSize; | |||
| int bytesPerSample, bytesPerFrame; | |||
| bool sampleRateHasChanged; | |||
| bool sampleRateHasChanged, shouldClose; | |||
| virtual void updateFormat (bool isFloat) = 0; | |||
| @@ -498,10 +504,17 @@ private: | |||
| JUCE_COMRESULT OnSimpleVolumeChanged (float, BOOL, LPCGUID) { return S_OK; } | |||
| JUCE_COMRESULT OnChannelVolumeChanged (DWORD, float*, DWORD, LPCGUID) { return S_OK; } | |||
| JUCE_COMRESULT OnGroupingParamChanged (LPCGUID, LPCGUID) { return S_OK; } | |||
| JUCE_COMRESULT OnStateChanged (AudioSessionState) { return S_OK; } | |||
| JUCE_COMRESULT OnStateChanged(AudioSessionState state) | |||
| { | |||
| if (state == AudioSessionStateInactive || state == AudioSessionStateExpired) | |||
| owner.deviceBecameInactive(); | |||
| return S_OK; | |||
| } | |||
| JUCE_COMRESULT OnSessionDisconnected (AudioSessionDisconnectReason reason) | |||
| { | |||
| Logger::writeToLog("OnSessionDisconnected"); | |||
| if (reason == DisconnectReasonFormatChanged) | |||
| owner.deviceSampleRateChanged(); | |||
| @@ -969,7 +982,8 @@ public: | |||
| isStarted (false), | |||
| currentBufferSizeSamples (0), | |||
| currentSampleRate (0), | |||
| callback (nullptr) | |||
| callback (nullptr), | |||
| deviceBecameInactive (false) | |||
| { | |||
| } | |||
| @@ -1107,6 +1121,8 @@ public: | |||
| if (inputDevice != nullptr) ResetEvent (inputDevice->clientEvent); | |||
| if (outputDevice != nullptr) ResetEvent (outputDevice->clientEvent); | |||
| deviceBecameInactive = false; | |||
| startThread (8); | |||
| Thread::sleep (5); | |||
| @@ -1226,8 +1242,14 @@ public: | |||
| while (! threadShouldExit()) | |||
| { | |||
| if (inputDevice != nullptr) | |||
| if (outputDevice != nullptr && outputDevice->shouldClose) | |||
| deviceBecameInactive = true; | |||
| if (inputDevice != nullptr && ! deviceBecameInactive) | |||
| { | |||
| if (inputDevice->shouldClose) | |||
| deviceBecameInactive = true; | |||
| if (outputDevice == nullptr) | |||
| { | |||
| if (WaitForSingleObject (inputDevice->clientEvent, 1000) == WAIT_TIMEOUT) | |||
| @@ -1253,6 +1275,7 @@ public: | |||
| } | |||
| } | |||
| if (! deviceBecameInactive) | |||
| { | |||
| const ScopedTryLock sl (startStopLock); | |||
| @@ -1263,7 +1286,7 @@ public: | |||
| outs.clear(); | |||
| } | |||
| if (outputDevice != nullptr) | |||
| if (outputDevice != nullptr && !deviceBecameInactive) | |||
| { | |||
| // Note that this function is handed the input device so it can check for the event and make sure | |||
| // the input reservoir is filled up correctly even when bufferSize > device actualBufferSize | |||
| @@ -1276,7 +1299,7 @@ public: | |||
| } | |||
| } | |||
| if (sampleRateHasChanged) | |||
| if (sampleRateHasChanged || deviceBecameInactive) | |||
| { | |||
| triggerAsyncUpdate(); | |||
| break; // Quit the thread... will restart it later! | |||
| @@ -1303,7 +1326,7 @@ private: | |||
| bool isOpen_, isStarted; | |||
| int currentBufferSizeSamples; | |||
| double currentSampleRate; | |||
| bool sampleRateChangedByOutput; | |||
| bool sampleRateChangedByOutput, deviceBecameInactive; | |||
| AudioIODeviceCallback* callback; | |||
| CriticalSection startStopLock; | |||
| @@ -1354,12 +1377,17 @@ private: | |||
| outputDevice = nullptr; | |||
| inputDevice = nullptr; | |||
| initialise(); | |||
| open (lastKnownInputChannels, lastKnownOutputChannels, | |||
| getChangedSampleRate(), currentBufferSizeSamples); | |||
| // sample rate change | |||
| if (! deviceBecameInactive) | |||
| { | |||
| initialise(); | |||
| open (lastKnownInputChannels, lastKnownOutputChannels, | |||
| getChangedSampleRate(), currentBufferSizeSamples); | |||
| start (callback); | |||
| start (callback); | |||
| } | |||
| } | |||
| double getChangedSampleRate() const | |||
| @@ -1481,7 +1509,7 @@ private: | |||
| HRESULT STDMETHODCALLTYPE OnDeviceAdded (LPCWSTR) { return notify(); } | |||
| HRESULT STDMETHODCALLTYPE OnDeviceRemoved (LPCWSTR) { return notify(); } | |||
| HRESULT STDMETHODCALLTYPE OnDeviceStateChanged (LPCWSTR, DWORD) { return notify(); } | |||
| HRESULT STDMETHODCALLTYPE OnDeviceStateChanged(LPCWSTR, DWORD) { return notify(); } | |||
| HRESULT STDMETHODCALLTYPE OnDefaultDeviceChanged (EDataFlow, ERole, LPCWSTR) { return notify(); } | |||
| HRESULT STDMETHODCALLTYPE OnPropertyValueChanged (LPCWSTR, const PROPERTYKEY) { return notify(); } | |||