AEC3: Utilize shadow filter output to respond to audio path changes

This CL adds functionality to use the shadow filter output instead
of the main filter output for cases when the former is better than
the latter. One case when that happens is when there have been an
echo path change, either in the acoustic path, in the audio buffers
or due to some active audio processing effects being applied on
the device.

The CL causes less echo leaks, in particular on devices with
active render processing.

Bug: webrtc:9581,chromium:869821
Change-Id: Icb8df1b94141598da82dc188051ac59e43338938
Reviewed-on: https://webrtc-review.googlesource.com/91820
Reviewed-by: Sam Zackrisson <saza@webrtc.org>
Commit-Queue: Per Åhgren <peah@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#24166}
This commit is contained in:
Per Åhgren 2018-08-01 16:24:08 +02:00 committed by Commit Bot
parent d2f4e8bd90
commit 78026754a7
4 changed files with 48 additions and 3 deletions

View File

@ -32,11 +32,17 @@
#include "rtc_base/atomicops.h"
#include "rtc_base/constructormagic.h"
#include "rtc_base/logging.h"
#include "system_wrappers/include/field_trial.h"
namespace webrtc {
namespace {
bool UseShadowFilterOutput() {
return !field_trial::IsEnabled(
"WebRTC-Aec3UtilizeShadowFilterOutputKillSwitch");
}
void LinearEchoPower(const FftData& E,
const FftData& Y,
std::array<float, kFftLengthBy2Plus1>* S2) {
@ -86,12 +92,41 @@ class EchoRemoverImpl final : public EchoRemover {
}
private:
// Selects which of the shadow and main linear filter outputs that is most
// appropriate to pass to the suppressor.
const std::array<float, kBlockSize>& ChooseLinearFilterOutput(
const SubtractorOutput& subtractor_output) {
if (!use_shadow_filter_output_) {
return subtractor_output.e_main;
}
// As the output of the main adaptive filter generally should be better than
// the shadow filter output, add a margin and threshold for when choosing
// the shadow filter output.
if (subtractor_output.e2_shadow < 0.9f * subtractor_output.e2_main &&
subtractor_output.y2 > 30.f * 30.f * kBlockSize &&
(subtractor_output.s2_main > 60.f * 60.f * kBlockSize ||
subtractor_output.s2_shadow > 60.f * 60.f * kBlockSize)) {
return subtractor_output.e_shadow;
}
// If the main filter is diverged, choose the filter output that has the
// lowest power.
if (subtractor_output.e2_shadow < subtractor_output.e2_main &&
subtractor_output.y2 < subtractor_output.e2_main) {
return subtractor_output.e_shadow;
}
return subtractor_output.e_main;
}
static int instance_count_;
const EchoCanceller3Config config_;
const Aec3Fft fft_;
std::unique_ptr<ApmDataDumper> data_dumper_;
const Aec3Optimization optimization_;
const int sample_rate_hz_;
const bool use_shadow_filter_output_;
Subtractor subtractor_;
SuppressionGain suppression_gain_;
ComfortNoiseGenerator cng_;
@ -121,6 +156,7 @@ EchoRemoverImpl::EchoRemoverImpl(const EchoCanceller3Config& config,
new ApmDataDumper(rtc::AtomicOps::Increment(&instance_count_))),
optimization_(DetectOptimization()),
sample_rate_hz_(sample_rate_hz),
use_shadow_filter_output_(UseShadowFilterOutput()),
subtractor_(config, data_dumper_.get(), optimization_),
suppression_gain_(config_, optimization_, sample_rate_hz),
cng_(optimization_),
@ -222,7 +258,7 @@ void EchoRemoverImpl::ProcessCapture(
// If the delay is known, use the echo subtractor.
subtractor_.Process(*render_buffer, y0, render_signal_analyzer_, aec_state_,
&subtractor_output);
const auto& e = subtractor_output.e_main;
const auto& e = ChooseLinearFilterOutput(subtractor_output);
// Compute spectra.
WindowedPaddedFft(fft_, y0, y_old_, &Y);

View File

@ -182,8 +182,8 @@ void Subtractor::Process(const RenderBuffer& render_buffer,
shadow_filter_.Filter(render_buffer, &S);
bool shadow_saturation = false;
PredictionError(fft_, S, y, &e_shadow, nullptr, adaptation_during_saturation_,
&shadow_saturation);
PredictionError(fft_, S, y, &e_shadow, &output->s_shadow,
adaptation_during_saturation_, &shadow_saturation);
// Compute the signal powers in the subtractor output.
output->UpdatePowers(y);

View File

@ -19,6 +19,7 @@ SubtractorOutput::~SubtractorOutput() = default;
void SubtractorOutput::Reset() {
s_main.fill(0.f);
s_shadow.fill(0.f);
e_main.fill(0.f);
e_shadow.fill(0.f);
E_main.re.fill(0.f);
@ -27,6 +28,8 @@ void SubtractorOutput::Reset() {
E2_shadow.fill(0.f);
e2_main = 0.f;
e2_shadow = 0.f;
s2_main = 0.f;
s2_shadow = 0.f;
y2 = 0.f;
}
@ -36,6 +39,9 @@ void SubtractorOutput::UpdatePowers(rtc::ArrayView<const float> y) {
e2_main = std::accumulate(e_main.begin(), e_main.end(), 0.f, sum_of_squares);
e2_shadow =
std::accumulate(e_shadow.begin(), e_shadow.end(), 0.f, sum_of_squares);
s2_main = std::accumulate(s_main.begin(), s_main.end(), 0.f, sum_of_squares);
s2_shadow =
std::accumulate(s_shadow.begin(), s_shadow.end(), 0.f, sum_of_squares);
}
} // namespace webrtc

View File

@ -25,11 +25,14 @@ struct SubtractorOutput {
~SubtractorOutput();
std::array<float, kBlockSize> s_main;
std::array<float, kBlockSize> s_shadow;
std::array<float, kBlockSize> e_main;
std::array<float, kBlockSize> e_shadow;
FftData E_main;
std::array<float, kFftLengthBy2Plus1> E2_main;
std::array<float, kFftLengthBy2Plus1> E2_shadow;
float s2_main = 0.f;
float s2_shadow = 0.f;
float e2_main = 0.f;
float e2_shadow = 0.f;
float y2 = 0.f;