Browse Source

WASAPI: Suspend processing when AudioSessionStateInactive session event is received and restart on AudioSessionStateActive

tags/2021-05-28
ed 5 years ago
parent
commit
fa0f3af034
1 changed files with 99 additions and 75 deletions
  1. +99
    -75
      modules/juce_audio_devices/native/juce_win32_WASAPI.cpp

+ 99
- 75
modules/juce_audio_devices/native/juce_win32_WASAPI.cpp View File

@@ -352,8 +352,8 @@ void copyWavFormat (WAVEFORMATEXTENSIBLE& dest, const WAVEFORMATEX* src) noexcep
class WASAPIDeviceBase
{
public:
WASAPIDeviceBase (const ComSmartPtr<IMMDevice>& d, bool exclusiveMode, std::function<void()>&& cb)
: device (d), useExclusiveMode (exclusiveMode), reopenCallback (cb)
WASAPIDeviceBase (const ComSmartPtr<IMMDevice>& d, bool exclusiveMode)
: device (d), useExclusiveMode (exclusiveMode)
{
clientEvent = CreateEvent (nullptr, false, false, nullptr);
@@ -429,7 +429,8 @@ public:
&& tryInitialisingWithBufferSize (bufferSizeSamples))
{
sampleRateHasChanged = false;
shouldClose = false;
shouldShutdown = false;
channelMaps.clear();
for (int i = 0; i <= channels.getHighestBit(); ++i)
@@ -468,9 +469,19 @@ public:
sampleRateHasChanged = true;
}
void deviceBecameInactive()
void deviceSessionBecameInactive()
{
isActive = false;
}
void deviceSessionExpired()
{
shouldShutdown = true;
}
void deviceSessionBecameActive()
{
shouldClose = true;
isActive = true;
}
//==============================================================================
@@ -487,8 +498,7 @@ public:
Array<int> channelMaps;
UINT32 actualBufferSize = 0;
int bytesPerSample = 0, bytesPerFrame = 0;
bool sampleRateHasChanged = false, shouldClose = false;
std::function<void()> reopenCallback;
std::atomic<bool> sampleRateHasChanged { false }, shouldShutdown { false }, isActive { true };
virtual void updateFormat (bool isFloat) = 0;
@@ -504,13 +514,20 @@ private:
JUCE_COMRESULT OnChannelVolumeChanged (DWORD, float*, DWORD, LPCGUID) { return S_OK; }
JUCE_COMRESULT OnGroupingParamChanged (LPCGUID, LPCGUID) { return S_OK; }
JUCE_COMRESULT OnStateChanged(AudioSessionState state)
JUCE_COMRESULT OnStateChanged (AudioSessionState state)
{
if (state == AudioSessionStateActive)
owner.reopenCallback();
if (state == AudioSessionStateInactive || state == AudioSessionStateExpired)
owner.deviceBecameInactive();
switch (state)
{
case AudioSessionStateInactive:
owner.deviceSessionBecameInactive();
break;
case AudioSessionStateExpired:
owner.deviceSessionExpired();
break;
case AudioSessionStateActive:
owner.deviceSessionBecameActive();
break;
}
return S_OK;
}
@@ -692,8 +709,8 @@ private:
class WASAPIInputDevice : public WASAPIDeviceBase
{
public:
WASAPIInputDevice (const ComSmartPtr<IMMDevice>& d, bool exclusiveMode, std::function<void()>&& reopenCallback)
: WASAPIDeviceBase (d, exclusiveMode, std::move (reopenCallback))
WASAPIInputDevice (const ComSmartPtr<IMMDevice>& d, bool exclusiveMode)
: WASAPIDeviceBase (d, exclusiveMode)
{
}
@@ -746,6 +763,8 @@ public:
return false;
purgeInputBuffers();
isActive = true;
return true;
}
@@ -853,8 +872,8 @@ private:
class WASAPIOutputDevice : public WASAPIDeviceBase
{
public:
WASAPIOutputDevice (const ComSmartPtr<IMMDevice>& d, bool exclusiveMode, std::function<void()>&& reopenCallback)
: WASAPIDeviceBase (d, exclusiveMode, std::move (reopenCallback))
WASAPIOutputDevice (const ComSmartPtr<IMMDevice>& d, bool exclusiveMode)
: WASAPIDeviceBase (d, exclusiveMode)
{
}
@@ -899,7 +918,12 @@ public:
if (check (renderClient->GetBuffer (samplesToDo, &outputData)))
renderClient->ReleaseBuffer (samplesToDo, AUDCLNT_BUFFERFLAGS_SILENT);
return check (client->Start());
if (! check (client->Start()))
return false;
isActive = true;
return true;
}
int getNumSamplesAvailableToCopy() const
@@ -1124,7 +1148,8 @@ public:
if (inputDevice != nullptr) ResetEvent (inputDevice->clientEvent);
if (outputDevice != nullptr) ResetEvent (outputDevice->clientEvent);
deviceBecameInactive = false;
shouldShutdown = false;
deviceSampleRateChanged = false;
startThread (8);
Thread::sleep (5);
@@ -1233,7 +1258,6 @@ public:
auto bufferSize = currentBufferSizeSamples;
auto numInputBuffers = getActiveInputChannels().countNumberOfSetBits();
auto numOutputBuffers = getActiveOutputChannels().countNumberOfSetBits();
bool sampleRateHasChanged = false;
AudioBuffer<float> ins (jmax (1, numInputBuffers), bufferSize + 32);
AudioBuffer<float> outs (jmax (1, numOutputBuffers), bufferSize + 32);
@@ -1244,13 +1268,22 @@ public:
while (! threadShouldExit())
{
if ((outputDevice != nullptr && outputDevice->shouldClose)
|| (inputDevice != nullptr && inputDevice->shouldClose))
if ((outputDevice != nullptr && outputDevice->shouldShutdown)
|| (inputDevice != nullptr && inputDevice->shouldShutdown))
{
deviceBecameInactive = true;
shouldShutdown = true;
triggerAsyncUpdate();
break;
}
if (inputDevice != nullptr && ! deviceBecameInactive)
auto inputDeviceActive = (inputDevice != nullptr && inputDevice->isActive);
auto outputDeviceActive = (outputDevice != nullptr && outputDevice->isActive);
if (! inputDeviceActive && ! outputDeviceActive)
continue;
if (inputDeviceActive)
{
if (outputDevice == nullptr)
{
@@ -1272,12 +1305,13 @@ public:
if (inputDevice->sampleRateHasChanged)
{
sampleRateHasChanged = true;
sampleRateChangedByOutput = false;
deviceSampleRateChanged = true;
triggerAsyncUpdate();
break;
}
}
if (! deviceBecameInactive)
{
const ScopedTryLock sl (startStopLock);
@@ -1288,7 +1322,7 @@ public:
outs.clear();
}
if (outputDevice != nullptr && ! deviceBecameInactive)
if (outputDeviceActive)
{
// 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
@@ -1296,15 +1330,11 @@ public:
if (outputDevice->sampleRateHasChanged)
{
sampleRateHasChanged = true;
sampleRateChangedByOutput = true;
}
}
deviceSampleRateChanged = true;
triggerAsyncUpdate();
if (sampleRateHasChanged || deviceBecameInactive)
{
triggerAsyncUpdate();
break; // Quit the thread... will restart it later!
break;
}
}
}
}
@@ -1332,7 +1362,7 @@ private:
AudioIODeviceCallback* callback = {};
CriticalSection startStopLock;
bool sampleRateChangedByOutput = false, deviceBecameInactive = false;
std::atomic<bool> shouldShutdown { false }, deviceSampleRateChanged { false };
BigInteger lastKnownInputChannels, lastKnownOutputChannels;
@@ -1368,60 +1398,54 @@ private:
auto flow = getDataFlow (device);
auto deviceReopenCallback = [this]
{
if (deviceBecameInactive)
{
MessageManager::callAsync ([this]
{
close();
reopenDevices();
});
}
};
if (deviceId == inputDeviceId && flow == eCapture)
inputDevice.reset (new WASAPIInputDevice (device, useExclusiveMode, deviceReopenCallback));
inputDevice.reset (new WASAPIInputDevice (device, useExclusiveMode));
else if (deviceId == outputDeviceId && flow == eRender)
outputDevice.reset (new WASAPIOutputDevice (device, useExclusiveMode, deviceReopenCallback));
outputDevice.reset (new WASAPIOutputDevice (device, useExclusiveMode));
}
return (outputDeviceId.isEmpty() || (outputDevice != nullptr && outputDevice->isOk()))
&& (inputDeviceId.isEmpty() || (inputDevice != nullptr && inputDevice->isOk()));
}
void reopenDevices()
//==============================================================================
void handleAsyncUpdate() override
{
outputDevice = nullptr;
inputDevice = nullptr;
auto closeDevices = [this]
{
close();
initialise();
outputDevice = nullptr;
inputDevice = nullptr;
};
open (lastKnownInputChannels, lastKnownOutputChannels,
getChangedSampleRate(), currentBufferSizeSamples);
if (shouldShutdown)
{
closeDevices();
}
else if (deviceSampleRateChanged)
{
auto sampleRateChangedByInput = (inputDevice != nullptr && inputDevice->sampleRateHasChanged);
start (callback);
}
closeDevices();
initialise();
//==============================================================================
void handleAsyncUpdate() override
{
stop();
auto changedSampleRate = [this, sampleRateChangedByInput] ()
{
if (inputDevice != nullptr && sampleRateChangedByInput)
return inputDevice->defaultSampleRate;
// sample rate change
if (! deviceBecameInactive)
reopenDevices();
}
if (outputDevice != nullptr && ! sampleRateChangedByInput)
return outputDevice->defaultSampleRate;
double getChangedSampleRate() const
{
if (outputDevice != nullptr && sampleRateChangedByOutput)
return outputDevice->defaultSampleRate;
return 0.0;
}();
if (inputDevice != nullptr && ! sampleRateChangedByOutput)
return inputDevice->defaultSampleRate;
open (lastKnownInputChannels, lastKnownOutputChannels,
changedSampleRate, currentBufferSizeSamples);
return 0.0;
start (callback);
}
}
//==============================================================================
@@ -1542,7 +1566,7 @@ private:
HRESULT notify()
{
if (device != nullptr)
device->triggerAsyncDeviceChangeCallback();
device->triggerAsyncDeviceChangeCallback();
return S_OK;
}


Loading…
Cancel
Save