Separating the AEC3 suppressor gain rampup behavior for call startup and in-call resets

This CL introduces a different rampup behavir for the call startup and after resets
that may occur due to delay changes, clock-drift and audio path glitches.

Bug: chromium:819111, webrtc:8979
Change-Id: Ied1d7896be7f0c69aa6deb61475117021ca6ab09
Reviewed-on: https://webrtc-review.googlesource.com/60002
Reviewed-by: Gustaf Ullberg <gustaf@webrtc.org>
Reviewed-by: Jesus de Vicente Pena <devicentepena@webrtc.org>
Commit-Queue: Per Åhgren <peah@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#22312}
This commit is contained in:
Per Åhgren
2018-03-06 10:40:51 +01:00
committed by Commit Bot
parent e3927c5885
commit 12eb85881c
5 changed files with 144 additions and 38 deletions

View File

@ -88,6 +88,8 @@ rtc_static_library("aec3") {
"suppression_filter.h",
"suppression_gain.cc",
"suppression_gain.h",
"suppression_gain_limiter.cc",
"suppression_gain_limiter.h",
"vector_buffer.cc",
"vector_buffer.h",
"vector_math.h",

View File

@ -63,7 +63,8 @@ AecState::AecState(const EchoCanceller3Config& config)
config_(config),
max_render_(config_.filter.main.length_blocks, 0.f),
reverb_decay_(fabsf(config_.ep_strength.default_len)),
gain_rampup_increase_(ComputeGainRampupIncrease(config_)) {}
gain_rampup_increase_(ComputeGainRampupIncrease(config_)),
suppression_gain_limiter_(config_) {}
AecState::~AecState() = default;
@ -83,6 +84,7 @@ void AecState::HandleEchoPathChange(
render_received_ = false;
blocks_with_active_render_ = 0;
initial_state_ = true;
suppression_gain_limiter_.Reset();
};
// TODO(peah): Refine the reset scheme according to the type of gain and
@ -96,7 +98,6 @@ void AecState::HandleEchoPathChange(
full_reset();
} else if (echo_path_variability.delay_change !=
EchoPathVariability::DelayAdjustment::kBufferFlush) {
active_render_seen_ = false;
full_reset();
} else if (echo_path_variability.delay_change !=
EchoPathVariability::DelayAdjustment::kDelayReset) {
@ -136,7 +137,7 @@ void AecState::Update(
// Update the limit on the echo suppression after an echo path change to avoid
// an initial echo burst.
UpdateSuppressorGainLimit(render_buffer.GetRenderActivity());
suppression_gain_limiter_.Update(render_buffer.GetRenderActivity());
// Update the ERL and ERLE measures.
if (converged_filter && capture_block_counter_ >= 2 * kNumBlocksPerSecond) {
@ -360,6 +361,7 @@ void AecState::UpdateReverb(const std::vector<float>& impulse_response) {
data_dumper_->DumpRaw("aec3_reverb_decay", reverb_decay_);
data_dumper_->DumpRaw("aec3_reverb_tail_energy", tail_energy_);
data_dumper_->DumpRaw("aec3_suppression_gain_limit", SuppressionGainLimit());
}
bool AecState::DetectActiveRender(rtc::ArrayView<const float> x) const {
@ -369,37 +371,6 @@ bool AecState::DetectActiveRender(rtc::ArrayView<const float> x) const {
kFftLengthBy2;
}
// Updates the suppressor gain limit.
void AecState::UpdateSuppressorGainLimit(bool render_activity) {
const auto& rampup_conf = config_.echo_removal_control.gain_rampup;
if (!active_render_seen_ && render_activity) {
active_render_seen_ = true;
realignment_counter_ = rampup_conf.full_gain_blocks;
} else if (realignment_counter_ > 0) {
--realignment_counter_;
}
if (realignment_counter_ <= 0) {
suppressor_gain_limit_ = 1.f;
return;
}
if (realignment_counter_ > rampup_conf.non_zero_gain_blocks) {
suppressor_gain_limit_ = 0.f;
return;
}
if (realignment_counter_ == rampup_conf.non_zero_gain_blocks) {
suppressor_gain_limit_ = rampup_conf.first_non_zero_gain;
return;
}
RTC_DCHECK_LT(0.f, suppressor_gain_limit_);
suppressor_gain_limit_ =
std::min(1.f, suppressor_gain_limit_ * gain_rampup_increase_);
RTC_DCHECK_GE(1.f, suppressor_gain_limit_);
}
bool AecState::DetectEchoSaturation(rtc::ArrayView<const float> x) {
RTC_DCHECK_LT(0, x.size());
const float max_sample = fabs(*std::max_element(

View File

@ -26,6 +26,7 @@
#include "modules/audio_processing/aec3/erl_estimator.h"
#include "modules/audio_processing/aec3/erle_estimator.h"
#include "modules/audio_processing/aec3/render_buffer.h"
#include "modules/audio_processing/aec3/suppression_gain_limiter.h"
#include "rtc_base/constructormagic.h"
namespace webrtc {
@ -91,7 +92,9 @@ class AecState {
float ReverbDecay() const { return reverb_decay_; }
// Returns the upper limit for the echo suppression gain.
float SuppressionGainLimit() const { return suppressor_gain_limit_; }
float SuppressionGainLimit() const {
return suppression_gain_limiter_.Limit();
}
// Returns whether the echo in the capture signal is audible.
bool InaudibleEcho() const { return echo_audibility_.InaudibleEcho(); }
@ -156,9 +159,6 @@ class AecState {
bool transparent_mode_ = false;
float previous_max_sample_ = 0.f;
bool render_received_ = false;
int realignment_counter_ = 0;
float suppressor_gain_limit_ = 1.f;
bool active_render_seen_ = false;
int filter_delay_ = 0;
size_t blocks_since_last_saturation_ = 1000;
float tail_energy_ = 0.f;
@ -179,6 +179,7 @@ class AecState {
bool filter_has_had_time_to_converge_ = false;
bool initial_state_ = true;
const float gain_rampup_increase_;
SuppressionGainUpperLimiter suppression_gain_limiter_;
RTC_DISALLOW_COPY_AND_ASSIGN(AecState);
};

View File

@ -0,0 +1,83 @@
/*
* Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "modules/audio_processing/aec3/suppression_gain_limiter.h"
#include <math.h>
#include <algorithm>
#include "modules/audio_processing/aec3/aec3_common.h"
namespace webrtc {
namespace {
// Computes the gain rampup factor to use.
float ComputeGainRampupIncrease(
const EchoCanceller3Config::EchoRemovalControl::GainRampup& rampup_config) {
return powf(1.f / rampup_config.first_non_zero_gain,
1.f / rampup_config.non_zero_gain_blocks);
}
} // namespace
SuppressionGainUpperLimiter::SuppressionGainUpperLimiter(
const EchoCanceller3Config& config)
: rampup_config_(config.echo_removal_control.gain_rampup),
gain_rampup_increase_(ComputeGainRampupIncrease(rampup_config_)) {
Reset();
}
void SuppressionGainUpperLimiter::Reset() {
recent_reset_ = true;
}
void SuppressionGainUpperLimiter::Update(bool render_activity) {
if (recent_reset_ && !call_startup_phase_) {
// Only enforce 250 ms full suppression after in-call resets,
constexpr int kMuteFramesAfterReset = kNumBlocksPerSecond / 4;
realignment_counter_ = kMuteFramesAfterReset;
} else if (!active_render_seen_ && render_activity) {
// Enforce a tailormade suppression limiting during call startup.
active_render_seen_ = true;
realignment_counter_ = rampup_config_.full_gain_blocks;
} else if (realignment_counter_ > 0) {
if (--realignment_counter_ == 0) {
call_startup_phase_ = false;
}
}
recent_reset_ = false;
// Do not enforce any gain limit on the suppressor.
if (realignment_counter_ <= 0) {
suppressor_gain_limit_ = 1.f;
return;
}
// Enforce full suppression.
if (realignment_counter_ > rampup_config_.non_zero_gain_blocks ||
(!call_startup_phase_ && realignment_counter_ > 0)) {
suppressor_gain_limit_ = 0.f;
return;
}
// Start increasing the gain limit.
if (realignment_counter_ == rampup_config_.non_zero_gain_blocks) {
suppressor_gain_limit_ = rampup_config_.first_non_zero_gain;
return;
}
// Increase the gain limit until it reaches 1.f.
RTC_DCHECK_LT(0.f, suppressor_gain_limit_);
suppressor_gain_limit_ =
std::min(1.f, suppressor_gain_limit_ * gain_rampup_increase_);
RTC_DCHECK_GE(1.f, suppressor_gain_limit_);
}
} // namespace webrtc

View File

@ -0,0 +1,49 @@
/*
* Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef MODULES_AUDIO_PROCESSING_AEC3_SUPPRESSION_GAIN_LIMITER_H_
#define MODULES_AUDIO_PROCESSING_AEC3_SUPPRESSION_GAIN_LIMITER_H_
#include "api/array_view.h"
#include "api/audio/echo_canceller3_config.h"
#include "rtc_base/constructormagic.h"
namespace webrtc {
// Class for applying a smoothly increasing limit for the suppression gain
// during call startup and after in-call resets.
class SuppressionGainUpperLimiter {
public:
explicit SuppressionGainUpperLimiter(const EchoCanceller3Config& config);
// Reset the limiting behavior.
void Reset();
// Updates the limiting behavior for the current capture bloc.
void Update(bool render_activity);
// Returns the current suppressor gain limit.
float Limit() const { return suppressor_gain_limit_; }
private:
const EchoCanceller3Config::EchoRemovalControl::GainRampup rampup_config_;
const float gain_rampup_increase_;
bool call_startup_phase_ = true;
int realignment_counter_ = 0;
bool active_render_seen_ = false;
float suppressor_gain_limit_ = 1.f;
bool recent_reset_ = false;
RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(SuppressionGainUpperLimiter);
};
} // namespace webrtc
#endif // MODULES_AUDIO_PROCESSING_AEC3_SUPPRESSION_GAIN_LIMITER_H_