Added forced zero AEC output after call startup and echo path changes
During the first few capture frames, there is no way for the AEC to tell whether there is echo in the capture signal as the echo removal functionality in the AEC has not yet seen any render signal. To avoid initial echo bursts due to this, this CL adds functionality for forcing the echo suppression gain to zero during the first 50 blocks (200 ms) after call start and after a reported echo path change. BUG=webrtc:6018 Review-Url: https://codereview.webrtc.org/2808733002 Cr-Commit-Position: refs/heads/master@{#17624}
This commit is contained in:
parent
ca31f175e1
commit
6d822adac4
@ -97,6 +97,11 @@ void AecState::HandleEchoPathChange(
|
||||
echo_saturation_ = false;
|
||||
headset_detected_ = false;
|
||||
previous_max_sample_ = 0.f;
|
||||
|
||||
if (echo_path_variability.delay_change) {
|
||||
force_zero_gain_counter_ = 0;
|
||||
force_zero_gain_ = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -117,6 +122,12 @@ void AecState::Update(const std::vector<std::array<float, kFftLengthBy2Plus1>>&
|
||||
active_render_blocks_ += active_render_block ? 1 : 0;
|
||||
--echo_path_change_counter_;
|
||||
|
||||
// Force zero echo suppression gain after an echo path change to allow at
|
||||
// least some render data to be collected in order to avoid an initial echo
|
||||
// burst.
|
||||
constexpr size_t kZeroGainBlocksAfterChange = kNumBlocksPerSecond / 5;
|
||||
force_zero_gain_ = (++force_zero_gain_counter_) < kZeroGainBlocksAfterChange;
|
||||
|
||||
// Estimate delays.
|
||||
filter_delay_ = EstimateFilterDelay(adaptive_filter_frequency_response);
|
||||
external_delay_ =
|
||||
|
||||
@ -80,6 +80,9 @@ class AecState {
|
||||
// TODO(peah): Make this adaptive.
|
||||
float ReverbDecayFactor() const { return 0.f; }
|
||||
|
||||
// Returns whether the echo suppression gain should be forced to zero.
|
||||
bool ForcedZeroGain() const { return force_zero_gain_; }
|
||||
|
||||
// Updates the aec state.
|
||||
void Update(const std::vector<std::array<float, kFftLengthBy2Plus1>>&
|
||||
adaptive_filter_frequency_response,
|
||||
@ -103,6 +106,8 @@ class AecState {
|
||||
bool echo_saturation_ = false;
|
||||
bool headset_detected_ = false;
|
||||
float previous_max_sample_ = 0.f;
|
||||
bool force_zero_gain_ = false;
|
||||
size_t force_zero_gain_counter_ = 0;
|
||||
rtc::Optional<size_t> filter_delay_;
|
||||
rtc::Optional<size_t> external_delay_;
|
||||
size_t blocks_since_last_saturation_ = 1000;
|
||||
|
||||
@ -182,7 +182,7 @@ void EchoRemoverImpl::ProcessCapture(
|
||||
// A choose and apply echo suppression gain.
|
||||
suppression_gain_.GetGain(E2, R2, cng_.NoiseSpectrum(),
|
||||
aec_state_.SaturatedEcho(), x, y->size(),
|
||||
&high_bands_gain, &G);
|
||||
aec_state_.ForcedZeroGain(), &high_bands_gain, &G);
|
||||
suppression_filter_.ApplyGain(comfort_noise, high_band_comfort_noise, G,
|
||||
high_bands_gain, y);
|
||||
|
||||
|
||||
@ -325,11 +325,21 @@ void SuppressionGain::GetGain(
|
||||
bool saturated_echo,
|
||||
const std::vector<std::vector<float>>& render,
|
||||
size_t num_capture_bands,
|
||||
bool force_zero_gain,
|
||||
float* high_bands_gain,
|
||||
std::array<float, kFftLengthBy2Plus1>* low_band_gain) {
|
||||
RTC_DCHECK(high_bands_gain);
|
||||
RTC_DCHECK(low_band_gain);
|
||||
|
||||
if (force_zero_gain) {
|
||||
previous_gain_squared_.fill(0.f);
|
||||
std::copy(comfort_noise_power.begin() + 1, comfort_noise_power.end() - 1,
|
||||
previous_masker_.begin());
|
||||
low_band_gain->fill(0.f);
|
||||
*high_bands_gain = 0.f;
|
||||
return;
|
||||
}
|
||||
|
||||
// Choose margin to use.
|
||||
const float margin = saturated_echo ? 0.001f : 0.01f;
|
||||
switch (optimization_) {
|
||||
|
||||
@ -52,6 +52,7 @@ class SuppressionGain {
|
||||
bool saturated_echo,
|
||||
const std::vector<std::vector<float>>& render,
|
||||
size_t num_capture_bands,
|
||||
bool force_zero_gain,
|
||||
float* high_bands_gain,
|
||||
std::array<float, kFftLengthBy2Plus1>* low_band_gain);
|
||||
|
||||
|
||||
@ -33,7 +33,7 @@ TEST(SuppressionGain, NullOutputGains) {
|
||||
.GetGain(E2, R2, N2, false,
|
||||
std::vector<std::vector<float>>(
|
||||
3, std::vector<float>(kBlockSize, 0.f)),
|
||||
1, &high_bands_gain, nullptr),
|
||||
1, false, &high_bands_gain, nullptr),
|
||||
"");
|
||||
}
|
||||
|
||||
@ -128,7 +128,8 @@ TEST(SuppressionGain, BasicGainComputation) {
|
||||
R2.fill(0.1f);
|
||||
N2.fill(100.f);
|
||||
for (int k = 0; k < 10; ++k) {
|
||||
suppression_gain.GetGain(E2, R2, N2, false, x, 1, &high_bands_gain, &g);
|
||||
suppression_gain.GetGain(E2, R2, N2, false, x, 1, false, &high_bands_gain,
|
||||
&g);
|
||||
}
|
||||
std::for_each(g.begin(), g.end(),
|
||||
[](float a) { EXPECT_NEAR(1.f, a, 0.001); });
|
||||
@ -138,7 +139,8 @@ TEST(SuppressionGain, BasicGainComputation) {
|
||||
R2.fill(0.1f);
|
||||
N2.fill(0.f);
|
||||
for (int k = 0; k < 10; ++k) {
|
||||
suppression_gain.GetGain(E2, R2, N2, false, x, 1, &high_bands_gain, &g);
|
||||
suppression_gain.GetGain(E2, R2, N2, false, x, 1, false, &high_bands_gain,
|
||||
&g);
|
||||
}
|
||||
std::for_each(g.begin(), g.end(),
|
||||
[](float a) { EXPECT_NEAR(1.f, a, 0.001); });
|
||||
@ -148,10 +150,16 @@ TEST(SuppressionGain, BasicGainComputation) {
|
||||
R2.fill(100.f);
|
||||
N2.fill(0.f);
|
||||
for (int k = 0; k < 10; ++k) {
|
||||
suppression_gain.GetGain(E2, R2, N2, false, x, 1, &high_bands_gain, &g);
|
||||
suppression_gain.GetGain(E2, R2, N2, false, x, 1, false, &high_bands_gain,
|
||||
&g);
|
||||
}
|
||||
std::for_each(g.begin(), g.end(),
|
||||
[](float a) { EXPECT_NEAR(0.f, a, 0.001); });
|
||||
|
||||
// Verify the functionality for forcing a zero gain.
|
||||
suppression_gain.GetGain(E2, R2, N2, false, x, 1, true, &high_bands_gain, &g);
|
||||
std::for_each(g.begin(), g.end(), [](float a) { EXPECT_FLOAT_EQ(0.f, a); });
|
||||
EXPECT_FLOAT_EQ(0.f, high_bands_gain);
|
||||
}
|
||||
|
||||
} // namespace aec3
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user