From ccfe6bda63eae782e602a9d9881ff886940450d9 Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Mon, 5 Aug 2019 10:34:03 -0700 Subject: [PATCH] Detect clipping prior to echo cancellation (overload of the uncancelled raw input will cause echo leakage!) --- libraries/audio-client/src/AudioClient.cpp | 52 +++++++++++----------- 1 file changed, 27 insertions(+), 25 deletions(-) diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp index c16e297c28..99add0f797 100644 --- a/libraries/audio-client/src/AudioClient.cpp +++ b/libraries/audio-client/src/AudioClient.cpp @@ -170,27 +170,21 @@ static void channelDownmix(int16_t* source, int16_t* dest, int numSamples) { } } -static float computeLoudness(int16_t* samples, int numSamples, int numChannels, bool& isClipping) { +static bool detectClipping(int16_t* samples, int numSamples, int numChannels) { const int32_t CLIPPING_THRESHOLD = 32392; // -0.1 dBFS - const int32_t CLIPPING_DETECTION = 3; // consecutive samples over threshold + const int CLIPPING_DETECTION = 3; // consecutive samples over threshold - float scale = numSamples ? 1.0f / numSamples : 0.0f; - - int32_t loudness = 0; - isClipping = false; + bool isClipping = false; if (numChannels == 2) { - int32_t oversLeft = 0; - int32_t oversRight = 0; + int oversLeft = 0; + int oversRight = 0; for (int i = 0; i < numSamples/2; i++) { int32_t left = std::abs((int32_t)samples[2*i+0]); int32_t right = std::abs((int32_t)samples[2*i+1]); - loudness += left; - loudness += right; - if (left > CLIPPING_THRESHOLD) { isClipping |= (++oversLeft >= CLIPPING_DETECTION); } else { @@ -203,13 +197,11 @@ static float computeLoudness(int16_t* samples, int numSamples, int numChannels, } } } else { - int32_t overs = 0; + int overs = 0; for (int i = 0; i < numSamples; i++) { int32_t sample = std::abs((int32_t)samples[i]); - loudness += sample; - if (sample > CLIPPING_THRESHOLD) { isClipping |= (++overs >= CLIPPING_DETECTION); } else { @@ -218,6 +210,17 @@ static float computeLoudness(int16_t* samples, int numSamples, int numChannels, } } + return isClipping; +} + +static float computeLoudness(int16_t* samples, int numSamples) { + + float scale = numSamples ? 1.0f / numSamples : 0.0f; + + int32_t loudness = 0; + for (int i = 0; i < numSamples; i++) { + loudness += std::abs((int32_t)samples[i]); + } return (float)loudness * scale; } @@ -1393,6 +1396,15 @@ void AudioClient::handleMicAudioInput() { _inputRingBuffer.readSamples(inputAudioSamples.get(), inputSamplesRequired); + // detect clipping on the raw input + bool isClipping = detectClipping(inputAudioSamples.get(), inputSamplesRequired, _inputFormat.channelCount()); + if (isClipping) { + _timeSinceLastClip = 0.0f; + } else if (_timeSinceLastClip >= 0.0f) { + _timeSinceLastClip += AudioConstants::NETWORK_FRAME_SECS; + } + isClipping = (_timeSinceLastClip >= 0.0f) && (_timeSinceLastClip < 2.0f); // 2 second hold time + #if defined(WEBRTC_ENABLED) if (_isAECEnabled) { processWebrtcNearEnd(inputAudioSamples.get(), inputSamplesRequired / _inputFormat.channelCount(), @@ -1400,9 +1412,7 @@ void AudioClient::handleMicAudioInput() { } #endif - // detect loudness and clipping on the raw input - bool isClipping = false; - float loudness = computeLoudness(inputAudioSamples.get(), inputSamplesRequired, _inputFormat.channelCount(), isClipping); + float loudness = computeLoudness(inputAudioSamples.get(), inputSamplesRequired); _lastRawInputLoudness = loudness; // envelope detection @@ -1410,14 +1420,6 @@ void AudioClient::handleMicAudioInput() { loudness += tc * (_lastSmoothedRawInputLoudness - loudness); _lastSmoothedRawInputLoudness = loudness; - // clipping indicator - if (isClipping) { - _timeSinceLastClip = 0.0f; - } else if (_timeSinceLastClip >= 0.0f) { - _timeSinceLastClip += AudioConstants::NETWORK_FRAME_SECS; - } - isClipping = (_timeSinceLastClip >= 0.0f) && (_timeSinceLastClip < 2.0f); // 2 second hold time - emit inputLoudnessChanged(_lastSmoothedRawInputLoudness, isClipping); if (!_muted) {