From 32b9b1e9db018a020c2a1e83d4592466e1078e8c Mon Sep 17 00:00:00 2001 From: ed Date: Fri, 23 Oct 2020 10:52:27 +0100 Subject: [PATCH] CoreAudio: Prevent audio glitches before microphone permission granted If input channels have been requested but no data is being sent from CoreAudio (usually due to permissions not being granted yet) then avoid waiting unnecessarily in AudioIODeviceCombiner::readInput() which could previously cause audio glitches. Also changed the wait time to use an exponential backoff. --- .../native/juce_mac_CoreAudio.cpp | 30 ++++++++++++++----- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/modules/juce_audio_devices/native/juce_mac_CoreAudio.cpp b/modules/juce_audio_devices/native/juce_mac_CoreAudio.cpp index 646aae7c7e..8d6776411a 100644 --- a/modules/juce_audio_devices/native/juce_mac_CoreAudio.cpp +++ b/modules/juce_audio_devices/native/juce_mac_CoreAudio.cpp @@ -1663,11 +1663,16 @@ private: void readInput (AudioBuffer& buffer, const int numSamples, const int blockSizeMs) { for (auto* d : devices) - d->done = (d->numInputChans == 0); + d->done = (d->numInputChans == 0 || d->isWaitingForInput); - for (int tries = 5;;) + float totalWaitTimeMs = blockSizeMs * 5.0f; + constexpr int numReadAttempts = 6; + auto sumPower2s = [] (int maxPower) { return (1 << (maxPower + 1)) - 1; }; + float waitTime = totalWaitTimeMs / (float) sumPower2s (numReadAttempts - 2); + + for (int numReadAttemptsRemaining = numReadAttempts;;) { - bool anyRemaining = false; + bool anySamplesRemaining = false; for (auto* d : devices) { @@ -1679,17 +1684,20 @@ private: d->done = true; } else - anyRemaining = true; + { + anySamplesRemaining = true; + } } } - if (! anyRemaining) + if (! anySamplesRemaining) return; - if (--tries == 0) + if (--numReadAttemptsRemaining == 0) break; - wait (blockSizeMs); + wait (jmax (1, roundToInt (waitTime))); + waitTime *= 2.0f; } for (auto* d : devices) @@ -1717,7 +1725,9 @@ private: d->done = true; } else + { anyRemaining = true; + } } } @@ -1808,6 +1818,8 @@ private: numInputChans = useInputs ? device->getActiveInputChannels().countNumberOfSetBits() : 0; numOutputChans = useOutputs ? device->getActiveOutputChannels().countNumberOfSetBits() : 0; + isWaitingForInput = numInputChans > 0; + inputIndex = channelIndex; outputIndex = channelIndex + numInputChans; @@ -1892,6 +1904,8 @@ private: { if (numInputChannels > 0) { + isWaitingForInput = false; + int start1, size1, start2, size2; inputFifo.prepareToWrite (numSamples, start1, size1, start2, size2); @@ -1972,7 +1986,7 @@ private: AudioIODeviceCombiner& owner; std::unique_ptr device; int inputIndex = 0, numInputChans = 0, outputIndex = 0, numOutputChans = 0; - bool useInputs = false, useOutputs = false; + bool useInputs = false, useOutputs = false, isWaitingForInput = false; AbstractFifo inputFifo { 32 }, outputFifo { 32 }; bool done = false;