First step of adding multi-channel support to the echo subtractor
This CL contains the first step of adding multi-channel support to the
echo subtractor.
The CL is bitexact for the mono case.
Bug: webrtc:10913
Change-Id: I10647b45c692bc001407afc6ff00e26a3e2cffaa
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/154356
Reviewed-by: Gustaf Ullberg <gustaf@webrtc.org>
Commit-Queue: Per Åhgren <peah@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#29303}
diff --git a/modules/audio_processing/aec3/echo_remover.cc b/modules/audio_processing/aec3/echo_remover.cc
index 717e9b0..ebd7981 100644
--- a/modules/audio_processing/aec3/echo_remover.cc
+++ b/modules/audio_processing/aec3/echo_remover.cc
@@ -147,7 +147,7 @@
const size_t num_render_channels_;
const size_t num_capture_channels_;
const bool use_shadow_filter_output_;
- std::vector<std::unique_ptr<Subtractor>> subtractors_;
+ Subtractor subtractor_;
std::vector<std::unique_ptr<SuppressionGain>> suppression_gains_;
std::vector<std::unique_ptr<ComfortNoiseGenerator>> cngs_;
SuppressionFilter suppression_filter_;
@@ -190,7 +190,11 @@
num_capture_channels_(num_capture_channels),
use_shadow_filter_output_(
config_.filter.enable_shadow_filter_output_usage),
- subtractors_(num_capture_channels_),
+ subtractor_(config,
+ num_render_channels_,
+ num_capture_channels_,
+ data_dumper_.get(),
+ optimization_),
suppression_gains_(num_capture_channels_),
cngs_(num_capture_channels_),
suppression_filter_(optimization_,
@@ -219,9 +223,6 @@
for (size_t ch = 0; ch < num_capture_channels_; ++ch) {
residual_echo_estimators_[ch] =
std::make_unique<ResidualEchoEstimator>(config_);
- subtractors_[ch] = std::make_unique<Subtractor>(
- config, num_render_channels_, num_capture_channels_, data_dumper_.get(),
- optimization_);
suppression_gains_[ch] = std::make_unique<SuppressionGain>(
config_, optimization_, sample_rate_hz);
cngs_[ch] = std::make_unique<ComfortNoiseGenerator>(optimization_);
@@ -339,9 +340,7 @@
}
}
- for (size_t ch = 0; ch < num_capture_channels_; ++ch) {
- subtractors_[ch]->HandleEchoPathChange(echo_path_variability);
- }
+ subtractor_.HandleEchoPathChange(echo_path_variability);
aec_state_.HandleEchoPathChange(echo_path_variability);
if (echo_path_variability.delay_change !=
@@ -359,21 +358,21 @@
render_signal_analyzer_.Update(*render_buffer,
aec_state_.FilterDelayBlocks());
- // Perform linear echo cancellation.
+ // State transition.
if (aec_state_.TransitionTriggered()) {
+ subtractor_.ExitInitialState();
for (size_t ch = 0; ch < num_capture_channels_; ++ch) {
- subtractors_[ch]->ExitInitialState();
suppression_gains_[ch]->SetInitialState(false);
}
}
+ // Perform linear echo cancellation.
+ subtractor_.Process(*render_buffer, (*y)[0], render_signal_analyzer_,
+ aec_state_, subtractor_output);
+
for (size_t ch = 0; ch < num_capture_channels_; ++ch) {
auto& y_low = (*y)[0][ch];
- // If the delay is known, use the echo subtractor.
- subtractors_[ch]->Process(*render_buffer, y_low, render_signal_analyzer_,
- aec_state_, &subtractor_output[ch]);
-
// Compute spectra.
FormLinearFilterOutput(subtractor_output[ch], e[ch]);
WindowedPaddedFft(fft_, y_low, y_old_[ch], &Y[ch]);
@@ -385,9 +384,9 @@
// Update the AEC state information.
// TODO(bugs.webrtc.org/10913): Take all subtractors into account.
- aec_state_.Update(external_delay, subtractors_[0]->FilterFrequencyResponse(),
- subtractors_[0]->FilterImpulseResponse(), *render_buffer,
- E2[0], Y2[0], subtractor_output[0], y0);
+ aec_state_.Update(external_delay, subtractor_.FilterFrequencyResponse(),
+ subtractor_.FilterImpulseResponse(), *render_buffer, E2[0],
+ Y2[0], subtractor_output[0], y0);
// Choose the linear output.
const auto& Y_fft = aec_state_.UseLinearFilterOutput() ? E : Y;
diff --git a/modules/audio_processing/aec3/subtractor.cc b/modules/audio_processing/aec3/subtractor.cc
index 4d86358..0c52ed6 100644
--- a/modules/audio_processing/aec3/subtractor.cc
+++ b/modules/audio_processing/aec3/subtractor.cc
@@ -65,32 +65,50 @@
data_dumper_(data_dumper),
optimization_(optimization),
config_(config),
- main_filter_(config_.filter.main.length_blocks,
- config_.filter.main_initial.length_blocks,
- config.filter.config_change_duration_blocks,
- num_render_channels,
- num_capture_channels,
- optimization,
- data_dumper_),
- shadow_filter_(config_.filter.shadow.length_blocks,
- config_.filter.shadow_initial.length_blocks,
- config.filter.config_change_duration_blocks,
- num_render_channels,
- num_capture_channels,
- optimization,
- data_dumper_),
- G_main_(config_.filter.main_initial,
- config_.filter.config_change_duration_blocks),
- G_shadow_(config_.filter.shadow_initial,
- config.filter.config_change_duration_blocks),
- main_frequency_response_(main_filter_.max_filter_size_partitions(),
- std::array<float, kFftLengthBy2Plus1>()),
+ num_capture_channels_(num_capture_channels),
+ main_filter_(num_capture_channels_),
+ shadow_filter_(num_capture_channels_),
+ G_main_(num_capture_channels_),
+ G_shadow_(num_capture_channels_),
+ filter_misadjustment_estimator_(num_capture_channels_),
+ poor_shadow_filter_counter_(num_capture_channels_, 0),
+ main_frequency_response_(
+ num_capture_channels_,
+ std::vector<std::array<float, kFftLengthBy2Plus1>>(
+ std::max(config_.filter.main_initial.length_blocks,
+ config_.filter.main.length_blocks),
+ std::array<float, kFftLengthBy2Plus1>())),
main_impulse_response_(
- GetTimeDomainLength(main_filter_.max_filter_size_partitions()),
- 0.f) {
+ num_capture_channels_,
+ std::vector<float>(GetTimeDomainLength(std::max(
+ config_.filter.main_initial.length_blocks,
+ config_.filter.main.length_blocks)),
+ 0.f)) {
+ for (size_t ch = 0; ch < num_capture_channels_; ++ch) {
+ main_filter_[ch] = std::make_unique<AdaptiveFirFilter>(
+ config_.filter.main.length_blocks,
+ config_.filter.main_initial.length_blocks,
+ config.filter.config_change_duration_blocks, num_render_channels,
+ num_capture_channels, optimization, data_dumper_);
+
+ shadow_filter_[ch] = std::make_unique<AdaptiveFirFilter>(
+ config_.filter.shadow.length_blocks,
+ config_.filter.shadow_initial.length_blocks,
+ config.filter.config_change_duration_blocks, num_render_channels,
+ num_capture_channels, optimization, data_dumper_);
+ G_main_[ch] = std::make_unique<MainFilterUpdateGain>(
+ config_.filter.main_initial,
+ config_.filter.config_change_duration_blocks);
+ G_shadow_[ch] = std::make_unique<ShadowFilterUpdateGain>(
+ config_.filter.shadow_initial,
+ config.filter.config_change_duration_blocks);
+ }
+
RTC_DCHECK(data_dumper_);
- for (auto& H2_k : main_frequency_response_) {
- H2_k.fill(0.f);
+ for (size_t ch = 0; ch < num_capture_channels_; ++ch) {
+ for (auto& H2_k : main_frequency_response_[ch]) {
+ H2_k.fill(0.f);
+ }
}
}
@@ -99,16 +117,18 @@
void Subtractor::HandleEchoPathChange(
const EchoPathVariability& echo_path_variability) {
const auto full_reset = [&]() {
- main_filter_.HandleEchoPathChange();
- shadow_filter_.HandleEchoPathChange();
- G_main_.HandleEchoPathChange(echo_path_variability);
- G_shadow_.HandleEchoPathChange();
- G_main_.SetConfig(config_.filter.main_initial, true);
- G_shadow_.SetConfig(config_.filter.shadow_initial, true);
- main_filter_.SetSizePartitions(config_.filter.main_initial.length_blocks,
- true);
- shadow_filter_.SetSizePartitions(
- config_.filter.shadow_initial.length_blocks, true);
+ for (size_t ch = 0; ch < num_capture_channels_; ++ch) {
+ main_filter_[ch]->HandleEchoPathChange();
+ shadow_filter_[ch]->HandleEchoPathChange();
+ G_main_[ch]->HandleEchoPathChange(echo_path_variability);
+ G_shadow_[ch]->HandleEchoPathChange();
+ G_main_[ch]->SetConfig(config_.filter.main_initial, true);
+ G_shadow_[ch]->SetConfig(config_.filter.shadow_initial, true);
+ main_filter_[ch]->SetSizePartitions(
+ config_.filter.main_initial.length_blocks, true);
+ shadow_filter_[ch]->SetSizePartitions(
+ config_.filter.shadow_initial.length_blocks, true);
+ }
};
if (echo_path_variability.delay_change !=
@@ -117,128 +137,149 @@
}
if (echo_path_variability.gain_change) {
- G_main_.HandleEchoPathChange(echo_path_variability);
+ for (size_t ch = 0; ch < num_capture_channels_; ++ch) {
+ G_main_[ch]->HandleEchoPathChange(echo_path_variability);
+ }
}
}
void Subtractor::ExitInitialState() {
- G_main_.SetConfig(config_.filter.main, false);
- G_shadow_.SetConfig(config_.filter.shadow, false);
- main_filter_.SetSizePartitions(config_.filter.main.length_blocks, false);
- shadow_filter_.SetSizePartitions(config_.filter.shadow.length_blocks, false);
+ for (size_t ch = 0; ch < num_capture_channels_; ++ch) {
+ G_main_[ch]->SetConfig(config_.filter.main, false);
+ G_shadow_[ch]->SetConfig(config_.filter.shadow, false);
+ main_filter_[ch]->SetSizePartitions(config_.filter.main.length_blocks,
+ false);
+ shadow_filter_[ch]->SetSizePartitions(config_.filter.shadow.length_blocks,
+ false);
+ }
}
void Subtractor::Process(const RenderBuffer& render_buffer,
- const rtc::ArrayView<const float> capture,
+ const std::vector<std::vector<float>>& capture,
const RenderSignalAnalyzer& render_signal_analyzer,
const AecState& aec_state,
- SubtractorOutput* output) {
- RTC_DCHECK_EQ(kBlockSize, capture.size());
- rtc::ArrayView<const float> y = capture;
- FftData& E_main = output->E_main;
- FftData E_shadow;
- std::array<float, kBlockSize>& e_main = output->e_main;
- std::array<float, kBlockSize>& e_shadow = output->e_shadow;
-
- FftData S;
- FftData& G = S;
-
- // Form the outputs of the main and shadow filters.
- main_filter_.Filter(render_buffer, &S);
- PredictionError(fft_, S, y, &e_main, &output->s_main);
-
- shadow_filter_.Filter(render_buffer, &S);
- PredictionError(fft_, S, y, &e_shadow, &output->s_shadow);
-
- // Compute the signal powers in the subtractor output.
- output->ComputeMetrics(y);
-
- // Adjust the filter if needed.
- bool main_filter_adjusted = false;
- filter_misadjustment_estimator_.Update(*output);
- if (filter_misadjustment_estimator_.IsAdjustmentNeeded()) {
- float scale = filter_misadjustment_estimator_.GetMisadjustment();
- main_filter_.ScaleFilter(scale);
- for (auto& h_k : main_impulse_response_) {
- h_k *= scale;
- }
- ScaleFilterOutput(y, scale, e_main, output->s_main);
- filter_misadjustment_estimator_.Reset();
- main_filter_adjusted = true;
- }
-
- // Compute the FFts of the main and shadow filter outputs.
- fft_.ZeroPaddedFft(e_main, Aec3Fft::Window::kHanning, &E_main);
- fft_.ZeroPaddedFft(e_shadow, Aec3Fft::Window::kHanning, &E_shadow);
-
- // Compute spectra for future use.
- E_shadow.Spectrum(optimization_, output->E2_shadow);
- E_main.Spectrum(optimization_, output->E2_main);
+ rtc::ArrayView<SubtractorOutput> outputs) {
+ RTC_DCHECK_EQ(num_capture_channels_, capture.size());
// Compute the render powers.
std::array<float, kFftLengthBy2Plus1> X2_main;
std::array<float, kFftLengthBy2Plus1> X2_shadow_data;
std::array<float, kFftLengthBy2Plus1>& X2_shadow =
- main_filter_.SizePartitions() == shadow_filter_.SizePartitions()
+ main_filter_[0]->SizePartitions() == shadow_filter_[0]->SizePartitions()
? X2_main
: X2_shadow_data;
- if (main_filter_.SizePartitions() == shadow_filter_.SizePartitions()) {
- render_buffer.SpectralSum(main_filter_.SizePartitions(), &X2_main);
- } else if (main_filter_.SizePartitions() > shadow_filter_.SizePartitions()) {
- render_buffer.SpectralSums(shadow_filter_.SizePartitions(),
- main_filter_.SizePartitions(), &X2_shadow,
+ if (main_filter_[0]->SizePartitions() ==
+ shadow_filter_[0]->SizePartitions()) {
+ render_buffer.SpectralSum(main_filter_[0]->SizePartitions(), &X2_main);
+ } else if (main_filter_[0]->SizePartitions() >
+ shadow_filter_[0]->SizePartitions()) {
+ render_buffer.SpectralSums(shadow_filter_[0]->SizePartitions(),
+ main_filter_[0]->SizePartitions(), &X2_shadow,
&X2_main);
} else {
- render_buffer.SpectralSums(main_filter_.SizePartitions(),
- shadow_filter_.SizePartitions(), &X2_main,
+ render_buffer.SpectralSums(main_filter_[0]->SizePartitions(),
+ shadow_filter_[0]->SizePartitions(), &X2_main,
&X2_shadow);
}
- // Update the main filter.
- if (!main_filter_adjusted) {
- std::array<float, kFftLengthBy2Plus1> erl;
- ComputeErl(optimization_, main_frequency_response_, erl);
- G_main_.Compute(X2_main, render_signal_analyzer, *output, erl,
- main_filter_.SizePartitions(), aec_state.SaturatedCapture(),
- &G);
- } else {
- G.re.fill(0.f);
- G.im.fill(0.f);
+ // Process all capture channels
+ for (size_t ch = 0; ch < num_capture_channels_; ++ch) {
+ RTC_DCHECK_EQ(kBlockSize, capture[ch].size());
+ SubtractorOutput& output = outputs[ch];
+ rtc::ArrayView<const float> y = capture[ch];
+ FftData& E_main = output.E_main;
+ FftData E_shadow;
+ std::array<float, kBlockSize>& e_main = output.e_main;
+ std::array<float, kBlockSize>& e_shadow = output.e_shadow;
+
+ FftData S;
+ FftData& G = S;
+
+ // Form the outputs of the main and shadow filters.
+ main_filter_[ch]->Filter(render_buffer, &S);
+ PredictionError(fft_, S, y, &e_main, &output.s_main);
+
+ shadow_filter_[ch]->Filter(render_buffer, &S);
+ PredictionError(fft_, S, y, &e_shadow, &output.s_shadow);
+
+ // Compute the signal powers in the subtractor output.
+ output.ComputeMetrics(y);
+
+ // Adjust the filter if needed.
+ bool main_filter_adjusted = false;
+ filter_misadjustment_estimator_[ch].Update(output);
+ if (filter_misadjustment_estimator_[ch].IsAdjustmentNeeded()) {
+ float scale = filter_misadjustment_estimator_[ch].GetMisadjustment();
+ main_filter_[ch]->ScaleFilter(scale);
+ for (auto& h_k : main_impulse_response_[ch]) {
+ h_k *= scale;
+ }
+ ScaleFilterOutput(y, scale, e_main, output.s_main);
+ filter_misadjustment_estimator_[ch].Reset();
+ main_filter_adjusted = true;
+ }
+
+ // Compute the FFts of the main and shadow filter outputs.
+ fft_.ZeroPaddedFft(e_main, Aec3Fft::Window::kHanning, &E_main);
+ fft_.ZeroPaddedFft(e_shadow, Aec3Fft::Window::kHanning, &E_shadow);
+
+ // Compute spectra for future use.
+ E_shadow.Spectrum(optimization_, output.E2_shadow);
+ E_main.Spectrum(optimization_, output.E2_main);
+
+ // Update the main filter.
+ if (!main_filter_adjusted) {
+ std::array<float, kFftLengthBy2Plus1> erl;
+ ComputeErl(optimization_, main_frequency_response_[ch], erl);
+ G_main_[ch]->Compute(X2_main, render_signal_analyzer, output, erl,
+ main_filter_[ch]->SizePartitions(),
+ aec_state.SaturatedCapture(), &G);
+ } else {
+ G.re.fill(0.f);
+ G.im.fill(0.f);
+ }
+ main_filter_[ch]->Adapt(render_buffer, G, &main_impulse_response_[ch]);
+ main_filter_[ch]->ComputeFrequencyResponse(&main_frequency_response_[ch]);
+
+ if (ch == 0) {
+ data_dumper_->DumpRaw("aec3_subtractor_G_main", G.re);
+ data_dumper_->DumpRaw("aec3_subtractor_G_main", G.im);
+ }
+
+ // Update the shadow filter.
+ poor_shadow_filter_counter_[ch] = output.e2_main < output.e2_shadow
+ ? poor_shadow_filter_counter_[ch] + 1
+ : 0;
+ if (poor_shadow_filter_counter_[ch] < 5) {
+ G_shadow_[ch]->Compute(X2_shadow, render_signal_analyzer, E_shadow,
+ shadow_filter_[ch]->SizePartitions(),
+ aec_state.SaturatedCapture(), &G);
+ } else {
+ poor_shadow_filter_counter_[ch] = 0;
+ shadow_filter_[ch]->SetFilter(main_filter_[ch]->GetFilter());
+ G_shadow_[ch]->Compute(X2_shadow, render_signal_analyzer, E_main,
+ shadow_filter_[ch]->SizePartitions(),
+ aec_state.SaturatedCapture(), &G);
+ }
+
+ shadow_filter_[ch]->Adapt(render_buffer, G);
+ if (ch == 0) {
+ data_dumper_->DumpRaw("aec3_subtractor_G_shadow", G.re);
+ data_dumper_->DumpRaw("aec3_subtractor_G_shadow", G.im);
+ filter_misadjustment_estimator_[ch].Dump(data_dumper_);
+ DumpFilters();
+ }
+
+ std::for_each(e_main.begin(), e_main.end(),
+ [](float& a) { a = rtc::SafeClamp(a, -32768.f, 32767.f); });
+
+ if (ch == 0) {
+ data_dumper_->DumpWav("aec3_main_filter_output", kBlockSize, &e_main[0],
+ 16000, 1);
+ data_dumper_->DumpWav("aec3_shadow_filter_output", kBlockSize,
+ &e_shadow[0], 16000, 1);
+ }
}
- main_filter_.Adapt(render_buffer, G, &main_impulse_response_);
- main_filter_.ComputeFrequencyResponse(&main_frequency_response_);
-
- data_dumper_->DumpRaw("aec3_subtractor_G_main", G.re);
- data_dumper_->DumpRaw("aec3_subtractor_G_main", G.im);
-
- // Update the shadow filter.
- poor_shadow_filter_counter_ =
- output->e2_main < output->e2_shadow ? poor_shadow_filter_counter_ + 1 : 0;
- if (poor_shadow_filter_counter_ < 5) {
- G_shadow_.Compute(X2_shadow, render_signal_analyzer, E_shadow,
- shadow_filter_.SizePartitions(),
- aec_state.SaturatedCapture(), &G);
- } else {
- poor_shadow_filter_counter_ = 0;
- shadow_filter_.SetFilter(main_filter_.GetFilter());
- G_shadow_.Compute(X2_shadow, render_signal_analyzer, E_main,
- shadow_filter_.SizePartitions(),
- aec_state.SaturatedCapture(), &G);
- }
-
- shadow_filter_.Adapt(render_buffer, G);
- data_dumper_->DumpRaw("aec3_subtractor_G_shadow", G.re);
- data_dumper_->DumpRaw("aec3_subtractor_G_shadow", G.im);
- filter_misadjustment_estimator_.Dump(data_dumper_);
- DumpFilters();
-
- std::for_each(e_main.begin(), e_main.end(),
- [](float& a) { a = rtc::SafeClamp(a, -32768.f, 32767.f); });
-
- data_dumper_->DumpWav("aec3_main_filter_output", kBlockSize, &e_main[0],
- 16000, 1);
- data_dumper_->DumpWav("aec3_shadow_filter_output", kBlockSize, &e_shadow[0],
- 16000, 1);
}
void Subtractor::FilterMisadjustmentEstimator::Update(
diff --git a/modules/audio_processing/aec3/subtractor.h b/modules/audio_processing/aec3/subtractor.h
index 7c3c5e0..c5fb765 100644
--- a/modules/audio_processing/aec3/subtractor.h
+++ b/modules/audio_processing/aec3/subtractor.h
@@ -48,35 +48,40 @@
// Performs the echo subtraction.
void Process(const RenderBuffer& render_buffer,
- const rtc::ArrayView<const float> capture,
+ const std::vector<std::vector<float>>& capture,
const RenderSignalAnalyzer& render_signal_analyzer,
const AecState& aec_state,
- SubtractorOutput* output);
+ rtc::ArrayView<SubtractorOutput> outputs);
void HandleEchoPathChange(const EchoPathVariability& echo_path_variability);
// Exits the initial state.
void ExitInitialState();
- // Returns the block-wise frequency response for the main adaptive filter.
+ // Returns the block-wise frequency responses for the main adaptive filters.
+ // TODO(bugs.webrtc.org/10913): Return the frequency responses for all capture
+ // channels.
const std::vector<std::array<float, kFftLengthBy2Plus1>>&
FilterFrequencyResponse() const {
- return main_frequency_response_;
+ return main_frequency_response_[0];
}
- // Returns the estimate of the impulse response for the main adaptive filter.
+ // Returns the estimates of the impulse responses for the main adaptive
+ // filters.
+ // TODO(bugs.webrtc.org/10913): Return the impulse responses for all capture
+ // channels.
const std::vector<float>& FilterImpulseResponse() const {
- return main_impulse_response_;
+ return main_impulse_response_[0];
}
void DumpFilters() {
- size_t current_size = main_impulse_response_.size();
- main_impulse_response_.resize(main_impulse_response_.capacity());
- data_dumper_->DumpRaw("aec3_subtractor_h_main", main_impulse_response_);
- main_impulse_response_.resize(current_size);
+ size_t current_size = main_impulse_response_[0].size();
+ main_impulse_response_[0].resize(main_impulse_response_[0].capacity());
+ data_dumper_->DumpRaw("aec3_subtractor_h_main", main_impulse_response_[0]);
+ main_impulse_response_[0].resize(current_size);
- main_filter_.DumpFilter("aec3_subtractor_H_main");
- shadow_filter_.DumpFilter("aec3_subtractor_H_shadow");
+ main_filter_[0]->DumpFilter("aec3_subtractor_H_main");
+ shadow_filter_[0]->DumpFilter("aec3_subtractor_H_shadow");
}
private:
@@ -115,15 +120,17 @@
ApmDataDumper* data_dumper_;
const Aec3Optimization optimization_;
const EchoCanceller3Config config_;
+ const size_t num_capture_channels_;
- AdaptiveFirFilter main_filter_;
- AdaptiveFirFilter shadow_filter_;
- MainFilterUpdateGain G_main_;
- ShadowFilterUpdateGain G_shadow_;
- FilterMisadjustmentEstimator filter_misadjustment_estimator_;
- size_t poor_shadow_filter_counter_ = 0;
- std::vector<std::array<float, kFftLengthBy2Plus1>> main_frequency_response_;
- std::vector<float> main_impulse_response_;
+ std::vector<std::unique_ptr<AdaptiveFirFilter>> main_filter_;
+ std::vector<std::unique_ptr<AdaptiveFirFilter>> shadow_filter_;
+ std::vector<std::unique_ptr<MainFilterUpdateGain>> G_main_;
+ std::vector<std::unique_ptr<ShadowFilterUpdateGain>> G_shadow_;
+ std::vector<FilterMisadjustmentEstimator> filter_misadjustment_estimator_;
+ std::vector<size_t> poor_shadow_filter_counter_;
+ std::vector<std::vector<std::array<float, kFftLengthBy2Plus1>>>
+ main_frequency_response_;
+ std::vector<std::vector<float>> main_impulse_response_;
};
} // namespace webrtc
diff --git a/modules/audio_processing/aec3/subtractor_unittest.cc b/modules/audio_processing/aec3/subtractor_unittest.cc
index 40d8569..daacbd3 100644
--- a/modules/audio_processing/aec3/subtractor_unittest.cc
+++ b/modules/audio_processing/aec3/subtractor_unittest.cc
@@ -43,9 +43,9 @@
std::vector<std::vector<std::vector<float>>> x(
kNumBands, std::vector<std::vector<float>>(
kNumChannels, std::vector<float>(kBlockSize, 0.f)));
- std::vector<float> y(kBlockSize, 0.f);
+ std::vector<std::vector<float>> y(1, std::vector<float>(kBlockSize, 0.f));
std::array<float, kBlockSize> x_old;
- SubtractorOutput output;
+ std::array<SubtractorOutput, 1> output;
config.delay.default_delay = 1;
std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
RenderDelayBuffer::Create(config, kSampleRateHz, kNumChannels));
@@ -65,9 +65,9 @@
for (int k = 0; k < num_blocks_to_process; ++k) {
RandomizeSampleVector(&random_generator, x[0][0]);
if (uncorrelated_inputs) {
- RandomizeSampleVector(&random_generator, y);
+ RandomizeSampleVector(&random_generator, y[0]);
} else {
- delay_buffer.Delay(x[0][0], y);
+ delay_buffer.Delay(x[0][0], y[0]);
}
render_delay_buffer->Insert(x);
if (k == 0) {
@@ -86,19 +86,21 @@
false));
}
subtractor.Process(*render_delay_buffer->GetRenderBuffer(), y,
- render_signal_analyzer, aec_state, &output);
+ render_signal_analyzer, aec_state, output);
aec_state.HandleEchoPathChange(EchoPathVariability(
false, EchoPathVariability::DelayAdjustment::kNone, false));
aec_state.Update(delay_estimate, subtractor.FilterFrequencyResponse(),
subtractor.FilterImpulseResponse(),
*render_delay_buffer->GetRenderBuffer(), E2_main, Y2,
- output, y);
+ output[0], y[0]);
}
- const float output_power = std::inner_product(
- output.e_main.begin(), output.e_main.end(), output.e_main.begin(), 0.f);
- const float y_power = std::inner_product(y.begin(), y.end(), y.begin(), 0.f);
+ const float output_power =
+ std::inner_product(output[0].e_main.begin(), output[0].e_main.end(),
+ output[0].e_main.begin(), 0.f);
+ const float y_power =
+ std::inner_product(y[0].begin(), y[0].end(), y[0].begin(), 0.f);
if (y_power == 0.f) {
ADD_FAILURE();
return -1.0;
@@ -124,24 +126,6 @@
"");
}
-// Verifies the check for null subtractor output.
-// TODO(peah): Re-enable the test once the issue with memory leaks during DEATH
-// tests on test bots has been fixed.
-TEST(Subtractor, DISABLED_NullOutput) {
- ApmDataDumper data_dumper(42);
- EchoCanceller3Config config;
- Subtractor subtractor(config, 1, 1, &data_dumper, DetectOptimization());
- std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
- RenderDelayBuffer::Create(config, 48000, 1));
- RenderSignalAnalyzer render_signal_analyzer(config);
- std::vector<float> y(kBlockSize, 0.f);
-
- EXPECT_DEATH(
- subtractor.Process(*render_delay_buffer->GetRenderBuffer(), y,
- render_signal_analyzer, AecState(config), nullptr),
- "");
-}
-
// Verifies the check for the capture signal size.
TEST(Subtractor, WrongCaptureSize) {
ApmDataDumper data_dumper(42);
@@ -150,12 +134,12 @@
std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
RenderDelayBuffer::Create(config, 48000, 1));
RenderSignalAnalyzer render_signal_analyzer(config);
- std::vector<float> y(kBlockSize - 1, 0.f);
- SubtractorOutput output;
+ std::vector<std::vector<float>> y(1, std::vector<float>(kBlockSize - 1, 0.f));
+ std::array<SubtractorOutput, 1> output;
EXPECT_DEATH(
subtractor.Process(*render_delay_buffer->GetRenderBuffer(), y,
- render_signal_analyzer, AecState(config), &output),
+ render_signal_analyzer, AecState(config), output),
"");
}