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:
parent
4cd92d88ea
commit
7e4ad828d6
@ -221,6 +221,7 @@ struct RTC_EXPORT EchoCanceller3Config {
|
||||
} high_bands_suppression;
|
||||
|
||||
float floor_first_increase = 0.00001f;
|
||||
bool conservative_hf_suppression = false;
|
||||
} suppressor;
|
||||
};
|
||||
} // namespace webrtc
|
||||
|
||||
@ -383,6 +383,8 @@ void Aec3ConfigFromJsonString(absl::string_view json_string,
|
||||
|
||||
ReadParam(section, "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\": "
|
||||
<< config.suppressor.high_bands_suppression.anti_howling_gain;
|
||||
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 << "}";
|
||||
|
||||
@ -368,6 +368,10 @@ EchoCanceller3Config AdjustConfig(const EchoCanceller3Config& config) {
|
||||
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")) {
|
||||
adjusted_cfg.echo_audibility.use_stationarity_properties = true;
|
||||
}
|
||||
|
||||
@ -414,12 +414,16 @@ void EchoRemoverImpl::ProcessCapture(
|
||||
const auto& echo_spectrum =
|
||||
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.
|
||||
float high_bands_gain;
|
||||
std::array<float, kFftLengthBy2Plus1> G;
|
||||
suppression_gain_.GetGain(nearend_spectrum, echo_spectrum, R2,
|
||||
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,
|
||||
high_bands_gain, Y_fft, y);
|
||||
|
||||
@ -27,39 +27,40 @@
|
||||
namespace webrtc {
|
||||
namespace {
|
||||
|
||||
void PostprocessGains(std::array<float, kFftLengthBy2Plus1>* gain) {
|
||||
// TODO(gustaf): Investigate if this can be relaxed to achieve higher
|
||||
// transparency above 2 kHz.
|
||||
|
||||
void LimitLowFrequencyGains(std::array<float, kFftLengthBy2Plus1>* gain) {
|
||||
// Limit the low frequency gains to avoid the impact of the high-pass filter
|
||||
// on the lower-frequency gain influencing the overall achieved gain.
|
||||
(*gain)[0] = (*gain)[1] = std::min((*gain)[1], (*gain)[2]);
|
||||
}
|
||||
|
||||
// Limit the high frequency gains to avoid the impact of the anti-aliasing
|
||||
// filter on the upper-frequency gains influencing the overall achieved
|
||||
// gain. TODO(peah): Update this when new anti-aliasing filters are
|
||||
// implemented.
|
||||
constexpr size_t kAntiAliasingImpactLimit = (64 * 2000) / 8000;
|
||||
const float min_upper_gain = (*gain)[kAntiAliasingImpactLimit];
|
||||
void LimitHighFrequencyGains(bool conservative_hf_suppression,
|
||||
std::array<float, kFftLengthBy2Plus1>* gain) {
|
||||
// Limit the high frequency gains to avoid echo leakage due to an imperfect
|
||||
// filter.
|
||||
constexpr size_t kFirstBandToLimit = (64 * 2000) / 8000;
|
||||
const float min_upper_gain = (*gain)[kFirstBandToLimit];
|
||||
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); });
|
||||
(*gain)[kFftLengthBy2] = (*gain)[kFftLengthBy2Minus1];
|
||||
|
||||
// Limits the gain in the frequencies for which the adaptive filter has not
|
||||
// converged.
|
||||
// TODO(peah): Make adaptive to take the actual filter error into account.
|
||||
constexpr size_t kUpperAccurateBandPlus1 = 29;
|
||||
if (conservative_hf_suppression) {
|
||||
// Limits the gain in the frequencies for which the adaptive filter has not
|
||||
// converged.
|
||||
// TODO(peah): Make adaptive to take the actual filter error into account.
|
||||
constexpr size_t kUpperAccurateBandPlus1 = 29;
|
||||
|
||||
constexpr float oneByBandsInSum =
|
||||
1 / static_cast<float>(kUpperAccurateBandPlus1 - 20);
|
||||
const float hf_gain_bound =
|
||||
std::accumulate(gain->begin() + 20,
|
||||
gain->begin() + kUpperAccurateBandPlus1, 0.f) *
|
||||
oneByBandsInSum;
|
||||
constexpr float oneByBandsInSum =
|
||||
1 / static_cast<float>(kUpperAccurateBandPlus1 - 20);
|
||||
const float hf_gain_bound =
|
||||
std::accumulate(gain->begin() + 20,
|
||||
gain->begin() + kUpperAccurateBandPlus1, 0.f) *
|
||||
oneByBandsInSum;
|
||||
|
||||
std::for_each(gain->begin() + kUpperAccurateBandPlus1, gain->end(),
|
||||
[hf_gain_bound](float& a) { a = std::min(a, hf_gain_bound); });
|
||||
std::for_each(
|
||||
gain->begin() + kUpperAccurateBandPlus1, gain->end(),
|
||||
[hf_gain_bound](float& a) { a = std::min(a, hf_gain_bound); });
|
||||
}
|
||||
}
|
||||
|
||||
// Scales the echo according to assessed audibility at the other end.
|
||||
@ -265,6 +266,7 @@ void SuppressionGain::LowerBandGain(
|
||||
suppressor_input,
|
||||
rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> residual_echo,
|
||||
rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> comfort_noise,
|
||||
bool clock_drift,
|
||||
std::array<float, kFftLengthBy2Plus1>* gain) {
|
||||
gain->fill(1.f);
|
||||
const bool saturated_echo = aec_state.SaturatedEcho();
|
||||
@ -298,8 +300,14 @@ void SuppressionGain::LowerBandGain(
|
||||
last_echo_[ch].begin());
|
||||
}
|
||||
|
||||
// Limit high-frequency gains.
|
||||
PostprocessGains(gain);
|
||||
LimitLowFrequencyGains(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.
|
||||
std::copy(gain->begin(), gain->end(), last_gain_.begin());
|
||||
@ -352,6 +360,7 @@ void SuppressionGain::GetGain(
|
||||
const RenderSignalAnalyzer& render_signal_analyzer,
|
||||
const AecState& aec_state,
|
||||
const std::vector<std::vector<std::vector<float>>>& render,
|
||||
bool clock_drift,
|
||||
float* high_bands_gain,
|
||||
std::array<float, kFftLengthBy2Plus1>* low_band_gain) {
|
||||
RTC_DCHECK(high_bands_gain);
|
||||
@ -364,7 +373,8 @@ void SuppressionGain::GetGain(
|
||||
// Compute gain for the lower band.
|
||||
bool low_noise_render = low_render_detector_.Detect(render);
|
||||
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.
|
||||
const absl::optional<int> narrow_peak_band =
|
||||
|
||||
@ -47,6 +47,7 @@ class SuppressionGain {
|
||||
const RenderSignalAnalyzer& render_signal_analyzer,
|
||||
const AecState& aec_state,
|
||||
const std::vector<std::vector<std::vector<float>>>& render,
|
||||
bool clock_drift,
|
||||
float* high_bands_gain,
|
||||
std::array<float, kFftLengthBy2Plus1>* low_band_gain);
|
||||
|
||||
@ -76,6 +77,7 @@ class SuppressionGain {
|
||||
suppressor_input,
|
||||
rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> residual_echo,
|
||||
rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> comfort_noise,
|
||||
bool clock_drift,
|
||||
std::array<float, kFftLengthBy2Plus1>* gain);
|
||||
|
||||
void GetMinGain(rtc::ArrayView<const float> weighted_residual_echo,
|
||||
|
||||
@ -49,7 +49,7 @@ TEST(SuppressionGainDeathTest, NullOutputGains) {
|
||||
std::vector<std::vector<std::vector<float>>>(
|
||||
3, std::vector<std::vector<float>>(
|
||||
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(),
|
||||
subtractor.FilterImpulseResponses(),
|
||||
*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);
|
||||
}
|
||||
std::for_each(g.begin(), g.end(),
|
||||
@ -126,7 +126,7 @@ TEST(SuppressionGain, BasicGainComputation) {
|
||||
aec_state.Update(delay_estimate, subtractor.FilterFrequencyResponses(),
|
||||
subtractor.FilterImpulseResponses(),
|
||||
*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);
|
||||
}
|
||||
std::for_each(g.begin(), g.end(),
|
||||
@ -137,7 +137,7 @@ TEST(SuppressionGain, BasicGainComputation) {
|
||||
R2[1].fill(10000000000000.f);
|
||||
|
||||
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);
|
||||
}
|
||||
std::for_each(g.begin(), g.end(),
|
||||
|
||||
@ -1 +1 @@
|
||||
4010b1fe15eda1b42968cdb3f9fed399e1aa7197
|
||||
0ff9ab4d46929552e21d16f266f9eba42575ba8d
|
||||
@ -1 +1 @@
|
||||
d22d4b0bc8f59aa27da61e158b9d35596f3844f5
|
||||
ed1172c80a1a001a8aa7ac0680a99018cbb7d278
|
||||
@ -1 +1 @@
|
||||
514543fbee78d0a71e87adb92e23138d762d1da8
|
||||
a1dd718a6882bf8033a934e5beec73086cc91240
|
||||
Loading…
x
Reference in New Issue
Block a user