Applied the render queueing to the agc.

BUG=webrtc:5099

Review URL: https://codereview.webrtc.org/1416583003

Cr-Commit-Position: refs/heads/master@{#10667}
diff --git a/webrtc/modules/audio_processing/agc/legacy/analog_agc.c b/webrtc/modules/audio_processing/agc/legacy/analog_agc.c
index be644d9..3a1dc9d 100644
--- a/webrtc/modules/audio_processing/agc/legacy/analog_agc.c
+++ b/webrtc/modules/audio_processing/agc/legacy/analog_agc.c
@@ -250,34 +250,35 @@
     return 0;
 }
 
-int WebRtcAgc_AddFarend(void *state, const int16_t *in_far, size_t samples)
-{
+int WebRtcAgc_AddFarend(void *state, const int16_t *in_far, size_t samples) {
+  LegacyAgc* stt = (LegacyAgc*)state;
+
+    int err =  WebRtcAgc_GetAddFarendError(state, samples);
+
+    if (err != 0)
+      return err;
+
+    return WebRtcAgc_AddFarendToDigital(&stt->digitalAgc, in_far, samples);
+}
+
+int WebRtcAgc_GetAddFarendError(void *state, size_t samples) {
   LegacyAgc* stt;
   stt = (LegacyAgc*)state;
 
-    if (stt == NULL)
-    {
-        return -1;
-    }
+  if (stt == NULL)
+    return -1;
 
-    if (stt->fs == 8000)
-    {
-        if (samples != 80)
-        {
-            return -1;
-        }
-    } else if (stt->fs == 16000 || stt->fs == 32000 || stt->fs == 48000)
-    {
-        if (samples != 160)
-        {
-            return -1;
-        }
-    } else
-    {
-        return -1;
-    }
+  if (stt->fs == 8000) {
+    if (samples != 80)
+      return -1;
+  } else if (stt->fs == 16000 || stt->fs == 32000 || stt->fs == 48000) {
+    if (samples != 160)
+      return -1;
+  } else {
+    return -1;
+  }
 
-    return WebRtcAgc_AddFarendToDigital(&stt->digitalAgc, in_far, samples);
+  return 0;
 }
 
 int WebRtcAgc_VirtualMic(void *agcInst, int16_t* const* in_near,
diff --git a/webrtc/modules/audio_processing/agc/legacy/gain_control.h b/webrtc/modules/audio_processing/agc/legacy/gain_control.h
index 08c1988..db942fe 100644
--- a/webrtc/modules/audio_processing/agc/legacy/gain_control.h
+++ b/webrtc/modules/audio_processing/agc/legacy/gain_control.h
@@ -50,6 +50,20 @@
 #endif
 
 /*
+ * This function analyses the number of samples passed to
+ * farend and produces any error code that could arise.
+ *
+ * Input:
+ *      - agcInst           : AGC instance.
+ *      - samples           : Number of samples in input vector.
+ *
+ * Return value:
+ *                          :  0 - Normal operation.
+ *                          : -1 - Error.
+ */
+int WebRtcAgc_GetAddFarendError(void* state, size_t samples);
+
+/*
  * This function processes a 10 ms frame of far-end speech to determine
  * if there is active speech. The length of the input speech vector must be
  * given in samples (80 when FS=8000, and 160 when FS=16000, FS=32000 or
diff --git a/webrtc/modules/audio_processing/audio_processing_impl.cc b/webrtc/modules/audio_processing/audio_processing_impl.cc
index 0daaf1f..3105224 100644
--- a/webrtc/modules/audio_processing/audio_processing_impl.cc
+++ b/webrtc/modules/audio_processing/audio_processing_impl.cc
@@ -532,6 +532,7 @@
 
   echo_cancellation_->ReadQueuedRenderData();
   echo_control_mobile_->ReadQueuedRenderData();
+  gain_control_->ReadQueuedRenderData();
 
   ProcessingConfig processing_config = api_format_;
   processing_config.input_stream() = input_config;
@@ -576,6 +577,7 @@
   CriticalSectionScoped crit_scoped(crit_);
   echo_cancellation_->ReadQueuedRenderData();
   echo_control_mobile_->ReadQueuedRenderData();
+  gain_control_->ReadQueuedRenderData();
 
   if (!frame) {
     return kNullPointerError;
diff --git a/webrtc/modules/audio_processing/gain_control_impl.cc b/webrtc/modules/audio_processing/gain_control_impl.cc
index 595596b..4d84b24 100644
--- a/webrtc/modules/audio_processing/gain_control_impl.cc
+++ b/webrtc/modules/audio_processing/gain_control_impl.cc
@@ -35,20 +35,26 @@
 }
 }  // namespace
 
+const size_t GainControlImpl::kAllowedValuesOfSamplesPerFrame1;
+const size_t GainControlImpl::kAllowedValuesOfSamplesPerFrame2;
+
 GainControlImpl::GainControlImpl(const AudioProcessing* apm,
                                  CriticalSectionWrapper* crit)
-  : ProcessingComponent(),
-    apm_(apm),
-    crit_(crit),
-    mode_(kAdaptiveAnalog),
-    minimum_capture_level_(0),
-    maximum_capture_level_(255),
-    limiter_enabled_(true),
-    target_level_dbfs_(3),
-    compression_gain_db_(9),
-    analog_capture_level_(0),
-    was_analog_level_set_(false),
-    stream_is_saturated_(false) {}
+    : ProcessingComponent(),
+      apm_(apm),
+      crit_(crit),
+      mode_(kAdaptiveAnalog),
+      minimum_capture_level_(0),
+      maximum_capture_level_(255),
+      limiter_enabled_(true),
+      target_level_dbfs_(3),
+      compression_gain_db_(9),
+      analog_capture_level_(0),
+      was_analog_level_set_(false),
+      stream_is_saturated_(false),
+      render_queue_element_max_size_(0) {
+  AllocateRenderQueue();
+}
 
 GainControlImpl::~GainControlImpl() {}
 
@@ -59,21 +65,53 @@
 
   assert(audio->num_frames_per_band() <= 160);
 
+  render_queue_buffer_.resize(0);
   for (int i = 0; i < num_handles(); i++) {
     Handle* my_handle = static_cast<Handle*>(handle(i));
-    int err = WebRtcAgc_AddFarend(
-        my_handle,
-        audio->mixed_low_pass_data(),
-        audio->num_frames_per_band());
+    int err =
+        WebRtcAgc_GetAddFarendError(my_handle, audio->num_frames_per_band());
 
-    if (err != apm_->kNoError) {
+    if (err != apm_->kNoError)
       return GetHandleError(my_handle);
-    }
+
+    // Buffer the samples in the render queue.
+    render_queue_buffer_.insert(
+        render_queue_buffer_.end(), audio->mixed_low_pass_data(),
+        (audio->mixed_low_pass_data() + audio->num_frames_per_band()));
+  }
+
+  // Insert the samples into the queue.
+  if (!render_signal_queue_->Insert(&render_queue_buffer_)) {
+    ReadQueuedRenderData();
+
+    // Retry the insert (should always work).
+    RTC_DCHECK_EQ(render_signal_queue_->Insert(&render_queue_buffer_), true);
   }
 
   return apm_->kNoError;
 }
 
+// Read chunks of data that were received and queued on the render side from
+// a queue. All the data chunks are buffered into the farend signal of the AGC.
+void GainControlImpl::ReadQueuedRenderData() {
+  if (!is_component_enabled()) {
+    return;
+  }
+
+  while (render_signal_queue_->Remove(&capture_queue_buffer_)) {
+    int buffer_index = 0;
+    const int num_frames_per_band =
+        capture_queue_buffer_.size() / num_handles();
+    for (int i = 0; i < num_handles(); i++) {
+      Handle* my_handle = static_cast<Handle*>(handle(i));
+      WebRtcAgc_AddFarend(my_handle, &capture_queue_buffer_[buffer_index],
+                          num_frames_per_band);
+
+      buffer_index += num_frames_per_band;
+    }
+  }
+}
+
 int GainControlImpl::AnalyzeCaptureAudio(AudioBuffer* audio) {
   if (!is_component_enabled()) {
     return apm_->kNoError;
@@ -179,6 +217,12 @@
 
 // TODO(ajm): ensure this is called under kAdaptiveAnalog.
 int GainControlImpl::set_stream_analog_level(int level) {
+  // TODO(peah): Verify that this is really needed to do the reading
+  // here as well as in ProcessStream. It works since these functions
+  // are called from the same thread, but it is not nice to do it in two
+  // places if not needed.
+  ReadQueuedRenderData();
+
   CriticalSectionScoped crit_scoped(crit_);
   was_analog_level_set_ = true;
   if (level < minimum_capture_level_ || level > maximum_capture_level_) {
@@ -296,12 +340,36 @@
     return err;
   }
 
+  AllocateRenderQueue();
+
   const int n = num_handles();
   RTC_CHECK_GE(n, 0) << "Bad number of handles: " << n;
   capture_levels_.assign(n, analog_capture_level_);
   return apm_->kNoError;
 }
 
+void GainControlImpl::AllocateRenderQueue() {
+  const size_t max_frame_size = std::max<size_t>(
+      kAllowedValuesOfSamplesPerFrame1, kAllowedValuesOfSamplesPerFrame2);
+
+  const size_t new_render_queue_element_max_size = std::max<size_t>(
+      static_cast<size_t>(1), (max_frame_size * num_handles()));
+
+  if (new_render_queue_element_max_size > render_queue_element_max_size_) {
+    std::vector<int16_t> template_queue_element(render_queue_element_max_size_);
+
+    render_signal_queue_.reset(
+        new SwapQueue<std::vector<int16_t>, RenderQueueItemVerifier<int16_t>>(
+            kMaxNumFramesToBuffer, template_queue_element,
+            RenderQueueItemVerifier<int16_t>(render_queue_element_max_size_)));
+  } else {
+    render_signal_queue_->Clear();
+  }
+
+  render_queue_buffer_.resize(new_render_queue_element_max_size);
+  capture_queue_buffer_.resize(new_render_queue_element_max_size);
+}
+
 void* GainControlImpl::CreateHandle() const {
   return WebRtcAgc_Create();
 }
diff --git a/webrtc/modules/audio_processing/gain_control_impl.h b/webrtc/modules/audio_processing/gain_control_impl.h
index f24d200..b766ca3 100644
--- a/webrtc/modules/audio_processing/gain_control_impl.h
+++ b/webrtc/modules/audio_processing/gain_control_impl.h
@@ -13,6 +13,8 @@
 
 #include <vector>
 
+#include "webrtc/base/scoped_ptr.h"
+#include "webrtc/common_audio/swap_queue.h"
 #include "webrtc/modules/audio_processing/include/audio_processing.h"
 #include "webrtc/modules/audio_processing/processing_component.h"
 
@@ -41,7 +43,16 @@
   bool is_limiter_enabled() const override;
   Mode mode() const override;
 
+  // Reads render side data that has been queued on the render call.
+  void ReadQueuedRenderData();
+
  private:
+  static const size_t kAllowedValuesOfSamplesPerFrame1 = 80;
+  static const size_t kAllowedValuesOfSamplesPerFrame2 = 160;
+  // TODO(peah): Decrease this once we properly handle hugely unbalanced
+  // reverse and forward call numbers.
+  static const size_t kMaxNumFramesToBuffer = 100;
+
   // GainControl implementation.
   int Enable(bool enable) override;
   int set_stream_analog_level(int level) override;
@@ -64,6 +75,8 @@
   int num_handles_required() const override;
   int GetHandleError(void* handle) const override;
 
+  void AllocateRenderQueue();
+
   const AudioProcessing* apm_;
   CriticalSectionWrapper* crit_;
   Mode mode_;
@@ -76,6 +89,13 @@
   int analog_capture_level_;
   bool was_analog_level_set_;
   bool stream_is_saturated_;
+
+  size_t render_queue_element_max_size_;
+  std::vector<int16_t> render_queue_buffer_;
+  std::vector<int16_t> capture_queue_buffer_;
+  rtc::scoped_ptr<
+      SwapQueue<std::vector<int16_t>, RenderQueueItemVerifier<int16_t>>>
+      render_signal_queue_;
 };
 }  // namespace webrtc