Add test to verify identical input channels result in identical output channels.

BUG=issue411
TEST=audioproc_unittest, trybots

Review URL: https://webrtc-codereview.appspot.com/553009

git-svn-id: http://webrtc.googlecode.com/svn/trunk@2182 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/src/modules/audio_processing/test/unit_test.cc b/src/modules/audio_processing/test/unit_test.cc
index 8689cec..6188d2c 100644
--- a/src/modules/audio_processing/test/unit_test.cc
+++ b/src/modules/audio_processing/test/unit_test.cc
@@ -10,6 +10,8 @@
 
 #include <stdio.h>
 
+#include <algorithm>
+
 #include "gtest/gtest.h"
 
 #include "audio_processing.h"
@@ -55,6 +57,15 @@
 const int kChannels[] = {1, 2};
 const size_t kChannelsSize = sizeof(kChannels) / sizeof(*kChannels);
 
+#if defined(WEBRTC_AUDIOPROC_FIXED_PROFILE)
+// AECM doesn't support super-wb.
+const int kProcessSampleRates[] = {8000, 16000};
+#elif defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
+const int kProcessSampleRates[] = {8000, 16000, 32000};
+#endif
+const size_t kProcessSampleRatesSize = sizeof(kProcessSampleRates) /
+    sizeof(*kProcessSampleRates);
+
 class ApmTest : public ::testing::Test {
  protected:
   ApmTest();
@@ -81,6 +92,8 @@
                              int num_reverse_channels,
                              int num_input_channels,
                              int num_output_channels);
+  void EnableAllComponents();
+  bool ReadFrame(FILE* file, AudioFrame* frame);
 
   const std::string output_path_;
   const std::string ref_path_;
@@ -238,14 +251,74 @@
   }
 }
 
-template <class T>
-T MaxValue(T a, T b) {
-  return a > b ? a : b;
+void CopyLeftToRightChannel(int16_t* stereo, int samples_per_channel) {
+  for (int i = 0; i < samples_per_channel; i++) {
+    stereo[i * 2 + 1] = stereo[i * 2];
+  }
 }
 
-template <class T>
-T AbsValue(T a) {
-  return a > 0 ? a : -a;
+void VerifyChannelsAreEqual(int16_t* stereo, int samples_per_channel) {
+  for (int i = 0; i < samples_per_channel; i++) {
+    EXPECT_EQ(stereo[i * 2 + 1], stereo[i * 2]);
+  }
+}
+
+void ApmTest::EnableAllComponents() {
+#if defined(WEBRTC_AUDIOPROC_FIXED_PROFILE)
+  EXPECT_EQ(apm_->kNoError, apm_->set_sample_rate_hz(16000));
+  EXPECT_EQ(apm_->kNoError, apm_->echo_control_mobile()->Enable(true));
+
+  EXPECT_EQ(apm_->kNoError,
+            apm_->gain_control()->set_mode(GainControl::kAdaptiveDigital));
+  EXPECT_EQ(apm_->kNoError, apm_->gain_control()->Enable(true));
+#elif defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
+  EXPECT_EQ(apm_->kNoError,
+            apm_->echo_cancellation()->enable_drift_compensation(true));
+  EXPECT_EQ(apm_->kNoError,
+            apm_->echo_cancellation()->enable_metrics(true));
+  EXPECT_EQ(apm_->kNoError,
+            apm_->echo_cancellation()->enable_delay_logging(true));
+  EXPECT_EQ(apm_->kNoError, apm_->echo_cancellation()->Enable(true));
+
+  EXPECT_EQ(apm_->kNoError,
+            apm_->gain_control()->set_mode(GainControl::kAdaptiveAnalog));
+  EXPECT_EQ(apm_->kNoError,
+            apm_->gain_control()->set_analog_level_limits(0, 255));
+  EXPECT_EQ(apm_->kNoError, apm_->gain_control()->Enable(true));
+#endif
+
+  EXPECT_EQ(apm_->kNoError,
+            apm_->high_pass_filter()->Enable(true));
+
+  EXPECT_EQ(apm_->kNoError,
+            apm_->level_estimator()->Enable(true));
+
+  EXPECT_EQ(apm_->kNoError,
+            apm_->noise_suppression()->Enable(true));
+
+  EXPECT_EQ(apm_->kNoError,
+            apm_->voice_detection()->Enable(true));
+}
+
+bool ApmTest::ReadFrame(FILE* file, AudioFrame* frame) {
+  // The files always contain stereo audio.
+  size_t frame_size = frame->samples_per_channel_ * 2;
+  size_t read_count = fread(frame->data_,
+                            sizeof(int16_t),
+                            frame_size,
+                            file);
+  if (read_count != frame_size) {
+    // Check that the file really ended.
+    EXPECT_NE(0, feof(file));
+    return false;  // This is expected.
+  }
+
+  if (frame->num_channels_ == 1) {
+    MixStereoToMono(frame->data_, frame->data_,
+                    frame->samples_per_channel_);
+  }
+
+  return true;
 }
 
 void SetFrameTo(AudioFrame* frame, int16_t value) {
@@ -263,14 +336,19 @@
   }
 }
 
+template <class T>
+T AbsValue(T a) {
+  return a > 0 ? a: -a;
+}
+
 int16_t MaxAudioFrame(const AudioFrame& frame) {
   const int length = frame.samples_per_channel_ * frame.num_channels_;
-  int16_t max = AbsValue(frame.data_[0]);
+  int16_t max_data = AbsValue(frame.data_[0]);
   for (int i = 1; i < length; i++) {
-    max = MaxValue(max, AbsValue(frame.data_[i]));
+    max_data = std::max(max_data, AbsValue(frame.data_[i]));
   }
 
-  return max;
+  return max_data;
 }
 
 bool FrameDataAreEqual(const AudioFrame& frame1, const AudioFrame& frame2) {
@@ -1009,6 +1087,35 @@
   }
 }
 
