AEC3: Avoid using filter output in suppression gain computation in non-linear mode

As non-linear mode uses a suppressed version of y (not e) as output, this change
uses Y2, rather than E2, as nearend spectrum when computing the suppression gains.
E2 is still used in linear mode.

This change also affects how the minimum suppression gains are calculated. The
minimum gain is now min_echo_power / weighted_residual_echo.

Bug: webrtc:10550
Change-Id: I2904c5a09dd64b06bf25eb5a37c18dab50297794
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/133023
Commit-Queue: Gustaf Ullberg <gustaf@webrtc.org>
Reviewed-by: Per Åhgren <peah@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#27629}
This commit is contained in:
Gustaf Ullberg 2019-04-15 17:15:37 +02:00 committed by Commit Bot
parent 01738c63aa
commit 2bab5ad3b1
5 changed files with 26 additions and 24 deletions

View file

@ -290,15 +290,22 @@ void EchoRemoverImpl::ProcessCapture(
// Estimate the comfort noise. // Estimate the comfort noise.
cng_.Compute(aec_state_, Y2, &comfort_noise, &high_band_comfort_noise); cng_.Compute(aec_state_, Y2, &comfort_noise, &high_band_comfort_noise);
// Compute and apply the suppression gain. // Suppressor echo estimate.
const auto& echo_spectrum = const auto& echo_spectrum =
aec_state_.UsableLinearEstimate() ? S2_linear : R2; aec_state_.UsableLinearEstimate() ? S2_linear : R2;
std::array<float, kFftLengthBy2Plus1> E2_bounded; // Suppressor nearend estimate.
std::transform(E2.begin(), E2.end(), Y2.begin(), E2_bounded.begin(), std::array<float, kFftLengthBy2Plus1> nearend_spectrum_bounded;
if (aec_state_.UsableLinearEstimate()) {
std::transform(E2.begin(), E2.end(), Y2.begin(),
nearend_spectrum_bounded.begin(),
[](float a, float b) { return std::min(a, b); }); [](float a, float b) { return std::min(a, b); });
}
auto& nearend_spectrum =
aec_state_.UsableLinearEstimate() ? nearend_spectrum_bounded : Y2;
suppression_gain_.GetGain(E2, E2_bounded, echo_spectrum, R2, // Compute and apply the suppression gain.
suppression_gain_.GetGain(nearend_spectrum, echo_spectrum, R2,
cng_.NoiseSpectrum(), render_signal_analyzer_, cng_.NoiseSpectrum(), render_signal_analyzer_,
aec_state_, x, &high_bands_gain, &G); aec_state_, x, &high_bands_gain, &G);

View file

@ -197,7 +197,6 @@ void SuppressionGain::GainToNoAudibleEcho(
// Compute the minimum gain as the attenuating gain to put the signal just // Compute the minimum gain as the attenuating gain to put the signal just
// above the zero sample values. // above the zero sample values.
void SuppressionGain::GetMinGain( void SuppressionGain::GetMinGain(
rtc::ArrayView<const float> suppressor_input,
rtc::ArrayView<const float> weighted_residual_echo, rtc::ArrayView<const float> weighted_residual_echo,
bool low_noise_render, bool low_noise_render,
bool saturated_echo, bool saturated_echo,
@ -207,10 +206,10 @@ void SuppressionGain::GetMinGain(
low_noise_render ? config_.echo_audibility.low_render_limit low_noise_render ? config_.echo_audibility.low_render_limit
: config_.echo_audibility.normal_render_limit; : config_.echo_audibility.normal_render_limit;
for (size_t k = 0; k < suppressor_input.size(); ++k) { for (size_t k = 0; k < min_gain.size(); ++k) {
const float denom = min_gain[k] = weighted_residual_echo[k] > 0.f
std::min(suppressor_input[k], weighted_residual_echo[k]); ? min_echo_power / weighted_residual_echo[k]
min_gain[k] = denom > 0.f ? min_echo_power / denom : 1.f; : 1.f;
min_gain[k] = std::min(min_gain[k], 1.f); min_gain[k] = std::min(min_gain[k], 1.f);
} }
for (size_t k = 0; k < 6; ++k) { for (size_t k = 0; k < 6; ++k) {
@ -259,8 +258,8 @@ void SuppressionGain::LowerBandGain(
WeightEchoForAudibility(config_, residual_echo, weighted_residual_echo); WeightEchoForAudibility(config_, residual_echo, weighted_residual_echo);
std::array<float, kFftLengthBy2Plus1> min_gain; std::array<float, kFftLengthBy2Plus1> min_gain;
GetMinGain(suppressor_input, weighted_residual_echo, low_noise_render, GetMinGain(weighted_residual_echo, low_noise_render, saturated_echo,
saturated_echo, min_gain); min_gain);
std::array<float, kFftLengthBy2Plus1> max_gain; std::array<float, kFftLengthBy2Plus1> max_gain;
GetMaxGain(max_gain); GetMaxGain(max_gain);
@ -311,7 +310,6 @@ SuppressionGain::SuppressionGain(const EchoCanceller3Config& config,
SuppressionGain::~SuppressionGain() = default; SuppressionGain::~SuppressionGain() = default;
void SuppressionGain::GetGain( void SuppressionGain::GetGain(
const std::array<float, kFftLengthBy2Plus1>& suppressor_input_spectrum,
const std::array<float, kFftLengthBy2Plus1>& nearend_spectrum, const std::array<float, kFftLengthBy2Plus1>& nearend_spectrum,
const std::array<float, kFftLengthBy2Plus1>& echo_spectrum, const std::array<float, kFftLengthBy2Plus1>& echo_spectrum,
const std::array<float, kFftLengthBy2Plus1>& residual_echo_spectrum, const std::array<float, kFftLengthBy2Plus1>& residual_echo_spectrum,
@ -340,9 +338,8 @@ void SuppressionGain::GetGain(
// Compute gain for the lower band. // Compute gain for the lower band.
bool low_noise_render = low_render_detector_.Detect(render); bool low_noise_render = low_render_detector_.Detect(render);
LowerBandGain(low_noise_render, aec_state, suppressor_input_spectrum, LowerBandGain(low_noise_render, aec_state, nearend_spectrum, nearend_average,
nearend_average, residual_echo_spectrum, comfort_noise_spectrum, residual_echo_spectrum, comfort_noise_spectrum, low_band_gain);
low_band_gain);
// Compute the gain for the upper bands. // Compute the gain for the upper bands.
const absl::optional<int> narrow_peak_band = const absl::optional<int> narrow_peak_band =

View file

@ -35,7 +35,6 @@ class SuppressionGain {
int sample_rate_hz); int sample_rate_hz);
~SuppressionGain(); ~SuppressionGain();
void GetGain( void GetGain(
const std::array<float, kFftLengthBy2Plus1>& suppressor_input_spectrum,
const std::array<float, kFftLengthBy2Plus1>& nearend_spectrum, const std::array<float, kFftLengthBy2Plus1>& nearend_spectrum,
const std::array<float, kFftLengthBy2Plus1>& echo_spectrum, const std::array<float, kFftLengthBy2Plus1>& echo_spectrum,
const std::array<float, kFftLengthBy2Plus1>& residual_echo_spectrum, const std::array<float, kFftLengthBy2Plus1>& residual_echo_spectrum,
@ -76,8 +75,7 @@ class SuppressionGain {
const std::array<float, kFftLengthBy2Plus1>& comfort_noise, const std::array<float, kFftLengthBy2Plus1>& comfort_noise,
std::array<float, kFftLengthBy2Plus1>* gain); std::array<float, kFftLengthBy2Plus1>* gain);
void GetMinGain(rtc::ArrayView<const float> suppressor_input, void GetMinGain(rtc::ArrayView<const float> weighted_residual_echo,
rtc::ArrayView<const float> weighted_residual_echo,
bool low_noise_render, bool low_noise_render,
bool saturated_echo, bool saturated_echo,
rtc::ArrayView<float> min_gain) const; rtc::ArrayView<float> min_gain) const;

View file

@ -45,7 +45,7 @@ TEST(SuppressionGain, NullOutputGains) {
AecState aec_state(EchoCanceller3Config{}); AecState aec_state(EchoCanceller3Config{});
EXPECT_DEATH( EXPECT_DEATH(
SuppressionGain(EchoCanceller3Config{}, DetectOptimization(), 16000) SuppressionGain(EchoCanceller3Config{}, DetectOptimization(), 16000)
.GetGain(E2, E2, S2, R2, N2, .GetGain(E2, S2, R2, N2,
RenderSignalAnalyzer((EchoCanceller3Config{})), aec_state, RenderSignalAnalyzer((EchoCanceller3Config{})), aec_state,
std::vector<std::vector<float>>( std::vector<std::vector<float>>(
3, std::vector<float>(kBlockSize, 0.f)), 3, std::vector<float>(kBlockSize, 0.f)),
@ -100,7 +100,7 @@ TEST(SuppressionGain, BasicGainComputation) {
subtractor.FilterImpulseResponse(), subtractor.FilterImpulseResponse(),
*render_delay_buffer->GetRenderBuffer(), E2, Y2, output, *render_delay_buffer->GetRenderBuffer(), E2, Y2, output,
y); y);
suppression_gain.GetGain(E2, E2, S2, R2, N2, analyzer, aec_state, x, suppression_gain.GetGain(E2, S2, R2, N2, analyzer, aec_state, x,
&high_bands_gain, &g); &high_bands_gain, &g);
} }
std::for_each(g.begin(), g.end(), std::for_each(g.begin(), g.end(),
@ -118,7 +118,7 @@ TEST(SuppressionGain, BasicGainComputation) {
subtractor.FilterImpulseResponse(), subtractor.FilterImpulseResponse(),
*render_delay_buffer->GetRenderBuffer(), E2, Y2, output, *render_delay_buffer->GetRenderBuffer(), E2, Y2, output,
y); y);
suppression_gain.GetGain(E2, E2, S2, R2, N2, analyzer, aec_state, x, suppression_gain.GetGain(E2, S2, R2, N2, analyzer, aec_state, x,
&high_bands_gain, &g); &high_bands_gain, &g);
} }
std::for_each(g.begin(), g.end(), std::for_each(g.begin(), g.end(),
@ -129,7 +129,7 @@ TEST(SuppressionGain, BasicGainComputation) {
R2.fill(10000000000000.f); R2.fill(10000000000000.f);
for (int k = 0; k < 10; ++k) { for (int k = 0; k < 10; ++k) {
suppression_gain.GetGain(E2, E2, S2, R2, N2, analyzer, aec_state, x, suppression_gain.GetGain(E2, S2, R2, N2, analyzer, aec_state, x,
&high_bands_gain, &g); &high_bands_gain, &g);
} }
std::for_each(g.begin(), g.end(), std::for_each(g.begin(), g.end(),

View file

@ -1 +1 @@
169276fe22bbeb1c06e0ed1a9df8149c5dbf8f80 bc19d9e9fd9503cad02f3b0c21cbd63ed3c5f22c