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;
|
} 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
|
||||||
|
|||||||
@ -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 << "}";
|
||||||
|
|||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
@ -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 =
|
||||||
|
|||||||
@ -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,
|
||||||
|
|||||||
@ -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(),
|
||||||
|
|||||||
@ -1 +1 @@
|
|||||||
4010b1fe15eda1b42968cdb3f9fed399e1aa7197
|
0ff9ab4d46929552e21d16f266f9eba42575ba8d
|
||||||
@ -1 +1 @@
|
|||||||
d22d4b0bc8f59aa27da61e158b9d35596f3844f5
|
ed1172c80a1a001a8aa7ac0680a99018cbb7d278
|
||||||
@ -1 +1 @@
|
|||||||
514543fbee78d0a71e87adb92e23138d762d1da8
|
a1dd718a6882bf8033a934e5beec73086cc91240
|
||||||
Loading…
x
Reference in New Issue
Block a user