+TEST_F(ApmTest, IdenticalInputChannelsResultInIdenticalOutputChannels) {
+  EnableAllComponents();
+
+  for (size_t i = 0; i < kProcessSampleRatesSize; i++) {
+    Init(kProcessSampleRates[i], 2, 2, 2, false);
+    int analog_level = 127;
+    while (1) {
+      if (!ReadFrame(far_file_, revframe_)) break;
+      CopyLeftToRightChannel(revframe_->data_, revframe_->samples_per_channel_);
+
+      EXPECT_EQ(apm_->kNoError, apm_->AnalyzeReverseStream(revframe_));
+
+      if (!ReadFrame(near_file_, frame_)) break;
+      CopyLeftToRightChannel(frame_->data_, frame_->samples_per_channel_);
+      frame_->vad_activity_ = AudioFrame::kVadUnknown;
+
+      EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(0));
+      EXPECT_EQ(apm_->kNoError,
+          apm_->echo_cancellation()->set_stream_drift_samples(0));
+      EXPECT_EQ(apm_->kNoError,
+          apm_->gain_control()->set_stream_analog_level(analog_level));
+      EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
+      analog_level = apm_->gain_control()->stream_analog_level();
+
+      VerifyChannelsAreEqual(frame_->data_, frame_->samples_per_channel_);
+    }
+  }
+}
+
 TEST_F(ApmTest, SplittingFilter) {
   // Verify the filter is not active through undistorted audio when:
   // 1. No components are enabled...
@@ -1129,14 +1236,6 @@
     ReadMessageLiteFromFile(ref_filename_, &ref_data);
   } else {
     // Write the desired tests to the protobuf reference file.
-#if defined(WEBRTC_AUDIOPROC_FIXED_PROFILE)
-    // AECM doesn't support super-wb.
-    const int kProcessSampleRates[] = {8000, 16000};
-#elif defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
-    const int kProcessSampleRates[] = {8000, 16000, 32000};
-#endif
-    const size_t kProcessSampleRatesSize = sizeof(kProcessSampleRates) /
-        sizeof(*kProcessSampleRates);
     for (size_t i = 0; i < kChannelsSize; i++) {
       for (size_t j = 0; j < kChannelsSize; j++) {
         // We can't have more output than input channels.
@@ -1153,40 +1252,7 @@
     }
   }
 
-#if defined(WEBRTC_AUDIOPROC_FIXED_PROFILE)
-  EXPECT_EQ(apm_->kNoError, apm_->set_sample_rate_hz(16000));
-  EXPECT_EQ(apm_->kNoError, apm_->echo_control_mobile()->Enable(true));
-
-  EXPECT_EQ(apm_->kNoError,
-            apm_->gain_control()->set_mode(GainControl::kAdaptiveDigital));
-  EXPECT_EQ(apm_->kNoError, apm_->gain_control()->Enable(true));
-#elif defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
-  EXPECT_EQ(apm_->kNoError,
-            apm_->echo_cancellation()->enable_drift_compensation(true));
-  EXPECT_EQ(apm_->kNoError,
-            apm_->echo_cancellation()->enable_metrics(true));
-  EXPECT_EQ(apm_->kNoError,
-            apm_->echo_cancellation()->enable_delay_logging(true));
-  EXPECT_EQ(apm_->kNoError, apm_->echo_cancellation()->Enable(true));
-
-  EXPECT_EQ(apm_->kNoError,
-            apm_->gain_control()->set_mode(GainControl::kAdaptiveAnalog));
-  EXPECT_EQ(apm_->kNoError,
-            apm_->gain_control()->set_analog_level_limits(0, 255));
-  EXPECT_EQ(apm_->kNoError, apm_->gain_control()->Enable(true));
-#endif
-
-  EXPECT_EQ(apm_->kNoError,
-            apm_->high_pass_filter()->Enable(true));
-
-  EXPECT_EQ(apm_->kNoError,
-            apm_->level_estimator()->Enable(true));
-
-  EXPECT_EQ(apm_->kNoError,
-            apm_->noise_suppression()->Enable(true));
-
-  EXPECT_EQ(apm_->kNoError,
-            apm_->voice_detection()->Enable(true));
+  EnableAllComponents();
 
   for (int i = 0; i < ref_data.test_size(); i++) {
     printf("Running test %d of %d...\n", i + 1, ref_data.test_size());
@@ -1195,7 +1261,6 @@
     Init(test->sample_rate(), test->num_reverse_channels(),
          test->num_input_channels(), test->num_output_channels(), true);
 
-    const int samples_per_channel = test->sample_rate() / 100;
     int frame_count = 0;
     int has_echo_count = 0;
     int has_voice_count = 0;
@@ -1205,48 +1270,18 @@
     int max_output_average = 0;
 
     while (1) {
-      // Read far-end frame, always stereo.
-      size_t frame_size = samples_per_channel * 2;
-      size_t read_count = fread(revframe_->data_,
-                                sizeof(int16_t),
-                                frame_size,
-                                far_file_);
-      if (read_count != frame_size) {
-        // Check that the file really ended.
-        ASSERT_NE(0, feof(far_file_));
-        break; // This is expected.
-      }
-
-      if (revframe_->num_channels_ == 1) {
-        MixStereoToMono(revframe_->data_, revframe_->data_,
-                        samples_per_channel);
-      }
-
+      if (!ReadFrame(far_file_, revframe_)) break;
       EXPECT_EQ(apm_->kNoError, apm_->AnalyzeReverseStream(revframe_));
 
+      if (!ReadFrame(near_file_, frame_)) break;
+      frame_->vad_activity_ = AudioFrame::kVadUnknown;
+
       EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(0));
       EXPECT_EQ(apm_->kNoError,
           apm_->echo_cancellation()->set_stream_drift_samples(0));
       EXPECT_EQ(apm_->kNoError,
           apm_->gain_control()->set_stream_analog_level(analog_level));
 
-      // Read near-end frame, always stereo.
-      read_count = fread(frame_->data_,
-                         sizeof(int16_t),
-                         frame_size,
-                         near_file_);
-      if (read_count != frame_size) {
-        // Check that the file really ended.
-        ASSERT_NE(0, feof(near_file_));
-        break; // This is expected.
-      }
-
-      if (frame_->num_channels_ == 1) {
-        MixStereoToMono(frame_->data_, frame_->data_,
-                        samples_per_channel);
-      }
-      frame_->vad_activity_ = AudioFrame::kVadUnknown;
-
       EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
       // Ensure the frame was downmixed properly.
       EXPECT_EQ(test->num_output_channels(), frame_->num_channels_);
@@ -1269,7 +1304,7 @@
         EXPECT_EQ(AudioFrame::kVadPassive, frame_->vad_activity_);
       }
 
-      frame_size = samples_per_channel * frame_->num_channels_;
+      size_t frame_size = frame_->samples_per_channel_ * frame_->num_channels_;
       size_t write_count = fwrite(frame_->data_,
                                   sizeof(int16_t),
                                   frame_size,