AEC3: Gain limiter: Improving the behavior of the gain limiter.

In this work, we change the behavior of the gain limiter so it also looks at the energy
 on farend around the default delay for deciding the suppression gain
that should be applied at the initial portion of the call.

Bug: webrtc:9311,chromium:846724
Change-Id: I0b777cedbbd7fd689e72070f72237296ce120d3c
Reviewed-on: https://webrtc-review.googlesource.com/78960
Reviewed-by: Per Åhgren <peah@webrtc.org>
Commit-Queue: Jesus de Vicente Pena <devicentepena@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#23400}
This commit is contained in:
Jesús de Vicente Peña
2018-05-25 16:55:11 +02:00
committed by Commit Bot
parent d7a076cc8e
commit dd09287514
10 changed files with 92 additions and 21 deletions

View File

@ -17,4 +17,8 @@ EchoCanceller3Config::EchoCanceller3Config(const EchoCanceller3Config& e) =
EchoCanceller3Config::Mask::Mask() = default; EchoCanceller3Config::Mask::Mask() = default;
EchoCanceller3Config::Mask::Mask(const EchoCanceller3Config::Mask& m) = default; EchoCanceller3Config::Mask::Mask(const EchoCanceller3Config::Mask& m) = default;
EchoCanceller3Config::EchoModel::EchoModel() = default;
EchoCanceller3Config::EchoModel::EchoModel(
const EchoCanceller3Config::EchoModel& e) = default;
} // namespace webrtc } // namespace webrtc

View File

