AEC3: Update SpectrumBuffer API

- RenderBuffer::Spectrum() loses its channel argument, allowing for
  greater flexibility in passing the multi-channel spectrum data into
  functions.
- The FFT spectra lengths are made compile-time constant, rendering
  some DCHECKs obsolete.

Bug: webrtc:10913
Change-Id: Ied0c50cf72d974cfef7279fd2b9c572d049b8b16
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/157104
Commit-Queue: Sam Zackrisson <saza@webrtc.org>
Reviewed-by: Per Ã…hgren <peah@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#29528}
diff --git a/modules/audio_processing/aec3/aec_state.cc b/modules/audio_processing/aec3/aec_state.cc
index c36cf6d..d35bed5 100644
--- a/modules/audio_processing/aec3/aec_state.cc
+++ b/modules/audio_processing/aec3/aec_state.cc
@@ -46,11 +46,11 @@
   if (num_render_channels > 1) {
     auto average_channels =
         [](size_t num_render_channels,
-           const std::vector<std::vector<float>>& spectrum_band_0,
+           rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>>
+               spectrum_band_0,
            rtc::ArrayView<float, kFftLengthBy2Plus1> render_power) {
           std::fill(render_power.begin(), render_power.end(), 0.f);
           for (size_t ch = 0; ch < num_render_channels; ++ch) {
-            RTC_DCHECK_EQ(spectrum_band_0[ch].size(), kFftLengthBy2Plus1);
             for (size_t k = 0; k < kFftLengthBy2Plus1; ++k) {
               render_power[k] += spectrum_band_0[ch][k];
             }
@@ -231,9 +231,8 @@
                          subtractor_output_analyzer_.ConvergedFilters());
 
   // TODO(bugs.webrtc.org/10913): Take all channels into account.
-  const auto& X2 =
-      render_buffer.Spectrum(delay_state_.MinDirectPathFilterDelay(),
-                             /*channel=*/0);
+  const auto& X2 = render_buffer.Spectrum(
+      delay_state_.MinDirectPathFilterDelay())[/*channel=*/0];
   erl_estimator_.Update(subtractor_output_analyzer_.ConvergedFilters()[0], X2,
                         Y2[0]);
 
diff --git a/modules/audio_processing/aec3/echo_remover.cc b/modules/audio_processing/aec3/echo_remover.cc
index a05a389..b508c95 100644
--- a/modules/audio_processing/aec3/echo_remover.cc
+++ b/modules/audio_processing/aec3/echo_remover.cc
@@ -461,8 +461,8 @@
   data_dumper_->DumpRaw("aec3_S2_linear", S2_linear[0]);
   data_dumper_->DumpRaw("aec3_Y2", Y2[0]);
   data_dumper_->DumpRaw(
-      "aec3_X2", render_buffer->Spectrum(aec_state_.MinDirectPathFilterDelay(),
-                                         /*channel=*/0));
+      "aec3_X2", render_buffer->Spectrum(
+                     aec_state_.MinDirectPathFilterDelay())[/*channel=*/0]);
   data_dumper_->DumpRaw("aec3_R2", R2[0]);
   data_dumper_->DumpRaw("aec3_filter_delay",
                         aec_state_.MinDirectPathFilterDelay());
diff --git a/modules/audio_processing/aec3/erl_estimator.cc b/modules/audio_processing/aec3/erl_estimator.cc
index 85b1e02..4a0c441 100644
--- a/modules/audio_processing/aec3/erl_estimator.cc
+++ b/modules/audio_processing/aec3/erl_estimator.cc
@@ -38,11 +38,10 @@
   blocks_since_reset_ = 0;
 }
 
