Allow extracting the linear AEC output

This CL enables extracting the linear AEC output,
allowing for more straightforward
testing/development.

Bug: b/140823178
Change-Id: I14f7934008d87066b35500466cb6e6d96f811688
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/153672
Commit-Queue: Per Åhgren <peah@webrtc.org>
Reviewed-by: Gustaf Ullberg <gustaf@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#29789}
diff --git a/modules/audio_processing/audio_processing_impl.cc b/modules/audio_processing/audio_processing_impl.cc
index 59d0c32..fad02a0 100644
--- a/modules/audio_processing/audio_processing_impl.cc
+++ b/modules/audio_processing/audio_processing_impl.cc
@@ -1342,8 +1342,9 @@
         submodules_.echo_controller->SetAudioBufferDelay(stream_delay_ms());
       }
 
+      AudioBuffer* linear_aec_buffer = capture_.linear_aec_output.get();
       submodules_.echo_controller->ProcessCapture(
-          capture_buffer, capture_.echo_path_gain_change);
+          capture_buffer, linear_aec_buffer, capture_.echo_path_gain_change);
     } else if (submodules_.echo_cancellation) {
       // Ensure that the stream delay was set before the call to the
       // AEC ProcessCaptureAudio function.
@@ -1625,6 +1626,31 @@
   return retval;
 }
 
+bool AudioProcessingImpl::GetLinearAecOutput(
+    rtc::ArrayView<std::array<float, 160>> linear_output) const {
+  rtc::CritScope cs(&crit_capture_);
+  AudioBuffer* linear_aec_buffer = capture_.linear_aec_output.get();
+
+  RTC_DCHECK(linear_aec_buffer);
+  if (linear_aec_buffer) {
+    RTC_DCHECK_EQ(1, linear_aec_buffer->num_bands());
+    RTC_DCHECK_EQ(linear_output.size(), linear_aec_buffer->num_channels());
+
+    for (size_t ch = 0; ch < linear_aec_buffer->num_channels(); ++ch) {
+      RTC_DCHECK_EQ(linear_output[ch].size(), linear_aec_buffer->num_frames());
+      rtc::ArrayView<const float> channel_view =
+          rtc::ArrayView<const float>(linear_aec_buffer->channels_const()[ch],
+                                      linear_aec_buffer->num_frames());
+      std::copy(channel_view.begin(), channel_view.end(),
+                linear_output[ch].begin());
+    }
+    return true;
+  }
+  RTC_LOG(LS_ERROR) << "No linear AEC output available";
+  RTC_NOTREACHED();
+  return false;
+}
+
 int AudioProcessingImpl::stream_delay_ms() const {
   // Used as callback from submodules, hence locking is not allowed.
   return capture_nonlocked_.stream_delay_ms;
@@ -1790,6 +1816,16 @@
           num_proc_channels());
     }
 
+    // Setup the storage for returning the linear AEC output.
+    if (config_.echo_canceller.export_linear_aec_output) {
+      constexpr int kLinearOutputRateHz = 16000;
+      capture_.linear_aec_output = std::make_unique<AudioBuffer>(
+          kLinearOutputRateHz, num_proc_channels(), kLinearOutputRateHz,
+          num_proc_channels(), kLinearOutputRateHz, num_proc_channels());
+    } else {
+      capture_.linear_aec_output.reset();
+    }
+
     capture_nonlocked_.echo_controller_enabled = true;
 
     submodules_.echo_cancellation.reset();
@@ -1801,6 +1837,7 @@
 
   submodules_.echo_controller.reset();
   capture_nonlocked_.echo_controller_enabled = false;
+  capture_.linear_aec_output.reset();
 
   if (!config_.echo_canceller.enabled) {
     submodules_.echo_cancellation.reset();