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:

committed by
Commit Bot

parent
d7a076cc8e
commit
dd09287514
@ -17,4 +17,8 @@ EchoCanceller3Config::EchoCanceller3Config(const EchoCanceller3Config& e) =
|
||||
EchoCanceller3Config::Mask::Mask() = default;
|
||||
EchoCanceller3Config::Mask::Mask(const EchoCanceller3Config::Mask& m) = default;
|
||||
|
||||
EchoCanceller3Config::EchoModel::EchoModel() = default;
|
||||
EchoCanceller3Config::EchoModel::EchoModel(
|
||||
const EchoCanceller3Config::EchoModel& e) = default;
|
||||
|
||||
} // namespace webrtc
|
||||
|
@ -128,15 +128,17 @@ struct EchoCanceller3Config {
|
||||
|
||||
struct EchoRemovalControl {
|
||||
struct GainRampup {
|
||||
float initial_gain = 0.0f;
|
||||
float first_non_zero_gain = 0.001f;
|
||||
int non_zero_gain_blocks = 187;
|
||||
int full_gain_blocks = 312;
|
||||
} gain_rampup;
|
||||
|
||||
bool has_clock_drift = false;
|
||||
} echo_removal_control;
|
||||
|
||||
struct EchoModel {
|
||||
EchoModel();
|
||||
EchoModel(const EchoModel& e);
|
||||
size_t noise_floor_hold = 50;
|
||||
float min_noise_floor_power = 1638400.f;
|
||||
float stationary_gate_slope = 10.f;
|
||||
@ -144,6 +146,8 @@ struct EchoCanceller3Config {
|
||||
float noise_gate_slope = 0.3f;
|
||||
size_t render_pre_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_release = 0.001f;
|
||||
} echo_model;
|
||||
|
@ -282,6 +282,8 @@ void AecState::Update(
|
||||
filter_has_had_time_to_converge);
|
||||
data_dumper_->DumpRaw("aec3_recently_converged_filter",
|
||||
recently_converged_filter);
|
||||
data_dumper_->DumpRaw("aec3_suppresion_gain_limiter_running",
|
||||
IsSuppressionGainLimitActive());
|
||||
}
|
||||
|
||||
void AecState::UpdateReverb(const std::vector<float>& impulse_response) {
|
||||
|
@ -111,6 +111,11 @@ class AecState {
|
||||
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.
|
||||
bool FilterHasHadTimeToConverge() const {
|
||||
return filter_has_had_time_to_converge_;
|
||||
|
@ -28,6 +28,45 @@ bool OverrideEstimatedEchoPathGain() {
|
||||
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
|
||||
|
||||
ResidualEchoEstimator::ResidualEchoEstimator(const EchoCanceller3Config& config)
|
||||
@ -61,14 +100,9 @@ void ResidualEchoEstimator::Estimate(
|
||||
// Estimate the echo generating signal power.
|
||||
std::array<float, kFftLengthBy2Plus1> X2;
|
||||
|
||||
// Computes the spectral power over the blocks surrounding the delay.
|
||||
size_t window_start = std::max(
|
||||
0, aec_state.FilterDelayBlocks() -
|
||||
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,
|
||||
EchoGeneratingPower(render_buffer.GetSpectrumBuffer(), config_.echo_model,
|
||||
render_buffer.Headroom(), aec_state.FilterDelayBlocks(),
|
||||
aec_state.IsSuppressionGainLimitActive(),
|
||||
!aec_state.UseStationaryProperties(), &X2);
|
||||
|
||||
// Subtract the stationary noise power to avoid stationary noise causing
|
||||
@ -81,8 +115,9 @@ void ResidualEchoEstimator::Estimate(
|
||||
|
||||
float echo_path_gain;
|
||||
if (override_estimated_echo_path_gain_) {
|
||||
echo_path_gain =
|
||||
aec_state.TransparentMode() && soft_transparent_mode_ ? 0.01f : 1.f;
|
||||
echo_path_gain = aec_state.TransparentMode() && soft_transparent_mode_
|
||||
? 0.01f
|
||||
: config_.ep_strength.lf;
|
||||
} else {
|
||||
echo_path_gain = aec_state.TransparentMode() && soft_transparent_mode_
|
||||
? 0.01f
|
||||
@ -208,14 +243,23 @@ void ResidualEchoEstimator::AddEchoReverb(
|
||||
}
|
||||
|
||||
void ResidualEchoEstimator::EchoGeneratingPower(
|
||||
const RenderBuffer& render_buffer,
|
||||
size_t min_delay,
|
||||
size_t max_delay,
|
||||
const VectorBuffer& spectrum_buffer,
|
||||
const EchoCanceller3Config::EchoModel& echo_model,
|
||||
int headroom_spectrum_buffer,
|
||||
int filter_delay_blocks,
|
||||
bool gain_limiter_running,
|
||||
bool apply_noise_gating,
|
||||
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);
|
||||
for (size_t k = min_delay; k <= max_delay; ++k) {
|
||||
std::transform(X2->begin(), X2->end(), render_buffer.Spectrum(k).begin(),
|
||||
for (int k = idx_start; k != idx_stop; k = spectrum_buffer.IncIndex(k)) {
|
||||
std::transform(X2->begin(), X2->end(), spectrum_buffer.buffer[k].begin(),
|
||||
X2->begin(),
|
||||
[](float a, float b) { return std::max(a, b); });
|
||||
}
|
||||
|
@ -61,9 +61,11 @@ class ResidualEchoEstimator {
|
||||
|
||||
// Estimates the echo generating signal power as gated maximal power over a
|
||||
// time window.
|
||||
void EchoGeneratingPower(const RenderBuffer& render_buffer,
|
||||
size_t min_delay,
|
||||
size_t max_delay,
|
||||
void EchoGeneratingPower(const VectorBuffer& spectrum_buffer,
|
||||
const EchoCanceller3Config::EchoModel& echo_model,
|
||||
int headroom_spectrum_buffer,
|
||||
int filter_delay_blocks,
|
||||
bool gain_limiter_running,
|
||||
bool apply_noise_gating,
|
||||
std::array<float, kFftLengthBy2Plus1>* X2) const;
|
||||
|
||||
|
@ -64,7 +64,7 @@ void SuppressionGainUpperLimiter::Update(bool render_activity,
|
||||
recent_reset_ = false;
|
||||
|
||||
// Do not enforce any gain limit on the suppressor.
|
||||
if (realignment_counter_ <= 0) {
|
||||
if (!IsActive()) {
|
||||
suppressor_gain_limit_ = 1.f;
|
||||
return;
|
||||
}
|
||||
@ -72,7 +72,7 @@ void SuppressionGainUpperLimiter::Update(bool render_activity,
|
||||
// Enforce full suppression.
|
||||
if (realignment_counter_ > rampup_config_.non_zero_gain_blocks ||
|
||||
(!call_startup_phase_ && realignment_counter_ > 0)) {
|
||||
suppressor_gain_limit_ = 0.f;
|
||||
suppressor_gain_limit_ = rampup_config_.initial_gain;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -32,6 +32,9 @@ class SuppressionGainUpperLimiter {
|
||||
// Returns the current 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:
|
||||
const EchoCanceller3Config::EchoRemovalControl::GainRampup rampup_config_;
|
||||
const float gain_rampup_increase_;
|
||||
|
@ -36,6 +36,7 @@ struct VectorBuffer {
|
||||
int OffsetIndex(int index, int offset) const {
|
||||
RTC_DCHECK_GE(size, offset);
|
||||
RTC_DCHECK_EQ(buffer.size(), static_cast<size_t>(size));
|
||||
RTC_DCHECK_GE(size + index + offset, 0);
|
||||
return (size + index + offset) % size;
|
||||
}
|
||||
|
||||
|
@ -255,6 +255,8 @@ EchoCanceller3Config ParseAec3Parameters(const std::string& filename) {
|
||||
if (rtc::GetValueFromJsonObject(root, "echo_removal_control", §ion)) {
|
||||
Json::Value 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",
|
||||
&cfg.echo_removal_control.gain_rampup.first_non_zero_gain);
|
||||
ReadParam(subsection, "non_zero_gain_blocks",
|
||||
@ -279,6 +281,10 @@ EchoCanceller3Config ParseAec3Parameters(const std::string& filename) {
|
||||
&cfg.echo_model.render_pre_window_size);
|
||||
ReadParam(section, "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_release", &cfg.echo_model.nonlinear_release);
|
||||
}
|
||||
|
Reference in New Issue
Block a user