-void ErlEstimator::Update(bool converged_filter,
-                          rtc::ArrayView<const float> render_spectrum,
-                          rtc::ArrayView<const float> capture_spectrum) {
-  RTC_DCHECK_EQ(kFftLengthBy2Plus1, render_spectrum.size());
-  RTC_DCHECK_EQ(kFftLengthBy2Plus1, capture_spectrum.size());
+void ErlEstimator::Update(
+    bool converged_filter,
+    rtc::ArrayView<const float, kFftLengthBy2Plus1> render_spectrum,
+    rtc::ArrayView<const float, kFftLengthBy2Plus1> capture_spectrum) {
   const auto& X2 = render_spectrum;
   const auto& Y2 = capture_spectrum;
 
diff --git a/modules/audio_processing/aec3/erl_estimator.h b/modules/audio_processing/aec3/erl_estimator.h
index 2ca21df..25dc39c 100644
--- a/modules/audio_processing/aec3/erl_estimator.h
+++ b/modules/audio_processing/aec3/erl_estimator.h
@@ -32,8 +32,8 @@
 
   // Updates the ERL estimate.
   void Update(bool converged_filter,
-              rtc::ArrayView<const float> render_spectrum,
-              rtc::ArrayView<const float> capture_spectrum);
+              rtc::ArrayView<const float, kFftLengthBy2Plus1> render_spectrum,
+              rtc::ArrayView<const float, kFftLengthBy2Plus1> capture_spectrum);
 
   // Returns the most recent ERL estimate.
   const std::array<float, kFftLengthBy2Plus1>& Erl() const { return erl_; }
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 f721fd8..d7099b0 100644
--- a/modules/audio_processing/aec3/mock/mock_render_delay_buffer.cc
+++ b/modules/audio_processing/aec3/mock/mock_render_delay_buffer.cc
@@ -19,9 +19,7 @@
                     NumBandsForRate(sample_rate_hz),
                     num_channels,
                     kBlockSize),
-      spectrum_buffer_(block_buffer_.buffer.size(),
-                       num_channels,
-                       kFftLengthBy2Plus1),
+      spectrum_buffer_(block_buffer_.buffer.size(), num_channels),
       fft_buffer_(block_buffer_.buffer.size(), num_channels),
       render_buffer_(&block_buffer_, &spectrum_buffer_, &fft_buffer_),
       downsampled_render_buffer_(GetDownSampledBufferSize(4, 4)) {
diff --git a/modules/audio_processing/aec3/render_buffer.h b/modules/audio_processing/aec3/render_buffer.h
index d44abd9..3422df3 100644
--- a/modules/audio_processing/aec3/render_buffer.h
+++ b/modules/audio_processing/aec3/render_buffer.h
@@ -44,11 +44,11 @@
   }
 
   // Get the spectrum from one of the FFTs in the buffer.
-  rtc::ArrayView<const float> Spectrum(int buffer_offset_ffts,
-                                       size_t channel) const {
+  rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> Spectrum(
+      int buffer_offset_ffts) const {
     int position = spectrum_buffer_->OffsetIndex(spectrum_buffer_->read,
                                                  buffer_offset_ffts);
-    return spectrum_buffer_->buffer[position][channel];
+    return spectrum_buffer_->buffer[position];
   }
 
   // Returns the circular fft buffer.
diff --git a/modules/audio_processing/aec3/render_buffer_unittest.cc b/modules/audio_processing/aec3/render_buffer_unittest.cc
index dca1e21..6981f6d 100644
--- a/modules/audio_processing/aec3/render_buffer_unittest.cc
+++ b/modules/audio_processing/aec3/render_buffer_unittest.cc
@@ -23,7 +23,7 @@
 // Verifies the check for non-null fft buffer.
 TEST(RenderBuffer, NullExternalFftBuffer) {
   BlockBuffer block_buffer(10, 3, 1, kBlockSize);
-  SpectrumBuffer spectrum_buffer(10, 1, kFftLengthBy2Plus1);
+  SpectrumBuffer spectrum_buffer(10, 1);
   EXPECT_DEATH(RenderBuffer(&block_buffer, &spectrum_buffer, nullptr), "");
 }
 
@@ -37,7 +37,7 @@
 // Verifies the check for non-null block buffer.
 TEST(RenderBuffer, NullExternalBlockBuffer) {
   FftBuffer fft_buffer(10, 1);
-  SpectrumBuffer spectrum_buffer(10, 1, kFftLengthBy2Plus1);
+  SpectrumBuffer spectrum_buffer(10, 1);
   EXPECT_DEATH(RenderBuffer(nullptr, &spectrum_buffer, &fft_buffer), "");
 }
 
diff --git a/modules/audio_processing/aec3/render_delay_buffer.cc b/modules/audio_processing/aec3/render_delay_buffer.cc
index 6eb32e4..14a6bd5 100644
--- a/modules/audio_processing/aec3/render_delay_buffer.cc
+++ b/modules/audio_processing/aec3/render_delay_buffer.cc
@@ -131,7 +131,7 @@
               NumBandsForRate(sample_rate_hz),
               num_render_channels,
               kBlockSize),
