diff --git a/modules/audio_processing/aec3/adaptive_fir_filter_unittest.cc b/modules/audio_processing/aec3/adaptive_fir_filter_unittest.cc index 6f1635fa60..69673c014c 100644 --- a/modules/audio_processing/aec3/adaptive_fir_filter_unittest.cc +++ b/modules/audio_processing/aec3/adaptive_fir_filter_unittest.cc @@ -346,11 +346,14 @@ TEST(AdaptiveFirFilter, FilterAndAdapt) { config.filter.main.length_blocks, config.filter.main.length_blocks, config.filter.config_change_duration_blocks, num_render_channels, DetectOptimization(), &data_dumper); - std::vector> H2( - filter.max_filter_size_partitions(), - std::array()); - std::vector h( - GetTimeDomainLength(filter.max_filter_size_partitions()), 0.f); + std::vector>> H2( + kNumCaptureChannels, std::vector>( + filter.max_filter_size_partitions(), + std::array())); + std::vector> h( + kNumCaptureChannels, + std::vector( + GetTimeDomainLength(filter.max_filter_size_partitions()), 0.f)); Aec3Fft fft; config.delay.default_delay = 1; std::unique_ptr render_delay_buffer( @@ -454,11 +457,11 @@ TEST(AdaptiveFirFilter, FilterAndAdapt) { render_buffer->SpectralSum(filter.SizePartitions(), &render_power); gain.Compute(render_power, render_signal_analyzer, E, filter.SizePartitions(), false, &G); - filter.Adapt(*render_buffer, G, &h); + filter.Adapt(*render_buffer, G, &h[0]); aec_state.HandleEchoPathChange(EchoPathVariability( false, EchoPathVariability::DelayAdjustment::kNone, false)); - filter.ComputeFrequencyResponse(&H2); + filter.ComputeFrequencyResponse(&H2[0]); aec_state.Update(delay_estimate, H2, h, *render_buffer, E2_main, Y2, output); } diff --git a/modules/audio_processing/aec3/aec_state.cc b/modules/audio_processing/aec3/aec_state.cc index 4b30d3017f..803a598e95 100644 --- a/modules/audio_processing/aec3/aec_state.cc +++ b/modules/audio_processing/aec3/aec_state.cc @@ -66,18 +66,26 @@ AecState::AecState(const EchoCanceller3Config& config, filter_quality_state_(config_), erl_estimator_(2 * kNumBlocksPerSecond), erle_estimator_(2 * kNumBlocksPerSecond, config_, num_capture_channels), - filter_analyzer_(config_), + max_echo_path_gain_(config_.ep_strength.default_gain), + filter_analyzers_(num_capture_channels), echo_audibility_( config_.echo_audibility.use_stationarity_properties_at_init), reverb_model_estimator_(config_), - subtractor_output_analyzers_(num_capture_channels) {} + subtractor_output_analyzers_(num_capture_channels) { + for (size_t ch = 0; ch < num_capture_channels; ++ch) { + filter_analyzers_[ch] = std::make_unique(config_); + } +} AecState::~AecState() = default; void AecState::HandleEchoPathChange( const EchoPathVariability& echo_path_variability) { const auto full_reset = [&]() { - filter_analyzer_.Reset(); + for (auto& filter_analyzer : filter_analyzers_) { + filter_analyzer->Reset(); + } + max_echo_path_gain_ = config_.ep_strength.default_gain; capture_signal_saturation_ = false; strong_not_saturated_render_blocks_ = 0; blocks_with_active_render_ = 0; @@ -104,26 +112,43 @@ void AecState::HandleEchoPathChange( void AecState::Update( const absl::optional& external_delay, - const std::vector>& + rtc::ArrayView>> adaptive_filter_frequency_response, - const std::vector& adaptive_filter_impulse_response, + rtc::ArrayView> adaptive_filter_impulse_response, const RenderBuffer& render_buffer, const std::array& E2_main, const std::array& Y2, rtc::ArrayView subtractor_output) { - RTC_DCHECK_EQ(subtractor_output.size(), subtractor_output_analyzers_.size()); + const size_t num_capture_channels = filter_analyzers_.size(); + RTC_DCHECK_EQ(num_capture_channels, subtractor_output.size()); + RTC_DCHECK_EQ(num_capture_channels, subtractor_output_analyzers_.size()); + RTC_DCHECK_EQ(num_capture_channels, + adaptive_filter_frequency_response.size()); + RTC_DCHECK_EQ(num_capture_channels, adaptive_filter_impulse_response.size()); - // Analyze the filter output. + // Analyze the filter outputs and filters. + bool any_filter_converged = false; + bool all_filters_diverged = true; + bool any_filter_consistent = false; + max_echo_path_gain_ = 0.f; for (size_t ch = 0; ch < subtractor_output.size(); ++ch) { subtractor_output_analyzers_[ch].Update(subtractor_output[ch]); - } + any_filter_converged = any_filter_converged || + subtractor_output_analyzers_[ch].ConvergedFilter(); + all_filters_diverged = all_filters_diverged && + subtractor_output_analyzers_[ch].DivergedFilter(); - // Analyze the properties of the filter. - filter_analyzer_.Update(adaptive_filter_impulse_response, render_buffer); + filter_analyzers_[ch]->Update(adaptive_filter_impulse_response[ch], + render_buffer); + any_filter_consistent = + any_filter_consistent || filter_analyzers_[ch]->Consistent(); + max_echo_path_gain_ = + std::max(max_echo_path_gain_, filter_analyzers_[ch]->Gain()); + } // Estimate the direct path delay of the filter. if (config_.filter.use_linear_filter) { - delay_state_.Update(filter_analyzer_, external_delay, + delay_state_.Update(filter_analyzers_, external_delay, strong_not_saturated_render_blocks_); } @@ -170,7 +195,7 @@ void AecState::Update( /*channel=*/0); const auto& X2_input_erle = X2_reverb; - erle_estimator_.Update(render_buffer, adaptive_filter_frequency_response, + erle_estimator_.Update(render_buffer, adaptive_filter_frequency_response[0], X2_input_erle, Y2, E2_main, subtractor_output_analyzers_[0].ConvergedFilter(), config_.erle.onset_detection); @@ -188,24 +213,22 @@ void AecState::Update( // Detect whether the transparent mode should be activated. transparent_state_.Update(delay_state_.DirectPathFilterDelay(), - filter_analyzer_.Consistent(), - subtractor_output_analyzers_[0].ConvergedFilter(), - subtractor_output_analyzers_[0].DivergedFilter(), - active_render, SaturatedCapture()); + any_filter_consistent, any_filter_converged, + all_filters_diverged, active_render, + SaturatedCapture()); // Analyze the quality of the filter. - filter_quality_state_.Update( - active_render, TransparentMode(), SaturatedCapture(), - filter_analyzer_.Consistent(), external_delay, - subtractor_output_analyzers_[0].ConvergedFilter()); + filter_quality_state_.Update(active_render, TransparentMode(), + SaturatedCapture(), external_delay, + any_filter_converged); // Update the reverb estimate. const bool stationary_block = config_.echo_audibility.use_stationarity_properties && echo_audibility_.IsBlockStationary(); - reverb_model_estimator_.Update(filter_analyzer_.GetAdjustedFilter(), - adaptive_filter_frequency_response, + reverb_model_estimator_.Update(filter_analyzers_[0]->GetAdjustedFilter(), + adaptive_filter_frequency_response[0], erle_estimator_.GetInstLinearQualityEstimate(), delay_state_.DirectPathFilterDelay(), UsableLinearEstimate(), stationary_block); @@ -217,18 +240,16 @@ void AecState::Update( data_dumper_->DumpRaw("aec3_erle", Erle()[0]); data_dumper_->DumpRaw("aec3_usable_linear_estimate", UsableLinearEstimate()); data_dumper_->DumpRaw("aec3_transparent_mode", TransparentMode()); - data_dumper_->DumpRaw("aec3_filter_delay", filter_analyzer_.DelayBlocks()); + data_dumper_->DumpRaw("aec3_filter_delay", + filter_analyzers_[0]->DelayBlocks()); - data_dumper_->DumpRaw("aec3_consistent_filter", - filter_analyzer_.Consistent()); + data_dumper_->DumpRaw("aec3_any_filter_consistent", any_filter_consistent); data_dumper_->DumpRaw("aec3_initial_state", initial_state_.InitialStateActive()); data_dumper_->DumpRaw("aec3_capture_saturation", SaturatedCapture()); data_dumper_->DumpRaw("aec3_echo_saturation", SaturatedEcho()); - data_dumper_->DumpRaw("aec3_converged_filter", - subtractor_output_analyzers_[0].ConvergedFilter()); - data_dumper_->DumpRaw("aec3_diverged_filter", - subtractor_output_analyzers_[0].DivergedFilter()); + data_dumper_->DumpRaw("aec3_any_filter_converged", any_filter_converged); + data_dumper_->DumpRaw("aec3_all_filters_diverged", all_filters_diverged); data_dumper_->DumpRaw("aec3_external_delay_avaliable", external_delay ? 1 : 0); @@ -268,7 +289,7 @@ AecState::FilterDelay::FilterDelay(const EchoCanceller3Config& config) : delay_headroom_samples_(config.delay.delay_headroom_samples) {} void AecState::FilterDelay::Update( - const FilterAnalyzer& filter_analyzer, + const std::vector>& filter_analyzers, const absl::optional& external_delay, size_t blocks_with_proper_filter_adaptation) { // Update the delay based on the external delay. @@ -285,7 +306,12 @@ void AecState::FilterDelay::Update( if (delay_estimator_may_not_have_converged && external_delay_) { filter_delay_blocks_ = delay_headroom_samples_ / kBlockSize; } else { - filter_delay_blocks_ = filter_analyzer.DelayBlocks(); + // Conservatively use the min delay among the filters. + filter_delay_blocks_ = filter_analyzers[0]->DelayBlocks(); + for (size_t ch = 1; ch < filter_analyzers.size(); ++ch) { + filter_delay_blocks_ = + std::min(filter_delay_blocks_, filter_analyzers[ch]->DelayBlocks()); + } } } @@ -306,16 +332,16 @@ void AecState::TransparentMode::Reset() { } void AecState::TransparentMode::Update(int filter_delay_blocks, - bool consistent_filter, - bool converged_filter, - bool diverged_filter, + bool any_filter_consistent, + bool any_filter_converged, + bool all_filters_diverged, bool active_render, bool saturated_capture) { ++capture_block_counter_; strong_not_saturated_render_blocks_ += active_render && !saturated_capture ? 1 : 0; - if (consistent_filter && filter_delay_blocks < 5) { + if (any_filter_consistent && filter_delay_blocks < 5) { sane_filter_observed_ = true; active_blocks_since_sane_filter_ = 0; } else if (active_render) { @@ -331,7 +357,7 @@ void AecState::TransparentMode::Update(int filter_delay_blocks, active_blocks_since_sane_filter_ <= 30 * kNumBlocksPerSecond; } - if (converged_filter) { + if (any_filter_converged) { recent_convergence_during_activity_ = true; active_non_converged_sequence_size_ = 0; non_converged_sequence_size_ = 0; @@ -347,7 +373,7 @@ void AecState::TransparentMode::Update(int filter_delay_blocks, } } - if (!diverged_filter) { + if (!all_filters_diverged) { diverged_sequence_size_ = 0; } else if (++diverged_sequence_size_ >= 60) { // TODO(peah): Change these lines to ensure proper triggering of usable @@ -387,16 +413,15 @@ void AecState::FilteringQualityAnalyzer::Update( bool active_render, bool transparent_mode, bool saturated_capture, - bool consistent_estimate_, const absl::optional& external_delay, - bool converged_filter) { + bool any_filter_converged) { // Update blocks counter. const bool filter_update = active_render && !saturated_capture; filter_update_blocks_since_reset_ += filter_update ? 1 : 0; filter_update_blocks_since_start_ += filter_update ? 1 : 0; // Store convergence flag when observed. - convergence_seen_ = convergence_seen_ || converged_filter; + convergence_seen_ = convergence_seen_ || any_filter_converged; // Verify requirements for achieving a decent filter. The requirements for // filter adaptation at call startup are more restrictive than after an diff --git a/modules/audio_processing/aec3/aec_state.h b/modules/audio_processing/aec3/aec_state.h index f860987296..f6a31d8e6e 100644 --- a/modules/audio_processing/aec3/aec_state.h +++ b/modules/audio_processing/aec3/aec_state.h @@ -57,7 +57,7 @@ class AecState { } // Returns the estimated echo path gain. - float EchoPathGain() const { return filter_analyzer_.Gain(); } + float EchoPathGain() const { return max_echo_path_gain_; } // Returns whether the render signal is currently active. bool ActiveRender() const { return blocks_with_active_render_ > 200; } @@ -131,18 +131,20 @@ class AecState { // Updates the aec state. // TODO(bugs.webrtc.org/10913): Handle multi-channel adaptive filter response. // TODO(bugs.webrtc.org/10913): Compute multi-channel ERL, ERLE, and reverb. - void Update(const absl::optional& external_delay, - const std::vector>& - adaptive_filter_frequency_response, - const std::vector& adaptive_filter_impulse_response, - const RenderBuffer& render_buffer, - const std::array& E2_main, - const std::array& Y2, - rtc::ArrayView subtractor_output); + void Update( + const absl::optional& external_delay, + rtc::ArrayView>> + adaptive_filter_frequency_response, + rtc::ArrayView> adaptive_filter_impulse_response, + const RenderBuffer& render_buffer, + const std::array& E2_main, + const std::array& Y2, + rtc::ArrayView subtractor_output); // Returns filter length in blocks. int FilterLengthBlocks() const { - return filter_analyzer_.FilterLengthBlocks(); + // All filters have the same length, so arbitrarily return channel 0 length. + return filter_analyzers_[/*channel=*/0]->FilterLengthBlocks(); } private: @@ -191,9 +193,10 @@ class AecState { int DirectPathFilterDelay() const { return filter_delay_blocks_; } // Updates the delay estimates based on new data. - void Update(const FilterAnalyzer& filter_analyzer, - const absl::optional& external_delay, - size_t blocks_with_proper_filter_adaptation); + void Update( + const std::vector>& filter_analyzer, + const absl::optional& external_delay, + size_t blocks_with_proper_filter_adaptation); private: const int delay_headroom_samples_; @@ -216,9 +219,9 @@ class AecState { // Updates the detection deciscion based on new data. void Update(int filter_delay_blocks, - bool consistent_filter, - bool converged_filter, - bool diverged_filter, + bool any_filter_consistent, + bool any_filter_converged, + bool all_filters_diverged, bool active_render, bool saturated_capture); @@ -257,9 +260,8 @@ class AecState { void Update(bool active_render, bool transparent_mode, bool saturated_capture, - bool consistent_estimate_, const absl::optional& external_delay, - bool converged_filter); + bool any_filter_converged); private: bool usable_linear_estimate_ = false; @@ -290,8 +292,9 @@ class AecState { ErleEstimator erle_estimator_; size_t strong_not_saturated_render_blocks_ = 0; size_t blocks_with_active_render_ = 0; + float max_echo_path_gain_; bool capture_signal_saturation_ = false; - FilterAnalyzer filter_analyzer_; + std::vector> filter_analyzers_; absl::optional external_delay_; EchoAudibility echo_audibility_; ReverbModelEstimator reverb_model_estimator_; diff --git a/modules/audio_processing/aec3/aec_state_unittest.cc b/modules/audio_processing/aec3/aec_state_unittest.cc index 5997ab177f..95a2134e31 100644 --- a/modules/audio_processing/aec3/aec_state_unittest.cc +++ b/modules/audio_processing/aec3/aec_state_unittest.cc @@ -55,17 +55,23 @@ void RunNormalUsageTest(size_t num_render_channels, y[ch].fill(1000.f); } Aec3Fft fft; - std::vector> - converged_filter_frequency_response(10); - for (auto& v : converged_filter_frequency_response) { - v.fill(0.01f); + std::vector>> + converged_filter_frequency_response( + num_capture_channels, + std::vector>(10)); + for (auto& v_ch : converged_filter_frequency_response) { + for (auto& v : v_ch) { + v.fill(0.01f); + } } - std::vector> + std::vector>> diverged_filter_frequency_response = converged_filter_frequency_response; - converged_filter_frequency_response[2].fill(100.f); - converged_filter_frequency_response[2][0] = 1.f; - std::vector impulse_response( - GetTimeDomainLength(config.filter.main.length_blocks), 0.f); + converged_filter_frequency_response[0][2].fill(100.f); + converged_filter_frequency_response[0][2][0] = 1.f; + std::vector> impulse_response( + num_capture_channels, + std::vector(GetTimeDomainLength(config.filter.main.length_blocks), + 0.f)); // Verify that linear AEC usability is true when the filter is converged for (size_t band = 0; band < kNumBands; ++band) { @@ -243,20 +249,28 @@ TEST(AecState, ConvergedFilterDelay) { x.fill(0.f); y.fill(0.f); - std::vector> frequency_response( - kFilterLengthBlocks); - for (auto& v : frequency_response) { - v.fill(0.01f); + std::vector>> + frequency_response( + kNumCaptureChannels, + std::vector>(kFilterLengthBlocks)); + for (auto& v_ch : frequency_response) { + for (auto& v : v_ch) { + v.fill(0.01f); + } } - std::vector impulse_response( - GetTimeDomainLength(config.filter.main.length_blocks), 0.f); + std::vector> impulse_response( + kNumCaptureChannels, + std::vector(GetTimeDomainLength(config.filter.main.length_blocks), + 0.f)); // Verify that the filter delay for a converged filter is properly // identified. for (int k = 0; k < kFilterLengthBlocks; ++k) { - std::fill(impulse_response.begin(), impulse_response.end(), 0.f); - impulse_response[k * kBlockSize + 1] = 1.f; + for (auto& ir : impulse_response) { + std::fill(ir.begin(), ir.end(), 0.f); + ir[k * kBlockSize + 1] = 1.f; + } state.HandleEchoPathChange(echo_path_variability); subtractor_output[0].ComputeMetrics(y); diff --git a/modules/audio_processing/aec3/echo_remover.cc b/modules/audio_processing/aec3/echo_remover.cc index 31736bf763..0127df11af 100644 --- a/modules/audio_processing/aec3/echo_remover.cc +++ b/modules/audio_processing/aec3/echo_remover.cc @@ -384,9 +384,9 @@ void EchoRemoverImpl::ProcessCapture( // Update the AEC state information. // TODO(bugs.webrtc.org/10913): Take all subtractors into account. - aec_state_.Update(external_delay, subtractor_.FilterFrequencyResponse()[0], - subtractor_.FilterImpulseResponse()[0], *render_buffer, - E2[0], Y2[0], subtractor_output); + aec_state_.Update(external_delay, subtractor_.FilterFrequencyResponse(), + subtractor_.FilterImpulseResponse(), *render_buffer, E2[0], + Y2[0], subtractor_output); // Choose the linear output. const auto& Y_fft = aec_state_.UseLinearFilterOutput() ? E : Y; diff --git a/modules/audio_processing/aec3/filter_analyzer.cc b/modules/audio_processing/aec3/filter_analyzer.cc index 138c188970..313460fbd4 100644 --- a/modules/audio_processing/aec3/filter_analyzer.cc +++ b/modules/audio_processing/aec3/filter_analyzer.cc @@ -96,8 +96,8 @@ void FilterAnalyzer::AnalyzeRegion( filter_length_blocks_ = filter_time_domain.size() * (1.f / kBlockSize); consistent_estimate_ = consistent_filter_detector_.Detect( - h_highpass_, region_, render_buffer.Block(-delay_blocks_)[0][0], - peak_index_, delay_blocks_); + h_highpass_, region_, render_buffer.Block(-delay_blocks_)[0], peak_index_, + delay_blocks_); } void FilterAnalyzer::UpdateFilterGain( @@ -176,7 +176,7 @@ void FilterAnalyzer::ConsistentFilterDetector::Reset() { bool FilterAnalyzer::ConsistentFilterDetector::Detect( rtc::ArrayView filter_to_analyze, const FilterRegion& region, - rtc::ArrayView x_block, + rtc::ArrayView> x_block, size_t peak_index, int delay_blocks) { if (region.start_sample_ == 0) { @@ -212,9 +212,15 @@ bool FilterAnalyzer::ConsistentFilterDetector::Detect( } if (significant_peak_) { - const float x_energy = std::inner_product(x_block.begin(), x_block.end(), - x_block.begin(), 0.f); - const bool active_render_block = x_energy > active_render_threshold_; + bool active_render_block = false; + for (auto& x_channel : x_block) { + const float x_energy = std::inner_product( + x_channel.begin(), x_channel.end(), x_channel.begin(), 0.f); + if (x_energy > active_render_threshold_) { + active_render_block = true; + break; + } + } if (consistent_delay_reference_ == delay_blocks) { if (active_render_block) { diff --git a/modules/audio_processing/aec3/filter_analyzer.h b/modules/audio_processing/aec3/filter_analyzer.h index bcce5287af..de6c8a7dd2 100644 --- a/modules/audio_processing/aec3/filter_analyzer.h +++ b/modules/audio_processing/aec3/filter_analyzer.h @@ -33,6 +33,9 @@ class FilterAnalyzer { explicit FilterAnalyzer(const EchoCanceller3Config& config); ~FilterAnalyzer(); + FilterAnalyzer(const FilterAnalyzer&) = delete; + FilterAnalyzer& operator=(const FilterAnalyzer&) = delete; + // Resets the analysis. void Reset(); @@ -82,7 +85,7 @@ class FilterAnalyzer { void Reset(); bool Detect(rtc::ArrayView filter_to_analyze, const FilterRegion& region, - rtc::ArrayView x_block, + rtc::ArrayView> x_block, size_t peak_index, int delay_blocks); @@ -110,8 +113,6 @@ class FilterAnalyzer { int filter_length_blocks_; FilterRegion region_; ConsistentFilterDetector consistent_filter_detector_; - - RTC_DISALLOW_COPY_AND_ASSIGN(FilterAnalyzer); }; } // namespace webrtc diff --git a/modules/audio_processing/aec3/main_filter_update_gain_unittest.cc b/modules/audio_processing/aec3/main_filter_update_gain_unittest.cc index 1a9e7929e7..4725af907d 100644 --- a/modules/audio_processing/aec3/main_filter_update_gain_unittest.cc +++ b/modules/audio_processing/aec3/main_filter_update_gain_unittest.cc @@ -59,14 +59,19 @@ void RunFilterUpdateTest(int num_blocks_to_process, config.filter.shadow.length_blocks, config.filter.config_change_duration_blocks, 1, optimization, &data_dumper); - std::vector> H2( - main_filter.max_filter_size_partitions(), - std::array()); - for (auto& H2_k : H2) { - H2_k.fill(0.f); + std::vector>> H2( + kNumChannels, std::vector>( + main_filter.max_filter_size_partitions(), + std::array())); + for (auto& H2_ch : H2) { + for (auto& H2_k : H2_ch) { + H2_k.fill(0.f); + } } - std::vector h( - GetTimeDomainLength(main_filter.max_filter_size_partitions()), 0.f); + std::vector> h( + kNumChannels, + std::vector( + GetTimeDomainLength(main_filter.max_filter_size_partitions()), 0.f)); Aec3Fft fft; std::array x_old; @@ -183,15 +188,15 @@ void RunFilterUpdateTest(int num_blocks_to_process, main_filter.SizePartitions(), &render_power); std::array erl; - ComputeErl(optimization, H2, erl); + ComputeErl(optimization, H2[0], erl); main_gain.Compute(render_power, render_signal_analyzer, output[0], erl, main_filter.SizePartitions(), saturation, &G); - main_filter.Adapt(*render_delay_buffer->GetRenderBuffer(), G, &h); + main_filter.Adapt(*render_delay_buffer->GetRenderBuffer(), G, &h[0]); // Update the delay. aec_state.HandleEchoPathChange(EchoPathVariability( false, EchoPathVariability::DelayAdjustment::kNone, false)); - main_filter.ComputeFrequencyResponse(&H2); + main_filter.ComputeFrequencyResponse(&H2[0]); aec_state.Update(delay_estimate, H2, h, *render_delay_buffer->GetRenderBuffer(), E2_main, Y2, output); diff --git a/modules/audio_processing/aec3/residual_echo_estimator_unittest.cc b/modules/audio_processing/aec3/residual_echo_estimator_unittest.cc index 55f634bb4b..7dbdbbefd4 100644 --- a/modules/audio_processing/aec3/residual_echo_estimator_unittest.cc +++ b/modules/audio_processing/aec3/residual_echo_estimator_unittest.cc @@ -28,7 +28,7 @@ TEST(ResidualEchoEstimator, BasicTest) { EchoCanceller3Config config; ResidualEchoEstimator estimator(config, num_render_channels); - AecState aec_state(config, num_render_channels); + AecState aec_state(config, num_capture_channels); std::unique_ptr render_delay_buffer( RenderDelayBuffer::Create(config, kSampleRateHz, num_render_channels)); @@ -44,20 +44,26 @@ TEST(ResidualEchoEstimator, BasicTest) { kNumBands, std::vector>(num_render_channels, std::vector(kBlockSize, 0.f))); - std::vector> H2(10); + std::vector>> H2( + num_capture_channels, + std::vector>(10)); Random random_generator(42U); - std::vector output(num_render_channels); + std::vector output(num_capture_channels); std::array y; absl::optional delay_estimate; - for (auto& H2_k : H2) { - H2_k.fill(0.01f); + for (auto& H2_ch : H2) { + for (auto& H2_k : H2_ch) { + H2_k.fill(0.01f); + } + H2_ch[2].fill(10.f); + H2_ch[2][0] = 0.1f; } - H2[2].fill(10.f); - H2[2][0] = 0.1f; - std::vector h( - GetTimeDomainLength(config.filter.main.length_blocks), 0.f); + std::vector> h( + num_capture_channels, + std::vector( + GetTimeDomainLength(config.filter.main.length_blocks), 0.f)); for (auto& subtractor_output : output) { subtractor_output.Reset(); diff --git a/modules/audio_processing/aec3/subtractor_unittest.cc b/modules/audio_processing/aec3/subtractor_unittest.cc index 23e7ead41d..717b481348 100644 --- a/modules/audio_processing/aec3/subtractor_unittest.cc +++ b/modules/audio_processing/aec3/subtractor_unittest.cc @@ -145,8 +145,8 @@ std::vector RunSubtractorTest( aec_state.HandleEchoPathChange(EchoPathVariability( false, EchoPathVariability::DelayAdjustment::kNone, false)); - aec_state.Update(delay_estimate, subtractor.FilterFrequencyResponse()[0], - subtractor.FilterImpulseResponse()[0], + aec_state.Update(delay_estimate, subtractor.FilterFrequencyResponse(), + subtractor.FilterImpulseResponse(), *render_delay_buffer->GetRenderBuffer(), E2_main, Y2, output); } diff --git a/modules/audio_processing/aec3/suppression_gain_unittest.cc b/modules/audio_processing/aec3/suppression_gain_unittest.cc index 465227ccec..490c7ec0cd 100644 --- a/modules/audio_processing/aec3/suppression_gain_unittest.cc +++ b/modules/audio_processing/aec3/suppression_gain_unittest.cc @@ -97,14 +97,14 @@ TEST(SuppressionGain, BasicGainComputation) { // Ensure that the gain is no longer forced to zero. for (int k = 0; k <= kNumBlocksPerSecond / 5 + 1; ++k) { - aec_state.Update(delay_estimate, subtractor.FilterFrequencyResponse()[0], - subtractor.FilterImpulseResponse()[0], + aec_state.Update(delay_estimate, subtractor.FilterFrequencyResponse(), + subtractor.FilterImpulseResponse(), *render_delay_buffer->GetRenderBuffer(), E2, Y2, output); } for (int k = 0; k < 100; ++k) { - aec_state.Update(delay_estimate, subtractor.FilterFrequencyResponse()[0], - subtractor.FilterImpulseResponse()[0], + aec_state.Update(delay_estimate, subtractor.FilterFrequencyResponse(), + subtractor.FilterImpulseResponse(), *render_delay_buffer->GetRenderBuffer(), E2, Y2, output); suppression_gain.GetGain(E2, S2, R2, N2, analyzer, aec_state, x, &high_bands_gain, &g); @@ -120,8 +120,8 @@ TEST(SuppressionGain, BasicGainComputation) { N2.fill(0.f); for (int k = 0; k < 100; ++k) { - aec_state.Update(delay_estimate, subtractor.FilterFrequencyResponse()[0], - subtractor.FilterImpulseResponse()[0], + aec_state.Update(delay_estimate, subtractor.FilterFrequencyResponse(), + subtractor.FilterImpulseResponse(), *render_delay_buffer->GetRenderBuffer(), E2, Y2, output); suppression_gain.GetGain(E2, S2, R2, N2, analyzer, aec_state, x, &high_bands_gain, &g);