Use the filter delay to use the proper render block in the AEC3 AecState

This CL corrects the way that the estimated filter delay is used in
AEC3. In particular
-It uses the filter delay to choose the correct render block in AecState
-It changes the code to reflect that the filter delay is always computed
-It removes part of the code that formerly relied on the filter delay
being an Optional.

Bug: webrtc:8671
Change-Id: I58135a5c174b404707e19a41c3617c09831e871d
Reviewed-on: https://webrtc-review.googlesource.com/35221
Reviewed-by: Gustaf Ullberg <gustaf@webrtc.org>
Commit-Queue: Per Åhgren <peah@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#21557}
This commit is contained in:
Per Åhgren
2017-12-20 22:19:56 +01:00
committed by Commit Bot
parent 77a47e0081
commit 0e6d2f5118
12 changed files with 60 additions and 79 deletions

View File

@ -390,13 +390,13 @@ TEST(AdaptiveFirFilter, FilterAndAdapt) {
false, EchoPathVariability::DelayAdjustment::kNone, false)); false, EchoPathVariability::DelayAdjustment::kNone, false));
aec_state.Update(filter.FilterFrequencyResponse(), aec_state.Update(filter.FilterFrequencyResponse(),
filter.FilterImpulseResponse(), true, *render_buffer, filter.FilterImpulseResponse(), true, *render_buffer,
E2_main, Y2, x[0], s, false); E2_main, Y2, s, false);
} }
// Verify that the filter is able to perform well. // Verify that the filter is able to perform well.
EXPECT_LT(1000 * std::inner_product(e.begin(), e.end(), e.begin(), 0.f), EXPECT_LT(1000 * std::inner_product(e.begin(), e.end(), e.begin(), 0.f),
std::inner_product(y.begin(), y.end(), y.begin(), 0.f)); std::inner_product(y.begin(), y.end(), y.begin(), 0.f));
ASSERT_TRUE(aec_state.FilterDelay()); EXPECT_EQ(delay_samples / kBlockSize,
EXPECT_EQ(delay_samples / kBlockSize, *aec_state.FilterDelay()); static_cast<size_t>(aec_state.FilterDelay()));
} }
} }
} // namespace aec3 } // namespace aec3

View File

@ -39,7 +39,6 @@ constexpr size_t kFftLengthBy2Minus1 = kFftLengthBy2 - 1;
constexpr size_t kFftLength = 2 * kFftLengthBy2; constexpr size_t kFftLength = 2 * kFftLengthBy2;
constexpr int kMaxAdaptiveFilterLength = 50; constexpr int kMaxAdaptiveFilterLength = 50;
constexpr int kUnknownDelayRenderWindowSize = 30;
constexpr int kRenderTransferQueueSizeFrames = 100; constexpr int kRenderTransferQueueSizeFrames = 100;
constexpr size_t kMaxNumBands = 3; constexpr size_t kMaxNumBands = 3;

View File

