Added forced zero AEC output after call startup and echo path changes

During the first few capture frames, there is no way for the AEC
to tell whether there is echo in the capture signal as the echo
removal functionality in the AEC has not yet seen any render
signal. To avoid initial echo bursts due to this, this CL adds
functionality for forcing the echo suppression gain to zero during
the first 50 blocks (200 ms) after call start and after a reported
echo path change.

BUG=webrtc:6018

Review-Url: https://codereview.webrtc.org/2808733002
Cr-Commit-Position: refs/heads/master@{#17624}
This commit is contained in:
peah 2017-04-10 13:52:14 -07:00 committed by Commit bot
parent ca31f175e1
commit 6d822adac4
6 changed files with 40 additions and 5 deletions

View File

@ -97,6 +97,11 @@ void AecState::HandleEchoPathChange(
echo_saturation_ = false;
headset_detected_ = false;
previous_max_sample_ = 0.f;
if (echo_path_variability.delay_change) {
force_zero_gain_counter_ = 0;
force_zero_gain_ = true;
}
}
}
@ -117,6 +122,12 @@ void AecState::Update(const std::vector<std::array<float, kFftLengthBy2Plus1>>&
active_render_blocks_ += active_render_block ? 1 : 0;
--echo_path_change_counter_;
// Force zero echo suppression gain after an echo path change to allow at
// least some render data to be collected in order to avoid an initial echo
// burst.
constexpr size_t kZeroGainBlocksAfterChange = kNumBlocksPerSecond / 5;
force_zero_gain_ = (++force_zero_gain_counter_) < kZeroGainBlocksAfterChange;
// Estimate delays.
filter_delay_ = EstimateFilterDelay(adaptive_filter_frequency_response);
external_delay_ =

View File

@ -80,6 +80,9 @@ class AecState {
// TODO(peah): Make this adaptive.
float ReverbDecayFactor() const { return 0.f; }
// Returns whether the echo suppression gain should be forced to zero.
bool ForcedZeroGain() const { return force_zero_gain_; }
// Updates the aec state.
void Update(const std::vector<std::array<float, kFftLengthBy2Plus1>>&
adaptive_filter_frequency_response,
@ -103,6 +106,8 @@ class AecState {
bool echo_saturation_ = false;
bool headset_detected_ = false;
float previous_max_sample_ = 0.f;
bool force_zero_gain_ = false;
size_t force_zero_gain_counter_ = 0;
rtc::Optional<size_t> filter_delay_;
rtc::Optional<size_t> external_delay_;
size_t blocks_since_last_saturation_ = 1000;

View File

@ -182,7 +182,7 @@ void EchoRemoverImpl::ProcessCapture(
// A choose and apply echo suppression gain.
suppression_gain_.GetGain(E2, R2, cng_.NoiseSpectrum(),
aec_state_.SaturatedEcho(), x, y->size(),
&high_bands_gain, &G);
aec_state_.ForcedZeroGain(), &high_bands_gain, &G);
suppression_filter_.ApplyGain(comfort_noise, high_band_comfort_noise, G,
high_bands_gain, y);

View File

@ -325,11 +325,21 @@ void SuppressionGain::GetGain(
bool saturated_echo,
const std::vector<std::vector<float>>& render,
size_t num_capture_bands,
bool force_zero_gain,
float* high_bands_gain,
std::array<float, kFftLengthBy2Plus1>* low_band_gain) {
RTC_DCHECK(high_bands_gain);
RTC_DCHECK(low_band_gain);
if (force_zero_gain) {
previous_gain_squared_.fill(0.f);
std::copy(comfort_noise_power.begin() + 1, comfort_noise_power.end() - 1,
previous_masker_.begin());
low_band_gain->fill(0.f);
*high_bands_gain = 0.f;
return;
}
// Choose margin to use.
const float margin = saturated_echo ? 0.001f : 0.01f;
switch (optimization_) {

View File

@ -52,6 +52,7 @@ class SuppressionGain {
bool saturated_echo,
const std::vector<std::vector<float>>& render,
size_t num_capture_bands,
bool force_zero_gain,
float* high_bands_gain,
std::array<float, kFftLengthBy2Plus1>* low_band_gain);

View File

@ -33,7 +33,7 @@ TEST(SuppressionGain, NullOutputGains) {
.GetGain(E2, R2, N2, false,
std::vector<std::vector<float>>(
3, std::vector<float>(kBlockSize, 0.f)),
1, &high_bands_gain, nullptr),
1, false, &high_bands_gain, nullptr),
"");
}
@ -128,7 +128,8 @@ TEST(SuppressionGain, BasicGainComputation) {
R2.fill(0.1f);
N2.fill(100.f);
for (int k = 0; k < 10; ++k) {
suppression_gain.GetGain(E2, R2, N2, false, x, 1, &high_bands_gain, &g);
suppression_gain.GetGain(E2, R2, N2, false, x, 1, false, &high_bands_gain,
&g);
}
std::for_each(g.begin(), g.end(),
[](float a) { EXPECT_NEAR(1.f, a, 0.001); });
@ -138,7 +139,8 @@ TEST(SuppressionGain, BasicGainComputation) {
R2.fill(0.1f);
N2.fill(0.f);
for (int k = 0; k < 10; ++k) {
suppression_gain.GetGain(E2, R2, N2, false, x, 1, &high_bands_gain, &g);
suppression_gain.GetGain(E2, R2, N2, false, x, 1, false, &high_bands_gain,
&g);
}
std::for_each(g.begin(), g.end(),
[](float a) { EXPECT_NEAR(1.f, a, 0.001); });
@ -148,10 +150,16 @@ TEST(SuppressionGain, BasicGainComputation) {
R2.fill(100.f);
N2.fill(0.f);
for (int k = 0; k < 10; ++k) {
suppression_gain.GetGain(E2, R2, N2, false, x, 1, &high_bands_gain, &g);
suppression_gain.GetGain(E2, R2, N2, false, x, 1, false, &high_bands_gain,
&g);
}
std::for_each(g.begin(), g.end(),
[](float a) { EXPECT_NEAR(0.f, a, 0.001); });
// Verify the functionality for forcing a zero gain.
suppression_gain.GetGain(E2, R2, N2, false, x, 1, true, &high_bands_gain, &g);
std::for_each(g.begin(), g.end(), [](float a) { EXPECT_FLOAT_EQ(0.f, a); });
EXPECT_FLOAT_EQ(0.f, high_bands_gain);
}
} // namespace aec3