From d3ead1a94256aea3a654a05a1a0fae733c8d1f1e Mon Sep 17 00:00:00 2001 From: Gustaf Ullberg Date: Mon, 23 May 2022 10:39:53 +0200 Subject: [PATCH] AEC3: 'Block' class MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This change adds a Block class to reduce the need for std::vector>>. This make the code easier to read and less error prone. It also enables future changes to the underlying data structure of a block. For instance, the data of all bands and channels could be stored in a single vector. The change has been verified to be bit-exact. Bug: webrtc:14089 Change-Id: Ied9a78124c0bbafe0e912017aef91f7c311de2ae Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/262252 Reviewed-by: Per Ã…hgren Commit-Queue: Gustaf Ullberg Cr-Commit-Position: refs/heads/main@{#36968} --- modules/audio_processing/aec3/BUILD.gn | 2 + .../aec3/adaptive_fir_filter_unittest.cc | 45 +++----- modules/audio_processing/aec3/aec_state.cc | 20 ++-- modules/audio_processing/aec3/aec_state.h | 2 +- .../aec3/aec_state_unittest.cc | 28 +++-- .../audio_processing/aec3/alignment_mixer.cc | 27 +++-- .../audio_processing/aec3/alignment_mixer.h | 9 +- .../aec3/alignment_mixer_unittest.cc | 30 ++--- modules/audio_processing/aec3/block.h | 73 ++++++++++++ modules/audio_processing/aec3/block_buffer.cc | 20 +--- modules/audio_processing/aec3/block_buffer.h | 8 +- modules/audio_processing/aec3/block_framer.cc | 27 ++--- modules/audio_processing/aec3/block_framer.h | 5 +- .../aec3/block_framer_unittest.cc | 95 ++++------------ .../audio_processing/aec3/block_processor.cc | 50 ++++----- .../audio_processing/aec3/block_processor.h | 13 +-- .../aec3/block_processor_unittest.cc | 105 +++++------------- .../coarse_filter_update_gain_unittest.cc | 13 +-- .../audio_processing/aec3/echo_audibility.cc | 5 +- .../audio_processing/aec3/echo_canceller3.cc | 64 +++++------ .../audio_processing/aec3/echo_canceller3.h | 8 +- .../aec3/echo_canceller3_unittest.cc | 32 +++--- .../aec3/echo_path_delay_estimator.cc | 4 +- .../aec3/echo_path_delay_estimator.h | 3 +- .../echo_path_delay_estimator_unittest.cc | 54 +++------ modules/audio_processing/aec3/echo_remover.cc | 69 ++++++------ modules/audio_processing/aec3/echo_remover.h | 5 +- .../aec3/echo_remover_unittest.cc | 79 ++++--------- .../aec3/erle_estimator_unittest.cc | 26 ++--- .../audio_processing/aec3/filter_analyzer.cc | 8 +- .../audio_processing/aec3/filter_analyzer.h | 3 +- .../audio_processing/aec3/frame_blocker.cc | 34 +++--- modules/audio_processing/aec3/frame_blocker.h | 5 +- .../aec3/frame_blocker_unittest.cc | 91 ++++----------- .../aec3/matched_filter_unittest.cc | 17 ++- .../aec3/mock/mock_block_processor.h | 9 +- .../aec3/mock/mock_echo_remover.h | 4 +- .../aec3/mock/mock_render_delay_buffer.cc | 3 +- .../aec3/mock/mock_render_delay_buffer.h | 2 +- .../aec3/mock/mock_render_delay_controller.h | 2 +- .../refined_filter_update_gain_unittest.cc | 18 ++- modules/audio_processing/aec3/render_buffer.h | 3 +- .../aec3/render_buffer_unittest.cc | 4 +- .../aec3/render_delay_buffer.cc | 49 ++++---- .../aec3/render_delay_buffer.h | 4 +- .../aec3/render_delay_buffer_unittest.cc | 36 +----- .../aec3/render_delay_controller.cc | 5 +- .../aec3/render_delay_controller.h | 3 +- .../aec3/render_delay_controller_unittest.cc | 89 +++++---------- .../aec3/render_signal_analyzer.cc | 16 +-- .../aec3/render_signal_analyzer_unittest.cc | 26 ++--- .../aec3/residual_echo_estimator_unittest.cc | 10 +- ...ignal_dependent_erle_estimator_unittest.cc | 19 ++-- modules/audio_processing/aec3/subtractor.cc | 7 +- modules/audio_processing/aec3/subtractor.h | 3 +- .../aec3/subtractor_unittest.cc | 45 +++----- .../aec3/suppression_filter.cc | 22 ++-- .../aec3/suppression_filter.h | 3 +- .../aec3/suppression_filter_unittest.cc | 90 ++++++++------- .../audio_processing/aec3/suppression_gain.cc | 34 +++--- .../audio_processing/aec3/suppression_gain.h | 6 +- .../aec3/suppression_gain_unittest.cc | 9 +- 62 files changed, 663 insertions(+), 937 deletions(-) create mode 100644 modules/audio_processing/aec3/block.h diff --git a/modules/audio_processing/aec3/BUILD.gn b/modules/audio_processing/aec3/BUILD.gn index 8876002990..6e9e7a3379 100644 --- a/modules/audio_processing/aec3/BUILD.gn +++ b/modules/audio_processing/aec3/BUILD.gn @@ -22,6 +22,7 @@ rtc_library("aec3") { "alignment_mixer.h", "api_call_jitter_metrics.cc", "api_call_jitter_metrics.h", + "block.h", "block_buffer.cc", "block_delay_buffer.cc", "block_delay_buffer.h", @@ -182,6 +183,7 @@ rtc_source_set("aec3_fft") { rtc_source_set("render_buffer") { sources = [ + "block.h", "block_buffer.h", "fft_buffer.h", "render_buffer.h", diff --git a/modules/audio_processing/aec3/adaptive_fir_filter_unittest.cc b/modules/audio_processing/aec3/adaptive_fir_filter_unittest.cc index af7ea1d34c..a13764c109 100644 --- a/modules/audio_processing/aec3/adaptive_fir_filter_unittest.cc +++ b/modules/audio_processing/aec3/adaptive_fir_filter_unittest.cc @@ -73,10 +73,7 @@ TEST_P(AdaptiveFirFilterOneTwoFourEightRenderChannels, RenderDelayBuffer::Create(EchoCanceller3Config(), kSampleRateHz, num_render_channels)); Random random_generator(42U); - std::vector>> x( - kNumBands, - std::vector>(num_render_channels, - std::vector(kBlockSize, 0.f))); + Block x(kNumBands, num_render_channels); FftData S_C; FftData S_Neon; FftData G; @@ -92,10 +89,10 @@ TEST_P(AdaptiveFirFilterOneTwoFourEightRenderChannels, } } - for (size_t k = 0; k < 30; ++k) { - for (size_t band = 0; band < x.size(); ++band) { - for (size_t ch = 0; ch < x[band].size(); ++ch) { - RandomizeSampleVector(&random_generator, x[band][ch]); + for (int k = 0; k < 30; ++k) { + for (int band = 0; band < x.NumBands(); ++band) { + for (int ch = 0; ch < x.NumChannels(); ++ch) { + RandomizeSampleVector(&random_generator, x.View(band, ch)); } } render_delay_buffer->Insert(x); @@ -186,10 +183,7 @@ TEST_P(AdaptiveFirFilterOneTwoFourEightRenderChannels, RenderDelayBuffer::Create(EchoCanceller3Config(), kSampleRateHz, num_render_channels)); Random random_generator(42U); - std::vector>> x( - kNumBands, - std::vector>(num_render_channels, - std::vector(kBlockSize, 0.f))); + Block x(kNumBands, num_render_channels); FftData S_C; FftData S_Sse2; FftData G; @@ -206,9 +200,9 @@ TEST_P(AdaptiveFirFilterOneTwoFourEightRenderChannels, } for (size_t k = 0; k < 500; ++k) { - for (size_t band = 0; band < x.size(); ++band) { - for (size_t ch = 0; ch < x[band].size(); ++ch) { - RandomizeSampleVector(&random_generator, x[band][ch]); + for (int band = 0; band < x.NumBands(); ++band) { + for (int ch = 0; ch < x.NumChannels(); ++ch) { + RandomizeSampleVector(&random_generator, x.View(band, ch)); } } render_delay_buffer->Insert(x); @@ -261,10 +255,7 @@ TEST_P(AdaptiveFirFilterOneTwoFourEightRenderChannels, RenderDelayBuffer::Create(EchoCanceller3Config(), kSampleRateHz, num_render_channels)); Random random_generator(42U); - std::vector>> x( - kNumBands, - std::vector>(num_render_channels, - std::vector(kBlockSize, 0.f))); + Block x(kNumBands, num_render_channels); FftData S_C; FftData S_Avx2; FftData G; @@ -281,9 +272,9 @@ TEST_P(AdaptiveFirFilterOneTwoFourEightRenderChannels, } for (size_t k = 0; k < 500; ++k) { - for (size_t band = 0; band < x.size(); ++band) { - for (size_t ch = 0; ch < x[band].size(); ++ch) { - RandomizeSampleVector(&random_generator, x[band][ch]); + for (int band = 0; band < x.NumBands(); ++band) { + for (int ch = 0; ch < x.NumChannels(); ++ch) { + RandomizeSampleVector(&random_generator, x.View(band, ch)); } } render_delay_buffer->Insert(x); @@ -488,9 +479,7 @@ TEST_P(AdaptiveFirFilterMultiChannel, FilterAndAdapt) { CoarseFilterUpdateGain gain(config.filter.coarse, config.filter.config_change_duration_blocks); Random random_generator(42U); - std::vector>> x( - kNumBands, std::vector>( - num_render_channels, std::vector(kBlockSize, 0.f))); + Block x(kNumBands, num_render_channels); std::vector n(kBlockSize, 0.f); std::vector y(kBlockSize, 0.f); AecState aec_state(EchoCanceller3Config{}, num_capture_channels); @@ -540,9 +529,9 @@ TEST_P(AdaptiveFirFilterMultiChannel, FilterAndAdapt) { for (size_t j = 0; j < num_blocks_to_process; ++j) { std::fill(y.begin(), y.end(), 0.f); for (size_t ch = 0; ch < num_render_channels; ++ch) { - RandomizeSampleVector(&random_generator, x[0][ch]); + RandomizeSampleVector(&random_generator, x.View(/*band=*/0, ch)); std::array y_channel; - delay_buffer[ch].Delay(x[0][ch], y_channel); + delay_buffer[ch].Delay(x.View(/*band=*/0, ch), y_channel); for (size_t k = 0; k < y.size(); ++k) { y[k] += y_channel[k] / num_render_channels; } @@ -555,7 +544,7 @@ TEST_P(AdaptiveFirFilterMultiChannel, FilterAndAdapt) { } for (size_t ch = 0; ch < num_render_channels; ++ch) { - x_hp_filter[ch]->Process(x[0][ch]); + x_hp_filter[ch]->Process(x.View(/*band=*/0, ch)); } y_hp_filter.Process(y); diff --git a/modules/audio_processing/aec3/aec_state.cc b/modules/audio_processing/aec3/aec_state.cc index b09acfd892..11f0a139ed 100644 --- a/modules/audio_processing/aec3/aec_state.cc +++ b/modules/audio_processing/aec3/aec_state.cc @@ -206,15 +206,16 @@ void AecState::Update( strong_not_saturated_render_blocks_); } - const std::vector>& aligned_render_block = - render_buffer.Block(-delay_state_.MinDirectPathFilterDelay())[0]; + const Block& aligned_render_block = + render_buffer.Block(-delay_state_.MinDirectPathFilterDelay()); // Update render counters. bool active_render = false; - for (size_t ch = 0; ch < aligned_render_block.size(); ++ch) { - const float render_energy = std::inner_product( - aligned_render_block[ch].begin(), aligned_render_block[ch].end(), - aligned_render_block[ch].begin(), 0.f); + for (int ch = 0; ch < aligned_render_block.NumChannels(); ++ch) { + const float render_energy = + std::inner_product(aligned_render_block.begin(/*block=*/0, ch), + aligned_render_block.end(/*block=*/0, ch), + aligned_render_block.begin(/*block=*/0, ch), 0.f); if (render_energy > (config_.render_levels.active_render_limit * config_.render_levels.active_render_limit) * kFftLengthBy2) { @@ -446,7 +447,7 @@ void AecState::FilteringQualityAnalyzer::Update( } void AecState::SaturationDetector::Update( - rtc::ArrayView> x, + const Block& x, bool saturated_capture, bool usable_linear_estimate, rtc::ArrayView subtractor_output, @@ -466,8 +467,9 @@ void AecState::SaturationDetector::Update( } } else { float max_sample = 0.f; - for (auto& channel : x) { - for (float sample : channel) { + for (int ch = 0; ch < x.NumChannels(); ++ch) { + rtc::ArrayView x_ch = x.View(/*band=*/0, ch); + for (float sample : x_ch) { max_sample = std::max(max_sample, fabsf(sample)); } } diff --git a/modules/audio_processing/aec3/aec_state.h b/modules/audio_processing/aec3/aec_state.h index 5994465688..dbd0fccb67 100644 --- a/modules/audio_processing/aec3/aec_state.h +++ b/modules/audio_processing/aec3/aec_state.h @@ -272,7 +272,7 @@ class AecState { bool SaturatedEcho() const { return saturated_echo_; } // Updates the detection decision based on new data. - void Update(rtc::ArrayView> x, + void Update(const Block& x, bool saturated_capture, bool usable_linear_estimate, rtc::ArrayView subtractor_output, diff --git a/modules/audio_processing/aec3/aec_state_unittest.cc b/modules/audio_processing/aec3/aec_state_unittest.cc index 6e62a586ed..6662c8fb1a 100644 --- a/modules/audio_processing/aec3/aec_state_unittest.cc +++ b/modules/audio_processing/aec3/aec_state_unittest.cc @@ -35,9 +35,7 @@ void RunNormalUsageTest(size_t num_render_channels, std::vector> E2_refined( num_capture_channels); std::vector> Y2(num_capture_channels); - std::vector>> x( - kNumBands, std::vector>( - num_render_channels, std::vector(kBlockSize, 0.f))); + Block x(kNumBands, num_render_channels); EchoPathVariability echo_path_variability( false, EchoPathVariability::DelayAdjustment::kNone, false); std::vector> y(num_capture_channels); @@ -52,9 +50,9 @@ void RunNormalUsageTest(size_t num_render_channels, } Aec3Fft fft; std::vector>> - converged_filter_frequency_response( - num_capture_channels, - std::vector>(10)); + 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); @@ -72,7 +70,7 @@ void RunNormalUsageTest(size_t num_render_channels, // Verify that linear AEC usability is true when the filter is converged for (size_t band = 0; band < kNumBands; ++band) { for (size_t ch = 0; ch < num_render_channels; ++ch) { - std::fill(x[band][ch].begin(), x[band][ch].end(), 101.f); + std::fill(x.begin(band, ch), x.end(band, ch), 101.f); } } for (int k = 0; k < 3000; ++k) { @@ -100,7 +98,7 @@ void RunNormalUsageTest(size_t num_render_channels, // Verify that the active render detection works as intended. for (size_t ch = 0; ch < num_render_channels; ++ch) { - std::fill(x[0][ch].begin(), x[0][ch].end(), 101.f); + std::fill(x.begin(0, ch), x.end(0, ch), 101.f); } render_delay_buffer->Insert(x); for (size_t ch = 0; ch < num_capture_channels; ++ch) { @@ -125,14 +123,14 @@ void RunNormalUsageTest(size_t num_render_channels, EXPECT_TRUE(state.ActiveRender()); // Verify that the ERL is properly estimated - for (auto& band : x) { - for (auto& channel : band) { - channel = std::vector(kBlockSize, 0.f); + for (int band = 0; band < x.NumBands(); ++band) { + for (int channel = 0; channel < x.NumChannels(); ++channel) { + std::fill(x.begin(band, channel), x.end(band, channel), 0.0f); } } for (size_t ch = 0; ch < num_render_channels; ++ch) { - x[0][ch][0] = 5000.f; + x.View(/*band=*/0, ch)[0] = 5000.f; } for (size_t k = 0; k < render_delay_buffer->GetRenderBuffer()->GetFftBuffer().size(); ++k) { @@ -266,9 +264,9 @@ TEST(AecState, ConvergedFilterDelay) { y.fill(0.f); std::vector>> - frequency_response( - kNumCaptureChannels, - std::vector>(kFilterLengthBlocks)); + frequency_response(kNumCaptureChannels, + std::vector>( + kFilterLengthBlocks)); for (auto& v_ch : frequency_response) { for (auto& v : v_ch) { v.fill(0.01f); diff --git a/modules/audio_processing/aec3/alignment_mixer.cc b/modules/audio_processing/aec3/alignment_mixer.cc index 87488d2674..7f076dea8e 100644 --- a/modules/audio_processing/aec3/alignment_mixer.cc +++ b/modules/audio_processing/aec3/alignment_mixer.cc @@ -63,9 +63,10 @@ AlignmentMixer::AlignmentMixer(size_t num_channels, } } -void AlignmentMixer::ProduceOutput(rtc::ArrayView> x, +void AlignmentMixer::ProduceOutput(const Block& x, rtc::ArrayView y) { - RTC_DCHECK_EQ(x.size(), num_channels_); + RTC_DCHECK_EQ(x.NumChannels(), num_channels_); + if (selection_variant_ == MixingVariant::kDownmix) { Downmix(x, y); return; @@ -73,18 +74,20 @@ void AlignmentMixer::ProduceOutput(rtc::ArrayView> x, int ch = selection_variant_ == MixingVariant::kFixed ? 0 : SelectChannel(x); - RTC_DCHECK_GE(x.size(), ch); - std::copy(x[ch].begin(), x[ch].end(), y.begin()); + RTC_DCHECK_GT(x.NumChannels(), ch); + std::copy(x.begin(/*band=*/0, ch), x.end(/*band=*/0, ch), y.begin()); } -void AlignmentMixer::Downmix(rtc::ArrayView> x, +void AlignmentMixer::Downmix(const Block& x, rtc::ArrayView y) const { - RTC_DCHECK_EQ(x.size(), num_channels_); + RTC_DCHECK_EQ(x.NumChannels(), num_channels_); RTC_DCHECK_GE(num_channels_, 2); - std::copy(x[0].begin(), x[0].end(), y.begin()); + std::memcpy(&y[0], x.View(/*band=*/0, /*channel=*/0).data(), + kBlockSize * sizeof(y[0])); for (size_t ch = 1; ch < num_channels_; ++ch) { + const auto x_ch = x.View(/*band=*/0, ch); for (size_t i = 0; i < kBlockSize; ++i) { - y[i] += x[ch][i]; + y[i] += x_ch[i]; } } @@ -93,8 +96,8 @@ void AlignmentMixer::Downmix(rtc::ArrayView> x, } } -int AlignmentMixer::SelectChannel(rtc::ArrayView> x) { - RTC_DCHECK_EQ(x.size(), num_channels_); +int AlignmentMixer::SelectChannel(const Block& x) { + RTC_DCHECK_EQ(x.NumChannels(), num_channels_); RTC_DCHECK_GE(num_channels_, 2); RTC_DCHECK_EQ(cumulative_energies_.size(), num_channels_); @@ -112,10 +115,10 @@ int AlignmentMixer::SelectChannel(rtc::ArrayView> x) { ++block_counter_; for (int ch = 0; ch < num_ch_to_analyze; ++ch) { - RTC_DCHECK_EQ(x[ch].size(), kBlockSize); float x2_sum = 0.f; + rtc::ArrayView x_ch = x.View(/*band=*/0, ch); for (size_t i = 0; i < kBlockSize; ++i) { - x2_sum += x[ch][i] * x[ch][i]; + x2_sum += x_ch[i] * x_ch[i]; } if (ch < 2 && x2_sum > excitation_energy_threshold_) { diff --git a/modules/audio_processing/aec3/alignment_mixer.h b/modules/audio_processing/aec3/alignment_mixer.h index aa1830fc03..b3ed04755c 100644 --- a/modules/audio_processing/aec3/alignment_mixer.h +++ b/modules/audio_processing/aec3/alignment_mixer.h @@ -16,6 +16,7 @@ #include "api/array_view.h" #include "api/audio/echo_canceller3_config.h" #include "modules/audio_processing/aec3/aec3_common.h" +#include "modules/audio_processing/aec3/block.h" namespace webrtc { @@ -33,8 +34,7 @@ class AlignmentMixer { float excitation_limit, bool prefer_first_two_channels); - void ProduceOutput(rtc::ArrayView> x, - rtc::ArrayView y); + void ProduceOutput(const Block& x, rtc::ArrayView y); enum class MixingVariant { kDownmix, kAdaptive, kFixed }; @@ -49,9 +49,8 @@ class AlignmentMixer { int selected_channel_ = 0; size_t block_counter_ = 0; - void Downmix(rtc::ArrayView> x, - rtc::ArrayView y) const; - int SelectChannel(rtc::ArrayView> x); + void Downmix(const Block& x, rtc::ArrayView y) const; + int SelectChannel(const Block& x); }; } // namespace webrtc diff --git a/modules/audio_processing/aec3/alignment_mixer_unittest.cc b/modules/audio_processing/aec3/alignment_mixer_unittest.cc index 03ef06614b..eaf6dcb235 100644 --- a/modules/audio_processing/aec3/alignment_mixer_unittest.cc +++ b/modules/audio_processing/aec3/alignment_mixer_unittest.cc @@ -60,12 +60,9 @@ TEST(AlignmentMixer, GeneralAdaptiveMode) { /*adaptive_selection*/ true, excitation_limit, prefer_first_two_channels); - std::vector> x( - num_channels, std::vector(kBlockSize, 0.f)); + Block x( + /*num_bands=*/1, num_channels); if (initial_silence) { - for (int ch = 0; ch < num_channels; ++ch) { - std::fill(x[ch].begin(), x[ch].end(), 0.f); - } std::array y; for (int frame = 0; frame < 10 * kNumBlocksPerSecond; ++frame) { am.ProduceOutput(x, y); @@ -82,7 +79,8 @@ TEST(AlignmentMixer, GeneralAdaptiveMode) { for (int ch = 0; ch < num_channels; ++ch) { float scaling = ch == strongest_ch ? kStrongestSignalScaling : 1.f; - std::fill(x[ch].begin(), x[ch].end(), + auto x_ch = x.View(/*band=*/0, ch); + std::fill(x_ch.begin(), x_ch.end(), channel_value(frame, ch) * scaling); } @@ -92,13 +90,15 @@ TEST(AlignmentMixer, GeneralAdaptiveMode) { if (frame > 1 * kNumBlocksPerSecond) { if (!prefer_first_two_channels || huge_activity_threshold) { - EXPECT_THAT(y, AllOf(Each(x[strongest_ch][0]))); + EXPECT_THAT(y, + AllOf(Each(x.View(/*band=*/0, strongest_ch)[0]))); } else { bool left_or_right_chosen; for (int ch = 0; ch < 2; ++ch) { left_or_right_chosen = true; + const auto x_ch = x.View(/*band=*/0, ch); for (size_t k = 0; k < kBlockSize; ++k) { - if (y[k] != x[ch][k]) { + if (y[k] != x_ch[k]) { left_or_right_chosen = false; break; } @@ -124,14 +124,14 @@ TEST(AlignmentMixer, DownmixMode) { /*adaptive_selection*/ false, /*excitation_limit*/ 1.f, /*prefer_first_two_channels*/ false); - std::vector> x(num_channels, - std::vector(kBlockSize, 0.f)); + Block x(/*num_bands=*/1, num_channels); const auto channel_value = [](int frame_index, int channel_index) { return static_cast(frame_index + channel_index); }; for (int frame = 0; frame < 10; ++frame) { for (int ch = 0; ch < num_channels; ++ch) { - std::fill(x[ch].begin(), x[ch].end(), channel_value(frame, ch)); + auto x_ch = x.View(/*band=*/0, ch); + std::fill(x_ch.begin(), x_ch.end(), channel_value(frame, ch)); } std::array y; @@ -155,20 +155,20 @@ TEST(AlignmentMixer, FixedMode) { /*adaptive_selection*/ false, /*excitation_limit*/ 1.f, /*prefer_first_two_channels*/ false); - std::vector> x(num_channels, - std::vector(kBlockSize, 0.f)); + Block x(/*num_band=*/1, num_channels); const auto channel_value = [](int frame_index, int channel_index) { return static_cast(frame_index + channel_index); }; for (int frame = 0; frame < 10; ++frame) { for (int ch = 0; ch < num_channels; ++ch) { - std::fill(x[ch].begin(), x[ch].end(), channel_value(frame, ch)); + auto x_ch = x.View(/*band=*/0, ch); + std::fill(x_ch.begin(), x_ch.end(), channel_value(frame, ch)); } std::array y; y.fill(-1.f); am.ProduceOutput(x, y); - EXPECT_THAT(y, AllOf(Each(x[0][0]))); + EXPECT_THAT(y, AllOf(Each(x.View(/*band=*/0, /*channel=*/0)[0]))); } } } diff --git a/modules/audio_processing/aec3/block.h b/modules/audio_processing/aec3/block.h new file mode 100644 index 0000000000..a250e4a9ba --- /dev/null +++ b/modules/audio_processing/aec3/block.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2022 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef MODULES_AUDIO_PROCESSING_AEC3_BLOCK_H_ +#define MODULES_AUDIO_PROCESSING_AEC3_BLOCK_H_ + +#include +#include + +#include "api/array_view.h" +#include "modules/audio_processing/aec3/aec3_common.h" + +namespace webrtc { + +class Block { + public: + Block(int num_bands, int num_channels, float default_value = 0.0f) + : data_(num_bands, + std::vector>( + num_channels, + std::array({default_value}))) {} + + // Returns the number of bands. + int NumBands() const { return data_.size(); } + + // Returns the number of channels. + int NumChannels() const { return data_[0].size(); } + + // Modifies the number of channels. + void SetNumChannels(int num_channels) { + for (std::vector>& block_band : data_) { + block_band.resize(num_channels, std::array({0.0f})); + } + } + + // Iterators for accessing the data. + auto begin(int band, int channel) { return data_[band][channel].begin(); } + + auto begin(int band, int channel) const { + return data_[band][channel].begin(); + } + + auto end(int band, int channel) { return data_[band][channel].end(); } + + auto end(int band, int channel) const { return data_[band][channel].end(); } + + // Access data via ArrayView. + rtc::ArrayView View(int band, int channel) { + return rtc::ArrayView(data_[band][channel].data(), + kBlockSize); + } + + rtc::ArrayView View(int band, int channel) const { + return rtc::ArrayView(data_[band][channel].data(), + kBlockSize); + } + + // Lets two Blocks swap audio data. + void Swap(Block& b) { data_.swap(b.data_); } + + private: + std::vector>> data_; +}; + +} // namespace webrtc +#endif // MODULES_AUDIO_PROCESSING_AEC3_BLOCK_H_ diff --git a/modules/audio_processing/aec3/block_buffer.cc b/modules/audio_processing/aec3/block_buffer.cc index 77ce3deaf8..289c3f0d10 100644 --- a/modules/audio_processing/aec3/block_buffer.cc +++ b/modules/audio_processing/aec3/block_buffer.cc @@ -14,25 +14,9 @@ namespace webrtc { -BlockBuffer::BlockBuffer(size_t size, - size_t num_bands, - size_t num_channels, - size_t frame_length) +BlockBuffer::BlockBuffer(size_t size, size_t num_bands, size_t num_channels) : size(static_cast(size)), - buffer(size, - std::vector>>( - num_bands, - std::vector>( - num_channels, - std::vector(frame_length, 0.f)))) { - for (auto& block : buffer) { - for (auto& band : block) { - for (auto& channel : band) { - std::fill(channel.begin(), channel.end(), 0.f); - } - } - } -} + buffer(size, Block(num_bands, num_channels)) {} BlockBuffer::~BlockBuffer() = default; diff --git a/modules/audio_processing/aec3/block_buffer.h b/modules/audio_processing/aec3/block_buffer.h index b28d659a14..3489d51646 100644 --- a/modules/audio_processing/aec3/block_buffer.h +++ b/modules/audio_processing/aec3/block_buffer.h @@ -15,6 +15,7 @@ #include +#include "modules/audio_processing/aec3/block.h" #include "rtc_base/checks.h" namespace webrtc { @@ -22,10 +23,7 @@ namespace webrtc { // Struct for bundling a circular buffer of two dimensional vector objects // together with the read and write indices. struct BlockBuffer { - BlockBuffer(size_t size, - size_t num_bands, - size_t num_channels, - size_t frame_length); + BlockBuffer(size_t size, size_t num_bands, size_t num_channels); ~BlockBuffer(); int IncIndex(int index) const { @@ -52,7 +50,7 @@ struct BlockBuffer { void DecReadIndex() { read = DecIndex(read); } const int size; - std::vector>>> buffer; + std::vector buffer; int write = 0; int read = 0; }; diff --git a/modules/audio_processing/aec3/block_framer.cc b/modules/audio_processing/aec3/block_framer.cc index 8241ce64f2..4243ddeba0 100644 --- a/modules/audio_processing/aec3/block_framer.cc +++ b/modules/audio_processing/aec3/block_framer.cc @@ -34,35 +34,32 @@ BlockFramer::~BlockFramer() = default; // samples for InsertBlockAndExtractSubFrame to produce a frame. In order to // achieve this, the InsertBlockAndExtractSubFrame and InsertBlock methods need // to be called in the correct order. -void BlockFramer::InsertBlock( - const std::vector>>& block) { - RTC_DCHECK_EQ(num_bands_, block.size()); +void BlockFramer::InsertBlock(const Block& block) { + RTC_DCHECK_EQ(num_bands_, block.NumBands()); + RTC_DCHECK_EQ(num_channels_, block.NumChannels()); for (size_t band = 0; band < num_bands_; ++band) { - RTC_DCHECK_EQ(num_channels_, block[band].size()); for (size_t channel = 0; channel < num_channels_; ++channel) { - RTC_DCHECK_EQ(kBlockSize, block[band][channel].size()); RTC_DCHECK_EQ(0, buffer_[band][channel].size()); buffer_[band][channel].insert(buffer_[band][channel].begin(), - block[band][channel].begin(), - block[band][channel].end()); + block.begin(band, channel), + block.end(band, channel)); } } } void BlockFramer::InsertBlockAndExtractSubFrame( - const std::vector>>& block, + const Block& block, std::vector>>* sub_frame) { RTC_DCHECK(sub_frame); - RTC_DCHECK_EQ(num_bands_, block.size()); + RTC_DCHECK_EQ(num_bands_, block.NumBands()); + RTC_DCHECK_EQ(num_channels_, block.NumChannels()); RTC_DCHECK_EQ(num_bands_, sub_frame->size()); for (size_t band = 0; band < num_bands_; ++band) { - RTC_DCHECK_EQ(num_channels_, block[band].size()); RTC_DCHECK_EQ(num_channels_, (*sub_frame)[0].size()); for (size_t channel = 0; channel < num_channels_; ++channel) { RTC_DCHECK_LE(kSubFrameLength, buffer_[band][channel].size() + kBlockSize); - RTC_DCHECK_EQ(kBlockSize, block[band][channel].size()); RTC_DCHECK_GE(kBlockSize, buffer_[band][channel].size()); RTC_DCHECK_EQ(kSubFrameLength, (*sub_frame)[band][channel].size()); @@ -71,14 +68,14 @@ void BlockFramer::InsertBlockAndExtractSubFrame( std::copy(buffer_[band][channel].begin(), buffer_[band][channel].end(), (*sub_frame)[band][channel].begin()); std::copy( - block[band][channel].begin(), - block[band][channel].begin() + samples_to_frame, + block.begin(band, channel), + block.begin(band, channel) + samples_to_frame, (*sub_frame)[band][channel].begin() + buffer_[band][channel].size()); buffer_[band][channel].clear(); buffer_[band][channel].insert( buffer_[band][channel].begin(), - block[band][channel].begin() + samples_to_frame, - block[band][channel].end()); + block.begin(band, channel) + samples_to_frame, + block.end(band, channel)); } } } diff --git a/modules/audio_processing/aec3/block_framer.h b/modules/audio_processing/aec3/block_framer.h index 1d378660c3..e2cdd5a17c 100644 --- a/modules/audio_processing/aec3/block_framer.h +++ b/modules/audio_processing/aec3/block_framer.h @@ -15,6 +15,7 @@ #include "api/array_view.h" #include "modules/audio_processing/aec3/aec3_common.h" +#include "modules/audio_processing/aec3/block.h" namespace webrtc { @@ -32,10 +33,10 @@ class BlockFramer { BlockFramer& operator=(const BlockFramer&) = delete; // Adds a 64 sample block into the data that will form the next output frame. - void InsertBlock(const std::vector>>& block); + void InsertBlock(const Block& block); // Adds a 64 sample block and extracts an 80 sample subframe. void InsertBlockAndExtractSubFrame( - const std::vector>>& block, + const Block& block, std::vector>>* sub_frame); private: diff --git a/modules/audio_processing/aec3/block_framer_unittest.cc b/modules/audio_processing/aec3/block_framer_unittest.cc index d67967bc02..9439623f72 100644 --- a/modules/audio_processing/aec3/block_framer_unittest.cc +++ b/modules/audio_processing/aec3/block_framer_unittest.cc @@ -64,14 +64,13 @@ bool VerifySubFrame( return true; } -void FillBlock(size_t block_counter, - std::vector>>* block) { - for (size_t band = 0; band < block->size(); ++band) { - for (size_t channel = 0; channel < (*block)[band].size(); ++channel) { - for (size_t sample = 0; sample < (*block)[band][channel].size(); - ++sample) { - (*block)[band][channel][sample] = ComputeSampleValue( - block_counter, kBlockSize, band, channel, sample, 0); +void FillBlock(size_t block_counter, Block* block) { + for (int band = 0; band < block->NumBands(); ++band) { + for (int channel = 0; channel < block->NumChannels(); ++channel) { + auto b = block->View(band, channel); + for (size_t sample = 0; sample < kBlockSize; ++sample) { + b[sample] = ComputeSampleValue(block_counter, kBlockSize, band, channel, + sample, 0); } } } @@ -82,9 +81,7 @@ void RunFramerTest(int sample_rate_hz, size_t num_channels) { constexpr size_t kNumSubFramesToProcess = 10; const size_t num_bands = NumBandsForRate(sample_rate_hz); - std::vector>> block( - num_bands, std::vector>( - num_channels, std::vector(kBlockSize, 0.f))); + Block block(num_bands, num_channels); std::vector>> output_sub_frame( num_bands, std::vector>( num_channels, std::vector(kSubFrameLength, 0.f))); @@ -117,16 +114,12 @@ void RunWronglySizedInsertAndExtractParametersTest( size_t correct_num_channels, size_t num_block_bands, size_t num_block_channels, - size_t block_length, size_t num_sub_frame_bands, size_t num_sub_frame_channels, size_t sub_frame_length) { const size_t correct_num_bands = NumBandsForRate(sample_rate_hz); - std::vector>> block( - num_block_bands, - std::vector>(num_block_channels, - std::vector(block_length, 0.f))); + Block block(num_block_bands, num_block_channels); std::vector>> output_sub_frame( num_sub_frame_bands, std::vector>( @@ -145,18 +138,11 @@ void RunWronglySizedInsertAndExtractParametersTest( void RunWronglySizedInsertParameterTest(int sample_rate_hz, size_t correct_num_channels, size_t num_block_bands, - size_t num_block_channels, - size_t block_length) { + size_t num_block_channels) { const size_t correct_num_bands = NumBandsForRate(sample_rate_hz); - std::vector>> correct_block( - correct_num_bands, - std::vector>(correct_num_channels, - std::vector(kBlockSize, 0.f))); - std::vector>> wrong_block( - num_block_bands, - std::vector>(num_block_channels, - std::vector(block_length, 0.f))); + Block correct_block(correct_num_bands, correct_num_channels); + Block wrong_block(num_block_bands, num_block_channels); std::vector>> output_sub_frame( correct_num_bands, std::vector>( @@ -183,10 +169,7 @@ void RunWronglyInsertOrderTest(int sample_rate_hz, size_t num_preceeding_api_calls) { const size_t correct_num_bands = NumBandsForRate(sample_rate_hz); - std::vector>> block( - correct_num_bands, - std::vector>(num_channels, - std::vector(kBlockSize, 0.f))); + Block block(correct_num_bands, num_channels); std::vector>> output_sub_frame( correct_num_bands, std::vector>( @@ -223,7 +206,7 @@ TEST(BlockFramerDeathTest, const size_t wrong_num_bands = (correct_num_bands % 3) + 1; RunWronglySizedInsertAndExtractParametersTest( rate, correct_num_channels, wrong_num_bands, correct_num_channels, - kBlockSize, correct_num_bands, correct_num_channels, kSubFrameLength); + correct_num_bands, correct_num_channels, kSubFrameLength); } } } @@ -237,7 +220,7 @@ TEST(BlockFramerDeathTest, const size_t wrong_num_channels = correct_num_channels + 1; RunWronglySizedInsertAndExtractParametersTest( rate, correct_num_channels, correct_num_bands, wrong_num_channels, - kBlockSize, correct_num_bands, correct_num_channels, kSubFrameLength); + correct_num_bands, correct_num_channels, kSubFrameLength); } } } @@ -251,7 +234,7 @@ TEST(BlockFramerDeathTest, const size_t wrong_num_bands = (correct_num_bands % 3) + 1; RunWronglySizedInsertAndExtractParametersTest( rate, correct_num_channels, correct_num_bands, correct_num_channels, - kBlockSize, wrong_num_bands, correct_num_channels, kSubFrameLength); + wrong_num_bands, correct_num_channels, kSubFrameLength); } } } @@ -265,21 +248,7 @@ TEST(BlockFramerDeathTest, const size_t wrong_num_channels = correct_num_channels + 1; RunWronglySizedInsertAndExtractParametersTest( rate, correct_num_channels, correct_num_bands, correct_num_channels, - kBlockSize, correct_num_bands, wrong_num_channels, kSubFrameLength); - } - } -} - -TEST(BlockFramerDeathTest, - WrongNumberOfSamplesInBlockForInsertBlockAndExtractSubFrame) { - for (auto rate : {16000, 32000, 48000}) { - for (auto correct_num_channels : {1, 2, 8}) { - SCOPED_TRACE(ProduceDebugText(rate, correct_num_channels)); - const size_t correct_num_bands = NumBandsForRate(rate); - RunWronglySizedInsertAndExtractParametersTest( - rate, correct_num_channels, correct_num_bands, correct_num_channels, - kBlockSize - 1, correct_num_bands, correct_num_channels, - kSubFrameLength); + correct_num_bands, wrong_num_channels, kSubFrameLength); } } } @@ -292,8 +261,7 @@ TEST(BlockFramerDeathTest, const size_t correct_num_bands = NumBandsForRate(rate); RunWronglySizedInsertAndExtractParametersTest( rate, correct_num_channels, correct_num_bands, correct_num_channels, - kBlockSize, correct_num_bands, correct_num_channels, - kSubFrameLength - 1); + correct_num_bands, correct_num_channels, kSubFrameLength - 1); } } @@ -304,8 +272,7 @@ TEST(BlockFramerDeathTest, WrongNumberOfBandsInBlockForInsertBlock) { const size_t correct_num_bands = NumBandsForRate(rate); const size_t wrong_num_bands = (correct_num_bands % 3) + 1; RunWronglySizedInsertParameterTest(rate, correct_num_channels, - wrong_num_bands, correct_num_channels, - kBlockSize); + wrong_num_bands, correct_num_channels); } } } @@ -317,20 +284,7 @@ TEST(BlockFramerDeathTest, WrongNumberOfChannelsInBlockForInsertBlock) { const size_t correct_num_bands = NumBandsForRate(rate); const size_t wrong_num_channels = correct_num_channels + 1; RunWronglySizedInsertParameterTest(rate, correct_num_channels, - correct_num_bands, wrong_num_channels, - kBlockSize); - } - } -} - -TEST(BlockFramerDeathTest, WrongNumberOfSamplesInBlockForInsertBlock) { - for (auto rate : {16000, 32000, 48000}) { - for (auto correct_num_channels : {1, 2, 8}) { - SCOPED_TRACE(ProduceDebugText(rate, correct_num_channels)); - const size_t correct_num_bands = NumBandsForRate(rate); - RunWronglySizedInsertParameterTest(rate, correct_num_channels, - correct_num_bands, - correct_num_channels, kBlockSize - 1); + correct_num_bands, wrong_num_channels); } } } @@ -364,12 +318,9 @@ TEST(BlockFramerDeathTest, ZeroNumberOfBandsParameter) { // Verifies that the verification for null sub_frame pointer works. TEST(BlockFramerDeathTest, NullSubFrameParameter) { - EXPECT_DEATH(BlockFramer(1, 1).InsertBlockAndExtractSubFrame( - std::vector>>( - 1, std::vector>( - 1, std::vector(kBlockSize, 0.f))), - nullptr), - ""); + EXPECT_DEATH( + BlockFramer(1, 1).InsertBlockAndExtractSubFrame(Block(1, 1), nullptr), + ""); } #endif diff --git a/modules/audio_processing/aec3/block_processor.cc b/modules/audio_processing/aec3/block_processor.cc index 2ee32b82dc..4525cc9d66 100644 --- a/modules/audio_processing/aec3/block_processor.cc +++ b/modules/audio_processing/aec3/block_processor.cc @@ -49,14 +49,12 @@ class BlockProcessorImpl final : public BlockProcessor { ~BlockProcessorImpl() override; - void ProcessCapture( - bool echo_path_gain_change, - bool capture_signal_saturation, - std::vector>>* linear_output, - std::vector>>* capture_block) override; + void ProcessCapture(bool echo_path_gain_change, + bool capture_signal_saturation, + Block* linear_output, + Block* capture_block) override; - void BufferRender( - const std::vector>>& block) override; + void BufferRender(const Block& block) override; void UpdateEchoLeakageStatus(bool leakage_detected) override; @@ -104,21 +102,20 @@ BlockProcessorImpl::BlockProcessorImpl( BlockProcessorImpl::~BlockProcessorImpl() = default; -void BlockProcessorImpl::ProcessCapture( - bool echo_path_gain_change, - bool capture_signal_saturation, - std::vector>>* linear_output, - std::vector>>* capture_block) { +void BlockProcessorImpl::ProcessCapture(bool echo_path_gain_change, + bool capture_signal_saturation, + Block* linear_output, + Block* capture_block) { RTC_DCHECK(capture_block); - RTC_DCHECK_EQ(NumBandsForRate(sample_rate_hz_), capture_block->size()); - RTC_DCHECK_EQ(kBlockSize, (*capture_block)[0][0].size()); + RTC_DCHECK_EQ(NumBandsForRate(sample_rate_hz_), capture_block->NumBands()); capture_call_counter_++; data_dumper_->DumpRaw("aec3_processblock_call_order", static_cast(BlockProcessorApiCall::kCapture)); - data_dumper_->DumpWav("aec3_processblock_capture_input", kBlockSize, - &(*capture_block)[0][0][0], 16000, 1); + data_dumper_->DumpWav("aec3_processblock_capture_input", + capture_block->View(/*band=*/0, /*channel=*/0), 16000, + 1); if (render_properly_started_) { if (!capture_properly_started_) { @@ -159,8 +156,9 @@ void BlockProcessorImpl::ProcessCapture( delay_controller_->Reset(false); } - data_dumper_->DumpWav("aec3_processblock_capture_input2", kBlockSize, - &(*capture_block)[0][0][0], 16000, 1); + data_dumper_->DumpWav("aec3_processblock_capture_input2", + capture_block->View(/*band=*/0, /*channel=*/0), 16000, + 1); bool has_delay_estimator = !config_.delay.use_external_delay_estimator; if (has_delay_estimator) { @@ -169,7 +167,7 @@ void BlockProcessorImpl::ProcessCapture( // alignment. estimated_delay_ = delay_controller_->GetDelay( render_buffer_->GetDownsampledRenderBuffer(), render_buffer_->Delay(), - (*capture_block)[0]); + *capture_block); if (estimated_delay_) { bool delay_change = @@ -202,16 +200,14 @@ void BlockProcessorImpl::ProcessCapture( metrics_.UpdateCapture(false); } -void BlockProcessorImpl::BufferRender( - const std::vector>>& block) { - RTC_DCHECK_EQ(NumBandsForRate(sample_rate_hz_), block.size()); - RTC_DCHECK_EQ(kBlockSize, block[0][0].size()); +void BlockProcessorImpl::BufferRender(const Block& block) { + RTC_DCHECK_EQ(NumBandsForRate(sample_rate_hz_), block.NumBands()); data_dumper_->DumpRaw("aec3_processblock_call_order", static_cast(BlockProcessorApiCall::kRender)); - data_dumper_->DumpWav("aec3_processblock_render_input", kBlockSize, - &block[0][0][0], 16000, 1); - data_dumper_->DumpWav("aec3_processblock_render_input2", kBlockSize, - &block[0][0][0], 16000, 1); + data_dumper_->DumpWav("aec3_processblock_render_input", + block.View(/*band=*/0, /*channel=*/0), 16000, 1); + data_dumper_->DumpWav("aec3_processblock_render_input2", + block.View(/*band=*/0, /*channel=*/0), 16000, 1); render_event_ = render_buffer_->Insert(block); diff --git a/modules/audio_processing/aec3/block_processor.h b/modules/audio_processing/aec3/block_processor.h index 41ce016dc0..01a83ae5f7 100644 --- a/modules/audio_processing/aec3/block_processor.h +++ b/modules/audio_processing/aec3/block_processor.h @@ -18,6 +18,7 @@ #include "api/audio/echo_canceller3_config.h" #include "api/audio/echo_control.h" +#include "modules/audio_processing/aec3/block.h" #include "modules/audio_processing/aec3/echo_remover.h" #include "modules/audio_processing/aec3/render_delay_buffer.h" #include "modules/audio_processing/aec3/render_delay_controller.h" @@ -56,15 +57,13 @@ class BlockProcessor { virtual void SetAudioBufferDelay(int delay_ms) = 0; // Processes a block of capture data. - virtual void ProcessCapture( - bool echo_path_gain_change, - bool capture_signal_saturation, - std::vector>>* linear_output, - std::vector>>* capture_block) = 0; + virtual void ProcessCapture(bool echo_path_gain_change, + bool capture_signal_saturation, + Block* linear_output, + Block* capture_block) = 0; // Buffers a block of render data supplied by a FrameBlocker object. - virtual void BufferRender( - const std::vector>>& render_block) = 0; + virtual void BufferRender(const Block& render_block) = 0; // Reports whether echo leakage has been detected in the echo canceller // output. diff --git a/modules/audio_processing/aec3/block_processor_unittest.cc b/modules/audio_processing/aec3/block_processor_unittest.cc index d87e27a927..535762140d 100644 --- a/modules/audio_processing/aec3/block_processor_unittest.cc +++ b/modules/audio_processing/aec3/block_processor_unittest.cc @@ -43,10 +43,7 @@ void RunBasicSetupAndApiCallTest(int sample_rate_hz, int num_iterations) { std::unique_ptr block_processor( BlockProcessor::Create(EchoCanceller3Config(), sample_rate_hz, kNumRenderChannels, kNumCaptureChannels)); - std::vector>> block( - NumBandsForRate(sample_rate_hz), - std::vector>(kNumRenderChannels, - std::vector(kBlockSize, 1000.f))); + Block block(NumBandsForRate(sample_rate_hz), kNumRenderChannels, 1000.f); for (int k = 0; k < num_iterations; ++k) { block_processor->BufferRender(block); block_processor->ProcessCapture(false, false, nullptr, &block); @@ -62,30 +59,11 @@ void RunRenderBlockSizeVerificationTest(int sample_rate_hz) { std::unique_ptr block_processor( BlockProcessor::Create(EchoCanceller3Config(), sample_rate_hz, kNumRenderChannels, kNumCaptureChannels)); - std::vector>> block( - NumBandsForRate(sample_rate_hz), - std::vector>(kNumRenderChannels, - std::vector(kBlockSize - 1, 0.f))); + Block block(NumBandsForRate(sample_rate_hz), kNumRenderChannels); EXPECT_DEATH(block_processor->BufferRender(block), ""); } -void RunCaptureBlockSizeVerificationTest(int sample_rate_hz) { - constexpr size_t kNumRenderChannels = 1; - constexpr size_t kNumCaptureChannels = 1; - - std::unique_ptr block_processor( - BlockProcessor::Create(EchoCanceller3Config(), sample_rate_hz, - kNumRenderChannels, kNumCaptureChannels)); - std::vector>> block( - NumBandsForRate(sample_rate_hz), - std::vector>(kNumRenderChannels, - std::vector(kBlockSize - 1, 0.f))); - - EXPECT_DEATH(block_processor->ProcessCapture(false, false, nullptr, &block), - ""); -} - void RunRenderNumBandsVerificationTest(int sample_rate_hz) { constexpr size_t kNumRenderChannels = 1; constexpr size_t kNumCaptureChannels = 1; @@ -96,10 +74,7 @@ void RunRenderNumBandsVerificationTest(int sample_rate_hz) { std::unique_ptr block_processor( BlockProcessor::Create(EchoCanceller3Config(), sample_rate_hz, kNumRenderChannels, kNumCaptureChannels)); - std::vector>> block( - wrong_num_bands, - std::vector>(kNumRenderChannels, - std::vector(kBlockSize, 0.f))); + Block block(wrong_num_bands, kNumRenderChannels); EXPECT_DEATH(block_processor->BufferRender(block), ""); } @@ -114,10 +89,7 @@ void RunCaptureNumBandsVerificationTest(int sample_rate_hz) { std::unique_ptr block_processor( BlockProcessor::Create(EchoCanceller3Config(), sample_rate_hz, kNumRenderChannels, kNumCaptureChannels)); - std::vector>> block( - wrong_num_bands, - std::vector>(kNumRenderChannels, - std::vector(kBlockSize, 0.f))); + Block block(wrong_num_bands, kNumRenderChannels); EXPECT_DEATH(block_processor->ProcessCapture(false, false, nullptr, &block), ""); @@ -170,18 +142,14 @@ TEST(BlockProcessor, DISABLED_DelayControllerIntegration) { EchoCanceller3Config(), rate, kNumRenderChannels, kNumCaptureChannels, std::move(render_delay_buffer_mock))); - std::vector>> render_block( - NumBandsForRate(rate), - std::vector>(kNumRenderChannels, - std::vector(kBlockSize, 0.f))); - std::vector>> capture_block( - NumBandsForRate(rate), - std::vector>(kNumCaptureChannels, - std::vector(kBlockSize, 0.f))); + Block render_block(NumBandsForRate(rate), kNumRenderChannels); + Block capture_block(NumBandsForRate(rate), kNumCaptureChannels); DelayBuffer signal_delay_buffer(kDelayInSamples); for (size_t k = 0; k < kNumBlocks; ++k) { - RandomizeSampleVector(&random_generator, render_block[0][0]); - signal_delay_buffer.Delay(render_block[0][0], capture_block[0][0]); + RandomizeSampleVector(&random_generator, + render_block.View(/*band=*/0, /*capture=*/0)); + signal_delay_buffer.Delay(render_block.View(/*band=*/0, /*capture=*/0), + capture_block.View(/*band=*/0, /*capture=*/0)); block_processor->BufferRender(render_block); block_processor->ProcessCapture(false, false, nullptr, &capture_block); } @@ -228,18 +196,14 @@ TEST(BlockProcessor, DISABLED_SubmoduleIntegration) { std::move(render_delay_buffer_mock), std::move(render_delay_controller_mock), std::move(echo_remover_mock))); - std::vector>> render_block( - NumBandsForRate(rate), - std::vector>(kNumRenderChannels, - std::vector(kBlockSize, 0.f))); - std::vector>> capture_block( - NumBandsForRate(rate), - std::vector>(kNumCaptureChannels, - std::vector(kBlockSize, 0.f))); + Block render_block(NumBandsForRate(rate), kNumRenderChannels); + Block capture_block(NumBandsForRate(rate), kNumCaptureChannels); DelayBuffer signal_delay_buffer(640); for (size_t k = 0; k < kNumBlocks; ++k) { - RandomizeSampleVector(&random_generator, render_block[0][0]); - signal_delay_buffer.Delay(render_block[0][0], capture_block[0][0]); + RandomizeSampleVector(&random_generator, + render_block.View(/*band=*/0, /*capture=*/0)); + signal_delay_buffer.Delay(render_block.View(/*band=*/0, /*capture=*/0), + capture_block.View(/*band=*/0, /*capture=*/0)); block_processor->BufferRender(render_block); block_processor->ProcessCapture(false, false, nullptr, &capture_block); block_processor->UpdateEchoLeakageStatus(false); @@ -268,13 +232,6 @@ TEST(BlockProcessorDeathTest, DISABLED_VerifyRenderBlockSizeCheck) { } } -TEST(BlockProcessorDeathTest, VerifyCaptureBlockSizeCheck) { - for (auto rate : {16000, 32000, 48000}) { - SCOPED_TRACE(ProduceDebugText(rate)); - RunCaptureBlockSizeVerificationTest(rate); - } -} - TEST(BlockProcessorDeathTest, VerifyRenderNumBandsCheck) { for (auto rate : {16000, 32000, 48000}) { SCOPED_TRACE(ProduceDebugText(rate)); @@ -333,14 +290,8 @@ TEST(BlockProcessor, ExternalDelayAppliedCorrectlyWithInitialCaptureCalls) { std::move(delay_buffer), /*delay_controller=*/nullptr, std::move(echo_remover_mock))); - std::vector>> render_block( - NumBandsForRate(kSampleRateHz), - std::vector>(kNumRenderChannels, - std::vector(kBlockSize, 0.f))); - std::vector>> capture_block( - NumBandsForRate(kSampleRateHz), - std::vector>(kNumCaptureChannels, - std::vector(kBlockSize, 0.f))); + Block render_block(NumBandsForRate(kSampleRateHz), kNumRenderChannels); + Block capture_block(NumBandsForRate(kSampleRateHz), kNumCaptureChannels); // Process... // - 10 capture calls, where no render data is available, @@ -354,11 +305,12 @@ TEST(BlockProcessor, ExternalDelayAppliedCorrectlyWithInitialCaptureCalls) { int render_call_counter = 0; for (size_t k = 0; k < 10; ++k) { FillSampleVector(++capture_call_counter, kDelayInBlocks, - capture_block[0][0]); + capture_block.View(/*band=*/0, /*capture=*/0)); block_processor->ProcessCapture(false, false, nullptr, &capture_block); } for (size_t k = 0; k < 10; ++k) { - FillSampleVector(++render_call_counter, 0, render_block[0][0]); + FillSampleVector(++render_call_counter, 0, + render_block.View(/*band=*/0, /*capture=*/0)); block_processor->BufferRender(render_block); } @@ -367,19 +319,22 @@ TEST(BlockProcessor, ExternalDelayAppliedCorrectlyWithInitialCaptureCalls) { [](EchoPathVariability /*echo_path_variability*/, bool /*capture_signal_saturation*/, const absl::optional& /*external_delay*/, - RenderBuffer* render_buffer, - std::vector>>* /*linear_output*/, - std::vector>>* capture) { + RenderBuffer* render_buffer, Block* /*linear_output*/, + Block* capture) { const auto& render = render_buffer->Block(0); + const auto render_view = render.View(/*band=*/0, /*channel=*/0); + const auto capture_view = capture->View(/*band=*/0, /*channel=*/0); for (size_t i = 0; i < kBlockSize; ++i) { - EXPECT_FLOAT_EQ(render[0][0][i], (*capture)[0][0][i]); + EXPECT_FLOAT_EQ(render_view[i], capture_view[i]); } }); - FillSampleVector(++capture_call_counter, kDelayInBlocks, capture_block[0][0]); + FillSampleVector(++capture_call_counter, kDelayInBlocks, + capture_block.View(/*band=*/0, /*capture=*/0)); block_processor->ProcessCapture(false, false, nullptr, &capture_block); - FillSampleVector(++capture_call_counter, kDelayInBlocks, capture_block[0][0]); + FillSampleVector(++capture_call_counter, kDelayInBlocks, + capture_block.View(/*band=*/0, /*capture=*/0)); block_processor->ProcessCapture(false, false, nullptr, &capture_block); } diff --git a/modules/audio_processing/aec3/coarse_filter_update_gain_unittest.cc b/modules/audio_processing/aec3/coarse_filter_update_gain_unittest.cc index 92775cf702..55b79bb812 100644 --- a/modules/audio_processing/aec3/coarse_filter_update_gain_unittest.cc +++ b/modules/audio_processing/aec3/coarse_filter_update_gain_unittest.cc @@ -59,10 +59,7 @@ void RunFilterUpdateTest(int num_blocks_to_process, CoarseFilterUpdateGain coarse_gain( config.filter.coarse, config.filter.config_change_duration_blocks); Random random_generator(42U); - std::vector>> x( - NumBandsForRate(kSampleRateHz), - std::vector>(num_render_channels, - std::vector(kBlockSize, 0.f))); + Block x(NumBandsForRate(kSampleRateHz), num_render_channels); std::array y; RenderSignalAnalyzer render_signal_analyzer(config); std::array s; @@ -81,12 +78,12 @@ void RunFilterUpdateTest(int num_blocks_to_process, k) != blocks_with_saturation.end(); // Create the render signal. - for (size_t band = 0; band < x.size(); ++band) { - for (size_t channel = 0; channel < x[band].size(); ++channel) { - RandomizeSampleVector(&random_generator, x[band][channel]); + for (int band = 0; band < x.NumBands(); ++band) { + for (int channel = 0; channel < x.NumChannels(); ++channel) { + RandomizeSampleVector(&random_generator, x.View(band, channel)); } } - delay_buffer.Delay(x[0][0], y); + delay_buffer.Delay(x.View(/*band=*/0, /*channel*/ 0), y); render_delay_buffer->Insert(x); if (k == 0) { diff --git a/modules/audio_processing/aec3/echo_audibility.cc b/modules/audio_processing/aec3/echo_audibility.cc index 6ae414e3cf..142a33d5e0 100644 --- a/modules/audio_processing/aec3/echo_audibility.cc +++ b/modules/audio_processing/aec3/echo_audibility.cc @@ -88,7 +88,7 @@ void EchoAudibility::UpdateRenderNoiseEstimator( bool EchoAudibility::IsRenderTooLow(const BlockBuffer& block_buffer) { const int num_render_channels = - static_cast(block_buffer.buffer[0][0].size()); + static_cast(block_buffer.buffer[0].NumChannels()); bool too_low = false; const int render_block_write_current = block_buffer.write; if (render_block_write_current == render_block_write_prev_) { @@ -98,7 +98,8 @@ bool EchoAudibility::IsRenderTooLow(const BlockBuffer& block_buffer) { idx = block_buffer.IncIndex(idx)) { float max_abs_over_channels = 0.f; for (int ch = 0; ch < num_render_channels; ++ch) { - auto block = block_buffer.buffer[idx][0][ch]; + rtc::ArrayView block = + block_buffer.buffer[idx].View(/*band=*/0, /*channel=*/ch); auto r = std::minmax_element(block.cbegin(), block.cend()); float max_abs_channel = std::max(std::fabs(*r.first), std::fabs(*r.second)); diff --git a/modules/audio_processing/aec3/echo_canceller3.cc b/modules/audio_processing/aec3/echo_canceller3.cc index 36bf8769f4..f4e3541071 100644 --- a/modules/audio_processing/aec3/echo_canceller3.cc +++ b/modules/audio_processing/aec3/echo_canceller3.cc @@ -154,10 +154,10 @@ void ProcessCaptureFrameContent( BlockFramer* linear_output_framer, BlockFramer* output_framer, BlockProcessor* block_processor, - std::vector>>* linear_output_block, + Block* linear_output_block, std::vector>>* linear_output_sub_frame_view, - std::vector>>* capture_block, + Block* capture_block, std::vector>>* capture_sub_frame_view) { FillSubFrameView(capture, sub_frame_index, capture_sub_frame_view); @@ -171,10 +171,10 @@ void ProcessCaptureFrameContent( capture_blocker->InsertSubFrameAndExtractBlock(*capture_sub_frame_view, capture_block); - block_processor->ProcessCapture(/*echo_path_gain_change=*/level_change || - aec_reference_is_downmixed_stereo, - saturated_microphone_signal, - linear_output_block, capture_block); + block_processor->ProcessCapture( + /*echo_path_gain_change=*/level_change || + aec_reference_is_downmixed_stereo, + saturated_microphone_signal, linear_output_block, capture_block); output_framer->InsertBlockAndExtractSubFrame(*capture_block, capture_sub_frame_view); @@ -185,16 +185,15 @@ void ProcessCaptureFrameContent( } } -void ProcessRemainingCaptureFrameContent( - bool level_change, - bool aec_reference_is_downmixed_stereo, - bool saturated_microphone_signal, - FrameBlocker* capture_blocker, - BlockFramer* linear_output_framer, - BlockFramer* output_framer, - BlockProcessor* block_processor, - std::vector>>* linear_output_block, - std::vector>>* block) { +void ProcessRemainingCaptureFrameContent(bool level_change, + bool aec_reference_is_downmixed_stereo, + bool saturated_microphone_signal, + FrameBlocker* capture_blocker, + BlockFramer* linear_output_framer, + BlockFramer* output_framer, + BlockProcessor* block_processor, + Block* linear_output_block, + Block* block) { if (!capture_blocker->IsBlockAvailable()) { return; } @@ -218,7 +217,7 @@ void BufferRenderFrameContent( size_t sub_frame_index, FrameBlocker* render_blocker, BlockProcessor* block_processor, - std::vector>>* block, + Block* block, std::vector>>* sub_frame_view) { FillSubFrameView(proper_downmix_needed, render_frame, sub_frame_index, sub_frame_view); @@ -226,10 +225,9 @@ void BufferRenderFrameContent( block_processor->BufferRender(*block); } -void BufferRemainingRenderFrameContent( - FrameBlocker* render_blocker, - BlockProcessor* block_processor, - std::vector>>* block) { +void BufferRemainingRenderFrameContent(FrameBlocker* render_blocker, + BlockProcessor* block_processor, + Block* block) { if (!render_blocker->IsBlockAvailable()) { return; } @@ -753,14 +751,8 @@ EchoCanceller3::EchoCanceller3( std::vector>( num_render_input_channels_, std::vector(AudioBuffer::kSplitBandSize, 0.f))), - render_block_( - num_bands_, - std::vector>(num_render_input_channels_, - std::vector(kBlockSize, 0.f))), - capture_block_( - num_bands_, - std::vector>(num_capture_channels_, - std::vector(kBlockSize, 0.f))), + render_block_(num_bands_, num_render_input_channels_), + capture_block_(num_bands_, num_capture_channels_), capture_sub_frame_view_( num_bands_, std::vector>(num_capture_channels_)) { @@ -780,11 +772,10 @@ EchoCanceller3::EchoCanceller3( RTC_DCHECK_GE(kMaxNumBands, num_bands_); if (config_selector_.active_config().filter.export_linear_aec_output) { - linear_output_framer_.reset(new BlockFramer(1, num_capture_channels_)); + linear_output_framer_.reset( + new BlockFramer(/*num_bands=*/1, num_capture_channels_)); linear_output_block_ = - std::make_unique>>>( - 1, std::vector>( - num_capture_channels_, std::vector(kBlockSize, 0.f))); + std::make_unique(/*num_bands=*/1, num_capture_channels_), linear_output_sub_frame_view_ = std::vector>>( 1, std::vector>(num_capture_channels_)); @@ -810,12 +801,7 @@ void EchoCanceller3::Initialize() { config_selector_.Update( multichannel_content_detector_.IsProperMultiChannelContentDetected()); - for (std::vector>& block_band : render_block_) { - block_band.resize(num_render_channels_to_aec_); - for (std::vector& block_channel : block_band) { - block_channel.resize(kBlockSize, 0.0f); - } - } + render_block_.SetNumChannels(num_render_channels_to_aec_); render_blocker_.reset( new FrameBlocker(num_bands_, num_render_channels_to_aec_)); diff --git a/modules/audio_processing/aec3/echo_canceller3.h b/modules/audio_processing/aec3/echo_canceller3.h index 831a7c738a..179659a032 100644 --- a/modules/audio_processing/aec3/echo_canceller3.h +++ b/modules/audio_processing/aec3/echo_canceller3.h @@ -210,12 +210,10 @@ class EchoCanceller3 : public EchoControl { RTC_GUARDED_BY(capture_race_checker_); bool saturated_microphone_signal_ RTC_GUARDED_BY(capture_race_checker_) = false; - std::vector>> render_block_ - RTC_GUARDED_BY(capture_race_checker_); - std::unique_ptr>>> - linear_output_block_ RTC_GUARDED_BY(capture_race_checker_); - std::vector>> capture_block_ + Block render_block_ RTC_GUARDED_BY(capture_race_checker_); + std::unique_ptr linear_output_block_ RTC_GUARDED_BY(capture_race_checker_); + Block capture_block_ RTC_GUARDED_BY(capture_race_checker_); std::vector>> render_sub_frame_view_ RTC_GUARDED_BY(capture_race_checker_); std::vector>> linear_output_sub_frame_view_ diff --git a/modules/audio_processing/aec3/echo_canceller3_unittest.cc b/modules/audio_processing/aec3/echo_canceller3_unittest.cc index 9a2df48dde..ad126af4d3 100644 --- a/modules/audio_processing/aec3/echo_canceller3_unittest.cc +++ b/modules/audio_processing/aec3/echo_canceller3_unittest.cc @@ -117,14 +117,12 @@ class CaptureTransportVerificationProcessor : public BlockProcessor { ~CaptureTransportVerificationProcessor() override = default; - void ProcessCapture( - bool level_change, - bool saturated_microphone_signal, - std::vector>>* linear_output, - std::vector>>* capture_block) override {} + void ProcessCapture(bool level_change, + bool saturated_microphone_signal, + Block* linear_output, + Block* capture_block) override {} - void BufferRender( - const std::vector>>& block) override {} + void BufferRender(const Block& block) override {} void UpdateEchoLeakageStatus(bool leakage_detected) override {} @@ -149,19 +147,16 @@ class RenderTransportVerificationProcessor : public BlockProcessor { ~RenderTransportVerificationProcessor() override = default; - void ProcessCapture( - bool level_change, - bool saturated_microphone_signal, - std::vector>>* linear_output, - std::vector>>* capture_block) override { - std::vector>> render_block = - received_render_blocks_.front(); + void ProcessCapture(bool level_change, + bool saturated_microphone_signal, + Block* linear_output, + Block* capture_block) override { + Block render_block = received_render_blocks_.front(); received_render_blocks_.pop_front(); - capture_block->swap(render_block); + capture_block->Swap(render_block); } - void BufferRender( - const std::vector>>& block) override { + void BufferRender(const Block& block) override { received_render_blocks_.push_back(block); } @@ -174,8 +169,7 @@ class RenderTransportVerificationProcessor : public BlockProcessor { void SetCaptureOutputUsage(bool capture_output_used) {} private: - std::deque>>> - received_render_blocks_; + std::deque received_render_blocks_; }; std::string ProduceDebugText(int sample_rate_hz) { diff --git a/modules/audio_processing/aec3/echo_path_delay_estimator.cc b/modules/audio_processing/aec3/echo_path_delay_estimator.cc index 8a78834143..e64c4493f6 100644 --- a/modules/audio_processing/aec3/echo_path_delay_estimator.cc +++ b/modules/audio_processing/aec3/echo_path_delay_estimator.cc @@ -59,9 +59,7 @@ void EchoPathDelayEstimator::Reset(bool reset_delay_confidence) { absl::optional EchoPathDelayEstimator::EstimateDelay( const DownsampledRenderBuffer& render_buffer, - const std::vector>& capture) { - RTC_DCHECK_EQ(kBlockSize, capture[0].size()); - + const Block& capture) { std::array downsampled_capture_data; rtc::ArrayView downsampled_capture(downsampled_capture_data.data(), sub_block_size_); diff --git a/modules/audio_processing/aec3/echo_path_delay_estimator.h b/modules/audio_processing/aec3/echo_path_delay_estimator.h index d8f97757bb..b24d0a29ec 100644 --- a/modules/audio_processing/aec3/echo_path_delay_estimator.h +++ b/modules/audio_processing/aec3/echo_path_delay_estimator.h @@ -16,6 +16,7 @@ #include "absl/types/optional.h" #include "api/array_view.h" #include "modules/audio_processing/aec3/alignment_mixer.h" +#include "modules/audio_processing/aec3/block.h" #include "modules/audio_processing/aec3/clockdrift_detector.h" #include "modules/audio_processing/aec3/decimator.h" #include "modules/audio_processing/aec3/delay_estimate.h" @@ -46,7 +47,7 @@ class EchoPathDelayEstimator { // Produce a delay estimate if such is avaliable. absl::optional EstimateDelay( const DownsampledRenderBuffer& render_buffer, - const std::vector>& capture); + const Block& capture); // Log delay estimator properties. void LogDelayEstimationProperties(int sample_rate_hz, size_t shift) const { diff --git a/modules/audio_processing/aec3/echo_path_delay_estimator_unittest.cc b/modules/audio_processing/aec3/echo_path_delay_estimator_unittest.cc index 6ba4cdd0d7..13c9c1122e 100644 --- a/modules/audio_processing/aec3/echo_path_delay_estimator_unittest.cc +++ b/modules/audio_processing/aec3/echo_path_delay_estimator_unittest.cc @@ -54,11 +54,8 @@ TEST_P(EchoPathDelayEstimatorMultiChannel, BasicApiCalls) { std::unique_ptr render_delay_buffer( RenderDelayBuffer::Create(config, kSampleRateHz, num_render_channels)); EchoPathDelayEstimator estimator(&data_dumper, config, num_capture_channels); - std::vector>> render( - kNumBands, std::vector>( - num_render_channels, std::vector(kBlockSize))); - std::vector> capture(num_capture_channels, - std::vector(kBlockSize)); + Block render(kNumBands, num_render_channels); + Block capture(/*num_bands=*/1, num_capture_channels); for (size_t k = 0; k < 100; ++k) { render_delay_buffer->Insert(render); estimator.EstimateDelay(render_delay_buffer->GetDownsampledRenderBuffer(), @@ -75,11 +72,8 @@ TEST(EchoPathDelayEstimator, DelayEstimation) { constexpr size_t kNumBands = NumBandsForRate(kSampleRateHz); Random random_generator(42U); - std::vector>> render( - kNumBands, std::vector>( - kNumRenderChannels, std::vector(kBlockSize))); - std::vector> capture(kNumCaptureChannels, - std::vector(kBlockSize)); + Block render(kNumBands, kNumRenderChannels); + Block capture(/*num_bands=*/1, kNumCaptureChannels); ApmDataDumper data_dumper(0); constexpr size_t kDownSamplingFactors[] = {2, 4, 8}; for (auto down_sampling_factor : kDownSamplingFactors) { @@ -96,8 +90,10 @@ TEST(EchoPathDelayEstimator, DelayEstimation) { absl::optional estimated_delay_samples; for (size_t k = 0; k < (500 + (delay_samples) / kBlockSize); ++k) { - RandomizeSampleVector(&random_generator, render[0][0]); - signal_delay_buffer.Delay(render[0][0], capture[0]); + RandomizeSampleVector(&random_generator, + render.View(/*band=*/0, /*channel=*/0)); + signal_delay_buffer.Delay(render.View(/*band=*/0, /*channel=*/0), + capture.View(/*band=*/0, /*channel=*/0)); render_delay_buffer->Insert(render); if (k == 0) { @@ -137,22 +133,22 @@ TEST(EchoPathDelayEstimator, NoDelayEstimatesForLowLevelRenderSignals) { constexpr size_t kNumBands = NumBandsForRate(kSampleRateHz); Random random_generator(42U); EchoCanceller3Config config; - std::vector>> render( - kNumBands, std::vector>( - kNumRenderChannels, std::vector(kBlockSize))); - std::vector> capture(kNumCaptureChannels, - std::vector(kBlockSize)); + Block render(kNumBands, kNumRenderChannels); + Block capture(/*num_bands=*/1, kNumCaptureChannels); ApmDataDumper data_dumper(0); EchoPathDelayEstimator estimator(&data_dumper, config, kNumCaptureChannels); std::unique_ptr render_delay_buffer( RenderDelayBuffer::Create(EchoCanceller3Config(), kSampleRateHz, kNumRenderChannels)); for (size_t k = 0; k < 100; ++k) { - RandomizeSampleVector(&random_generator, render[0][0]); - for (auto& render_k : render[0][0]) { + RandomizeSampleVector(&random_generator, + render.View(/*band=*/0, /*channel=*/0)); + for (auto& render_k : render.View(/*band=*/0, /*channel=*/0)) { render_k *= 100.f / 32767.f; } - std::copy(render[0][0].begin(), render[0][0].end(), capture[0].begin()); + std::copy(render.begin(/*band=*/0, /*channel=*/0), + render.end(/*band=*/0, /*channel=*/0), + capture.begin(/*band*/ 0, /*channel=*/0)); render_delay_buffer->Insert(render); render_delay_buffer->PrepareCaptureProcessing(); EXPECT_FALSE(estimator.EstimateDelay( @@ -171,23 +167,7 @@ TEST(EchoPathDelayEstimatorDeathTest, DISABLED_WrongRenderBlockSize) { EchoPathDelayEstimator estimator(&data_dumper, config, 1); std::unique_ptr render_delay_buffer( RenderDelayBuffer::Create(config, 48000, 1)); - std::vector> capture(1, std::vector(kBlockSize)); - EXPECT_DEATH(estimator.EstimateDelay( - render_delay_buffer->GetDownsampledRenderBuffer(), capture), - ""); -} - -// Verifies the check for the capture blocksize. -// TODO(peah): Re-enable the test once the issue with memory leaks during DEATH -// tests on test bots has been fixed. -TEST(EchoPathDelayEstimatorDeathTest, WrongCaptureBlockSize) { - ApmDataDumper data_dumper(0); - EchoCanceller3Config config; - EchoPathDelayEstimator estimator(&data_dumper, config, 1); - std::unique_ptr render_delay_buffer( - RenderDelayBuffer::Create(config, 48000, 1)); - std::vector> capture(1, - std::vector(kBlockSize - 1)); + Block capture(/*num_bands=*/1, /*num_channels=*/1); EXPECT_DEATH(estimator.EstimateDelay( render_delay_buffer->GetDownsampledRenderBuffer(), capture), ""); diff --git a/modules/audio_processing/aec3/echo_remover.cc b/modules/audio_processing/aec3/echo_remover.cc index 2bfaa951d8..09b5da3a04 100644 --- a/modules/audio_processing/aec3/echo_remover.cc +++ b/modules/audio_processing/aec3/echo_remover.cc @@ -118,13 +118,12 @@ class EchoRemoverImpl final : public EchoRemover { // Removes the echo from a block of samples from the capture signal. The // supplied render signal is assumed to be pre-aligned with the capture // signal. - void ProcessCapture( - EchoPathVariability echo_path_variability, - bool capture_signal_saturation, - const absl::optional& external_delay, - RenderBuffer* render_buffer, - std::vector>>* linear_output, - std::vector>>* capture) override; + void ProcessCapture(EchoPathVariability echo_path_variability, + bool capture_signal_saturation, + const absl::optional& external_delay, + RenderBuffer* render_buffer, + Block* linear_output, + Block* capture) override; // Updates the status on whether echo leakage is detected in the output of the // echo remover. @@ -243,20 +242,17 @@ void EchoRemoverImpl::ProcessCapture( bool capture_signal_saturation, const absl::optional& external_delay, RenderBuffer* render_buffer, - std::vector>>* linear_output, - std::vector>>* capture) { + Block* linear_output, + Block* capture) { ++block_counter_; - const std::vector>>& x = - render_buffer->Block(0); - std::vector>>* y = capture; + const Block& x = render_buffer->Block(0); + Block* y = capture; RTC_DCHECK(render_buffer); RTC_DCHECK(y); - RTC_DCHECK_EQ(x.size(), NumBandsForRate(sample_rate_hz_)); - RTC_DCHECK_EQ(y->size(), NumBandsForRate(sample_rate_hz_)); - RTC_DCHECK_EQ(x[0].size(), num_render_channels_); - RTC_DCHECK_EQ((*y)[0].size(), num_capture_channels_); - RTC_DCHECK_EQ(x[0][0].size(), kBlockSize); - RTC_DCHECK_EQ((*y)[0][0].size(), kBlockSize); + RTC_DCHECK_EQ(x.NumBands(), NumBandsForRate(sample_rate_hz_)); + RTC_DCHECK_EQ(y->NumBands(), NumBandsForRate(sample_rate_hz_)); + RTC_DCHECK_EQ(x.NumChannels(), num_render_channels_); + RTC_DCHECK_EQ(y->NumChannels(), num_capture_channels_); // Stack allocated data to use when the number of channels is low. std::array, kMaxNumChannelsOnStack> e_stack; @@ -321,12 +317,14 @@ void EchoRemoverImpl::ProcessCapture( subtractor_output_heap_.data(), num_capture_channels_); } - data_dumper_->DumpWav("aec3_echo_remover_capture_input", kBlockSize, - &(*y)[0][0][0], 16000, 1); - data_dumper_->DumpWav("aec3_echo_remover_render_input", kBlockSize, - &x[0][0][0], 16000, 1); - data_dumper_->DumpRaw("aec3_echo_remover_capture_input", (*y)[0][0]); - data_dumper_->DumpRaw("aec3_echo_remover_render_input", x[0][0]); + data_dumper_->DumpWav("aec3_echo_remover_capture_input", + y->View(/*band=*/0, /*channel=*/0), 16000, 1); + data_dumper_->DumpWav("aec3_echo_remover_render_input", + x.View(/*band=*/0, /*channel=*/0), 16000, 1); + data_dumper_->DumpRaw("aec3_echo_remover_capture_input", + y->View(/*band=*/0, /*channel=*/0)); + data_dumper_->DumpRaw("aec3_echo_remover_render_input", + x.View(/*band=*/0, /*channel=*/0)); aec_state_.UpdateCaptureSaturation(capture_signal_saturation); @@ -369,13 +367,13 @@ void EchoRemoverImpl::ProcessCapture( } // Perform linear echo cancellation. - subtractor_.Process(*render_buffer, (*y)[0], render_signal_analyzer_, - aec_state_, subtractor_output); + subtractor_.Process(*render_buffer, *y, render_signal_analyzer_, aec_state_, + subtractor_output); // Compute spectra. for (size_t ch = 0; ch < num_capture_channels_; ++ch) { FormLinearFilterOutput(subtractor_output[ch], e[ch]); - WindowedPaddedFft(fft_, (*y)[0][ch], y_old_[ch], &Y[ch]); + WindowedPaddedFft(fft_, y->View(/*band=*/0, ch), y_old_[ch], &Y[ch]); WindowedPaddedFft(fft_, e[ch], e_old_[ch], &E[ch]); LinearEchoPower(E[ch], Y[ch], &S2_linear[ch]); Y[ch].Spectrum(optimization_, Y2[ch]); @@ -384,11 +382,11 @@ void EchoRemoverImpl::ProcessCapture( // Optionally return the linear filter output. if (linear_output) { - RTC_DCHECK_GE(1, linear_output->size()); - RTC_DCHECK_EQ(num_capture_channels_, linear_output[0].size()); + RTC_DCHECK_GE(1, linear_output->NumBands()); + RTC_DCHECK_EQ(num_capture_channels_, linear_output->NumChannels()); for (size_t ch = 0; ch < num_capture_channels_; ++ch) { - RTC_DCHECK_EQ(kBlockSize, (*linear_output)[0][ch].size()); - std::copy(e[ch].begin(), e[ch].end(), (*linear_output)[0][ch].begin()); + std::copy(e[ch].begin(), e[ch].end(), + linear_output->begin(/*band=*/0, ch)); } } @@ -400,8 +398,8 @@ void EchoRemoverImpl::ProcessCapture( // Choose the linear output. const auto& Y_fft = aec_state_.UseLinearFilterOutput() ? E : Y; - data_dumper_->DumpWav("aec3_output_linear", kBlockSize, &(*y)[0][0][0], 16000, - 1); + data_dumper_->DumpWav("aec3_output_linear", + y->View(/*band=*/0, /*channel=*/0), 16000, 1); data_dumper_->DumpWav("aec3_output_linear2", kBlockSize, &e[0][0], 16000, 1); // Estimate the comfort noise. @@ -455,13 +453,12 @@ void EchoRemoverImpl::ProcessCapture( // Debug outputs for the purpose of development and analysis. data_dumper_->DumpWav("aec3_echo_estimate", kBlockSize, &subtractor_output[0].s_refined[0], 16000, 1); - data_dumper_->DumpRaw("aec3_output", (*y)[0][0]); + data_dumper_->DumpRaw("aec3_output", y->View(/*band=*/0, /*channel=*/0)); data_dumper_->DumpRaw("aec3_narrow_render", render_signal_analyzer_.NarrowPeakBand() ? 1 : 0); data_dumper_->DumpRaw("aec3_N2", cng_.NoiseSpectrum()[0]); data_dumper_->DumpRaw("aec3_suppressor_gain", G); - data_dumper_->DumpWav("aec3_output", - rtc::ArrayView(&(*y)[0][0][0], kBlockSize), + data_dumper_->DumpWav("aec3_output", y->View(/*band=*/0, /*channel=*/0), 16000, 1); data_dumper_->DumpRaw("aec3_using_subtractor_output[0]", aec_state_.UseLinearFilterOutput() ? 1 : 0); diff --git a/modules/audio_processing/aec3/echo_remover.h b/modules/audio_processing/aec3/echo_remover.h index 486a9a72f4..f2f4f5e64d 100644 --- a/modules/audio_processing/aec3/echo_remover.h +++ b/modules/audio_processing/aec3/echo_remover.h @@ -16,6 +16,7 @@ #include "absl/types/optional.h" #include "api/audio/echo_canceller3_config.h" #include "api/audio/echo_control.h" +#include "modules/audio_processing/aec3/block.h" #include "modules/audio_processing/aec3/delay_estimate.h" #include "modules/audio_processing/aec3/echo_path_variability.h" #include "modules/audio_processing/aec3/render_buffer.h" @@ -42,8 +43,8 @@ class EchoRemover { bool capture_signal_saturation, const absl::optional& external_delay, RenderBuffer* render_buffer, - std::vector>>* linear_output, - std::vector>>* capture) = 0; + Block* linear_output, + Block* capture) = 0; // Updates the status on whether echo leakage is detected in the output of the // echo remover. diff --git a/modules/audio_processing/aec3/echo_remover_unittest.cc b/modules/audio_processing/aec3/echo_remover_unittest.cc index 77a207659c..66168ab08d 100644 --- a/modules/audio_processing/aec3/echo_remover_unittest.cc +++ b/modules/audio_processing/aec3/echo_remover_unittest.cc @@ -62,14 +62,8 @@ TEST_P(EchoRemoverMultiChannel, BasicApiCalls) { std::unique_ptr render_buffer(RenderDelayBuffer::Create( EchoCanceller3Config(), rate, num_render_channels)); - std::vector>> render( - NumBandsForRate(rate), - std::vector>(num_render_channels, - std::vector(kBlockSize, 0.f))); - std::vector>> capture( - NumBandsForRate(rate), - std::vector>(num_capture_channels, - std::vector(kBlockSize, 0.f))); + Block render(NumBandsForRate(rate), num_render_channels); + Block capture(NumBandsForRate(rate), num_capture_channels); for (size_t k = 0; k < 100; ++k) { EchoPathVariability echo_path_variability( k % 3 == 0 ? true : false, @@ -97,27 +91,6 @@ TEST(EchoRemoverDeathTest, DISABLED_WrongSampleRate) { ""); } -// Verifies the check for the capture block size. -TEST(EchoRemoverDeathTest, WrongCaptureBlockSize) { - absl::optional delay_estimate; - for (auto rate : {16000, 32000, 48000}) { - SCOPED_TRACE(ProduceDebugText(rate)); - std::unique_ptr remover( - EchoRemover::Create(EchoCanceller3Config(), rate, 1, 1)); - std::unique_ptr render_buffer( - RenderDelayBuffer::Create(EchoCanceller3Config(), rate, 1)); - std::vector>> capture( - NumBandsForRate(rate), std::vector>( - 1, std::vector(kBlockSize - 1, 0.f))); - EchoPathVariability echo_path_variability( - false, EchoPathVariability::DelayAdjustment::kNone, false); - EXPECT_DEATH(remover->ProcessCapture( - echo_path_variability, false, delay_estimate, - render_buffer->GetRenderBuffer(), nullptr, &capture), - ""); - } -} - // Verifies the check for the number of capture bands. // TODO(peah): Re-enable the test once the issue with memory leaks during DEATH // tests on test bots has been fixed.c @@ -129,10 +102,7 @@ TEST(EchoRemoverDeathTest, DISABLED_WrongCaptureNumBands) { EchoRemover::Create(EchoCanceller3Config(), rate, 1, 1)); std::unique_ptr render_buffer( RenderDelayBuffer::Create(EchoCanceller3Config(), rate, 1)); - std::vector>> capture( - NumBandsForRate(rate == 48000 ? 16000 : rate + 16000), - std::vector>(1, - std::vector(kBlockSize, 0.f))); + Block capture(NumBandsForRate(rate == 48000 ? 16000 : rate + 16000), 1); EchoPathVariability echo_path_variability( false, EchoPathVariability::DelayAdjustment::kNone, false); EXPECT_DEATH(remover->ProcessCapture( @@ -167,14 +137,8 @@ TEST(EchoRemover, BasicEchoRemoval) { absl::optional delay_estimate; for (size_t num_channels : {1, 2, 4}) { for (auto rate : {16000, 32000, 48000}) { - std::vector>> x( - NumBandsForRate(rate), - std::vector>(num_channels, - std::vector(kBlockSize, 0.f))); - std::vector>> y( - NumBandsForRate(rate), - std::vector>(num_channels, - std::vector(kBlockSize, 0.f))); + Block x(NumBandsForRate(rate), num_channels); + Block y(NumBandsForRate(rate), num_channels); EchoPathVariability echo_path_variability( false, EchoPathVariability::DelayAdjustment::kNone, false); for (size_t delay_samples : {0, 64, 150, 200, 301}) { @@ -187,13 +151,13 @@ TEST(EchoRemover, BasicEchoRemoval) { render_buffer->AlignFromDelay(delay_samples / kBlockSize); std::vector>>> - delay_buffers(x.size()); + delay_buffers(x.NumBands()); for (size_t band = 0; band < delay_buffers.size(); ++band) { - delay_buffers[band].resize(x[0].size()); + delay_buffers[band].resize(x.NumChannels()); } - for (size_t band = 0; band < x.size(); ++band) { - for (size_t channel = 0; channel < x[0].size(); ++channel) { + for (int band = 0; band < x.NumBands(); ++band) { + for (int channel = 0; channel < x.NumChannels(); ++channel) { delay_buffers[band][channel].reset( new DelayBuffer(delay_samples)); } @@ -204,22 +168,23 @@ TEST(EchoRemover, BasicEchoRemoval) { for (int k = 0; k < kNumBlocksToProcess; ++k) { const bool silence = k < 100 || (k % 100 >= 10); - for (size_t band = 0; band < x.size(); ++band) { - for (size_t channel = 0; channel < x[0].size(); ++channel) { + for (int band = 0; band < x.NumBands(); ++band) { + for (int channel = 0; channel < x.NumChannels(); ++channel) { if (silence) { - std::fill(x[band][channel].begin(), x[band][channel].end(), - 0.f); + std::fill(x.begin(band, channel), x.end(band, channel), 0.f); } else { - RandomizeSampleVector(&random_generator, x[band][channel]); + RandomizeSampleVector(&random_generator, x.View(band, channel)); } - delay_buffers[band][channel]->Delay(x[band][channel], - y[band][channel]); + delay_buffers[band][channel]->Delay(x.View(band, channel), + y.View(band, channel)); } } if (k > kNumBlocksToProcess / 2) { - input_energy = std::inner_product(y[0][0].begin(), y[0][0].end(), - y[0][0].begin(), input_energy); + input_energy = std::inner_product( + y.begin(/*band=*/0, /*channel=*/0), + y.end(/*band=*/0, /*channel=*/0), + y.begin(/*band=*/0, /*channel=*/0), input_energy); } render_buffer->Insert(x); @@ -230,8 +195,10 @@ TEST(EchoRemover, BasicEchoRemoval) { &y); if (k > kNumBlocksToProcess / 2) { - output_energy = std::inner_product(y[0][0].begin(), y[0][0].end(), - y[0][0].begin(), output_energy); + output_energy = std::inner_product( + y.begin(/*band=*/0, /*channel=*/0), + y.end(/*band=*/0, /*channel=*/0), + y.begin(/*band=*/0, /*channel=*/0), output_energy); } } EXPECT_GT(input_energy, 10.f * output_energy); diff --git a/modules/audio_processing/aec3/erle_estimator_unittest.cc b/modules/audio_processing/aec3/erle_estimator_unittest.cc index e38f2386f7..42be7d9c7d 100644 --- a/modules/audio_processing/aec3/erle_estimator_unittest.cc +++ b/modules/audio_processing/aec3/erle_estimator_unittest.cc @@ -60,7 +60,7 @@ void VerifyErleGreaterOrEqual( } } -void FormFarendTimeFrame(std::vector>>* x) { +void FormFarendTimeFrame(Block* x) { const std::array frame = { 7459.88, 17209.6, 17383, 20768.9, 16816.7, 18386.3, 4492.83, 9675.85, 6665.52, 14808.6, 9342.3, 7483.28, 19261.7, 4145.98, 1622.18, 13475.2, @@ -70,10 +70,10 @@ void FormFarendTimeFrame(std::vector>>* x) { 11405, 15031.4, 14541.6, 19765.5, 18346.3, 19350.2, 3157.47, 18095.8, 1743.68, 21328.2, 19727.5, 7295.16, 10332.4, 11055.5, 20107.4, 14708.4, 12416.2, 16434, 2454.69, 9840.8, 6867.23, 1615.75, 6059.9, 8394.19}; - for (size_t band = 0; band < x->size(); ++band) { - for (size_t channel = 0; channel < (*x)[band].size(); ++channel) { - RTC_DCHECK_GE((*x)[band][channel].size(), frame.size()); - std::copy(frame.begin(), frame.end(), (*x)[band][channel].begin()); + for (int band = 0; band < x->NumBands(); ++band) { + for (int channel = 0; channel < x->NumChannels(); ++channel) { + RTC_DCHECK_GE(kBlockSize, frame.size()); + std::copy(frame.begin(), frame.end(), x->begin(band, channel)); } } } @@ -104,13 +104,13 @@ void FormFarendFrame(const RenderBuffer& render_buffer, } void FormNearendFrame( - std::vector>>* x, + Block* x, std::array* X2, rtc::ArrayView> E2, rtc::ArrayView> Y2) { - for (size_t band = 0; band < x->size(); ++band) { - for (size_t ch = 0; ch < (*x)[band].size(); ++ch) { - std::fill((*x)[band][ch].begin(), (*x)[band][ch].end(), 0.f); + for (int band = 0; band < x->NumBands(); ++band) { + for (int ch = 0; ch < x->NumChannels(); ++ch) { + std::fill(x->begin(band, ch), x->end(band, ch), 0.f); } } @@ -162,9 +162,7 @@ TEST_P(ErleEstimatorMultiChannel, VerifyErleIncreaseAndHold) { EchoCanceller3Config config; config.erle.onset_detection = true; - std::vector>> x( - kNumBands, std::vector>( - num_render_channels, std::vector(kBlockSize, 0.f))); + Block x(kNumBands, num_render_channels); std::vector>> filter_frequency_response( config.filter.refined.length_blocks, @@ -227,9 +225,7 @@ TEST_P(ErleEstimatorMultiChannel, VerifyErleTrackingOnOnsets) { std::vector converged_filters(num_capture_channels, true); EchoCanceller3Config config; config.erle.onset_detection = true; - std::vector>> x( - kNumBands, std::vector>( - num_render_channels, std::vector(kBlockSize, 0.f))); + Block x(kNumBands, num_render_channels); std::vector>> filter_frequency_response( config.filter.refined.length_blocks, diff --git a/modules/audio_processing/aec3/filter_analyzer.cc b/modules/audio_processing/aec3/filter_analyzer.cc index c07e5c8648..5587584c51 100644 --- a/modules/audio_processing/aec3/filter_analyzer.cc +++ b/modules/audio_processing/aec3/filter_analyzer.cc @@ -131,7 +131,7 @@ void FilterAnalyzer::AnalyzeRegion( st_ch.consistent_estimate = st_ch.consistent_filter_detector.Detect( h_highpass_[ch], region_, - render_buffer.Block(-filter_delays_blocks_[ch])[0], st_ch.peak_index, + render_buffer.Block(-filter_delays_blocks_[ch]), st_ch.peak_index, filter_delays_blocks_[ch]); } } @@ -224,7 +224,7 @@ void FilterAnalyzer::ConsistentFilterDetector::Reset() { bool FilterAnalyzer::ConsistentFilterDetector::Detect( rtc::ArrayView filter_to_analyze, const FilterRegion& region, - rtc::ArrayView> x_block, + const Block& x_block, size_t peak_index, int delay_blocks) { if (region.start_sample_ == 0) { @@ -265,7 +265,9 @@ bool FilterAnalyzer::ConsistentFilterDetector::Detect( if (significant_peak_) { bool active_render_block = false; - for (auto& x_channel : x_block) { + for (int ch = 0; ch < x_block.NumChannels(); ++ch) { + rtc::ArrayView x_channel = + x_block.View(/*band=*/0, ch); const float x_energy = std::inner_product( x_channel.begin(), x_channel.end(), x_channel.begin(), 0.f); if (x_energy > active_render_threshold_) { diff --git a/modules/audio_processing/aec3/filter_analyzer.h b/modules/audio_processing/aec3/filter_analyzer.h index e05fb71138..7c6b5409e8 100644 --- a/modules/audio_processing/aec3/filter_analyzer.h +++ b/modules/audio_processing/aec3/filter_analyzer.h @@ -20,6 +20,7 @@ #include "api/array_view.h" #include "api/audio/echo_canceller3_config.h" #include "modules/audio_processing/aec3/aec3_common.h" +#include "modules/audio_processing/aec3/block.h" namespace webrtc { @@ -93,7 +94,7 @@ class FilterAnalyzer { void Reset(); bool Detect(rtc::ArrayView filter_to_analyze, const FilterRegion& region, - rtc::ArrayView> x_block, + const Block& x_block, size_t peak_index, int delay_blocks); diff --git a/modules/audio_processing/aec3/frame_blocker.cc b/modules/audio_processing/aec3/frame_blocker.cc index 63aaf098c5..3039dcf7f1 100644 --- a/modules/audio_processing/aec3/frame_blocker.cc +++ b/modules/audio_processing/aec3/frame_blocker.cc @@ -33,26 +33,22 @@ FrameBlocker::~FrameBlocker() = default; void FrameBlocker::InsertSubFrameAndExtractBlock( const std::vector>>& sub_frame, - std::vector>>* block) { + Block* block) { RTC_DCHECK(block); - RTC_DCHECK_EQ(num_bands_, block->size()); + RTC_DCHECK_EQ(num_bands_, block->NumBands()); RTC_DCHECK_EQ(num_bands_, sub_frame.size()); for (size_t band = 0; band < num_bands_; ++band) { - RTC_DCHECK_EQ(num_channels_, (*block)[band].size()); + RTC_DCHECK_EQ(num_channels_, block->NumChannels()); RTC_DCHECK_EQ(num_channels_, sub_frame[band].size()); for (size_t channel = 0; channel < num_channels_; ++channel) { RTC_DCHECK_GE(kBlockSize - 16, buffer_[band][channel].size()); - RTC_DCHECK_EQ(kBlockSize, (*block)[band][channel].size()); RTC_DCHECK_EQ(kSubFrameLength, sub_frame[band][channel].size()); const int samples_to_block = kBlockSize - buffer_[band][channel].size(); - (*block)[band][channel].clear(); - (*block)[band][channel].insert((*block)[band][channel].begin(), - buffer_[band][channel].begin(), - buffer_[band][channel].end()); - (*block)[band][channel].insert( - (*block)[band][channel].begin() + buffer_[band][channel].size(), - sub_frame[band][channel].begin(), - sub_frame[band][channel].begin() + samples_to_block); + std::copy(buffer_[band][channel].begin(), buffer_[band][channel].end(), + block->begin(band, channel)); + std::copy(sub_frame[band][channel].begin(), + sub_frame[band][channel].begin() + samples_to_block, + block->begin(band, channel) + kBlockSize - samples_to_block); buffer_[band][channel].clear(); buffer_[band][channel].insert( buffer_[band][channel].begin(), @@ -66,20 +62,16 @@ bool FrameBlocker::IsBlockAvailable() const { return kBlockSize == buffer_[0][0].size(); } -void FrameBlocker::ExtractBlock( - std::vector>>* block) { +void FrameBlocker::ExtractBlock(Block* block) { RTC_DCHECK(block); - RTC_DCHECK_EQ(num_bands_, block->size()); + RTC_DCHECK_EQ(num_bands_, block->NumBands()); + RTC_DCHECK_EQ(num_channels_, block->NumChannels()); RTC_DCHECK(IsBlockAvailable()); for (size_t band = 0; band < num_bands_; ++band) { - RTC_DCHECK_EQ(num_channels_, (*block)[band].size()); for (size_t channel = 0; channel < num_channels_; ++channel) { RTC_DCHECK_EQ(kBlockSize, buffer_[band][channel].size()); - RTC_DCHECK_EQ(kBlockSize, (*block)[band][channel].size()); - (*block)[band][channel].clear(); - (*block)[band][channel].insert((*block)[band][channel].begin(), - buffer_[band][channel].begin(), - buffer_[band][channel].end()); + std::copy(buffer_[band][channel].begin(), buffer_[band][channel].end(), + block->begin(band, channel)); buffer_[band][channel].clear(); } } diff --git a/modules/audio_processing/aec3/frame_blocker.h b/modules/audio_processing/aec3/frame_blocker.h index ebd6f776f1..623c812157 100644 --- a/modules/audio_processing/aec3/frame_blocker.h +++ b/modules/audio_processing/aec3/frame_blocker.h @@ -17,6 +17,7 @@ #include "api/array_view.h" #include "modules/audio_processing/aec3/aec3_common.h" +#include "modules/audio_processing/aec3/block.h" namespace webrtc { @@ -33,12 +34,12 @@ class FrameBlocker { // extracts one 64 sample multiband block. void InsertSubFrameAndExtractBlock( const std::vector>>& sub_frame, - std::vector>>* block); + Block* block); // Reports whether a multiband block of 64 samples is available for // extraction. bool IsBlockAvailable() const; // Extracts a multiband block of 64 samples. - void ExtractBlock(std::vector>>* block); + void ExtractBlock(Block* block); private: const size_t num_bands_; diff --git a/modules/audio_processing/aec3/frame_blocker_unittest.cc b/modules/audio_processing/aec3/frame_blocker_unittest.cc index 216f515037..92e393023a 100644 --- a/modules/audio_processing/aec3/frame_blocker_unittest.cc +++ b/modules/audio_processing/aec3/frame_blocker_unittest.cc @@ -86,15 +86,14 @@ bool VerifySubFrame( return true; } -bool VerifyBlock(size_t block_counter, - int offset, - const std::vector>>& block) { - for (size_t band = 0; band < block.size(); ++band) { - for (size_t channel = 0; channel < block[band].size(); ++channel) { - for (size_t sample = 0; sample < block[band][channel].size(); ++sample) { +bool VerifyBlock(size_t block_counter, int offset, const Block& block) { + for (int band = 0; band < block.NumBands(); ++band) { + for (int channel = 0; channel < block.NumChannels(); ++channel) { + for (size_t sample = 0; sample < kBlockSize; ++sample) { + auto it = block.begin(band, channel) + sample; const float reference_value = ComputeSampleValue( block_counter, kBlockSize, band, channel, sample, offset); - if (reference_value != block[band][channel][sample]) { + if (reference_value != *it) { return false; } } @@ -108,9 +107,7 @@ void RunBlockerTest(int sample_rate_hz, size_t num_channels) { constexpr size_t kNumSubFramesToProcess = 20; const size_t num_bands = NumBandsForRate(sample_rate_hz); - std::vector>> block( - num_bands, std::vector>( - num_channels, std::vector(kBlockSize, 0.f))); + Block block(num_bands, num_channels); std::vector>> input_sub_frame( num_bands, std::vector>( num_channels, std::vector(kSubFrameLength, 0.f))); @@ -145,9 +142,7 @@ void RunBlockerAndFramerTest(int sample_rate_hz, size_t num_channels) { const size_t kNumSubFramesToProcess = 20; const size_t num_bands = NumBandsForRate(sample_rate_hz); - std::vector>> block( - num_bands, std::vector>( - num_channels, std::vector(kBlockSize, 0.f))); + Block block(num_bands, num_channels); std::vector>> input_sub_frame( num_bands, std::vector>( num_channels, std::vector(kSubFrameLength, 0.f))); @@ -194,16 +189,12 @@ void RunWronglySizedInsertAndExtractParametersTest( size_t correct_num_channels, size_t num_block_bands, size_t num_block_channels, - size_t block_length, size_t num_sub_frame_bands, size_t num_sub_frame_channels, size_t sub_frame_length) { const size_t correct_num_bands = NumBandsForRate(sample_rate_hz); - std::vector>> block( - num_block_bands, - std::vector>(num_block_channels, - std::vector(block_length, 0.f))); + Block block(num_block_bands, num_block_channels); std::vector>> input_sub_frame( num_sub_frame_bands, std::vector>( @@ -222,18 +213,11 @@ void RunWronglySizedInsertAndExtractParametersTest( void RunWronglySizedExtractParameterTest(int sample_rate_hz, size_t correct_num_channels, size_t num_block_bands, - size_t num_block_channels, - size_t block_length) { + size_t num_block_channels) { const size_t correct_num_bands = NumBandsForRate(sample_rate_hz); - std::vector>> correct_block( - correct_num_bands, - std::vector>(correct_num_channels, - std::vector(kBlockSize, 0.f))); - std::vector>> wrong_block( - num_block_bands, - std::vector>(num_block_channels, - std::vector(block_length, 0.f))); + Block correct_block(correct_num_bands, correct_num_channels); + Block wrong_block(num_block_bands, num_block_channels); std::vector>> input_sub_frame( correct_num_bands, std::vector>( @@ -259,9 +243,7 @@ void RunWrongExtractOrderTest(int sample_rate_hz, size_t num_preceeding_api_calls) { const size_t num_bands = NumBandsForRate(sample_rate_hz); - std::vector>> block( - num_bands, std::vector>( - num_channels, std::vector(kBlockSize, 0.f))); + Block block(num_bands, num_channels); std::vector>> input_sub_frame( num_bands, std::vector>( num_channels, std::vector(kSubFrameLength, 0.f))); @@ -296,7 +278,7 @@ TEST(FrameBlockerDeathTest, const size_t wrong_num_bands = (correct_num_bands % 3) + 1; RunWronglySizedInsertAndExtractParametersTest( rate, correct_num_channels, wrong_num_bands, correct_num_channels, - kBlockSize, correct_num_bands, correct_num_channels, kSubFrameLength); + correct_num_bands, correct_num_channels, kSubFrameLength); } } } @@ -310,7 +292,7 @@ TEST(FrameBlockerDeathTest, const size_t wrong_num_channels = correct_num_channels + 1; RunWronglySizedInsertAndExtractParametersTest( rate, correct_num_channels, correct_num_bands, wrong_num_channels, - kBlockSize, correct_num_bands, correct_num_channels, kSubFrameLength); + correct_num_bands, correct_num_channels, kSubFrameLength); } } } @@ -324,7 +306,7 @@ TEST(FrameBlockerDeathTest, const size_t wrong_num_bands = (correct_num_bands % 3) + 1; RunWronglySizedInsertAndExtractParametersTest( rate, correct_num_channels, correct_num_bands, correct_num_channels, - kBlockSize, wrong_num_bands, correct_num_channels, kSubFrameLength); + wrong_num_bands, correct_num_channels, kSubFrameLength); } } } @@ -338,21 +320,7 @@ TEST(FrameBlockerDeathTest, const size_t wrong_num_channels = correct_num_channels + 1; RunWronglySizedInsertAndExtractParametersTest( rate, correct_num_channels, correct_num_bands, wrong_num_channels, - kBlockSize, correct_num_bands, wrong_num_channels, kSubFrameLength); - } - } -} - -TEST(FrameBlockerDeathTest, - WrongNumberOfSamplesInBlockForInsertSubFrameAndExtractBlock) { - for (auto rate : {16000, 32000, 48000}) { - for (size_t correct_num_channels : {1, 2, 4, 8}) { - SCOPED_TRACE(ProduceDebugText(rate, correct_num_channels)); - const size_t correct_num_bands = NumBandsForRate(rate); - RunWronglySizedInsertAndExtractParametersTest( - rate, correct_num_channels, correct_num_bands, correct_num_channels, - kBlockSize - 1, correct_num_bands, correct_num_channels, - kSubFrameLength); + correct_num_bands, wrong_num_channels, kSubFrameLength); } } } @@ -365,8 +333,7 @@ TEST(FrameBlockerDeathTest, const size_t correct_num_bands = NumBandsForRate(rate); RunWronglySizedInsertAndExtractParametersTest( rate, correct_num_channels, correct_num_bands, correct_num_channels, - kBlockSize, correct_num_bands, correct_num_channels, - kSubFrameLength - 1); + correct_num_bands, correct_num_channels, kSubFrameLength - 1); } } } @@ -377,9 +344,8 @@ TEST(FrameBlockerDeathTest, WrongNumberOfBandsInBlockForExtractBlock) { SCOPED_TRACE(ProduceDebugText(rate, correct_num_channels)); const size_t correct_num_bands = NumBandsForRate(rate); const size_t wrong_num_bands = (correct_num_bands % 3) + 1; - RunWronglySizedExtractParameterTest(rate, correct_num_channels, - wrong_num_bands, correct_num_channels, - kBlockSize); + RunWronglySizedExtractParameterTest( + rate, correct_num_channels, wrong_num_bands, correct_num_channels); } } } @@ -390,21 +356,8 @@ TEST(FrameBlockerDeathTest, WrongNumberOfChannelsInBlockForExtractBlock) { SCOPED_TRACE(ProduceDebugText(rate, correct_num_channels)); const size_t correct_num_bands = NumBandsForRate(rate); const size_t wrong_num_channels = correct_num_channels + 1; - RunWronglySizedExtractParameterTest(rate, correct_num_channels, - correct_num_bands, wrong_num_channels, - kBlockSize); - } - } -} - -TEST(FrameBlockerDeathTest, WrongNumberOfSamplesInBlockForExtractBlock) { - for (auto rate : {16000, 32000, 48000}) { - for (size_t correct_num_channels : {1, 2, 4, 8}) { - SCOPED_TRACE(ProduceDebugText(rate, correct_num_channels)); - const size_t correct_num_bands = NumBandsForRate(rate); - RunWronglySizedExtractParameterTest(rate, correct_num_channels, - correct_num_bands, - correct_num_channels, kBlockSize - 1); + RunWronglySizedExtractParameterTest( + rate, correct_num_channels, correct_num_bands, wrong_num_channels); } } } diff --git a/modules/audio_processing/aec3/matched_filter_unittest.cc b/modules/audio_processing/aec3/matched_filter_unittest.cc index 8abfb69a7a..9924256f0c 100644 --- a/modules/audio_processing/aec3/matched_filter_unittest.cc +++ b/modules/audio_processing/aec3/matched_filter_unittest.cc @@ -210,9 +210,7 @@ TEST(MatchedFilter, LagEstimation) { for (auto down_sampling_factor : kDownSamplingFactors) { const size_t sub_block_size = kBlockSize / down_sampling_factor; - std::vector>> render( - kNumBands, std::vector>( - kNumChannels, std::vector(kBlockSize, 0.f))); + Block render(kNumBands, kNumChannels); std::vector> capture( 1, std::vector(kBlockSize, 0.f)); ApmDataDumper data_dumper(0); @@ -238,10 +236,12 @@ TEST(MatchedFilter, LagEstimation) { for (size_t k = 0; k < (600 + delay_samples / sub_block_size); ++k) { for (size_t band = 0; band < kNumBands; ++band) { for (size_t channel = 0; channel < kNumChannels; ++channel) { - RandomizeSampleVector(&random_generator, render[band][channel]); + RandomizeSampleVector(&random_generator, + render.View(band, channel)); } } - signal_delay_buffer.Delay(render[0][0], capture[0]); + signal_delay_buffer.Delay(render.View(/*band=*/0, /*channel=*/0), + capture[0]); render_delay_buffer->Insert(render); if (k == 0) { @@ -328,9 +328,7 @@ TEST(MatchedFilter, LagNotReliableForUncorrelatedRenderAndCapture) { config.delay.num_filters = kNumMatchedFilters; const size_t sub_block_size = kBlockSize / down_sampling_factor; - std::vector>> render( - kNumBands, std::vector>( - kNumChannels, std::vector(kBlockSize, 0.f))); + Block render(kNumBands, kNumChannels); std::array capture_data; rtc::ArrayView capture(capture_data.data(), sub_block_size); std::fill(capture.begin(), capture.end(), 0.f); @@ -346,7 +344,8 @@ TEST(MatchedFilter, LagNotReliableForUncorrelatedRenderAndCapture) { // Analyze the correlation between render and capture. for (size_t k = 0; k < 100; ++k) { - RandomizeSampleVector(&random_generator, render[0][0]); + RandomizeSampleVector(&random_generator, + render.View(/*band=*/0, /*channel=*/0)); RandomizeSampleVector(&random_generator, capture); render_delay_buffer->Insert(render); filter.Update(render_delay_buffer->GetDownsampledRenderBuffer(), capture, diff --git a/modules/audio_processing/aec3/mock/mock_block_processor.h b/modules/audio_processing/aec3/mock/mock_block_processor.h index aa612257ea..c9ae38c4aa 100644 --- a/modules/audio_processing/aec3/mock/mock_block_processor.h +++ b/modules/audio_processing/aec3/mock/mock_block_processor.h @@ -28,13 +28,10 @@ class MockBlockProcessor : public BlockProcessor { ProcessCapture, (bool level_change, bool saturated_microphone_signal, - std::vector>>* linear_output, - std::vector>>* capture_block), - (override)); - MOCK_METHOD(void, - BufferRender, - (const std::vector>>& block), + Block* linear_output, + Block* capture_block), (override)); + MOCK_METHOD(void, BufferRender, (const Block& block), (override)); MOCK_METHOD(void, UpdateEchoLeakageStatus, (bool leakage_detected), diff --git a/modules/audio_processing/aec3/mock/mock_echo_remover.h b/modules/audio_processing/aec3/mock/mock_echo_remover.h index 60c5bf433e..31f075ef0a 100644 --- a/modules/audio_processing/aec3/mock/mock_echo_remover.h +++ b/modules/audio_processing/aec3/mock/mock_echo_remover.h @@ -33,8 +33,8 @@ class MockEchoRemover : public EchoRemover { bool capture_signal_saturation, const absl::optional& delay_estimate, RenderBuffer* render_buffer, - std::vector>>* linear_output, - std::vector>>* capture), + Block* linear_output, + Block* capture), (override)); MOCK_METHOD(void, UpdateEchoLeakageStatus, diff --git a/modules/audio_processing/aec3/mock/mock_render_delay_buffer.cc b/modules/audio_processing/aec3/mock/mock_render_delay_buffer.cc index d7099b03e3..d4ad09b4bc 100644 --- a/modules/audio_processing/aec3/mock/mock_render_delay_buffer.cc +++ b/modules/audio_processing/aec3/mock/mock_render_delay_buffer.cc @@ -17,8 +17,7 @@ MockRenderDelayBuffer::MockRenderDelayBuffer(int sample_rate_hz, size_t num_channels) : block_buffer_(GetRenderDelayBufferSize(4, 4, 12), NumBandsForRate(sample_rate_hz), - num_channels, - kBlockSize), + num_channels), spectrum_buffer_(block_buffer_.buffer.size(), num_channels), fft_buffer_(block_buffer_.buffer.size(), num_channels), render_buffer_(&block_buffer_, &spectrum_buffer_, &fft_buffer_), diff --git a/modules/audio_processing/aec3/mock/mock_render_delay_buffer.h b/modules/audio_processing/aec3/mock/mock_render_delay_buffer.h index 9d7b8f4e86..c17fd62caa 100644 --- a/modules/audio_processing/aec3/mock/mock_render_delay_buffer.h +++ b/modules/audio_processing/aec3/mock/mock_render_delay_buffer.h @@ -30,7 +30,7 @@ class MockRenderDelayBuffer : public RenderDelayBuffer { MOCK_METHOD(void, Reset, (), (override)); MOCK_METHOD(RenderDelayBuffer::BufferingEvent, Insert, - (const std::vector>>& block), + (const Block& block), (override)); MOCK_METHOD(void, HandleSkippedCaptureProcessing, (), (override)); MOCK_METHOD(RenderDelayBuffer::BufferingEvent, diff --git a/modules/audio_processing/aec3/mock/mock_render_delay_controller.h b/modules/audio_processing/aec3/mock/mock_render_delay_controller.h index 67d8baefe6..14d499dd28 100644 --- a/modules/audio_processing/aec3/mock/mock_render_delay_controller.h +++ b/modules/audio_processing/aec3/mock/mock_render_delay_controller.h @@ -31,7 +31,7 @@ class MockRenderDelayController : public RenderDelayController { GetDelay, (const DownsampledRenderBuffer& render_buffer, size_t render_delay_buffer_delay, - const std::vector>& capture), + const Block& capture), (override)); MOCK_METHOD(bool, HasClockdrift, (), (const, override)); }; diff --git a/modules/audio_processing/aec3/refined_filter_update_gain_unittest.cc b/modules/audio_processing/aec3/refined_filter_update_gain_unittest.cc index 6fce858f16..c77c5b53d5 100644 --- a/modules/audio_processing/aec3/refined_filter_update_gain_unittest.cc +++ b/modules/audio_processing/aec3/refined_filter_update_gain_unittest.cc @@ -84,9 +84,7 @@ void RunFilterUpdateTest(int num_blocks_to_process, RefinedFilterUpdateGain refined_gain( config.filter.refined, config.filter.config_change_duration_blocks); Random random_generator(42U); - std::vector>> x( - kNumBands, std::vector>( - kNumRenderChannels, std::vector(kBlockSize, 0.f))); + Block x(kNumBands, kNumRenderChannels); std::vector y(kBlockSize, 0.f); config.delay.default_delay = 1; std::unique_ptr render_delay_buffer( @@ -131,19 +129,19 @@ void RunFilterUpdateTest(int num_blocks_to_process, // Create the render signal. if (use_silent_render_in_second_half && k > num_blocks_to_process / 2) { - for (size_t band = 0; band < x.size(); ++band) { - for (size_t channel = 0; channel < x[band].size(); ++channel) { - std::fill(x[band][channel].begin(), x[band][channel].end(), 0.f); + for (int band = 0; band < x.NumBands(); ++band) { + for (int channel = 0; channel < x.NumChannels(); ++channel) { + std::fill(x.begin(band, channel), x.end(band, channel), 0.f); } } } else { - for (size_t band = 0; band < x.size(); ++band) { - for (size_t channel = 0; channel < x[band].size(); ++channel) { - RandomizeSampleVector(&random_generator, x[band][channel]); + for (int band = 0; band < x.NumChannels(); ++band) { + for (int channel = 0; channel < x.NumChannels(); ++channel) { + RandomizeSampleVector(&random_generator, x.View(band, channel)); } } } - delay_buffer.Delay(x[0][0], y); + delay_buffer.Delay(x.View(/*band=*/0, /*channel=*/0), y); render_delay_buffer->Insert(x); if (k == 0) { diff --git a/modules/audio_processing/aec3/render_buffer.h b/modules/audio_processing/aec3/render_buffer.h index b8be6f517a..410ac32b14 100644 --- a/modules/audio_processing/aec3/render_buffer.h +++ b/modules/audio_processing/aec3/render_buffer.h @@ -40,8 +40,7 @@ class RenderBuffer { ~RenderBuffer(); // Get a block. - const std::vector>>& Block( - int buffer_offset_blocks) const { + const Block& Block(int buffer_offset_blocks) const { int position = block_buffer_->OffsetIndex(block_buffer_->read, buffer_offset_blocks); return block_buffer_->buffer[position]; diff --git a/modules/audio_processing/aec3/render_buffer_unittest.cc b/modules/audio_processing/aec3/render_buffer_unittest.cc index 4559528600..5d9d646e76 100644 --- a/modules/audio_processing/aec3/render_buffer_unittest.cc +++ b/modules/audio_processing/aec3/render_buffer_unittest.cc @@ -22,7 +22,7 @@ namespace webrtc { // Verifies the check for non-null fft buffer. TEST(RenderBufferDeathTest, NullExternalFftBuffer) { - BlockBuffer block_buffer(10, 3, 1, kBlockSize); + BlockBuffer block_buffer(10, 3, 1); SpectrumBuffer spectrum_buffer(10, 1); EXPECT_DEATH(RenderBuffer(&block_buffer, &spectrum_buffer, nullptr), ""); } @@ -30,7 +30,7 @@ TEST(RenderBufferDeathTest, NullExternalFftBuffer) { // Verifies the check for non-null spectrum buffer. TEST(RenderBufferDeathTest, NullExternalSpectrumBuffer) { FftBuffer fft_buffer(10, 1); - BlockBuffer block_buffer(10, 3, 1, kBlockSize); + BlockBuffer block_buffer(10, 3, 1); EXPECT_DEATH(RenderBuffer(&block_buffer, nullptr, &fft_buffer), ""); } diff --git a/modules/audio_processing/aec3/render_delay_buffer.cc b/modules/audio_processing/aec3/render_delay_buffer.cc index 7bebc6fd47..a46c378a1c 100644 --- a/modules/audio_processing/aec3/render_delay_buffer.cc +++ b/modules/audio_processing/aec3/render_delay_buffer.cc @@ -54,8 +54,7 @@ class RenderDelayBufferImpl final : public RenderDelayBuffer { ~RenderDelayBufferImpl() override; void Reset() override; - BufferingEvent Insert( - const std::vector>>& block) override; + BufferingEvent Insert(const Block& block) override; BufferingEvent PrepareCaptureProcessing() override; void HandleSkippedCaptureProcessing() override; bool AlignFromDelay(size_t delay) override; @@ -110,8 +109,7 @@ class RenderDelayBufferImpl final : public RenderDelayBuffer { int MapDelayToTotalDelay(size_t delay) const; int ComputeDelay() const; void ApplyTotalDelay(int delay); - void InsertBlock(const std::vector>>& block, - int previous_write); + void InsertBlock(const Block& block, int previous_write); bool DetectActiveRender(rtc::ArrayView x) const; bool DetectExcessRenderBlocks(); void IncrementWriteIndices(); @@ -145,8 +143,7 @@ RenderDelayBufferImpl::RenderDelayBufferImpl(const EchoCanceller3Config& config, config.delay.num_filters, config.filter.refined.length_blocks), NumBandsForRate(sample_rate_hz), - num_render_channels, - kBlockSize), + num_render_channels), spectra_(blocks_.buffer.size(), num_render_channels), ffts_(blocks_.buffer.size(), num_render_channels), delay_(config_.delay.default_delay), @@ -161,7 +158,7 @@ RenderDelayBufferImpl::RenderDelayBufferImpl(const EchoCanceller3Config& config, RTC_DCHECK_EQ(blocks_.buffer.size(), ffts_.buffer.size()); RTC_DCHECK_EQ(spectra_.buffer.size(), ffts_.buffer.size()); for (size_t i = 0; i < blocks_.buffer.size(); ++i) { - RTC_DCHECK_EQ(blocks_.buffer[i][0].size(), ffts_.buffer[i].size()); + RTC_DCHECK_EQ(blocks_.buffer[i].NumChannels(), ffts_.buffer[i].size()); RTC_DCHECK_EQ(spectra_.buffer[i].size(), ffts_.buffer[i].size()); } @@ -211,7 +208,7 @@ void RenderDelayBufferImpl::Reset() { // Inserts a new block into the render buffers. RenderDelayBuffer::BufferingEvent RenderDelayBufferImpl::Insert( - const std::vector>>& block) { + const Block& block) { ++render_call_counter_; if (delay_) { if (!last_call_was_render_) { @@ -239,7 +236,8 @@ RenderDelayBuffer::BufferingEvent RenderDelayBufferImpl::Insert( // Detect and update render activity. if (!render_activity_) { - render_activity_counter_ += DetectActiveRender(block[0][0]) ? 1 : 0; + render_activity_counter_ += + DetectActiveRender(block.View(/*band=*/0, /*channel=*/0)) ? 1 : 0; render_activity_ = render_activity_counter_ >= 20; } @@ -394,46 +392,45 @@ void RenderDelayBufferImpl::AlignFromExternalDelay() { } // Inserts a block into the render buffers. -void RenderDelayBufferImpl::InsertBlock( - const std::vector>>& block, - int previous_write) { +void RenderDelayBufferImpl::InsertBlock(const Block& block, + int previous_write) { auto& b = blocks_; auto& lr = low_rate_; auto& ds = render_ds_; auto& f = ffts_; auto& s = spectra_; - const size_t num_bands = b.buffer[b.write].size(); - const size_t num_render_channels = b.buffer[b.write][0].size(); - RTC_DCHECK_EQ(block.size(), b.buffer[b.write].size()); + const size_t num_bands = b.buffer[b.write].NumBands(); + const size_t num_render_channels = b.buffer[b.write].NumChannels(); + RTC_DCHECK_EQ(block.NumBands(), num_bands); + RTC_DCHECK_EQ(block.NumChannels(), num_render_channels); for (size_t band = 0; band < num_bands; ++band) { - RTC_DCHECK_EQ(block[band].size(), num_render_channels); - RTC_DCHECK_EQ(b.buffer[b.write][band].size(), num_render_channels); for (size_t ch = 0; ch < num_render_channels; ++ch) { - RTC_DCHECK_EQ(block[band][ch].size(), b.buffer[b.write][band][ch].size()); - std::copy(block[band][ch].begin(), block[band][ch].end(), - b.buffer[b.write][band][ch].begin()); + std::copy(block.begin(band, ch), block.end(band, ch), + b.buffer[b.write].begin(band, ch)); } } if (render_linear_amplitude_gain_ != 1.f) { for (size_t band = 0; band < num_bands; ++band) { for (size_t ch = 0; ch < num_render_channels; ++ch) { - for (size_t k = 0; k < 64; ++k) { - b.buffer[b.write][band][ch][k] *= render_linear_amplitude_gain_; + rtc::ArrayView b_view = + b.buffer[b.write].View(band, ch); + for (float& sample : b_view) { + sample *= render_linear_amplitude_gain_; } } } } std::array downmixed_render; - render_mixer_.ProduceOutput(b.buffer[b.write][0], downmixed_render); + render_mixer_.ProduceOutput(b.buffer[b.write], downmixed_render); render_decimator_.Decimate(downmixed_render, ds); data_dumper_->DumpWav("aec3_render_decimator_output", ds.size(), ds.data(), 16000 / down_sampling_factor_, 1); std::copy(ds.rbegin(), ds.rend(), lr.buffer.begin() + lr.write); - for (size_t channel = 0; channel < b.buffer[b.write][0].size(); ++channel) { - fft_.PaddedFft(b.buffer[b.write][0][channel], - b.buffer[previous_write][0][channel], + for (int channel = 0; channel < b.buffer[b.write].NumChannels(); ++channel) { + fft_.PaddedFft(b.buffer[b.write].View(/*band=*/0, channel), + b.buffer[previous_write].View(/*band=*/0, channel), &f.buffer[f.write][channel]); f.buffer[f.write][channel].Spectrum(optimization_, s.buffer[s.write][channel]); diff --git a/modules/audio_processing/aec3/render_delay_buffer.h b/modules/audio_processing/aec3/render_delay_buffer.h index 79ffc4d8c9..6dc1aefb85 100644 --- a/modules/audio_processing/aec3/render_delay_buffer.h +++ b/modules/audio_processing/aec3/render_delay_buffer.h @@ -16,6 +16,7 @@ #include #include "api/audio/echo_canceller3_config.h" +#include "modules/audio_processing/aec3/block.h" #include "modules/audio_processing/aec3/downsampled_render_buffer.h" #include "modules/audio_processing/aec3/render_buffer.h" @@ -41,8 +42,7 @@ class RenderDelayBuffer { virtual void Reset() = 0; // Inserts a block into the buffer. - virtual BufferingEvent Insert( - const std::vector>>& block) = 0; + virtual BufferingEvent Insert(const Block& block) = 0; // Updates the buffers one step based on the specified buffer delay. Returns // an enum indicating whether there was a special event that occurred. diff --git a/modules/audio_processing/aec3/render_delay_buffer_unittest.cc b/modules/audio_processing/aec3/render_delay_buffer_unittest.cc index efd4a29920..d51e06a1ac 100644 --- a/modules/audio_processing/aec3/render_delay_buffer_unittest.cc +++ b/modules/audio_processing/aec3/render_delay_buffer_unittest.cc @@ -40,10 +40,7 @@ TEST(RenderDelayBuffer, BufferOverflow) { SCOPED_TRACE(ProduceDebugText(rate)); std::unique_ptr delay_buffer( RenderDelayBuffer::Create(config, rate, num_channels)); - std::vector>> block_to_insert( - NumBandsForRate(rate), - std::vector>(num_channels, - std::vector(kBlockSize, 0.f))); + Block block_to_insert(NumBandsForRate(rate), num_channels); for (size_t k = 0; k < 10; ++k) { EXPECT_EQ(RenderDelayBuffer::BufferingEvent::kNone, delay_buffer->Insert(block_to_insert)); @@ -69,9 +66,7 @@ TEST(RenderDelayBuffer, AvailableBlock) { constexpr size_t kNumBands = NumBandsForRate(kSampleRateHz); std::unique_ptr delay_buffer(RenderDelayBuffer::Create( EchoCanceller3Config(), kSampleRateHz, kNumChannels)); - std::vector>> input_block( - kNumBands, std::vector>( - kNumChannels, std::vector(kBlockSize, 1.f))); + Block input_block(kNumBands, kNumChannels, 1.0f); EXPECT_EQ(RenderDelayBuffer::BufferingEvent::kNone, delay_buffer->Insert(input_block)); delay_buffer->PrepareCaptureProcessing(); @@ -110,10 +105,8 @@ TEST(RenderDelayBufferDeathTest, WrongNumberOfBands) { SCOPED_TRACE(ProduceDebugText(rate)); std::unique_ptr delay_buffer(RenderDelayBuffer::Create( EchoCanceller3Config(), rate, num_channels)); - std::vector>> block_to_insert( - NumBandsForRate(rate < 48000 ? rate + 16000 : 16000), - std::vector>(num_channels, - std::vector(kBlockSize, 0.f))); + Block block_to_insert( + NumBandsForRate(rate < 48000 ? rate + 16000 : 16000), num_channels); EXPECT_DEATH(delay_buffer->Insert(block_to_insert), ""); } } @@ -126,26 +119,7 @@ TEST(RenderDelayBufferDeathTest, WrongNumberOfChannels) { SCOPED_TRACE(ProduceDebugText(rate)); std::unique_ptr delay_buffer(RenderDelayBuffer::Create( EchoCanceller3Config(), rate, num_channels)); - std::vector>> block_to_insert( - NumBandsForRate(rate), - std::vector>(num_channels + 1, - std::vector(kBlockSize, 0.f))); - EXPECT_DEATH(delay_buffer->Insert(block_to_insert), ""); - } - } -} - -// Verifies the check of the length of the inserted blocks. -TEST(RenderDelayBufferDeathTest, WrongBlockLength) { - for (auto rate : {16000, 32000, 48000}) { - for (size_t num_channels : {1, 2, 8}) { - SCOPED_TRACE(ProduceDebugText(rate)); - std::unique_ptr delay_buffer(RenderDelayBuffer::Create( - EchoCanceller3Config(), rate, num_channels)); - std::vector>> block_to_insert( - NumBandsForRate(rate), - std::vector>( - num_channels, std::vector(kBlockSize - 1, 0.f))); + Block block_to_insert(NumBandsForRate(rate), num_channels + 1); EXPECT_DEATH(delay_buffer->Insert(block_to_insert), ""); } } diff --git a/modules/audio_processing/aec3/render_delay_controller.cc b/modules/audio_processing/aec3/render_delay_controller.cc index 3677085d81..8860404665 100644 --- a/modules/audio_processing/aec3/render_delay_controller.cc +++ b/modules/audio_processing/aec3/render_delay_controller.cc @@ -47,7 +47,7 @@ class RenderDelayControllerImpl final : public RenderDelayController { absl::optional GetDelay( const DownsampledRenderBuffer& render_buffer, size_t render_delay_buffer_delay, - const std::vector>& capture) override; + const Block& capture) override; bool HasClockdrift() const override; private: @@ -124,8 +124,7 @@ void RenderDelayControllerImpl::LogRenderCall() {} absl::optional RenderDelayControllerImpl::GetDelay( const DownsampledRenderBuffer& render_buffer, size_t render_delay_buffer_delay, - const std::vector>& capture) { - RTC_DCHECK_EQ(kBlockSize, capture[0].size()); + const Block& capture) { ++capture_call_counter_; auto delay_samples = delay_estimator_.EstimateDelay(render_buffer, capture); diff --git a/modules/audio_processing/aec3/render_delay_controller.h b/modules/audio_processing/aec3/render_delay_controller.h index c45ab1f089..4a18a11e36 100644 --- a/modules/audio_processing/aec3/render_delay_controller.h +++ b/modules/audio_processing/aec3/render_delay_controller.h @@ -14,6 +14,7 @@ #include "absl/types/optional.h" #include "api/array_view.h" #include "api/audio/echo_canceller3_config.h" +#include "modules/audio_processing/aec3/block.h" #include "modules/audio_processing/aec3/delay_estimate.h" #include "modules/audio_processing/aec3/downsampled_render_buffer.h" #include "modules/audio_processing/aec3/render_delay_buffer.h" @@ -40,7 +41,7 @@ class RenderDelayController { virtual absl::optional GetDelay( const DownsampledRenderBuffer& render_buffer, size_t render_delay_buffer_delay, - const std::vector>& capture) = 0; + const Block& capture) = 0; // Returns true if clockdrift has been detected. virtual bool HasClockdrift() const = 0; diff --git a/modules/audio_processing/aec3/render_delay_controller_unittest.cc b/modules/audio_processing/aec3/render_delay_controller_unittest.cc index 0d3c856466..e1a54fca9e 100644 --- a/modules/audio_processing/aec3/render_delay_controller_unittest.cc +++ b/modules/audio_processing/aec3/render_delay_controller_unittest.cc @@ -53,8 +53,7 @@ constexpr size_t kDownSamplingFactors[] = {2, 4, 8}; // TODO(bugs.webrtc.org/11161): Re-enable tests. TEST(RenderDelayController, DISABLED_NoRenderSignal) { for (size_t num_render_channels : {1, 2, 8}) { - std::vector> block(1, - std::vector(kBlockSize, 0.f)); + Block block(/*num_bands=1*/ 1, /*num_channels=*/1); EchoCanceller3Config config; for (size_t num_matched_filters = 4; num_matched_filters <= 10; num_matched_filters++) { @@ -85,8 +84,7 @@ TEST(RenderDelayController, DISABLED_NoRenderSignal) { TEST(RenderDelayController, DISABLED_BasicApiCalls) { for (size_t num_capture_channels : {1, 2, 4}) { for (size_t num_render_channels : {1, 2, 8}) { - std::vector> capture_block( - num_capture_channels, std::vector(kBlockSize, 0.f)); + Block capture_block(/*num_bands=*/1, num_capture_channels); absl::optional delay_blocks; for (size_t num_matched_filters = 4; num_matched_filters <= 10; num_matched_filters++) { @@ -98,10 +96,7 @@ TEST(RenderDelayController, DISABLED_BasicApiCalls) { config.delay.capture_alignment_mixing.adaptive_selection = false; for (auto rate : {16000, 32000, 48000}) { - std::vector>> render_block( - NumBandsForRate(rate), - std::vector>( - num_render_channels, std::vector(kBlockSize, 0.f))); + Block render_block(NumBandsForRate(rate), num_render_channels); std::unique_ptr render_delay_buffer( RenderDelayBuffer::Create(config, rate, num_render_channels)); std::unique_ptr delay_controller( @@ -130,8 +125,7 @@ TEST(RenderDelayController, DISABLED_BasicApiCalls) { TEST(RenderDelayController, DISABLED_Alignment) { Random random_generator(42U); for (size_t num_capture_channels : {1, 2, 4}) { - std::vector> capture_block( - num_capture_channels, std::vector(kBlockSize, 0.f)); + Block capture_block(/*num_bands=*/1, num_capture_channels); for (size_t num_matched_filters = 4; num_matched_filters <= 10; num_matched_filters++) { for (auto down_sampling_factor : kDownSamplingFactors) { @@ -143,10 +137,7 @@ TEST(RenderDelayController, DISABLED_Alignment) { for (size_t num_render_channels : {1, 2, 8}) { for (auto rate : {16000, 32000, 48000}) { - std::vector>> render_block( - NumBandsForRate(rate), - std::vector>( - num_render_channels, std::vector(kBlockSize, 0.f))); + Block render_block(NumBandsForRate(rate), num_render_channels); for (size_t delay_samples : {15, 50, 150, 200, 800, 4000}) { absl::optional delay_blocks; @@ -160,14 +151,16 @@ TEST(RenderDelayController, DISABLED_Alignment) { num_capture_channels)); DelayBuffer signal_delay_buffer(delay_samples); for (size_t k = 0; k < (400 + delay_samples / kBlockSize); ++k) { - for (size_t band = 0; band < render_block.size(); ++band) { - for (size_t channel = 0; channel < render_block[band].size(); + for (int band = 0; band < render_block.NumBands(); ++band) { + for (int channel = 0; channel < render_block.NumChannels(); ++channel) { RandomizeSampleVector(&random_generator, - render_block[band][channel]); + render_block.View(band, channel)); } } - signal_delay_buffer.Delay(render_block[0][0], capture_block[0]); + signal_delay_buffer.Delay( + render_block.View(/*band=*/0, /*channel=*/0), + capture_block.View(/*band=*/0, /*channel=*/0)); render_delay_buffer->Insert(render_block); render_delay_buffer->PrepareCaptureProcessing(); delay_blocks = delay_controller->GetDelay( @@ -206,14 +199,8 @@ TEST(RenderDelayController, DISABLED_NonCausalAlignment) { config.delay.capture_alignment_mixing.downmix = false; config.delay.capture_alignment_mixing.adaptive_selection = false; for (auto rate : {16000, 32000, 48000}) { - std::vector>> render_block( - NumBandsForRate(rate), - std::vector>( - num_render_channels, std::vector(kBlockSize, 0.f))); - std::vector>> capture_block( - NumBandsForRate(rate), - std::vector>( - num_capture_channels, std::vector(kBlockSize, 0.f))); + Block render_block(NumBandsForRate(rate), num_render_channels); + Block capture_block(NumBandsForRate(rate), num_capture_channels); for (int delay_samples : {-15, -50, -150, -200}) { absl::optional delay_blocks; @@ -229,14 +216,17 @@ TEST(RenderDelayController, DISABLED_NonCausalAlignment) { for (int k = 0; k < (400 - delay_samples / static_cast(kBlockSize)); ++k) { - RandomizeSampleVector(&random_generator, capture_block[0][0]); - signal_delay_buffer.Delay(capture_block[0][0], - render_block[0][0]); + RandomizeSampleVector( + &random_generator, + capture_block.View(/*band=*/0, /*channel=*/0)); + signal_delay_buffer.Delay( + capture_block.View(/*band=*/0, /*channel=*/0), + render_block.View(/*band=*/0, /*channel=*/0)); render_delay_buffer->Insert(render_block); render_delay_buffer->PrepareCaptureProcessing(); delay_blocks = delay_controller->GetDelay( render_delay_buffer->GetDownsampledRenderBuffer(), - render_delay_buffer->Delay(), capture_block[0]); + render_delay_buffer->Delay(), capture_block); } ASSERT_FALSE(delay_blocks); @@ -255,8 +245,8 @@ TEST(RenderDelayController, DISABLED_AlignmentWithJitter) { Random random_generator(42U); for (size_t num_capture_channels : {1, 2, 4}) { for (size_t num_render_channels : {1, 2, 8}) { - std::vector> capture_block( - num_capture_channels, std::vector(kBlockSize, 0.f)); + Block capture_block( + /*num_bands=*/1, num_capture_channels); for (size_t num_matched_filters = 4; num_matched_filters <= 10; num_matched_filters++) { for (auto down_sampling_factor : kDownSamplingFactors) { @@ -267,10 +257,7 @@ TEST(RenderDelayController, DISABLED_AlignmentWithJitter) { config.delay.capture_alignment_mixing.adaptive_selection = false; for (auto rate : {16000, 32000, 48000}) { - std::vector>> render_block( - NumBandsForRate(rate), - std::vector>( - num_render_channels, std::vector(kBlockSize, 0.f))); + Block render_block(NumBandsForRate(rate), num_render_channels); for (size_t delay_samples : {15, 50, 300, 800}) { absl::optional delay_blocks; SCOPED_TRACE(ProduceDebugText(rate, delay_samples, @@ -287,12 +274,14 @@ TEST(RenderDelayController, DISABLED_AlignmentWithJitter) { kMaxTestJitterBlocks + 1; ++j) { - std::vector>> - capture_block_buffer; + std::vector capture_block_buffer; for (size_t k = 0; k < (kMaxTestJitterBlocks - 1); ++k) { - RandomizeSampleVector(&random_generator, render_block[0][0]); - signal_delay_buffer.Delay(render_block[0][0], - capture_block[0]); + RandomizeSampleVector( + &random_generator, + render_block.View(/*band=*/0, /*channel=*/0)); + signal_delay_buffer.Delay( + render_block.View(/*band=*/0, /*channel=*/0), + capture_block.View(/*band=*/0, /*channel=*/0)); capture_block_buffer.push_back(capture_block); render_delay_buffer->Insert(render_block); } @@ -324,24 +313,6 @@ TEST(RenderDelayController, DISABLED_AlignmentWithJitter) { #if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID) -// Verifies the check for the capture signal block size. -TEST(RenderDelayControllerDeathTest, WrongCaptureSize) { - std::vector> block( - 1, std::vector(kBlockSize - 1, 0.f)); - EchoCanceller3Config config; - for (auto rate : {16000, 32000, 48000}) { - SCOPED_TRACE(ProduceDebugText(rate)); - std::unique_ptr render_delay_buffer( - RenderDelayBuffer::Create(config, rate, 1)); - EXPECT_DEATH( - std::unique_ptr( - RenderDelayController::Create(EchoCanceller3Config(), rate, 1)) - ->GetDelay(render_delay_buffer->GetDownsampledRenderBuffer(), - render_delay_buffer->Delay(), block), - ""); - } -} - // Verifies the check for correct sample rate. // TODO(peah): Re-enable the test once the issue with memory leaks during DEATH // tests on test bots has been fixed. diff --git a/modules/audio_processing/aec3/render_signal_analyzer.cc b/modules/audio_processing/aec3/render_signal_analyzer.cc index f570aac3a0..a3f27b7b56 100644 --- a/modules/audio_processing/aec3/render_signal_analyzer.cc +++ b/modules/audio_processing/aec3/render_signal_analyzer.cc @@ -66,10 +66,9 @@ void IdentifyStrongNarrowBandComponent(const RenderBuffer& render_buffer, *narrow_peak_band = absl::nullopt; } - const std::vector>>& x_latest = - render_buffer.Block(0); + const Block& x_latest = render_buffer.Block(0); float max_peak_level = 0.f; - for (size_t channel = 0; channel < x_latest[0].size(); ++channel) { + for (int channel = 0; channel < x_latest.NumChannels(); ++channel) { rtc::ArrayView X2_latest = render_buffer.Spectrum(0)[channel]; @@ -90,13 +89,14 @@ void IdentifyStrongNarrowBandComponent(const RenderBuffer& render_buffer, } // Assess the render signal strength. - auto result0 = std::minmax_element(x_latest[0][channel].begin(), - x_latest[0][channel].end()); + auto result0 = std::minmax_element(x_latest.begin(/*band=*/0, channel), + x_latest.end(/*band=*/0, channel)); float max_abs = std::max(fabs(*result0.first), fabs(*result0.second)); - if (x_latest.size() > 1) { - const auto result1 = std::minmax_element(x_latest[1][channel].begin(), - x_latest[1][channel].end()); + if (x_latest.NumBands() > 1) { + const auto result1 = + std::minmax_element(x_latest.begin(/*band=*/1, channel), + x_latest.end(/*band=*/1, channel)); max_abs = std::max(max_abs, static_cast(std::max( fabs(*result1.first), fabs(*result1.second)))); diff --git a/modules/audio_processing/aec3/render_signal_analyzer_unittest.cc b/modules/audio_processing/aec3/render_signal_analyzer_unittest.cc index 7a48cc4b69..16f6280cb6 100644 --- a/modules/audio_processing/aec3/render_signal_analyzer_unittest.cc +++ b/modules/audio_processing/aec3/render_signal_analyzer_unittest.cc @@ -36,18 +36,18 @@ void ProduceSinusoidInNoise(int sample_rate_hz, float sinusoidal_frequency_hz, Random* random_generator, size_t* sample_counter, - std::vector>>* x) { + Block* x) { // Fill x with low-amplitude noise. - for (auto& band : *x) { - for (auto& channel : band) { - RandomizeSampleVector(random_generator, channel, + for (int band = 0; band < x->NumBands(); ++band) { + for (int channel = 0; channel < x->NumChannels(); ++channel) { + RandomizeSampleVector(random_generator, x->View(band, channel), /*amplitude=*/500.f); } } // Produce a sinusoid of the specified frequency in the specified channel. for (size_t k = *sample_counter, j = 0; k < (*sample_counter + kBlockSize); ++k, ++j) { - (*x)[0][sinusoid_channel][j] += + x->View(/*band=*/0, sinusoid_channel)[j] += 32000.f * std::sin(2.f * kPi * sinusoidal_frequency_hz * k / sample_rate_hz); } @@ -59,9 +59,7 @@ void RunNarrowBandDetectionTest(size_t num_channels) { Random random_generator(42U); constexpr int kSampleRateHz = 48000; constexpr size_t kNumBands = NumBandsForRate(kSampleRateHz); - std::vector>> x( - kNumBands, std::vector>( - num_channels, std::vector(kBlockSize, 0.f))); + Block x(kNumBands, num_channels); std::array x_old; Aec3Fft fft; EchoCanceller3Config config; @@ -130,19 +128,17 @@ TEST(RenderSignalAnalyzer, NoFalseDetectionOfNarrowBands) { SCOPED_TRACE(ProduceDebugText(num_channels)); RenderSignalAnalyzer analyzer(EchoCanceller3Config{}); Random random_generator(42U); - std::vector>> x( - 3, std::vector>( - num_channels, std::vector(kBlockSize, 0.f))); + Block x(3, num_channels); std::array x_old; std::unique_ptr render_delay_buffer( RenderDelayBuffer::Create(EchoCanceller3Config(), 48000, num_channels)); std::array mask; x_old.fill(0.f); - for (size_t k = 0; k < 100; ++k) { - for (auto& band : x) { - for (auto& channel : band) { - RandomizeSampleVector(&random_generator, channel); + for (int k = 0; k < 100; ++k) { + for (int band = 0; band < x.NumBands(); ++band) { + for (int channel = 0; channel < x.NumChannels(); ++channel) { + RandomizeSampleVector(&random_generator, x.View(band, channel)); } } diff --git a/modules/audio_processing/aec3/residual_echo_estimator_unittest.cc b/modules/audio_processing/aec3/residual_echo_estimator_unittest.cc index 05a610335b..9a7bf0a89c 100644 --- a/modules/audio_processing/aec3/residual_echo_estimator_unittest.cc +++ b/modules/audio_processing/aec3/residual_echo_estimator_unittest.cc @@ -47,10 +47,7 @@ class ResidualEchoEstimatorTest { Y2_(num_capture_channels_), R2_(num_capture_channels_), R2_unbounded_(num_capture_channels_), - x_(kNumBands, - std::vector>( - num_render_channels_, - std::vector(kBlockSize, 0.0f))), + x_(kNumBands, num_render_channels_), H2_(num_capture_channels_, std::vector>(10)), h_(num_capture_channels_, @@ -84,7 +81,8 @@ class ResidualEchoEstimatorTest { } void RunOneFrame(bool dominant_nearend) { - RandomizeSampleVector(&random_generator_, x_[0][0]); + RandomizeSampleVector(&random_generator_, + x_.View(/*band=*/0, /*channel=*/0)); render_delay_buffer_->Insert(x_); if (first_frame_) { render_delay_buffer_->Reset(); @@ -116,7 +114,7 @@ class ResidualEchoEstimatorTest { std::vector> Y2_; std::vector> R2_; std::vector> R2_unbounded_; - std::vector>> x_; + Block x_; std::vector>> H2_; std::vector> h_; Random random_generator_; diff --git a/modules/audio_processing/aec3/signal_dependent_erle_estimator_unittest.cc b/modules/audio_processing/aec3/signal_dependent_erle_estimator_unittest.cc index 58f56d8d53..67927a6c68 100644 --- a/modules/audio_processing/aec3/signal_dependent_erle_estimator_unittest.cc +++ b/modules/audio_processing/aec3/signal_dependent_erle_estimator_unittest.cc @@ -24,7 +24,7 @@ namespace webrtc { namespace { -void GetActiveFrame(std::vector>>* x) { +void GetActiveFrame(Block* x) { const std::array frame = { 7459.88, 17209.6, 17383, 20768.9, 16816.7, 18386.3, 4492.83, 9675.85, 6665.52, 14808.6, 9342.3, 7483.28, 19261.7, 4145.98, 1622.18, 13475.2, @@ -34,10 +34,10 @@ void GetActiveFrame(std::vector>>* x) { 11405, 15031.4, 14541.6, 19765.5, 18346.3, 19350.2, 3157.47, 18095.8, 1743.68, 21328.2, 19727.5, 7295.16, 10332.4, 11055.5, 20107.4, 14708.4, 12416.2, 16434, 2454.69, 9840.8, 6867.23, 1615.75, 6059.9, 8394.19}; - for (size_t band = 0; band < x->size(); ++band) { - for (size_t channel = 0; channel < (*x)[band].size(); ++channel) { - RTC_DCHECK_GE((*x)[band][channel].size(), frame.size()); - std::copy(frame.begin(), frame.end(), (*x)[band][channel].begin()); + for (int band = 0; band < x->NumBands(); ++band) { + for (int channel = 0; channel < x->NumChannels(); ++channel) { + RTC_DCHECK_GE(kBlockSize, frame.size()); + std::copy(frame.begin(), frame.end(), x->begin(band, channel)); } } } @@ -74,7 +74,7 @@ class TestInputs { std::vector> Y2_; std::vector> E2_; std::vector>> H2_; - std::vector>> x_; + Block x_; std::vector converged_filters_; }; @@ -88,9 +88,7 @@ TestInputs::TestInputs(const EchoCanceller3Config& cfg, H2_(num_capture_channels, std::vector>( cfg.filter.refined.length_blocks)), - x_(1, - std::vector>(num_render_channels, - std::vector(kBlockSize, 0.f))), + x_(1, num_render_channels), converged_filters_(num_capture_channels, true) { render_delay_buffer_->AlignFromDelay(4); render_buffer_ = render_delay_buffer_->GetRenderBuffer(); @@ -108,7 +106,8 @@ TestInputs::~TestInputs() = default; void TestInputs::Update() { if (n_ % 2 == 0) { - std::fill(x_[0][0].begin(), x_[0][0].end(), 0.f); + std::fill(x_.begin(/*band=*/0, /*channel=*/0), + x_.end(/*band=*/0, /*channel=*/0), 0.f); } else { GetActiveFrame(&x_); } diff --git a/modules/audio_processing/aec3/subtractor.cc b/modules/audio_processing/aec3/subtractor.cc index 2eae686752..aa36bb272a 100644 --- a/modules/audio_processing/aec3/subtractor.cc +++ b/modules/audio_processing/aec3/subtractor.cc @@ -176,11 +176,11 @@ void Subtractor::ExitInitialState() { } void Subtractor::Process(const RenderBuffer& render_buffer, - const std::vector>& capture, + const Block& capture, const RenderSignalAnalyzer& render_signal_analyzer, const AecState& aec_state, rtc::ArrayView outputs) { - RTC_DCHECK_EQ(num_capture_channels_, capture.size()); + RTC_DCHECK_EQ(num_capture_channels_, capture.NumChannels()); // Compute the render powers. const bool same_filter_sizes = refined_filters_[0]->SizePartitions() == @@ -204,9 +204,8 @@ void Subtractor::Process(const RenderBuffer& render_buffer, // 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 y = capture[ch]; + rtc::ArrayView y = capture.View(/*band=*/0, ch); FftData& E_refined = output.E_refined; FftData E_coarse; std::array& e_refined = output.e_refined; diff --git a/modules/audio_processing/aec3/subtractor.h b/modules/audio_processing/aec3/subtractor.h index 767e4aad46..86159a3442 100644 --- a/modules/audio_processing/aec3/subtractor.h +++ b/modules/audio_processing/aec3/subtractor.h @@ -23,6 +23,7 @@ #include "modules/audio_processing/aec3/aec3_common.h" #include "modules/audio_processing/aec3/aec3_fft.h" #include "modules/audio_processing/aec3/aec_state.h" +#include "modules/audio_processing/aec3/block.h" #include "modules/audio_processing/aec3/coarse_filter_update_gain.h" #include "modules/audio_processing/aec3/echo_path_variability.h" #include "modules/audio_processing/aec3/refined_filter_update_gain.h" @@ -48,7 +49,7 @@ class Subtractor { // Performs the echo subtraction. void Process(const RenderBuffer& render_buffer, - const std::vector>& capture, + const Block& capture, const RenderSignalAnalyzer& render_signal_analyzer, const AecState& aec_state, rtc::ArrayView outputs); diff --git a/modules/audio_processing/aec3/subtractor_unittest.cc b/modules/audio_processing/aec3/subtractor_unittest.cc index bbc1e4ffc6..56b9cec9f1 100644 --- a/modules/audio_processing/aec3/subtractor_unittest.cc +++ b/modules/audio_processing/aec3/subtractor_unittest.cc @@ -45,11 +45,8 @@ std::vector RunSubtractorTest( Subtractor subtractor(config, num_render_channels, num_capture_channels, &data_dumper, DetectOptimization()); absl::optional delay_estimate; - std::vector>> x( - kNumBands, std::vector>( - num_render_channels, std::vector(kBlockSize, 0.f))); - std::vector> y(num_capture_channels, - std::vector(kBlockSize, 0.f)); + Block x(kNumBands, num_render_channels); + Block y(/*num_bands=*/1, num_capture_channels); std::array x_old; std::vector output(num_capture_channels); config.delay.default_delay = 1; @@ -101,32 +98,34 @@ std::vector RunSubtractorTest( for (int k = 0; k < num_blocks_to_process; ++k) { for (size_t render_ch = 0; render_ch < num_render_channels; ++render_ch) { - RandomizeSampleVector(&random_generator, x[0][render_ch]); + RandomizeSampleVector(&random_generator, x.View(/*band=*/0, render_ch)); } if (uncorrelated_inputs) { for (size_t capture_ch = 0; capture_ch < num_capture_channels; ++capture_ch) { - RandomizeSampleVector(&random_generator, y[capture_ch]); + RandomizeSampleVector(&random_generator, + y.View(/*band=*/0, capture_ch)); } } else { for (size_t capture_ch = 0; capture_ch < num_capture_channels; ++capture_ch) { + rtc::ArrayView y_view = y.View(/*band=*/0, capture_ch); for (size_t render_ch = 0; render_ch < num_render_channels; ++render_ch) { std::array y_channel; - delay_buffer[capture_ch][render_ch]->Delay(x[0][render_ch], - y_channel); - for (size_t k = 0; k < y.size(); ++k) { - y[capture_ch][k] += y_channel[k] / num_render_channels; + delay_buffer[capture_ch][render_ch]->Delay( + x.View(/*band=*/0, render_ch), y_channel); + for (size_t k = 0; k < kBlockSize; ++k) { + y_view[k] += y_channel[k] / num_render_channels; } } } } for (size_t ch = 0; ch < num_render_channels; ++ch) { - x_hp_filter[ch]->Process(x[0][ch]); + x_hp_filter[ch]->Process(x.View(/*band=*/0, ch)); } for (size_t ch = 0; ch < num_capture_channels; ++ch) { - y_hp_filter[ch]->Process(y[ch]); + y_hp_filter[ch]->Process(y.View(/*band=*/0, ch)); } render_delay_buffer->Insert(x); @@ -162,7 +161,8 @@ std::vector RunSubtractorTest( output[ch].e_refined.begin(), output[ch].e_refined.end(), output[ch].e_refined.begin(), 0.f); const float y_power = - std::inner_product(y[ch].begin(), y[ch].end(), y[ch].begin(), 0.f); + std::inner_product(y.begin(/*band=*/0, ch), y.end(/*band=*/0, ch), + y.begin(/*band=*/0, ch), 0.f); if (y_power == 0.f) { ADD_FAILURE(); results[ch] = -1.f; @@ -195,23 +195,6 @@ TEST(SubtractorDeathTest, NullDataDumper) { ""); } -// Verifies the check for the capture signal size. -TEST(Subtractor, WrongCaptureSize) { - ApmDataDumper data_dumper(42); - EchoCanceller3Config config; - Subtractor subtractor(config, 1, 1, &data_dumper, DetectOptimization()); - std::unique_ptr render_delay_buffer( - RenderDelayBuffer::Create(config, 48000, 1)); - RenderSignalAnalyzer render_signal_analyzer(config); - std::vector> y(1, std::vector(kBlockSize - 1, 0.f)); - std::array output; - - EXPECT_DEATH( - subtractor.Process(*render_delay_buffer->GetRenderBuffer(), y, - render_signal_analyzer, AecState(config, 1), output), - ""); -} - #endif // Verifies that the subtractor is able to converge on correlated data. diff --git a/modules/audio_processing/aec3/suppression_filter.cc b/modules/audio_processing/aec3/suppression_filter.cc index 1312fa892b..83ded425d5 100644 --- a/modules/audio_processing/aec3/suppression_filter.cc +++ b/modules/audio_processing/aec3/suppression_filter.cc @@ -86,9 +86,9 @@ void SuppressionFilter::ApplyGain( const std::array& suppression_gain, float high_bands_gain, rtc::ArrayView E_lowest_band, - std::vector>>* e) { + Block* e) { RTC_DCHECK(e); - RTC_DCHECK_EQ(e->size(), NumBandsForRate(sample_rate_hz_)); + RTC_DCHECK_EQ(e->NumBands(), NumBandsForRate(sample_rate_hz_)); // Comfort noise gain is sqrt(1-g^2), where g is the suppression gain. std::array noise_gain; @@ -121,7 +121,7 @@ void SuppressionFilter::ApplyGain( constexpr float kIfftNormalization = 2.f / kFftLength; fft_.Ifft(E, &e_extended); - float* e0 = (*e)[0][ch].data(); + auto e0 = e->View(/*band=*/0, ch); float* e0_old = e_output_old_[0][ch].data(); // Window and add the first half of e_extended with the second half of @@ -138,20 +138,20 @@ void SuppressionFilter::ApplyGain( std::begin(e_output_old_[0][ch])); // Apply suppression gain to upper bands. - for (size_t b = 1; b < e->size(); ++b) { - float* e_band = (*e)[b][ch].data(); + for (int b = 1; b < e->NumBands(); ++b) { + auto e_band = e->View(b, ch); for (size_t i = 0; i < kFftLengthBy2; ++i) { e_band[i] *= high_bands_gain; } } // Add comfort noise to band 1. - if (e->size() > 1) { + if (e->NumBands() > 1) { E.Assign(comfort_noise_high_band[ch]); std::array time_domain_high_band_noise; fft_.Ifft(E, &time_domain_high_band_noise); - float* e1 = (*e)[1][ch].data(); + auto e1 = e->View(/*band=*/1, ch); const float gain = high_bands_noise_scaling * kIfftNormalization; for (size_t i = 0; i < kFftLengthBy2; ++i) { e1[i] += time_domain_high_band_noise[i] * gain; @@ -159,8 +159,8 @@ void SuppressionFilter::ApplyGain( } // Delay upper bands to match the delay of the filter bank. - for (size_t b = 1; b < e->size(); ++b) { - float* e_band = (*e)[b][ch].data(); + for (int b = 1; b < e->NumBands(); ++b) { + auto e_band = e->View(b, ch); float* e_band_old = e_output_old_[b][ch].data(); for (size_t i = 0; i < kFftLengthBy2; ++i) { std::swap(e_band[i], e_band_old[i]); @@ -168,8 +168,8 @@ void SuppressionFilter::ApplyGain( } // Clamp output of all bands. - for (size_t b = 0; b < e->size(); ++b) { - float* e_band = (*e)[b][ch].data(); + for (int b = 0; b < e->NumBands(); ++b) { + auto e_band = e->View(b, ch); for (size_t i = 0; i < kFftLengthBy2; ++i) { e_band[i] = rtc::SafeClamp(e_band[i], -32768.f, 32767.f); } diff --git a/modules/audio_processing/aec3/suppression_filter.h b/modules/audio_processing/aec3/suppression_filter.h index 375bfda5a7..c18b2334bf 100644 --- a/modules/audio_processing/aec3/suppression_filter.h +++ b/modules/audio_processing/aec3/suppression_filter.h @@ -16,6 +16,7 @@ #include "modules/audio_processing/aec3/aec3_common.h" #include "modules/audio_processing/aec3/aec3_fft.h" +#include "modules/audio_processing/aec3/block.h" #include "modules/audio_processing/aec3/fft_data.h" namespace webrtc { @@ -35,7 +36,7 @@ class SuppressionFilter { const std::array& suppression_gain, float high_bands_gain, rtc::ArrayView E_lowest_band, - std::vector>>* e); + Block* e); private: const Aec3Optimization optimization_; diff --git a/modules/audio_processing/aec3/suppression_filter_unittest.cc b/modules/audio_processing/aec3/suppression_filter_unittest.cc index a160bec045..464f5cfed2 100644 --- a/modules/audio_processing/aec3/suppression_filter_unittest.cc +++ b/modules/audio_processing/aec3/suppression_filter_unittest.cc @@ -26,21 +26,21 @@ constexpr float kPi = 3.141592f; void ProduceSinusoid(int sample_rate_hz, float sinusoidal_frequency_hz, size_t* sample_counter, - std::vector>>* x) { + Block* x) { // Produce a sinusoid of the specified frequency. for (size_t k = *sample_counter, j = 0; k < (*sample_counter + kBlockSize); ++k, ++j) { - for (size_t channel = 0; channel < (*x)[0].size(); ++channel) { - (*x)[0][channel][j] = + for (int channel = 0; channel < x->NumChannels(); ++channel) { + x->View(/*band=*/0, channel)[j] = 32767.f * std::sin(2.f * kPi * sinusoidal_frequency_hz * k / sample_rate_hz); } } *sample_counter = *sample_counter + kBlockSize; - for (size_t band = 1; band < x->size(); ++band) { - for (size_t channel = 0; channel < (*x)[band].size(); ++channel) { - std::fill((*x)[band][channel].begin(), (*x)[band][channel].end(), 0.f); + for (int band = 1; band < x->NumBands(); ++band) { + for (int channel = 0; channel < x->NumChannels(); ++channel) { + std::fill(x->begin(band, channel), x->end(band, channel), 0.f); } } } @@ -84,21 +84,23 @@ TEST(SuppressionFilter, ComfortNoiseInUnityGain) { cn_high_bands[0].re.fill(1.f); cn_high_bands[0].im.fill(1.f); - std::vector>> e( - 3, - std::vector>(1, std::vector(kBlockSize, 0.f))); - std::vector>> e_ref = e; + Block e(3, kBlockSize); + Block e_ref = e; std::vector E(1); - fft.PaddedFft(e[0][0], e_old_, Aec3Fft::Window::kSqrtHanning, &E[0]); - std::copy(e[0][0].begin(), e[0][0].end(), e_old_.begin()); + fft.PaddedFft(e.View(/*band=*/0, /*channel=*/0), e_old_, + Aec3Fft::Window::kSqrtHanning, &E[0]); + std::copy(e.begin(/*band=*/0, /*channel=*/0), + e.end(/*band=*/0, /*channel=*/0), e_old_.begin()); filter.ApplyGain(cn, cn_high_bands, gain, 1.f, E, &e); - for (size_t band = 0; band < e.size(); ++band) { - for (size_t channel = 0; channel < e[band].size(); ++channel) { - for (size_t sample = 0; sample < e[band][channel].size(); ++sample) { - EXPECT_EQ(e_ref[band][channel][sample], e[band][channel][sample]); + for (int band = 0; band < e.NumBands(); ++band) { + for (int channel = 0; channel < e.NumChannels(); ++channel) { + const auto e_view = e.View(band, channel); + const auto e_ref_view = e_ref.View(band, channel); + for (size_t sample = 0; sample < e_view.size(); ++sample) { + EXPECT_EQ(e_ref_view[sample], e_view[sample]); } } } @@ -116,9 +118,7 @@ TEST(SuppressionFilter, SignalSuppression) { std::array e_old_; Aec3Fft fft; std::array gain; - std::vector>> e( - kNumBands, std::vector>( - kNumChannels, std::vector(kBlockSize, 0.f))); + Block e(kNumBands, kNumChannels); e_old_.fill(0.f); gain.fill(1.f); @@ -135,16 +135,20 @@ TEST(SuppressionFilter, SignalSuppression) { float e0_output = 0.f; for (size_t k = 0; k < 100; ++k) { ProduceSinusoid(16000, 16000 * 40 / kFftLengthBy2 / 2, &sample_counter, &e); - e0_input = std::inner_product(e[0][0].begin(), e[0][0].end(), - e[0][0].begin(), e0_input); + e0_input = std::inner_product(e.begin(/*band=*/0, /*channel=*/0), + e.end(/*band=*/0, /*channel=*/0), + e.begin(/*band=*/0, /*channel=*/0), e0_input); std::vector E(1); - fft.PaddedFft(e[0][0], e_old_, Aec3Fft::Window::kSqrtHanning, &E[0]); - std::copy(e[0][0].begin(), e[0][0].end(), e_old_.begin()); + fft.PaddedFft(e.View(/*band=*/0, /*channel=*/0), e_old_, + Aec3Fft::Window::kSqrtHanning, &E[0]); + std::copy(e.begin(/*band=*/0, /*channel=*/0), + e.end(/*band=*/0, /*channel=*/0), e_old_.begin()); filter.ApplyGain(cn, cn_high_bands, gain, 1.f, E, &e); - e0_output = std::inner_product(e[0][0].begin(), e[0][0].end(), - e[0][0].begin(), e0_output); + e0_output = std::inner_product( + e.begin(/*band=*/0, /*channel=*/0), e.end(/*band=*/0, /*channel=*/0), + e.begin(/*band=*/0, /*channel=*/0), e0_output); } EXPECT_LT(e0_output, e0_input / 1000.f); @@ -163,9 +167,7 @@ TEST(SuppressionFilter, SignalTransparency) { Aec3Fft fft; std::vector cn_high_bands(1); std::array gain; - std::vector>> e( - kNumBands, std::vector>( - kNumChannels, std::vector(kBlockSize, 0.f))); + Block e(kNumBands, kNumChannels); e_old_.fill(0.f); gain.fill(1.f); std::for_each(gain.begin() + 30, gain.end(), [](float& a) { a = 0.f; }); @@ -181,16 +183,20 @@ TEST(SuppressionFilter, SignalTransparency) { float e0_output = 0.f; for (size_t k = 0; k < 100; ++k) { ProduceSinusoid(16000, 16000 * 10 / kFftLengthBy2 / 2, &sample_counter, &e); - e0_input = std::inner_product(e[0][0].begin(), e[0][0].end(), - e[0][0].begin(), e0_input); + e0_input = std::inner_product(e.begin(/*band=*/0, /*channel=*/0), + e.end(/*band=*/0, /*channel=*/0), + e.begin(/*band=*/0, /*channel=*/0), e0_input); std::vector E(1); - fft.PaddedFft(e[0][0], e_old_, Aec3Fft::Window::kSqrtHanning, &E[0]); - std::copy(e[0][0].begin(), e[0][0].end(), e_old_.begin()); + fft.PaddedFft(e.View(/*band=*/0, /*channel=*/0), e_old_, + Aec3Fft::Window::kSqrtHanning, &E[0]); + std::copy(e.begin(/*band=*/0, /*channel=*/0), + e.end(/*band=*/0, /*channel=*/0), e_old_.begin()); filter.ApplyGain(cn, cn_high_bands, gain, 1.f, E, &e); - e0_output = std::inner_product(e[0][0].begin(), e[0][0].end(), - e[0][0].begin(), e0_output); + e0_output = std::inner_product( + e.begin(/*band=*/0, /*channel=*/0), e.end(/*band=*/0, /*channel=*/0), + e.begin(/*band=*/0, /*channel=*/0), e0_output); } EXPECT_LT(0.9f * e0_input, e0_output); @@ -208,9 +214,7 @@ TEST(SuppressionFilter, Delay) { std::array e_old_; Aec3Fft fft; std::array gain; - std::vector>> e( - kNumBands, std::vector>( - kNumChannels, std::vector(kBlockSize, 0.f))); + Block e(kNumBands, kNumChannels); gain.fill(1.f); @@ -222,23 +226,27 @@ TEST(SuppressionFilter, Delay) { for (size_t k = 0; k < 100; ++k) { for (size_t band = 0; band < kNumBands; ++band) { for (size_t channel = 0; channel < kNumChannels; ++channel) { + auto e_view = e.View(band, channel); for (size_t sample = 0; sample < kBlockSize; ++sample) { - e[band][channel][sample] = k * kBlockSize + sample + channel; + e_view[sample] = k * kBlockSize + sample + channel; } } } std::vector E(1); - fft.PaddedFft(e[0][0], e_old_, Aec3Fft::Window::kSqrtHanning, &E[0]); - std::copy(e[0][0].begin(), e[0][0].end(), e_old_.begin()); + fft.PaddedFft(e.View(/*band=*/0, /*channel=*/0), e_old_, + Aec3Fft::Window::kSqrtHanning, &E[0]); + std::copy(e.begin(/*band=*/0, /*channel=*/0), + e.end(/*band=*/0, /*channel=*/0), e_old_.begin()); filter.ApplyGain(cn, cn_high_bands, gain, 1.f, E, &e); if (k > 2) { for (size_t band = 0; band < kNumBands; ++band) { for (size_t channel = 0; channel < kNumChannels; ++channel) { + const auto e_view = e.View(band, channel); for (size_t sample = 0; sample < kBlockSize; ++sample) { EXPECT_NEAR(k * kBlockSize + sample - kBlockSize + channel, - e[band][channel][sample], 0.01); + e_view[sample], 0.01); } } } diff --git a/modules/audio_processing/aec3/suppression_gain.cc b/modules/audio_processing/aec3/suppression_gain.cc index 14366f1aec..d6f592ae74 100644 --- a/modules/audio_processing/aec3/suppression_gain.cc +++ b/modules/audio_processing/aec3/suppression_gain.cc @@ -110,13 +110,13 @@ float SuppressionGain::UpperBandsGain( comfort_noise_spectrum, const absl::optional& narrow_peak_band, bool saturated_echo, - const std::vector>>& render, + const Block& render, const std::array& low_band_gain) const { - RTC_DCHECK_LT(0, render.size()); - if (render.size() == 1) { + RTC_DCHECK_LT(0, render.NumBands()); + if (render.NumBands() == 1) { return 1.f; } - const size_t num_render_channels = render[0].size(); + const int num_render_channels = render.NumChannels(); if (narrow_peak_band && (*narrow_peak_band > static_cast(kFftLengthBy2Plus1 - 10))) { @@ -135,16 +135,19 @@ float SuppressionGain::UpperBandsGain( // Compute the upper and lower band energies. const auto sum_of_squares = [](float a, float b) { return a + b * b; }; float low_band_energy = 0.f; - for (size_t ch = 0; ch < num_render_channels; ++ch) { + for (int ch = 0; ch < num_render_channels; ++ch) { + // TODO(bugs.webrtc.org/14108): Fix the computation below to compute the + // energy for each channel. const float channel_energy = std::accumulate( - render[0][0].begin(), render[0][0].end(), 0.f, sum_of_squares); + render.begin(/*band=0*/ 0, /*channel=*/0), + render.end(/*band=0*/ 0, /*channel=*/0), 0.f, sum_of_squares); low_band_energy = std::max(low_band_energy, channel_energy); } float high_band_energy = 0.f; - for (size_t k = 1; k < render.size(); ++k) { - for (size_t ch = 0; ch < num_render_channels; ++ch) { + for (int k = 1; k < render.NumBands(); ++k) { + for (int ch = 0; ch < num_render_channels; ++ch) { const float energy = std::accumulate( - render[k][ch].begin(), render[k][ch].end(), 0.f, sum_of_squares); + render.begin(k, ch), render.end(k, ch), 0.f, sum_of_squares); high_band_energy = std::max(high_band_energy, energy); } } @@ -372,7 +375,7 @@ void SuppressionGain::GetGain( comfort_noise_spectrum, const RenderSignalAnalyzer& render_signal_analyzer, const AecState& aec_state, - const std::vector>>& render, + const Block& render, bool clock_drift, float* high_bands_gain, std::array* low_band_gain) { @@ -417,20 +420,17 @@ void SuppressionGain::SetInitialState(bool state) { // Detects when the render signal can be considered to have low power and // consist of stationary noise. -bool SuppressionGain::LowNoiseRenderDetector::Detect( - const std::vector>>& render) { +bool SuppressionGain::LowNoiseRenderDetector::Detect(const Block& render) { float x2_sum = 0.f; float x2_max = 0.f; - for (const auto& x_ch : render[0]) { - for (const auto& x_k : x_ch) { + for (int ch = 0; ch < render.NumChannels(); ++ch) { + for (float x_k : render.View(/*band=*/0, ch)) { const float x2 = x_k * x_k; x2_sum += x2; x2_max = std::max(x2_max, x2); } } - const size_t num_render_channels = render[0].size(); - x2_sum = x2_sum / num_render_channels; - ; + x2_sum = x2_sum / render.NumChannels(); constexpr float kThreshold = 50.f * 50.f * 64.f; const bool low_noise_render = diff --git a/modules/audio_processing/aec3/suppression_gain.h b/modules/audio_processing/aec3/suppression_gain.h index c8e13f7cf4..e63c045c2d 100644 --- a/modules/audio_processing/aec3/suppression_gain.h +++ b/modules/audio_processing/aec3/suppression_gain.h @@ -51,7 +51,7 @@ class SuppressionGain { comfort_noise_spectrum, const RenderSignalAnalyzer& render_signal_analyzer, const AecState& aec_state, - const std::vector>>& render, + const Block& render, bool clock_drift, float* high_bands_gain, std::array* low_band_gain); @@ -71,7 +71,7 @@ class SuppressionGain { comfort_noise_spectrum, const absl::optional& narrow_peak_band, bool saturated_echo, - const std::vector>>& render, + const Block& render, const std::array& low_band_gain) const; void GainToNoAudibleEcho(const std::array& nearend, @@ -100,7 +100,7 @@ class SuppressionGain { class LowNoiseRenderDetector { public: - bool Detect(const std::vector>>& render); + bool Detect(const Block& render); private: float average_power_ = 32768.f * 32768.f; diff --git a/modules/audio_processing/aec3/suppression_gain_unittest.cc b/modules/audio_processing/aec3/suppression_gain_unittest.cc index 999b0f27ab..02de706c77 100644 --- a/modules/audio_processing/aec3/suppression_gain_unittest.cc +++ b/modules/audio_processing/aec3/suppression_gain_unittest.cc @@ -47,10 +47,7 @@ TEST(SuppressionGainDeathTest, NullOutputGains) { SuppressionGain(EchoCanceller3Config{}, DetectOptimization(), 16000, 1) .GetGain(E2, S2, R2, R2_unbounded, N2, RenderSignalAnalyzer((EchoCanceller3Config{})), aec_state, - std::vector>>( - 3, std::vector>( - 1, std::vector(kBlockSize, 0.0f))), - false, &high_bands_gain, nullptr), + Block(3, 1), false, &high_bands_gain, nullptr), ""); } @@ -76,9 +73,7 @@ TEST(SuppressionGain, BasicGainComputation) { std::vector> N2(kNumCaptureChannels); std::array g; std::vector output(kNumCaptureChannels); - std::vector>> x( - kNumBands, std::vector>( - kNumRenderChannels, std::vector(kBlockSize, 0.0f))); + Block x(kNumBands, kNumRenderChannels); EchoCanceller3Config config; AecState aec_state(config, kNumCaptureChannels); ApmDataDumper data_dumper(42);