diff --git a/modules/audio_processing/aec3/adaptive_fir_filter_unittest.cc b/modules/audio_processing/aec3/adaptive_fir_filter_unittest.cc index 69673c014c..f1a6489a6d 100644 --- a/modules/audio_processing/aec3/adaptive_fir_filter_unittest.cc +++ b/modules/audio_processing/aec3/adaptive_fir_filter_unittest.cc @@ -376,15 +376,20 @@ TEST(AdaptiveFirFilter, FilterAndAdapt) { FftData S; FftData G; FftData E; - std::array Y2; - std::array E2_main; + std::vector> Y2(kNumCaptureChannels); + std::vector> E2_main( + kNumCaptureChannels); std::array E2_shadow; // [B,A] = butter(2,100/8000,'high') constexpr CascadedBiQuadFilter::BiQuadCoefficients kHighPassFilterCoefficients = {{0.97261f, -1.94523f, 0.97261f}, {-1.94448f, 0.94598f}}; - Y2.fill(0.f); - E2_main.fill(0.f); + for (auto& Y2_ch : Y2) { + Y2_ch.fill(0.f); + } + for (auto& E2_main_ch : E2_main) { + E2_main_ch.fill(0.f); + } E2_shadow.fill(0.f); for (auto& subtractor_output : output) { subtractor_output.Reset(); diff --git a/modules/audio_processing/aec3/aec_state.cc b/modules/audio_processing/aec3/aec_state.cc index bd6710ab25..686592398c 100644 --- a/modules/audio_processing/aec3/aec_state.cc +++ b/modules/audio_processing/aec3/aec_state.cc @@ -164,10 +164,12 @@ void AecState::Update( 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> E2_main, + rtc::ArrayView> Y2, rtc::ArrayView subtractor_output) { const size_t num_capture_channels = filter_analyzers_.size(); + RTC_DCHECK_EQ(num_capture_channels, E2_main.size()); + RTC_DCHECK_EQ(num_capture_channels, Y2.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, @@ -244,12 +246,12 @@ void AecState::Update( const auto& X2_input_erle = X2_reverb; erle_estimator_.Update(render_buffer, adaptive_filter_frequency_response[0], - X2_input_erle, Y2, E2_main, + X2_input_erle, Y2[0], E2_main[0], subtractor_output_analyzers_[0].ConvergedFilter(), config_.erle.onset_detection); erl_estimator_.Update(subtractor_output_analyzers_[0].ConvergedFilter(), X2, - Y2); + Y2[0]); // Detect and flag echo saturation. saturation_detector_.Update(aligned_render_block, SaturatedCapture(), diff --git a/modules/audio_processing/aec3/aec_state.h b/modules/audio_processing/aec3/aec_state.h index 69cdafd9c9..7a7a71e8a0 100644 --- a/modules/audio_processing/aec3/aec_state.h +++ b/modules/audio_processing/aec3/aec_state.h @@ -133,8 +133,8 @@ class AecState { 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> E2_main, + rtc::ArrayView> Y2, rtc::ArrayView subtractor_output); // Returns filter length in blocks. diff --git a/modules/audio_processing/aec3/aec_state_unittest.cc b/modules/audio_processing/aec3/aec_state_unittest.cc index 95a2134e31..b038770b11 100644 --- a/modules/audio_processing/aec3/aec_state_unittest.cc +++ b/modules/audio_processing/aec3/aec_state_unittest.cc @@ -39,8 +39,9 @@ void RunNormalUsageTest(size_t num_render_channels, DelayEstimate(DelayEstimate::Quality::kRefined, 10); std::unique_ptr render_delay_buffer( RenderDelayBuffer::Create(config, kSampleRateHz, num_render_channels)); - std::array E2_main = {}; - std::array Y2 = {}; + std::vector> E2_main( + num_capture_channels); + std::vector> Y2(num_capture_channels); std::vector>> x( kNumBands, std::vector>( num_render_channels, std::vector(kBlockSize, 0.f))); @@ -53,6 +54,8 @@ void RunNormalUsageTest(size_t num_render_channels, subtractor_output[ch].s_main.fill(100.f); subtractor_output[ch].e_main.fill(100.f); y[ch].fill(1000.f); + E2_main[ch].fill(0.f); + Y2[ch].fill(0.f); } Aec3Fft fft; std::vector>> @@ -143,7 +146,9 @@ void RunNormalUsageTest(size_t num_render_channels, render_delay_buffer->PrepareCaptureProcessing(); } - Y2.fill(10.f * 10000.f * 10000.f); + for (auto& Y2_ch : Y2) { + Y2_ch.fill(10.f * 10000.f * 10000.f); + } for (size_t k = 0; k < 1000; ++k) { for (size_t ch = 0; ch < num_capture_channels; ++ch) { subtractor_output[ch].ComputeMetrics(y[ch]); @@ -162,8 +167,12 @@ void RunNormalUsageTest(size_t num_render_channels, EXPECT_EQ(erl[erl.size() - 2], erl[erl.size() - 1]); // Verify that the ERLE is properly estimated - E2_main.fill(1.f * 10000.f * 10000.f); - Y2.fill(10.f * E2_main[0]); + for (auto& E2_main_ch : E2_main) { + E2_main_ch.fill(1.f * 10000.f * 10000.f); + } + for (auto& Y2_ch : Y2) { + Y2_ch.fill(10.f * E2_main[0][0]); + } for (size_t k = 0; k < 1000; ++k) { for (size_t ch = 0; ch < num_capture_channels; ++ch) { subtractor_output[ch].ComputeMetrics(y[ch]); @@ -187,9 +196,12 @@ void RunNormalUsageTest(size_t num_render_channels, } EXPECT_EQ(erle[erle.size() - 2], erle[erle.size() - 1]); } - - E2_main.fill(1.f * 10000.f * 10000.f); - Y2.fill(5.f * E2_main[0]); + for (auto& E2_main_ch : E2_main) { + E2_main_ch.fill(1.f * 10000.f * 10000.f); + } + for (auto& Y2_ch : Y2) { + Y2_ch.fill(5.f * E2_main[0][0]); + } for (size_t k = 0; k < 1000; ++k) { for (size_t ch = 0; ch < num_capture_channels; ++ch) { subtractor_output[ch].ComputeMetrics(y[ch]); @@ -235,8 +247,9 @@ TEST(AecState, ConvergedFilterDelay) { std::unique_ptr render_delay_buffer( RenderDelayBuffer::Create(config, 48000, 1)); absl::optional delay_estimate; - std::array E2_main; - std::array Y2; + std::vector> E2_main( + kNumCaptureChannels); + std::vector> Y2(kNumCaptureChannels); std::array x; EchoPathVariability echo_path_variability( false, EchoPathVariability::DelayAdjustment::kNone, false); diff --git a/modules/audio_processing/aec3/echo_remover.cc b/modules/audio_processing/aec3/echo_remover.cc index 0127df11af..e6f17c7e32 100644 --- a/modules/audio_processing/aec3/echo_remover.cc +++ b/modules/audio_processing/aec3/echo_remover.cc @@ -385,8 +385,8 @@ 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(), - subtractor_.FilterImpulseResponse(), *render_buffer, E2[0], - Y2[0], subtractor_output); + subtractor_.FilterImpulseResponse(), *render_buffer, E2, Y2, + subtractor_output); // Choose the linear output. const auto& Y_fft = aec_state_.UseLinearFilterOutput() ? E : Y; 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 4725af907d..92334c21b7 100644 --- a/modules/audio_processing/aec3/main_filter_update_gain_unittest.cc +++ b/modules/audio_processing/aec3/main_filter_update_gain_unittest.cc @@ -44,7 +44,8 @@ void RunFilterUpdateTest(int num_blocks_to_process, FftData* G_last_block) { ApmDataDumper data_dumper(42); Aec3Optimization optimization = DetectOptimization(); - constexpr size_t kNumChannels = 1; + constexpr size_t kNumRenderChannels = 1; + constexpr size_t kNumCaptureChannels = 1; constexpr int kSampleRateHz = 48000; constexpr size_t kNumBands = NumBandsForRate(kSampleRateHz); @@ -60,16 +61,16 @@ void RunFilterUpdateTest(int num_blocks_to_process, config.filter.config_change_duration_blocks, 1, optimization, &data_dumper); std::vector>> H2( - kNumChannels, std::vector>( - main_filter.max_filter_size_partitions(), - std::array())); + kNumCaptureChannels, 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( - kNumChannels, + kNumCaptureChannels, std::vector( GetTimeDomainLength(main_filter.max_filter_size_partitions()), 0.f)); @@ -83,29 +84,32 @@ void RunFilterUpdateTest(int num_blocks_to_process, Random random_generator(42U); std::vector>> x( kNumBands, std::vector>( - kNumChannels, std::vector(kBlockSize, 0.f))); + kNumRenderChannels, std::vector(kBlockSize, 0.f))); std::vector y(kBlockSize, 0.f); config.delay.default_delay = 1; std::unique_ptr render_delay_buffer( - RenderDelayBuffer::Create(config, kSampleRateHz, kNumChannels)); - AecState aec_state(config, kNumChannels); + RenderDelayBuffer::Create(config, kSampleRateHz, kNumRenderChannels)); + AecState aec_state(config, kNumCaptureChannels); RenderSignalAnalyzer render_signal_analyzer(config); absl::optional delay_estimate; std::array s_scratch; std::array s; FftData S; FftData G; - std::vector output(kNumChannels); + std::vector output(kNumCaptureChannels); for (auto& subtractor_output : output) { subtractor_output.Reset(); } FftData& E_main = output[0].E_main; FftData E_shadow; - std::array Y2; - std::array& E2_main = output[0].E2_main; + std::vector> Y2(kNumCaptureChannels); + std::vector> E2_main( + kNumCaptureChannels); std::array& e_main = output[0].e_main; std::array& e_shadow = output[0].e_shadow; - Y2.fill(0.f); + for (auto& Y2_ch : Y2) { + Y2_ch.fill(0.f); + } constexpr float kScale = 1.0f / kFftLengthBy2; @@ -197,6 +201,8 @@ void RunFilterUpdateTest(int num_blocks_to_process, aec_state.HandleEchoPathChange(EchoPathVariability( false, EchoPathVariability::DelayAdjustment::kNone, false)); main_filter.ComputeFrequencyResponse(&H2[0]); + std::copy(output[0].E2_main.begin(), output[0].E2_main.end(), + E2_main[0].begin()); 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 7dbdbbefd4..c8a45a40e3 100644 --- a/modules/audio_processing/aec3/residual_echo_estimator_unittest.cc +++ b/modules/audio_processing/aec3/residual_echo_estimator_unittest.cc @@ -33,7 +33,8 @@ TEST(ResidualEchoEstimator, BasicTest) { RenderDelayBuffer::Create(config, kSampleRateHz, num_render_channels)); - std::array E2_main; + std::vector> E2_main( + num_capture_channels); std::vector> S2_linear( num_capture_channels); std::vector> Y2( @@ -72,9 +73,13 @@ TEST(ResidualEchoEstimator, BasicTest) { y.fill(0.f); constexpr float kLevel = 10.f; - E2_main.fill(kLevel); + for (auto& E2_main_ch : E2_main) { + E2_main_ch.fill(kLevel); + } S2_linear[0].fill(kLevel); - Y2[0].fill(kLevel); + for (auto& Y2_ch : Y2) { + Y2_ch.fill(kLevel); + } for (int k = 0; k < 1993; ++k) { RandomizeSampleVector(&random_generator, x[0][0]); @@ -85,8 +90,8 @@ TEST(ResidualEchoEstimator, BasicTest) { render_delay_buffer->PrepareCaptureProcessing(); aec_state.Update(delay_estimate, H2, h, - *render_delay_buffer->GetRenderBuffer(), E2_main, - Y2[0], output); + *render_delay_buffer->GetRenderBuffer(), E2_main, Y2, + output); estimator.Estimate(aec_state, *render_delay_buffer->GetRenderBuffer(), S2_linear, Y2, R2); diff --git a/modules/audio_processing/aec3/subtractor_unittest.cc b/modules/audio_processing/aec3/subtractor_unittest.cc index 717b481348..05faa4fd70 100644 --- a/modules/audio_processing/aec3/subtractor_unittest.cc +++ b/modules/audio_processing/aec3/subtractor_unittest.cc @@ -58,13 +58,18 @@ std::vector RunSubtractorTest( RenderSignalAnalyzer render_signal_analyzer(config); Random random_generator(42U); Aec3Fft fft; - std::array Y2; - std::array E2_main; + std::vector> Y2(num_capture_channels); + std::vector> E2_main( + num_capture_channels); std::array E2_shadow; AecState aec_state(config, num_capture_channels); x_old.fill(0.f); - Y2.fill(0.f); - E2_main.fill(0.f); + for (auto& Y2_ch : Y2) { + Y2_ch.fill(0.f); + } + for (auto& E2_main_ch : E2_main) { + E2_main_ch.fill(0.f); + } E2_shadow.fill(0.f); std::vector>>> delay_buffer( diff --git a/modules/audio_processing/aec3/suppression_gain_unittest.cc b/modules/audio_processing/aec3/suppression_gain_unittest.cc index 490c7ec0cd..d068328772 100644 --- a/modules/audio_processing/aec3/suppression_gain_unittest.cc +++ b/modules/audio_processing/aec3/suppression_gain_unittest.cc @@ -58,35 +58,40 @@ TEST(SuppressionGain, NullOutputGains) { // Does a sanity check that the gains are correctly computed. TEST(SuppressionGain, BasicGainComputation) { - constexpr size_t kNumChannels = 1; + constexpr size_t kNumRenderChannels = 1; + constexpr size_t kNumCaptureChannels = 1; constexpr int kSampleRateHz = 16000; constexpr size_t kNumBands = NumBandsForRate(kSampleRateHz); SuppressionGain suppression_gain(EchoCanceller3Config(), DetectOptimization(), kSampleRateHz); RenderSignalAnalyzer analyzer(EchoCanceller3Config{}); float high_bands_gain; - std::array E2; + std::vector> E2(kNumCaptureChannels); std::array S2; - std::array Y2; + std::vector> Y2(kNumCaptureChannels); std::array R2; std::array N2; std::array g; - std::vector output(kNumChannels); + std::vector output(kNumCaptureChannels); std::array y; std::vector>> x( kNumBands, std::vector>( - kNumChannels, std::vector(kBlockSize, 0.f))); + kNumRenderChannels, std::vector(kBlockSize, 0.f))); EchoCanceller3Config config; - AecState aec_state(config, kNumChannels); + AecState aec_state(config, kNumCaptureChannels); ApmDataDumper data_dumper(42); Subtractor subtractor(config, 1, 1, &data_dumper, DetectOptimization()); std::unique_ptr render_delay_buffer( - RenderDelayBuffer::Create(config, kSampleRateHz, kNumChannels)); + RenderDelayBuffer::Create(config, kSampleRateHz, kNumRenderChannels)); absl::optional delay_estimate; // Ensure that a strong noise is detected to mask any echoes. - E2.fill(10.f); - Y2.fill(10.f); + for (auto& E2_k : E2) { + E2_k.fill(10.f); + } + for (auto& Y2_k : Y2) { + Y2_k.fill(10.f); + } R2.fill(0.1f); S2.fill(0.1f); N2.fill(100.f); @@ -106,15 +111,19 @@ TEST(SuppressionGain, BasicGainComputation) { 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, + suppression_gain.GetGain(E2[0], S2, R2, N2, analyzer, aec_state, x, &high_bands_gain, &g); } std::for_each(g.begin(), g.end(), [](float a) { EXPECT_NEAR(1.f, a, 0.001); }); // Ensure that a strong nearend is detected to mask any echoes. - E2.fill(100.f); - Y2.fill(100.f); + for (auto& E2_k : E2) { + E2_k.fill(100.f); + } + for (auto& Y2_k : Y2) { + Y2_k.fill(100.f); + } R2.fill(0.1f); S2.fill(0.1f); N2.fill(0.f); @@ -123,18 +132,20 @@ TEST(SuppressionGain, BasicGainComputation) { 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, + suppression_gain.GetGain(E2[0], S2, R2, N2, analyzer, aec_state, x, &high_bands_gain, &g); } std::for_each(g.begin(), g.end(), [](float a) { EXPECT_NEAR(1.f, a, 0.001); }); // Ensure that a strong echo is suppressed. - E2.fill(1000000000.f); + for (auto& E2_k : E2) { + E2_k.fill(1000000000.f); + } R2.fill(10000000000000.f); for (int k = 0; k < 10; ++k) { - suppression_gain.GetGain(E2, S2, R2, N2, analyzer, aec_state, x, + suppression_gain.GetGain(E2[0], S2, R2, N2, analyzer, aec_state, x, &high_bands_gain, &g); } std::for_each(g.begin(), g.end(),