From bf1c4f5b311901a7d18899a5009e32931376052a Mon Sep 17 00:00:00 2001 From: Julian Storer Date: Wed, 9 Mar 2011 13:44:53 +0000 Subject: [PATCH] WASAPI session event callbacks. --- .../wrapper/juce_NPAPI_GlueCode.mm | 1 - juce_amalgamated.cpp | 80 +++++++++++++++++- .../plugins/formats/juce_VSTPluginFormat.mm | 1 - .../windows/juce_win32_NativeIncludes.h | 1 + src/native/windows/juce_win32_WASAPI.cpp | 81 ++++++++++++++++++- 5 files changed, 158 insertions(+), 6 deletions(-) diff --git a/extras/browser plugins/wrapper/juce_NPAPI_GlueCode.mm b/extras/browser plugins/wrapper/juce_NPAPI_GlueCode.mm index 1d40c87ac3..028bf46325 100644 --- a/extras/browser plugins/wrapper/juce_NPAPI_GlueCode.mm +++ b/extras/browser plugins/wrapper/juce_NPAPI_GlueCode.mm @@ -30,4 +30,3 @@ #include #define JUCE_NPAPI_WRAPPED_IN_MM 1 #include "juce_NPAPI_GlueCode.cpp" - diff --git a/juce_amalgamated.cpp b/juce_amalgamated.cpp index b78838377c..a5243f3ec3 100644 --- a/juce_amalgamated.cpp +++ b/juce_amalgamated.cpp @@ -608,6 +608,7 @@ #include #include #include + #include #include #include #endif @@ -256239,7 +256240,8 @@ public: minBufferSize (0), defaultBufferSize (0), latencySamples (0), - useExclusiveMode (useExclusiveMode_) + useExclusiveMode (useExclusiveMode_), + sampleRateHasChanged (false) { clientEvent = CreateEvent (0, false, false, _T("JuceWASAPI")); @@ -256306,6 +256308,8 @@ public: && (tryInitialisingWithFormat (true, 4) || tryInitialisingWithFormat (false, 4) || tryInitialisingWithFormat (false, 3) || tryInitialisingWithFormat (false, 2))) { + sampleRateHasChanged = false; + channelMaps.clear(); for (int i = 0; i <= channels.getHighestBit(); ++i) if (channels[i]) @@ -256317,6 +256321,8 @@ public: (void) check (client->GetBufferSize (&actualBufferSize)); + createSessionEventCallback(); + return check (client->SetEventHandle (clientEvent)); } @@ -256328,10 +256334,16 @@ public: if (client != 0) client->Stop(); + deleteSessionEventCallback(); client = 0; ResetEvent (clientEvent); } + void deviceSampleRateChanged() + { + sampleRateHasChanged = true; + } + ComSmartPtr device; ComSmartPtr client; double sampleRate, defaultSampleRate; @@ -256344,10 +256356,60 @@ public: Array channelMaps; UINT32 actualBufferSize; int bytesPerSample; + bool sampleRateHasChanged; virtual void updateFormat (bool isFloat) = 0; private: + + class SessionEventCallback : public ComBaseClassHelper + { + public: + SessionEventCallback (WASAPIDeviceBase& owner_) : owner (owner_) {} + + HRESULT __stdcall OnDisplayNameChanged (LPCWSTR, LPCGUID) { return S_OK; } + HRESULT __stdcall OnIconPathChanged (LPCWSTR, LPCGUID) { return S_OK; } + HRESULT __stdcall OnSimpleVolumeChanged (float, BOOL, LPCGUID) { return S_OK; } + HRESULT __stdcall OnChannelVolumeChanged (DWORD, float*, DWORD, LPCGUID) { return S_OK; } + HRESULT __stdcall OnGroupingParamChanged (LPCGUID, LPCGUID) { return S_OK; } + HRESULT __stdcall OnStateChanged (AudioSessionState) { return S_OK; } + + HRESULT __stdcall OnSessionDisconnected (AudioSessionDisconnectReason reason) + { + if (reason == DisconnectReasonFormatChanged) + owner.deviceSampleRateChanged(); + + return S_OK; + } + + private: + WASAPIDeviceBase& owner; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SessionEventCallback); + }; + + ComSmartPtr audioSessionControl; + ComSmartPtr sessionEventCallback; + + void createSessionEventCallback() + { + deleteSessionEventCallback(); + client->GetService (__uuidof (IAudioSessionControl), + (void**) audioSessionControl.resetAndGetPointerAddress()); + + if (audioSessionControl != 0) + { + sessionEventCallback = new SessionEventCallback (*this); + audioSessionControl->RegisterAudioSessionNotification (sessionEventCallback); + } + } + + void deleteSessionEventCallback() + { + audioSessionControl = 0; + sessionEventCallback = 0; + } + const ComSmartPtr createClient() { ComSmartPtr client; @@ -256873,9 +256935,9 @@ public: setMMThreadPriority(); const int bufferSize = currentBufferSizeSamples; - const int numInputBuffers = getActiveInputChannels().countNumberOfSetBits(); const int numOutputBuffers = getActiveOutputChannels().countNumberOfSetBits(); + bool sampleRateChanged = false; AudioSampleBuffer ins (jmax (1, numInputBuffers), bufferSize + 32); AudioSampleBuffer outs (jmax (1, numOutputBuffers), bufferSize + 32); @@ -256891,6 +256953,9 @@ public: if (threadShouldExit()) break; + + if (inputDevice->sampleRateHasChanged) + sampleRateChanged = true; } JUCE_TRY @@ -256906,7 +256971,18 @@ public: JUCE_CATCH_EXCEPTION if (outputDevice != 0) + { outputDevice->copyBuffers (const_cast (outputBuffers), numOutputBuffers, bufferSize, *this); + + if (outputDevice->sampleRateHasChanged) + sampleRateChanged = true; + } + + if (sampleRateChanged) + { + // xxx one of the devices has had its sample rate changed externally.. not 100% sure how + // to handle this.. + } } } diff --git a/src/audio/plugins/formats/juce_VSTPluginFormat.mm b/src/audio/plugins/formats/juce_VSTPluginFormat.mm index d0499353e3..411396ccf7 100644 --- a/src/audio/plugins/formats/juce_VSTPluginFormat.mm +++ b/src/audio/plugins/formats/juce_VSTPluginFormat.mm @@ -26,4 +26,3 @@ // This file just wraps juce_VSTPluginFormat.cpp in an objective-C wrapper #define JUCE_MAC_VST_INCLUDED 1 #include "juce_VSTPluginFormat.cpp" - diff --git a/src/native/windows/juce_win32_NativeIncludes.h b/src/native/windows/juce_win32_NativeIncludes.h index 8b4482f89a..b1fcd817f2 100644 --- a/src/native/windows/juce_win32_NativeIncludes.h +++ b/src/native/windows/juce_win32_NativeIncludes.h @@ -147,6 +147,7 @@ #include #include #include + #include #include #include #endif diff --git a/src/native/windows/juce_win32_WASAPI.cpp b/src/native/windows/juce_win32_WASAPI.cpp index ffd8d569b3..f5b30d6ee9 100644 --- a/src/native/windows/juce_win32_WASAPI.cpp +++ b/src/native/windows/juce_win32_WASAPI.cpp @@ -139,7 +139,8 @@ public: minBufferSize (0), defaultBufferSize (0), latencySamples (0), - useExclusiveMode (useExclusiveMode_) + useExclusiveMode (useExclusiveMode_), + sampleRateHasChanged (false) { clientEvent = CreateEvent (0, false, false, _T("JuceWASAPI")); @@ -206,6 +207,8 @@ public: && (tryInitialisingWithFormat (true, 4) || tryInitialisingWithFormat (false, 4) || tryInitialisingWithFormat (false, 3) || tryInitialisingWithFormat (false, 2))) { + sampleRateHasChanged = false; + channelMaps.clear(); for (int i = 0; i <= channels.getHighestBit(); ++i) if (channels[i]) @@ -217,6 +220,8 @@ public: (void) check (client->GetBufferSize (&actualBufferSize)); + createSessionEventCallback(); + return check (client->SetEventHandle (clientEvent)); } @@ -228,10 +233,17 @@ public: if (client != 0) client->Stop(); + deleteSessionEventCallback(); client = 0; ResetEvent (clientEvent); } + void deviceSampleRateChanged() + { + sampleRateHasChanged = true; + } + + //============================================================================== ComSmartPtr device; ComSmartPtr client; double sampleRate, defaultSampleRate; @@ -244,10 +256,61 @@ public: Array channelMaps; UINT32 actualBufferSize; int bytesPerSample; + bool sampleRateHasChanged; virtual void updateFormat (bool isFloat) = 0; private: + //============================================================================== + class SessionEventCallback : public ComBaseClassHelper + { + public: + SessionEventCallback (WASAPIDeviceBase& owner_) : owner (owner_) {} + + HRESULT __stdcall OnDisplayNameChanged (LPCWSTR, LPCGUID) { return S_OK; } + HRESULT __stdcall OnIconPathChanged (LPCWSTR, LPCGUID) { return S_OK; } + HRESULT __stdcall OnSimpleVolumeChanged (float, BOOL, LPCGUID) { return S_OK; } + HRESULT __stdcall OnChannelVolumeChanged (DWORD, float*, DWORD, LPCGUID) { return S_OK; } + HRESULT __stdcall OnGroupingParamChanged (LPCGUID, LPCGUID) { return S_OK; } + HRESULT __stdcall OnStateChanged (AudioSessionState) { return S_OK; } + + HRESULT __stdcall OnSessionDisconnected (AudioSessionDisconnectReason reason) + { + if (reason == DisconnectReasonFormatChanged) + owner.deviceSampleRateChanged(); + + return S_OK; + } + + private: + WASAPIDeviceBase& owner; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SessionEventCallback); + }; + + ComSmartPtr audioSessionControl; + ComSmartPtr sessionEventCallback; + + void createSessionEventCallback() + { + deleteSessionEventCallback(); + client->GetService (__uuidof (IAudioSessionControl), + (void**) audioSessionControl.resetAndGetPointerAddress()); + + if (audioSessionControl != 0) + { + sessionEventCallback = new SessionEventCallback (*this); + audioSessionControl->RegisterAudioSessionNotification (sessionEventCallback); + } + } + + void deleteSessionEventCallback() + { + audioSessionControl = 0; + sessionEventCallback = 0; + } + + //============================================================================== const ComSmartPtr createClient() { ComSmartPtr client; @@ -777,9 +840,9 @@ public: setMMThreadPriority(); const int bufferSize = currentBufferSizeSamples; - const int numInputBuffers = getActiveInputChannels().countNumberOfSetBits(); const int numOutputBuffers = getActiveOutputChannels().countNumberOfSetBits(); + bool sampleRateChanged = false; AudioSampleBuffer ins (jmax (1, numInputBuffers), bufferSize + 32); AudioSampleBuffer outs (jmax (1, numOutputBuffers), bufferSize + 32); @@ -795,6 +858,9 @@ public: if (threadShouldExit()) break; + + if (inputDevice->sampleRateHasChanged) + sampleRateChanged = true; } JUCE_TRY @@ -810,7 +876,18 @@ public: JUCE_CATCH_EXCEPTION if (outputDevice != 0) + { outputDevice->copyBuffers (const_cast (outputBuffers), numOutputBuffers, bufferSize, *this); + + if (outputDevice->sampleRateHasChanged) + sampleRateChanged = true; + } + + if (sampleRateChanged) + { + // xxx one of the devices has had its sample rate changed externally.. not 100% sure how + // to handle this.. + } } }