-      spectra_(blocks_.buffer.size(), num_render_channels, kFftLengthBy2Plus1),
+      spectra_(blocks_.buffer.size(), num_render_channels),
       ffts_(blocks_.buffer.size(), num_render_channels),
       delay_(config_.delay.default_delay),
       echo_remover_buffer_(&blocks_, &spectra_, &ffts_),
diff --git a/modules/audio_processing/aec3/render_signal_analyzer.cc b/modules/audio_processing/aec3/render_signal_analyzer.cc
index 0b155f6..e64610e 100644
--- a/modules/audio_processing/aec3/render_signal_analyzer.cc
+++ b/modules/audio_processing/aec3/render_signal_analyzer.cc
@@ -38,13 +38,11 @@
 
   std::array<size_t, kFftLengthBy2 - 1> channel_counters;
   channel_counters.fill(0);
-  for (size_t channel = 0; channel < render_buffer.Block(0)[0].size();
-       ++channel) {
-    rtc::ArrayView<const float> X2 =
-        render_buffer.Spectrum(*delay_partitions, channel);
-    RTC_DCHECK_EQ(kFftLengthBy2Plus1, X2.size());
+  rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> X2 =
+      render_buffer.Spectrum(*delay_partitions);
+  for (size_t ch = 0; ch < X2.size(); ++ch) {
     for (size_t k = 1; k < kFftLengthBy2; ++k) {
-      if (X2[k] > 3 * std::max(X2[k - 1], X2[k + 1])) {
+      if (X2[ch][k] > 3 * std::max(X2[ch][k - 1], X2[ch][k + 1])) {
         ++channel_counters[k - 1];
       }
     }
@@ -72,7 +70,8 @@
       render_buffer.Block(0);
   float max_peak_level = 0.f;
   for (size_t channel = 0; channel < x_latest[0].size(); ++channel) {
-    const auto X2_latest = render_buffer.Spectrum(0, channel);
+    rtc::ArrayView<const float, kFftLengthBy2Plus1> X2_latest =
+        render_buffer.Spectrum(0)[channel];
 
     // Identify the spectral peak.
     const int peak_bin =
diff --git a/modules/audio_processing/aec3/residual_echo_estimator.cc b/modules/audio_processing/aec3/residual_echo_estimator.cc
index 6a8a3f2..3846a79 100644
--- a/modules/audio_processing/aec3/residual_echo_estimator.cc
+++ b/modules/audio_processing/aec3/residual_echo_estimator.cc
@@ -244,21 +244,20 @@
 void ResidualEchoEstimator::UpdateRenderNoisePower(
     const RenderBuffer& render_buffer) {
   std::array<float, kFftLengthBy2Plus1> render_power_data;
-  rtc::ArrayView<const float> render_power;
-  if (num_render_channels_ == 1) {
-    render_power = render_buffer.Spectrum(0, /*channel=*/0);
-  } else {
+  rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> X2 =
+      render_buffer.Spectrum(0);
+  rtc::ArrayView<const float, kFftLengthBy2Plus1> render_power =
+      X2[/*channel=*/0];
+  if (num_render_channels_ > 1) {
     render_power_data.fill(0.f);
     for (size_t ch = 0; ch < num_render_channels_; ++ch) {
-      const auto& channel_power = render_buffer.Spectrum(0, ch);
-      RTC_DCHECK_EQ(channel_power.size(), kFftLengthBy2Plus1);
+      const auto& channel_power = X2[ch];
       for (size_t k = 0; k < kFftLengthBy2Plus1; ++k) {
         render_power_data[k] += channel_power[k];
       }
     }
     render_power = render_power_data;
   }
-  RTC_DCHECK_EQ(render_power.size(), kFftLengthBy2Plus1);
 
   // Estimate the stationary noise power in a minimum statistics manner.
   for (size_t k = 0; k < kFftLengthBy2Plus1; ++k) {
@@ -295,23 +294,20 @@
 
   // Compute render power for the reverb.
   std::array<float, kFftLengthBy2Plus1> render_power_data;
-  rtc::ArrayView<const float> render_power;
-  if (num_render_channels_ == 1) {
-    render_power =
-        render_buffer.Spectrum(first_reverb_partition, /*channel=*/0);
-  } else {
+  rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> X2 =
+      render_buffer.Spectrum(first_reverb_partition);
+  rtc::ArrayView<const float, kFftLengthBy2Plus1> render_power =
+      X2[/*channel=*/0];
+  if (num_render_channels_ > 1) {
     render_power_data.fill(0.f);
     for (size_t ch = 0; ch < num_render_channels_; ++ch) {
-      const auto& channel_power =
-          render_buffer.Spectrum(first_reverb_partition, ch);
-      RTC_DCHECK_EQ(channel_power.size(), kFftLengthBy2Plus1);
+      const auto& channel_power = X2[ch];
       for (size_t k = 0; k < kFftLengthBy2Plus1; ++k) {
         render_power_data[k] += channel_power[k];
       }
     }
     render_power = render_power_data;
   }
-  RTC_DCHECK_EQ(render_power.size(), kFftLengthBy2Plus1);
 
   // Update the reverb estimate.
   if (reverb_type == ReverbType::kLinear) {
diff --git a/modules/audio_processing/aec3/spectrum_buffer.cc b/modules/audio_processing/aec3/spectrum_buffer.cc
index 8e7fed7..fe32ece 100644
--- a/modules/audio_processing/aec3/spectrum_buffer.cc
+++ b/modules/audio_processing/aec3/spectrum_buffer.cc
@@ -14,14 +14,10 @@
 
 namespace webrtc {
 
-SpectrumBuffer::SpectrumBuffer(size_t size,
-                               size_t num_channels,
-                               size_t spectrum_length)
+SpectrumBuffer::SpectrumBuffer(size_t size, size_t num_channels)
     : size(static_cast<int>(size)),
       buffer(size,
-             std::vector<std::vector<float>>(
-                 num_channels,
-                 std::vector<float>(spectrum_length, 0.f))) {
+             std::vector<std::array<float, kFftLengthBy2Plus1>>(num_channels)) {
   for (auto& channel : buffer) {
     for (auto& c : channel) {
       std::fill(c.begin(), c.end(), 0.f);
diff --git a/modules/audio_processing/aec3/spectrum_buffer.h b/modules/audio_processing/aec3/spectrum_buffer.h
index d6c0ba0..51e1317 100644
--- a/modules/audio_processing/aec3/spectrum_buffer.h
+++ b/modules/audio_processing/aec3/spectrum_buffer.h
@@ -13,8 +13,10 @@
 
 #include <stddef.h>
 
+#include <array>
 #include <vector>
 
+#include "modules/audio_processing/aec3/aec3_common.h"
 #include "rtc_base/checks.h"
 
 namespace webrtc {
@@ -22,7 +24,7 @@
 // Struct for bundling a circular buffer of one dimensional vector objects
 // together with the read and write indices.
 struct SpectrumBuffer {
-  SpectrumBuffer(size_t size, size_t num_channels, size_t spectrum_length);
+  SpectrumBuffer(size_t size, size_t num_channels);
   ~SpectrumBuffer();
 
   int IncIndex(int index) const {
@@ -50,7 +52,7 @@
   void DecReadIndex() { read = DecIndex(read); }
 
   const int size;
-  std::vector<std::vector<std::vector<float>>> buffer;
+  std::vector<std::vector<std::array<float, kFftLengthBy2Plus1>>> buffer;
   int write = 0;
   int read = 0;
 };
diff --git a/modules/audio_processing/aec3/stationarity_estimator.cc b/modules/audio_processing/aec3/stationarity_estimator.cc
index d0c3c9c..01628f3 100644
--- a/modules/audio_processing/aec3/stationarity_estimator.cc
+++ b/modules/audio_processing/aec3/stationarity_estimator.cc
@@ -12,7 +12,6 @@
 
 #include <algorithm>
 #include <array>
-#include <vector>
 
 #include "api/array_view.h"
 #include "modules/audio_processing/aec3/aec3_common.h"
@@ -45,7 +44,7 @@
 
 // Update just the noise estimator. Usefull until the delay is known
 void StationarityEstimator::UpdateNoiseEstimator(
-    rtc::ArrayView<const std::vector<float>> spectrum) {
+    rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> spectrum) {
   noise_.Update(spectrum);
   data_dumper_->DumpRaw("aec3_stationarity_noise_spectrum", noise_.Spectrum());
   data_dumper_->DumpRaw("aec3_stationarity_is_block_stationary",
@@ -168,13 +167,12 @@
 }
 
 void StationarityEstimator::NoiseSpectrum::Update(
-    rtc::ArrayView<const std::vector<float>> spectrum) {
+    rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> spectrum) {
   RTC_DCHECK_LE(1, spectrum[0].size());
   const int num_render_channels = static_cast<int>(spectrum.size());
 
   std::array<float, kFftLengthBy2Plus1> avg_spectrum_data;
   rtc::ArrayView<const float> avg_spectrum;
-  RTC_DCHECK_EQ(kFftLengthBy2Plus1, spectrum[0].size());
   if (num_render_channels == 1) {
     avg_spectrum = spectrum[0];
   } else {
@@ -184,7 +182,6 @@
     std::copy(spectrum[0].begin(), spectrum[0].end(),
               avg_spectrum_data.begin());
     for (int ch = 1; ch < num_render_channels; ++ch) {
-      RTC_DCHECK_EQ(kFftLengthBy2Plus1, spectrum[ch].size());
       for (size_t k = 1; k < kFftLengthBy2Plus1; ++k) {
         avg_spectrum_data[k] += spectrum[ch][k];
       }
diff --git a/modules/audio_processing/aec3/stationarity_estimator.h b/modules/audio_processing/aec3/stationarity_estimator.h
index 5860ef1..6f7ad40 100644
--- a/modules/audio_processing/aec3/stationarity_estimator.h
+++ b/modules/audio_processing/aec3/stationarity_estimator.h
@@ -15,7 +15,6 @@
 
 #include <array>
 #include <memory>
-#include <vector>
 
 #include "api/array_view.h"
 #include "modules/audio_processing/aec3/aec3_common.h"  // kFftLengthBy2Plus1...
@@ -36,7 +35,8 @@
   void Reset();
 
   // Update just the noise estimator. Usefull until the delay is known
-  void UpdateNoiseEstimator(rtc::ArrayView<const std::vector<float>> spectrum);
+  void UpdateNoiseEstimator(
+      rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> spectrum);
 
   // Update the flag indicating whether this current frame is stationary. For
   // getting a more robust estimation, it looks at future and/or past frames.
@@ -86,7 +86,8 @@
     void Reset();
 
     // Update the noise power spectrum with a new frame.
-    void Update(rtc::ArrayView<const std::vector<float>> spectrum);
+    void Update(
+        rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> spectrum);
 
     // Get the noise estimation power spectrum.
     rtc::ArrayView<const float> Spectrum() const { return noise_spectrum_; }