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:
@ -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
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -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());
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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());
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user