@ -112,12 +112,15 @@ void AecState::Update(
const RenderBuffer& render_buffer, const RenderBuffer& render_buffer,
const std::array<float, kFftLengthBy2Plus1>& E2_main, const std::array<float, kFftLengthBy2Plus1>& E2_main,
const std::array<float, kFftLengthBy2Plus1>& Y2, const std::array<float, kFftLengthBy2Plus1>& Y2,
rtc::ArrayView<const float> x,
const std::array<float, kBlockSize>& s, const std::array<float, kBlockSize>& s,
bool echo_leakage_detected) { bool echo_leakage_detected) {
// Store input parameters. // Store input parameters.
echo_leakage_detected_ = echo_leakage_detected; echo_leakage_detected_ = echo_leakage_detected;
// Estimate the filter delay.
filter_delay_ = EstimateFilterDelay(adaptive_filter_frequency_response);
const std::vector<float>& x = render_buffer.Block(-filter_delay_)[0];
// Update counters. // Update counters.
++capture_block_counter_; ++capture_block_counter_;
const bool active_render_block = DetectActiveRender(x); const bool active_render_block = DetectActiveRender(x);
@ -130,12 +133,10 @@ void AecState::Update(
// burst. // burst.
force_zero_gain_ = ++force_zero_gain_counter_ < kNumBlocksPerSecond / 5; force_zero_gain_ = ++force_zero_gain_counter_ < kNumBlocksPerSecond / 5;
// Estimate delays.
filter_delay_ = EstimateFilterDelay(adaptive_filter_frequency_response);
// Update the ERL and ERLE measures. // Update the ERL and ERLE measures.
if (converged_filter && capture_block_counter_ >= 2 * kNumBlocksPerSecond) { if (converged_filter && capture_block_counter_ >= 2 * kNumBlocksPerSecond) {
const auto& X2 = render_buffer.Spectrum(*filter_delay_); const auto& X2 = render_buffer.Spectrum(filter_delay_);
erle_estimator_.Update(X2, Y2, E2_main); erle_estimator_.Update(X2, Y2, E2_main);
erl_estimator_.Update(X2, Y2); erl_estimator_.Update(X2, Y2);
} }
@ -174,7 +175,7 @@ void AecState::Update(
void AecState::UpdateReverb(const std::vector<float>& impulse_response) { void AecState::UpdateReverb(const std::vector<float>& impulse_response) {
if ((!(filter_delay_ && usable_linear_estimate_)) || if ((!(filter_delay_ && usable_linear_estimate_)) ||
(*filter_delay_ > config_.filter.length_blocks - 4)) { (filter_delay_ > static_cast<int>(config_.filter.length_blocks) - 4)) {
return; return;
} }

View File

@ -62,7 +62,7 @@ class AecState {
float ErlTimeDomain() const { return erl_estimator_.ErlTimeDomain(); } float ErlTimeDomain() const { return erl_estimator_.ErlTimeDomain(); }
// Returns the delay estimate based on the linear filter. // Returns the delay estimate based on the linear filter.
rtc::Optional<size_t> FilterDelay() const { return filter_delay_; } int FilterDelay() const { return filter_delay_; }
// Returns whether the capture signal is saturated. // Returns whether the capture signal is saturated.
bool SaturatedCapture() const { return capture_signal_saturation_; } bool SaturatedCapture() const { return capture_signal_saturation_; }
@ -111,7 +111,6 @@ class AecState {
const RenderBuffer& render_buffer, const RenderBuffer& render_buffer,
const std::array<float, kFftLengthBy2Plus1>& E2_main, const std::array<float, kFftLengthBy2Plus1>& E2_main,
const std::array<float, kFftLengthBy2Plus1>& Y2, const std::array<float, kFftLengthBy2Plus1>& Y2,
rtc::ArrayView<const float> x,
const std::array<float, kBlockSize>& s_main, const std::array<float, kBlockSize>& s_main,
bool echo_leakage_detected); bool echo_leakage_detected);
@ -151,7 +150,7 @@ class AecState {
bool force_zero_gain_ = false; bool force_zero_gain_ = false;
bool render_received_ = false; bool render_received_ = false;
size_t force_zero_gain_counter_ = 0; size_t force_zero_gain_counter_ = 0;
rtc::Optional<size_t> filter_delay_; int filter_delay_ = 0;
size_t blocks_since_last_saturation_ = 1000; size_t blocks_since_last_saturation_ = 1000;
float reverb_decay_to_test_ = 0.9f; float reverb_decay_to_test_ = 0.9f;
float reverb_decay_candidate_ = 0.f; float reverb_decay_candidate_ = 0.f;

View File

@ -48,15 +48,15 @@ TEST(AecState, NormalUsage) {
// Verify that linear AEC usability is false when the filter is diverged. // Verify that linear AEC usability is false when the filter is diverged.
state.Update(diverged_filter_frequency_response, impulse_response, true, state.Update(diverged_filter_frequency_response, impulse_response, true,
*render_delay_buffer->GetRenderBuffer(), E2_main, Y2, x[0], s, *render_delay_buffer->GetRenderBuffer(), E2_main, Y2, s, false);
false);
EXPECT_FALSE(state.UsableLinearEstimate()); EXPECT_FALSE(state.UsableLinearEstimate());
// Verify that linear AEC usability is true when the filter is converged // Verify that linear AEC usability is true when the filter is converged
std::fill(x[0].begin(), x[0].end(), 101.f); std::fill(x[0].begin(), x[0].end(), 101.f);
for (int k = 0; k < 3000; ++k) { for (int k = 0; k < 3000; ++k) {
render_delay_buffer->Insert(x);
state.Update(converged_filter_frequency_response, impulse_response, true, state.Update(converged_filter_frequency_response, impulse_response, true,
*render_delay_buffer->GetRenderBuffer(), E2_main, Y2, x[0], s, *render_delay_buffer->GetRenderBuffer(), E2_main, Y2, s,
false); false);
} }
EXPECT_TRUE(state.UsableLinearEstimate()); EXPECT_TRUE(state.UsableLinearEstimate());
@ -66,35 +66,33 @@ TEST(AecState, NormalUsage) {
state.HandleEchoPathChange(EchoPathVariability( state.HandleEchoPathChange(EchoPathVariability(
true, EchoPathVariability::DelayAdjustment::kNone, false)); true, EchoPathVariability::DelayAdjustment::kNone, false));
state.Update(converged_filter_frequency_response, impulse_response, true, state.Update(converged_filter_frequency_response, impulse_response, true,
*render_delay_buffer->GetRenderBuffer(), E2_main, Y2, x[0], s, *render_delay_buffer->GetRenderBuffer(), E2_main, Y2, s, false);
false);
EXPECT_FALSE(state.UsableLinearEstimate()); EXPECT_FALSE(state.UsableLinearEstimate());
// Verify that the active render detection works as intended. // Verify that the active render detection works as intended.
std::fill(x[0].begin(), x[0].end(), 101.f); std::fill(x[0].begin(), x[0].end(), 101.f);
render_delay_buffer->Insert(x);
state.HandleEchoPathChange(EchoPathVariability( state.HandleEchoPathChange(EchoPathVariability(
true, EchoPathVariability::DelayAdjustment::kNewDetectedDelay, false)); true, EchoPathVariability::DelayAdjustment::kNewDetectedDelay, false));
state.Update(converged_filter_frequency_response, impulse_response, true, state.Update(converged_filter_frequency_response, impulse_response, true,
*render_delay_buffer->GetRenderBuffer(), E2_main, Y2, x[0], s, *render_delay_buffer->GetRenderBuffer(), E2_main, Y2, s, false);
false);
EXPECT_FALSE(state.ActiveRender()); EXPECT_FALSE(state.ActiveRender());
for (int k = 0; k < 1000; ++k) { for (int k = 0; k < 1000; ++k) {
render_delay_buffer->Insert(x);
state.Update(converged_filter_frequency_response, impulse_response, true, state.Update(converged_filter_frequency_response, impulse_response, true,
*render_delay_buffer->GetRenderBuffer(), E2_main, Y2, x[0], s, *render_delay_buffer->GetRenderBuffer(), E2_main, Y2, s,
false); false);
} }
EXPECT_TRUE(state.ActiveRender()); EXPECT_TRUE(state.ActiveRender());
// Verify that echo leakage is properly reported. // Verify that echo leakage is properly reported.
state.Update(converged_filter_frequency_response, impulse_response, true, state.Update(converged_filter_frequency_response, impulse_response, true,
*render_delay_buffer->GetRenderBuffer(), E2_main, Y2, x[0], s, *render_delay_buffer->GetRenderBuffer(), E2_main, Y2, s, false);
false);
EXPECT_FALSE(state.EchoLeakageDetected()); EXPECT_FALSE(state.EchoLeakageDetected());
state.Update(converged_filter_frequency_response, impulse_response, true, state.Update(converged_filter_frequency_response, impulse_response, true,
*render_delay_buffer->GetRenderBuffer(), E2_main, Y2, x[0], s, *render_delay_buffer->GetRenderBuffer(), E2_main, Y2, s, true);
true);
EXPECT_TRUE(state.EchoLeakageDetected()); EXPECT_TRUE(state.EchoLeakageDetected());
// Verify that the ERL is properly estimated // Verify that the ERL is properly estimated
@ -115,7 +113,7 @@ TEST(AecState, NormalUsage) {
Y2.fill(10.f * 10000.f * 10000.f); Y2.fill(10.f * 10000.f * 10000.f);
for (size_t k = 0; k < 1000; ++k) { for (size_t k = 0; k < 1000; ++k) {
state.Update(converged_filter_frequency_response, impulse_response, true, state.Update(converged_filter_frequency_response, impulse_response, true,
*render_delay_buffer->GetRenderBuffer(), E2_main, Y2, x[0], s, *render_delay_buffer->GetRenderBuffer(), E2_main, Y2, s,
false); false);
} }
@ -132,7 +130,7 @@ TEST(AecState, NormalUsage) {
Y2.fill(10.f * E2_main[0]); Y2.fill(10.f * E2_main[0]);
for (size_t k = 0; k < 1000; ++k) { for (size_t k = 0; k < 1000; ++k) {
state.Update(converged_filter_frequency_response, impulse_response, true, state.Update(converged_filter_frequency_response, impulse_response, true,
*render_delay_buffer->GetRenderBuffer(), E2_main, Y2, x[0], s, *render_delay_buffer->GetRenderBuffer(), E2_main, Y2, s,
false); false);
} }
ASSERT_TRUE(state.UsableLinearEstimate()); ASSERT_TRUE(state.UsableLinearEstimate());
@ -153,7 +151,7 @@ TEST(AecState, NormalUsage) {
Y2.fill(5.f * E2_main[0]); Y2.fill(5.f * E2_main[0]);
for (size_t k = 0; k < 1000; ++k) { for (size_t k = 0; k < 1000; ++k) {
state.Update(converged_filter_frequency_response, impulse_response, true, state.Update(converged_filter_frequency_response, impulse_response, true,
*render_delay_buffer->GetRenderBuffer(), E2_main, Y2, x[0], s, *render_delay_buffer->GetRenderBuffer(), E2_main, Y2, s,
false); false);
} }
@ -203,9 +201,8 @@ TEST(AecState, ConvergedFilterDelay) {
frequency_response[k][0] = 0.f; frequency_response[k][0] = 0.f;
state.HandleEchoPathChange(echo_path_variability); state.HandleEchoPathChange(echo_path_variability);
state.Update(frequency_response, impulse_response, true, state.Update(frequency_response, impulse_response, true,
*render_delay_buffer->GetRenderBuffer(), E2_main, Y2, x, s, *render_delay_buffer->GetRenderBuffer(), E2_main, Y2, s,
false); false);
EXPECT_TRUE(k == (kFilterLength - 1) || state.FilterDelay());
if (k != (kFilterLength - 1)) { if (k != (kFilterLength - 1)) {
EXPECT_EQ(k, state.FilterDelay()); EXPECT_EQ(k, state.FilterDelay());
} }

View File

@ -178,7 +178,7 @@ void EchoRemoverImpl::ProcessCapture(
aec_state_.Update(subtractor_.FilterFrequencyResponse(), aec_state_.Update(subtractor_.FilterFrequencyResponse(),
subtractor_.FilterImpulseResponse(), subtractor_.FilterImpulseResponse(),
subtractor_.ConvergedFilter(), *render_buffer, E2_main, Y2, subtractor_.ConvergedFilter(), *render_buffer, E2_main, Y2,
x0, subtractor_output.s_main, echo_leakage_detected_); subtractor_output.s_main, echo_leakage_detected_);
// Choose the linear output. // Choose the linear output.
output_selector_.FormLinearOutput(!aec_state_.TransparentMode(), e_main, y0); output_selector_.FormLinearOutput(!aec_state_.TransparentMode(), e_main, y0);
@ -232,9 +232,7 @@ void EchoRemoverImpl::ProcessCapture(
data_dumper_->DumpRaw("aec3_erl", aec_state_.Erl()); data_dumper_->DumpRaw("aec3_erl", aec_state_.Erl());
data_dumper_->DumpRaw("aec3_usable_linear_estimate", data_dumper_->DumpRaw("aec3_usable_linear_estimate",
aec_state_.UsableLinearEstimate()); aec_state_.UsableLinearEstimate());
data_dumper_->DumpRaw( data_dumper_->DumpRaw("aec3_filter_delay", aec_state_.FilterDelay());
"aec3_filter_delay",
aec_state_.FilterDelay() ? *aec_state_.FilterDelay() : -1);
data_dumper_->DumpRaw("aec3_capture_saturation", data_dumper_->DumpRaw("aec3_capture_saturation",
aec_state_.SaturatedCapture() ? 1 : 0); aec_state_.SaturatedCapture() ? 1 : 0);
} }

View File

@ -236,10 +236,8 @@ void EchoRemoverMetrics::Update(
"WebRTC.Audio.EchoCanceller.ActiveRender", "WebRTC.Audio.EchoCanceller.ActiveRender",
static_cast<int>( static_cast<int>(
active_render_count_ > kMetricsCollectionBlocksBy2 ? 1 : 0)); active_render_count_ > kMetricsCollectionBlocksBy2 ? 1 : 0));
RTC_HISTOGRAM_COUNTS_LINEAR( RTC_HISTOGRAM_COUNTS_LINEAR("WebRTC.Audio.EchoCanceller.FilterDelay",
"WebRTC.Audio.EchoCanceller.FilterDelay", aec_state.FilterDelay(), 0, 30, 31);
aec_state.FilterDelay() ? *aec_state.FilterDelay() + 1 : 0, 0, 30,
31);
RTC_HISTOGRAM_BOOLEAN("WebRTC.Audio.EchoCanceller.CaptureSaturation", RTC_HISTOGRAM_BOOLEAN("WebRTC.Audio.EchoCanceller.CaptureSaturation",
static_cast<int>(saturated_capture_ ? 1 : 0)); static_cast<int>(saturated_capture_ ? 1 : 0));
break; break;

View File

@ -158,8 +158,8 @@ void RunFilterUpdateTest(int num_blocks_to_process,
false, EchoPathVariability::DelayAdjustment::kNone, false)); false, EchoPathVariability::DelayAdjustment::kNone, false));
aec_state.Update(main_filter.FilterFrequencyResponse(), aec_state.Update(main_filter.FilterFrequencyResponse(),
main_filter.FilterImpulseResponse(), true, main_filter.FilterImpulseResponse(), true,
*render_delay_buffer->GetRenderBuffer(), E2_main, Y2, x[0], *render_delay_buffer->GetRenderBuffer(), E2_main, Y2, s,
s, false); false);
} }
std::copy(e_main.begin(), e_main.end(), e_last_block->begin()); std::copy(e_main.begin(), e_main.end(), e_last_block->begin());

View File

@ -96,10 +96,8 @@ void ResidualEchoEstimator::Estimate(
// Estimate the residual echo power. // Estimate the residual echo power.
if (aec_state.UsableLinearEstimate()) { if (aec_state.UsableLinearEstimate()) {
RTC_DCHECK(aec_state.FilterDelay()); LinearEstimate(S2_linear, aec_state.Erle(), aec_state.FilterDelay(), R2);
const int filter_delay = *aec_state.FilterDelay(); AddEchoReverb(S2_linear, aec_state.SaturatedEcho(), aec_state.FilterDelay(),
LinearEstimate(S2_linear, aec_state.Erle(), filter_delay, R2);
AddEchoReverb(S2_linear, aec_state.SaturatedEcho(), filter_delay,
aec_state.ReverbDecay(), R2); aec_state.ReverbDecay(), R2);
// If the echo is saturated, estimate the echo power as the maximum echo // If the echo is saturated, estimate the echo power as the maximum echo
@ -110,24 +108,14 @@ void ResidualEchoEstimator::Estimate(
} else { } else {
// Estimate the echo generating signal power. // Estimate the echo generating signal power.
std::array<float, kFftLengthBy2Plus1> X2; std::array<float, kFftLengthBy2Plus1> X2;
if (aec_state.FilterDelay()) {
const int delay_use = static_cast<int>(*aec_state.FilterDelay());
// Computes the spectral power over the blocks surrounding the delay. // Computes the spectral power over the blocks surrounding the delay.
constexpr int kKnownDelayRenderWindowSize = 5; constexpr int kKnownDelayRenderWindowSize = 5;
// TODO(peah): Add lookahead since that was what was there initially. // TODO(peah): Add lookahead since that was what was there initially.
static_assert( EchoGeneratingPower(
kUnknownDelayRenderWindowSize >= kKnownDelayRenderWindowSize, render_buffer, std::max(0, aec_state.FilterDelay() - 1),
"Requirement to ensure that the render buffer is overrun"); std::min(kKnownDelayRenderWindowSize - 1, aec_state.FilterDelay() + 1),
EchoGeneratingPower( &X2);
render_buffer, std::max(0, delay_use - 1),
std::min(kKnownDelayRenderWindowSize - 1, delay_use + 1), &X2);
} else {
// Computes the spectral power over the latest blocks.
// TODO(peah): Add lookahead since that was what was there initially.
EchoGeneratingPower(render_buffer, 0, kUnknownDelayRenderWindowSize - 1,
&X2);
}
// Subtract the stationary noise power to avoid stationary noise causing // Subtract the stationary noise power to avoid stationary noise causing
// excessive echo suppression. // excessive echo suppression.
@ -140,7 +128,8 @@ void ResidualEchoEstimator::Estimate(
config_.ep_strength.bounded_erl, config_.ep_strength.bounded_erl,
aec_state.TransparentMode(), X2, Y2, R2); aec_state.TransparentMode(), X2, Y2, R2);
if (aec_state.FilterDelay() && aec_state.SaturatedEcho()) { if (aec_state.SaturatedEcho()) {
// TODO(peah): Modify to make sense theoretically.
AddEchoReverb(*R2, aec_state.SaturatedEcho(), AddEchoReverb(*R2, aec_state.SaturatedEcho(),
config_.filter.length_blocks, aec_state.ReverbDecay(), R2); config_.filter.length_blocks, aec_state.ReverbDecay(), R2);
} }

View File

@ -92,7 +92,7 @@ TEST(ResidualEchoEstimator, DISABLED_BasicTest) {
aec_state.HandleEchoPathChange(echo_path_variability); aec_state.HandleEchoPathChange(echo_path_variability);
aec_state.Update(H2, h, true, *render_delay_buffer->GetRenderBuffer(), aec_state.Update(H2, h, true, *render_delay_buffer->GetRenderBuffer(),
E2_main, Y2, x[0], s, false); E2_main, Y2, s, false);
estimator.Estimate(aec_state, *render_delay_buffer->GetRenderBuffer(), estimator.Estimate(aec_state, *render_delay_buffer->GetRenderBuffer(),
S2_linear, Y2, &R2); S2_linear, Y2, &R2);

View File

@ -84,7 +84,7 @@ float RunSubtractorTest(int num_blocks_to_process,
aec_state.Update(subtractor.FilterFrequencyResponse(), aec_state.Update(subtractor.FilterFrequencyResponse(),
subtractor.FilterImpulseResponse(), subtractor.FilterImpulseResponse(),
subtractor.ConvergedFilter(), subtractor.ConvergedFilter(),
*render_delay_buffer->GetRenderBuffer(), E2_main, Y2, x[0], *render_delay_buffer->GetRenderBuffer(), E2_main, Y2,
output.s_main, false); output.s_main, false);
} }

View File

@ -69,10 +69,10 @@ TEST(SuppressionGain, BasicGainComputation) {
R2.fill(10000000000000.f); R2.fill(10000000000000.f);
N2.fill(0.f); N2.fill(0.f);
s.fill(10.f); s.fill(10.f);
aec_state.Update( aec_state.Update(subtractor.FilterFrequencyResponse(),
subtractor.FilterFrequencyResponse(), subtractor.FilterImpulseResponse(), subtractor.FilterImpulseResponse(),
subtractor.ConvergedFilter(), *render_delay_buffer->GetRenderBuffer(), E2, subtractor.ConvergedFilter(),
Y2, x[0], s, false); *render_delay_buffer->GetRenderBuffer(), E2, Y2, s, false);
suppression_gain.GetGain(E2, R2, N2, analyzer, aec_state, x, &high_bands_gain, suppression_gain.GetGain(E2, R2, N2, analyzer, aec_state, x, &high_bands_gain,
&g); &g);
std::for_each(g.begin(), g.end(), [](float a) { EXPECT_FLOAT_EQ(0.f, a); }); std::for_each(g.begin(), g.end(), [](float a) { EXPECT_FLOAT_EQ(0.f, a); });
@ -85,17 +85,17 @@ TEST(SuppressionGain, BasicGainComputation) {
N2.fill(100.f); N2.fill(100.f);
// Ensure that the gain is no longer forced to zero. // Ensure that the gain is no longer forced to zero.
for (int k = 0; k <= kNumBlocksPerSecond / 5 + 1; ++k) { for (int k = 0; k <= kNumBlocksPerSecond / 5 + 1; ++k) {
aec_state.Update( aec_state.Update(subtractor.FilterFrequencyResponse(),
subtractor.FilterFrequencyResponse(), subtractor.FilterImpulseResponse(),
subtractor.FilterImpulseResponse(), subtractor.ConvergedFilter(), subtractor.ConvergedFilter(),
*render_delay_buffer->GetRenderBuffer(), E2, Y2, x[0], s, false); *render_delay_buffer->GetRenderBuffer(), E2, Y2, s, false);
} }
for (int k = 0; k < 100; ++k) { for (int k = 0; k < 100; ++k) {
aec_state.Update( aec_state.Update(subtractor.FilterFrequencyResponse(),
subtractor.FilterFrequencyResponse(), subtractor.FilterImpulseResponse(),
subtractor.FilterImpulseResponse(), subtractor.ConvergedFilter(), subtractor.ConvergedFilter(),
*render_delay_buffer->GetRenderBuffer(), E2, Y2, x[0], s, false); *render_delay_buffer->GetRenderBuffer(), E2, Y2, s, false);
suppression_gain.GetGain(E2, R2, N2, analyzer, aec_state, x, suppression_gain.GetGain(E2, R2, N2, analyzer, aec_state, x,
&high_bands_gain, &g); &high_bands_gain, &g);
} }
@ -108,10 +108,10 @@ TEST(SuppressionGain, BasicGainComputation) {
R2.fill(0.1f); R2.fill(0.1f);
N2.fill(0.f); N2.fill(0.f);
for (int k = 0; k < 100; ++k) { for (int k = 0; k < 100; ++k) {
aec_state.Update( aec_state.Update(subtractor.FilterFrequencyResponse(),
subtractor.FilterFrequencyResponse(), subtractor.FilterImpulseResponse(),
subtractor.FilterImpulseResponse(), subtractor.ConvergedFilter(), subtractor.ConvergedFilter(),
*render_delay_buffer->GetRenderBuffer(), E2, Y2, x[0], s, false); *render_delay_buffer->GetRenderBuffer(), E2, Y2, s, false);
suppression_gain.GetGain(E2, R2, N2, analyzer, aec_state, x, suppression_gain.GetGain(E2, R2, N2, analyzer, aec_state, x,
&high_bands_gain, &g); &high_bands_gain, &g);
} }