Increased high frequency transparency

Avoid excessive echo suppression in frequencies above 2 kHz when
there is a dominant nearend. Calls with clock drift will not be affected
by this change as they tend to have less accurate linear filters.

Bug: webrtc:11985
Change-Id: Iddc628da5e2ba572c1b47acd87dd3be35260dca1
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/188580
Reviewed-by: Per Åhgren <peah@webrtc.org>
Commit-Queue: Gustaf Ullberg <gustaf@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#32533}
This commit is contained in:
Gustaf Ullberg 2020-10-22 14:36:37 +02:00 committed by Commit Bot
parent 4cd92d88ea
commit 7e4ad828d6
10 changed files with 61 additions and 35 deletions

View File

@ -221,6 +221,7 @@ struct RTC_EXPORT EchoCanceller3Config {
} high_bands_suppression; } high_bands_suppression;
float floor_first_increase = 0.00001f; float floor_first_increase = 0.00001f;
bool conservative_hf_suppression = false;
} suppressor; } suppressor;
}; };
} // namespace webrtc } // namespace webrtc

View File

@ -383,6 +383,8 @@ void Aec3ConfigFromJsonString(absl::string_view json_string,
ReadParam(section, "floor_first_increase", ReadParam(section, "floor_first_increase",
&cfg.suppressor.floor_first_increase); &cfg.suppressor.floor_first_increase);
ReadParam(section, "conservative_hf_suppression",
&cfg.suppressor.conservative_hf_suppression);
} }
} }
@ -676,7 +678,10 @@ std::string Aec3ConfigToJsonString(const EchoCanceller3Config& config) {
ost << "\"anti_howling_gain\": " ost << "\"anti_howling_gain\": "
<< config.suppressor.high_bands_suppression.anti_howling_gain; << config.suppressor.high_bands_suppression.anti_howling_gain;
ost << "},"; ost << "},";
ost << "\"floor_first_increase\": " << config.suppressor.floor_first_increase; ost << "\"floor_first_increase\": " << config.suppressor.floor_first_increase
<< ",";
ost << "\"conservative_hf_suppression\": "
<< config.suppressor.conservative_hf_suppression;
ost << "}"; ost << "}";
ost << "}"; ost << "}";
ost << "}"; ost << "}";

View File

@ -368,6 +368,10 @@ EchoCanceller3Config AdjustConfig(const EchoCanceller3Config& config) {
adjusted_cfg.suppressor.nearend_tuning.max_dec_factor_lf = .2f; adjusted_cfg.suppressor.nearend_tuning.max_dec_factor_lf = .2f;
} }
if (field_trial::IsEnabled("WebRTC-Aec3EnforceConservativeHfSuppression")) {
adjusted_cfg.suppressor.conservative_hf_suppression = true;
}
if (field_trial::IsEnabled("WebRTC-Aec3EnforceStationarityProperties")) { if (field_trial::IsEnabled("WebRTC-Aec3EnforceStationarityProperties")) {
adjusted_cfg.echo_audibility.use_stationarity_properties = true; adjusted_cfg.echo_audibility.use_stationarity_properties = true;
} }

View File