@ -128,15 +128,17 @@ struct EchoCanceller3Config {
struct EchoRemovalControl { struct EchoRemovalControl {
struct GainRampup { struct GainRampup {
float initial_gain = 0.0f;
float first_non_zero_gain = 0.001f; float first_non_zero_gain = 0.001f;
int non_zero_gain_blocks = 187; int non_zero_gain_blocks = 187;
int full_gain_blocks = 312; int full_gain_blocks = 312;
} gain_rampup; } gain_rampup;
bool has_clock_drift = false; bool has_clock_drift = false;
} echo_removal_control; } echo_removal_control;
struct EchoModel { struct EchoModel {
EchoModel();
EchoModel(const EchoModel& e);
size_t noise_floor_hold = 50; size_t noise_floor_hold = 50;
float min_noise_floor_power = 1638400.f; float min_noise_floor_power = 1638400.f;
float stationary_gate_slope = 10.f; float stationary_gate_slope = 10.f;
@ -144,6 +146,8 @@ struct EchoCanceller3Config {
float noise_gate_slope = 0.3f; float noise_gate_slope = 0.3f;
size_t render_pre_window_size = 1; size_t render_pre_window_size = 1;
size_t render_post_window_size = 1; size_t render_post_window_size = 1;
size_t render_pre_window_size_init = 10;
size_t render_post_window_size_init = 10;
float nonlinear_hold = 1; float nonlinear_hold = 1;
float nonlinear_release = 0.001f; float nonlinear_release = 0.001f;
} echo_model; } echo_model;

View File

@ -282,6 +282,8 @@ void AecState::Update(
filter_has_had_time_to_converge); filter_has_had_time_to_converge);
data_dumper_->DumpRaw("aec3_recently_converged_filter", data_dumper_->DumpRaw("aec3_recently_converged_filter",
recently_converged_filter); recently_converged_filter);
data_dumper_->DumpRaw("aec3_suppresion_gain_limiter_running",
IsSuppressionGainLimitActive());
} }
void AecState::UpdateReverb(const std::vector<float>& impulse_response) { void AecState::UpdateReverb(const std::vector<float>& impulse_response) {

View File

@ -111,6 +111,11 @@ class AecState {
return suppression_gain_limiter_.Limit(); return suppression_gain_limiter_.Limit();
} }
// Returns whether the suppression gain limiter is active.
bool IsSuppressionGainLimitActive() const {
return suppression_gain_limiter_.IsActive();
}
// Returns whether the linear filter should have been able to properly adapt. // Returns whether the linear filter should have been able to properly adapt.
bool FilterHasHadTimeToConverge() const { bool FilterHasHadTimeToConverge() const {
return filter_has_had_time_to_converge_; return filter_has_had_time_to_converge_;

View File

@ -28,6 +28,45 @@ bool OverrideEstimatedEchoPathGain() {
return !field_trial::IsEnabled("WebRTC-Aec3OverrideEchoPathGainKillSwitch"); return !field_trial::IsEnabled("WebRTC-Aec3OverrideEchoPathGainKillSwitch");
} }
// Computes the indexes that will be used for computing spectral power over
// the blocks surrounding the delay.
void GetRenderIndexesToAnalyze(
const VectorBuffer& spectrum_buffer,
const EchoCanceller3Config::EchoModel& echo_model,
int filter_delay_blocks,
bool gain_limiter_running,
int headroom,
int* idx_start,
int* idx_stop) {
RTC_DCHECK(idx_start);
RTC_DCHECK(idx_stop);
if (gain_limiter_running) {
if (static_cast<size_t>(headroom) >
echo_model.render_post_window_size_init) {
*idx_start = spectrum_buffer.OffsetIndex(
spectrum_buffer.read,
-static_cast<int>(echo_model.render_post_window_size_init));
} else {
*idx_start = spectrum_buffer.IncIndex(spectrum_buffer.write);
}
*idx_stop = spectrum_buffer.OffsetIndex(
spectrum_buffer.read, echo_model.render_pre_window_size_init);
} else {
size_t window_start;
size_t window_end;
window_start =
std::max(0, filter_delay_blocks -
static_cast<int>(echo_model.render_pre_window_size));
window_end = filter_delay_blocks +
static_cast<int>(echo_model.render_post_window_size);
*idx_start =
spectrum_buffer.OffsetIndex(spectrum_buffer.read, window_start);
*idx_stop =
spectrum_buffer.OffsetIndex(spectrum_buffer.read, window_end + 1);
}
}
} // namespace } // namespace
ResidualEchoEstimator::ResidualEchoEstimator(const EchoCanceller3Config& config) ResidualEchoEstimator::ResidualEchoEstimator(const EchoCanceller3Config& config)
@ -61,14 +100,9 @@ void ResidualEchoEstimator::Estimate(
// Estimate the echo generating signal power. // Estimate the echo generating signal power.
std::array<float, kFftLengthBy2Plus1> X2; std::array<float, kFftLengthBy2Plus1> X2;
// Computes the spectral power over the blocks surrounding the delay. EchoGeneratingPower(render_buffer.GetSpectrumBuffer(), config_.echo_model,
size_t window_start = std::max( render_buffer.Headroom(), aec_state.FilterDelayBlocks(),
0, aec_state.FilterDelayBlocks() - aec_state.IsSuppressionGainLimitActive(),
static_cast<int>(config_.echo_model.render_pre_window_size));
size_t window_end =
aec_state.FilterDelayBlocks() +
static_cast<int>(config_.echo_model.render_post_window_size);
EchoGeneratingPower(render_buffer, window_start, window_end,
!aec_state.UseStationaryProperties(), &X2); !aec_state.UseStationaryProperties(), &X2);
// Subtract the stationary noise power to avoid stationary noise causing // Subtract the stationary noise power to avoid stationary noise causing
@ -81,8 +115,9 @@ void ResidualEchoEstimator::Estimate(
float echo_path_gain; float echo_path_gain;
if (override_estimated_echo_path_gain_) { if (override_estimated_echo_path_gain_) {
echo_path_gain = echo_path_gain = aec_state.TransparentMode() && soft_transparent_mode_
aec_state.TransparentMode() && soft_transparent_mode_ ? 0.01f : 1.f; ? 0.01f
: config_.ep_strength.lf;
} else { } else {
echo_path_gain = aec_state.TransparentMode() && soft_transparent_mode_ echo_path_gain = aec_state.TransparentMode() && soft_transparent_mode_
? 0.01f ? 0.01f
@ -208,14 +243,23 @@ void ResidualEchoEstimator::AddEchoReverb(
} }
void ResidualEchoEstimator::EchoGeneratingPower( void ResidualEchoEstimator::EchoGeneratingPower(
const RenderBuffer& render_buffer, const VectorBuffer& spectrum_buffer,
size_t min_delay, const EchoCanceller3Config::EchoModel& echo_model,
size_t max_delay, int headroom_spectrum_buffer,
int filter_delay_blocks,
bool gain_limiter_running,
bool apply_noise_gating, bool apply_noise_gating,
std::array<float, kFftLengthBy2Plus1>* X2) const { std::array<float, kFftLengthBy2Plus1>* X2) const {
int idx_stop, idx_start;
RTC_DCHECK(X2);
GetRenderIndexesToAnalyze(spectrum_buffer, config_.echo_model,
filter_delay_blocks, gain_limiter_running,
headroom_spectrum_buffer, &idx_start, &idx_stop);
X2->fill(0.f); X2->fill(0.f);
for (size_t k = min_delay; k <= max_delay; ++k) { for (int k = idx_start; k != idx_stop; k = spectrum_buffer.IncIndex(k)) {
std::transform(X2->begin(), X2->end(), render_buffer.Spectrum(k).begin(), std::transform(X2->begin(), X2->end(), spectrum_buffer.buffer[k].begin(),
X2->begin(), X2->begin(),
[](float a, float b) { return std::max(a, b); }); [](float a, float b) { return std::max(a, b); });
} }

View File

@ -61,9 +61,11 @@ class ResidualEchoEstimator {
// Estimates the echo generating signal power as gated maximal power over a // Estimates the echo generating signal power as gated maximal power over a
// time window. // time window.
void EchoGeneratingPower(const RenderBuffer& render_buffer, void EchoGeneratingPower(const VectorBuffer& spectrum_buffer,
size_t min_delay, const EchoCanceller3Config::EchoModel& echo_model,
size_t max_delay, int headroom_spectrum_buffer,
int filter_delay_blocks,
bool gain_limiter_running,
bool apply_noise_gating, bool apply_noise_gating,
std::array<float, kFftLengthBy2Plus1>* X2) const; std::array<float, kFftLengthBy2Plus1>* X2) const;

View File

@ -64,7 +64,7 @@ void SuppressionGainUpperLimiter::Update(bool render_activity,
recent_reset_ = false; recent_reset_ = false;
// Do not enforce any gain limit on the suppressor. // Do not enforce any gain limit on the suppressor.
if (realignment_counter_ <= 0) { if (!IsActive()) {
suppressor_gain_limit_ = 1.f; suppressor_gain_limit_ = 1.f;
return; return;
} }
@ -72,7 +72,7 @@ void SuppressionGainUpperLimiter::Update(bool render_activity,
// Enforce full suppression. // Enforce full suppression.
if (realignment_counter_ > rampup_config_.non_zero_gain_blocks || if (realignment_counter_ > rampup_config_.non_zero_gain_blocks ||
(!call_startup_phase_ && realignment_counter_ > 0)) { (!call_startup_phase_ && realignment_counter_ > 0)) {
suppressor_gain_limit_ = 0.f; suppressor_gain_limit_ = rampup_config_.initial_gain;
return; return;
} }

View File

@ -32,6 +32,9 @@ class SuppressionGainUpperLimiter {
// Returns the current suppressor gain limit. // Returns the current suppressor gain limit.
float Limit() const { return suppressor_gain_limit_; } float Limit() const { return suppressor_gain_limit_; }
// Return whether the suppressor gain limit is active.
bool IsActive() const { return (realignment_counter_ > 0); }
private: private:
const EchoCanceller3Config::EchoRemovalControl::GainRampup rampup_config_; const EchoCanceller3Config::EchoRemovalControl::GainRampup rampup_config_;
const float gain_rampup_increase_; const float gain_rampup_increase_;

View File

@ -36,6 +36,7 @@ struct VectorBuffer {
int OffsetIndex(int index, int offset) const { int OffsetIndex(int index, int offset) const {
RTC_DCHECK_GE(size, offset); RTC_DCHECK_GE(size, offset);
RTC_DCHECK_EQ(buffer.size(), static_cast<size_t>(size)); RTC_DCHECK_EQ(buffer.size(), static_cast<size_t>(size));
RTC_DCHECK_GE(size + index + offset, 0);
return (size + index + offset) % size; return (size + index + offset) % size;
} }

View File

@ -255,6 +255,8 @@ EchoCanceller3Config ParseAec3Parameters(const std::string& filename) {
if (rtc::GetValueFromJsonObject(root, "echo_removal_control", &section)) { if (rtc::GetValueFromJsonObject(root, "echo_removal_control", &section)) {
Json::Value subsection; Json::Value subsection;
if (rtc::GetValueFromJsonObject(section, "gain_rampup", &subsection)) { if (rtc::GetValueFromJsonObject(section, "gain_rampup", &subsection)) {
ReadParam(subsection, "initial_gain",
&cfg.echo_removal_control.gain_rampup.initial_gain);
ReadParam(subsection, "first_non_zero_gain", ReadParam(subsection, "first_non_zero_gain",
&cfg.echo_removal_control.gain_rampup.first_non_zero_gain); &cfg.echo_removal_control.gain_rampup.first_non_zero_gain);
ReadParam(subsection, "non_zero_gain_blocks", ReadParam(subsection, "non_zero_gain_blocks",
@ -279,6 +281,10 @@ EchoCanceller3Config ParseAec3Parameters(const std::string& filename) {
&cfg.echo_model.render_pre_window_size); &cfg.echo_model.render_pre_window_size);
ReadParam(section, "render_post_window_size", ReadParam(section, "render_post_window_size",
&cfg.echo_model.render_post_window_size); &cfg.echo_model.render_post_window_size);
ReadParam(section, "render_pre_window_size_init",
&cfg.echo_model.render_pre_window_size_init);
ReadParam(section, "render_post_window_size_init",
&cfg.echo_model.render_post_window_size_init);
ReadParam(section, "nonlinear_hold", &cfg.echo_model.nonlinear_hold); ReadParam(section, "nonlinear_hold", &cfg.echo_model.nonlinear_hold);
ReadParam(section, "nonlinear_release", &cfg.echo_model.nonlinear_release); ReadParam(section, "nonlinear_release", &cfg.echo_model.nonlinear_release);
} }