@ -414,12 +414,16 @@ void EchoRemoverImpl::ProcessCapture(
const auto& echo_spectrum = const auto& echo_spectrum =
aec_state_.UsableLinearEstimate() ? S2_linear : R2; aec_state_.UsableLinearEstimate() ? S2_linear : R2;
// Determine if the suppressor should assume clock drift.
const bool clock_drift = config_.echo_removal_control.has_clock_drift ||
echo_path_variability.clock_drift;
// Compute preferred gains. // Compute preferred gains.
float high_bands_gain; float high_bands_gain;
std::array<float, kFftLengthBy2Plus1> G; std::array<float, kFftLengthBy2Plus1> G;
suppression_gain_.GetGain(nearend_spectrum, echo_spectrum, R2, 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, clock_drift, &high_bands_gain, &G);
suppression_filter_.ApplyGain(comfort_noise, high_band_comfort_noise, G, suppression_filter_.ApplyGain(comfort_noise, high_band_comfort_noise, G,
high_bands_gain, Y_fft, y); high_bands_gain, Y_fft, y);

View File

@ -27,25 +27,24 @@
namespace webrtc { namespace webrtc {
namespace { namespace {
void PostprocessGains(std::array<float, kFftLengthBy2Plus1>* gain) { void LimitLowFrequencyGains(std::array<float, kFftLengthBy2Plus1>* gain) {
// TODO(gustaf): Investigate if this can be relaxed to achieve higher
// transparency above 2 kHz.
// Limit the low frequency gains to avoid the impact of the high-pass filter // Limit the low frequency gains to avoid the impact of the high-pass filter
// on the lower-frequency gain influencing the overall achieved gain. // on the lower-frequency gain influencing the overall achieved gain.
(*gain)[0] = (*gain)[1] = std::min((*gain)[1], (*gain)[2]); (*gain)[0] = (*gain)[1] = std::min((*gain)[1], (*gain)[2]);
}
// Limit the high frequency gains to avoid the impact of the anti-aliasing void LimitHighFrequencyGains(bool conservative_hf_suppression,
// filter on the upper-frequency gains influencing the overall achieved std::array<float, kFftLengthBy2Plus1>* gain) {
// gain. TODO(peah): Update this when new anti-aliasing filters are // Limit the high frequency gains to avoid echo leakage due to an imperfect
// implemented. // filter.
constexpr size_t kAntiAliasingImpactLimit = (64 * 2000) / 8000; constexpr size_t kFirstBandToLimit = (64 * 2000) / 8000;
const float min_upper_gain = (*gain)[kAntiAliasingImpactLimit]; const float min_upper_gain = (*gain)[kFirstBandToLimit];
std::for_each( std::for_each(
gain->begin() + kAntiAliasingImpactLimit, gain->end() - 1, gain->begin() + kFirstBandToLimit + 1, gain->end(),
[min_upper_gain](float& a) { a = std::min(a, min_upper_gain); }); [min_upper_gain](float& a) { a = std::min(a, min_upper_gain); });
(*gain)[kFftLengthBy2] = (*gain)[kFftLengthBy2Minus1]; (*gain)[kFftLengthBy2] = (*gain)[kFftLengthBy2Minus1];
if (conservative_hf_suppression) {
// Limits the gain in the frequencies for which the adaptive filter has not // Limits the gain in the frequencies for which the adaptive filter has not
// converged. // converged.
// TODO(peah): Make adaptive to take the actual filter error into account. // TODO(peah): Make adaptive to take the actual filter error into account.
@ -58,8 +57,10 @@ void PostprocessGains(std::array<float, kFftLengthBy2Plus1>* gain) {
gain->begin() + kUpperAccurateBandPlus1, 0.f) * gain->begin() + kUpperAccurateBandPlus1, 0.f) *
oneByBandsInSum; oneByBandsInSum;
std::for_each(gain->begin() + kUpperAccurateBandPlus1, gain->end(), std::for_each(
gain->begin() + kUpperAccurateBandPlus1, gain->end(),
[hf_gain_bound](float& a) { a = std::min(a, hf_gain_bound); }); [hf_gain_bound](float& a) { a = std::min(a, hf_gain_bound); });
}
} }
// Scales the echo according to assessed audibility at the other end. // Scales the echo according to assessed audibility at the other end.
@ -265,6 +266,7 @@ void SuppressionGain::LowerBandGain(
suppressor_input, suppressor_input,
rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> residual_echo, rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> residual_echo,
rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> comfort_noise, rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> comfort_noise,
bool clock_drift,
std::array<float, kFftLengthBy2Plus1>* gain) { std::array<float, kFftLengthBy2Plus1>* gain) {
gain->fill(1.f); gain->fill(1.f);
const bool saturated_echo = aec_state.SaturatedEcho(); const bool saturated_echo = aec_state.SaturatedEcho();
@ -298,8 +300,14 @@ void SuppressionGain::LowerBandGain(
last_echo_[ch].begin()); last_echo_[ch].begin());
} }
// Limit high-frequency gains. LimitLowFrequencyGains(gain);
PostprocessGains(gain); // Use conservative high-frequency gains during clock-drift or when not in
// dominant nearend.
if (!dominant_nearend_detector_->IsNearendState() || clock_drift ||
config_.suppressor.conservative_hf_suppression) {
LimitHighFrequencyGains(config_.suppressor.conservative_hf_suppression,
gain);
}
// Store computed gains. // Store computed gains.
std::copy(gain->begin(), gain->end(), last_gain_.begin()); std::copy(gain->begin(), gain->end(), last_gain_.begin());
@ -352,6 +360,7 @@ void SuppressionGain::GetGain(
const RenderSignalAnalyzer& render_signal_analyzer, const RenderSignalAnalyzer& render_signal_analyzer,
const AecState& aec_state, const AecState& aec_state,
const std::vector<std::vector<std::vector<float>>>& render, const std::vector<std::vector<std::vector<float>>>& render,
bool clock_drift,
float* high_bands_gain, float* high_bands_gain,
std::array<float, kFftLengthBy2Plus1>* low_band_gain) { std::array<float, kFftLengthBy2Plus1>* low_band_gain) {
RTC_DCHECK(high_bands_gain); RTC_DCHECK(high_bands_gain);
@ -364,7 +373,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, nearend_spectrum, LowerBandGain(low_noise_render, aec_state, nearend_spectrum,
residual_echo_spectrum, comfort_noise_spectrum, low_band_gain); residual_echo_spectrum, comfort_noise_spectrum, clock_drift,
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

@ -47,6 +47,7 @@ class SuppressionGain {
const RenderSignalAnalyzer& render_signal_analyzer, const RenderSignalAnalyzer& render_signal_analyzer,
const AecState& aec_state, const AecState& aec_state,
const std::vector<std::vector<std::vector<float>>>& render, const std::vector<std::vector<std::vector<float>>>& render,
bool clock_drift,
float* high_bands_gain, float* high_bands_gain,
std::array<float, kFftLengthBy2Plus1>* low_band_gain); std::array<float, kFftLengthBy2Plus1>* low_band_gain);
@ -76,6 +77,7 @@ class SuppressionGain {
suppressor_input, suppressor_input,
rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> residual_echo, rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> residual_echo,
rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> comfort_noise, rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> comfort_noise,
bool clock_drift,
std::array<float, kFftLengthBy2Plus1>* gain); std::array<float, kFftLengthBy2Plus1>* gain);
void GetMinGain(rtc::ArrayView<const float> weighted_residual_echo, void GetMinGain(rtc::ArrayView<const float> weighted_residual_echo,

View File

@ -49,7 +49,7 @@ TEST(SuppressionGainDeathTest, NullOutputGains) {
std::vector<std::vector<std::vector<float>>>( std::vector<std::vector<std::vector<float>>>(
3, std::vector<std::vector<float>>( 3, std::vector<std::vector<float>>(
1, std::vector<float>(kBlockSize, 0.f))), 1, std::vector<float>(kBlockSize, 0.f))),
&high_bands_gain, nullptr), false, &high_bands_gain, nullptr),
""); "");
} }
@ -107,7 +107,7 @@ TEST(SuppressionGain, BasicGainComputation) {
aec_state.Update(delay_estimate, subtractor.FilterFrequencyResponses(), aec_state.Update(delay_estimate, subtractor.FilterFrequencyResponses(),
subtractor.FilterImpulseResponses(), subtractor.FilterImpulseResponses(),
*render_delay_buffer->GetRenderBuffer(), E2, Y2, output); *render_delay_buffer->GetRenderBuffer(), E2, Y2, output);
suppression_gain.GetGain(E2, S2, R2, N2, analyzer, aec_state, x, suppression_gain.GetGain(E2, S2, R2, N2, analyzer, aec_state, x, false,
&high_bands_gain, &g); &high_bands_gain, &g);
} }
std::for_each(g.begin(), g.end(), std::for_each(g.begin(), g.end(),
@ -126,7 +126,7 @@ TEST(SuppressionGain, BasicGainComputation) {
aec_state.Update(delay_estimate, subtractor.FilterFrequencyResponses(), aec_state.Update(delay_estimate, subtractor.FilterFrequencyResponses(),
subtractor.FilterImpulseResponses(), subtractor.FilterImpulseResponses(),
*render_delay_buffer->GetRenderBuffer(), E2, Y2, output); *render_delay_buffer->GetRenderBuffer(), E2, Y2, output);
suppression_gain.GetGain(E2, S2, R2, N2, analyzer, aec_state, x, suppression_gain.GetGain(E2, S2, R2, N2, analyzer, aec_state, x, false,
&high_bands_gain, &g); &high_bands_gain, &g);
} }
std::for_each(g.begin(), g.end(), std::for_each(g.begin(), g.end(),
@ -137,7 +137,7 @@ TEST(SuppressionGain, BasicGainComputation) {
R2[1].fill(10000000000000.f); R2[1].fill(10000000000000.f);
for (int k = 0; k < 10; ++k) { for (int k = 0; k < 10; ++k) {
suppression_gain.GetGain(E2, S2, R2, N2, analyzer, aec_state, x, suppression_gain.GetGain(E2, S2, R2, N2, analyzer, aec_state, x, false,
&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 @@
4010b1fe15eda1b42968cdb3f9fed399e1aa7197 0ff9ab4d46929552e21d16f266f9eba42575ba8d

View File

@ -1 +1 @@
d22d4b0bc8f59aa27da61e158b9d35596f3844f5 ed1172c80a1a001a8aa7ac0680a99018cbb7d278

View File

@ -1 +1 @@
514543fbee78d0a71e87adb92e23138d762d1da8 a1dd718a6882bf8033a934e5beec73086cc91240