Support 4 channel mic in Windows Core Audio

BUG=webrtc:7220

Review-Url: https://codereview.webrtc.org/2712743004
Cr-Commit-Position: refs/heads/master@{#16940}
diff --git a/webrtc/voice_engine/utility_unittest.cc b/webrtc/voice_engine/utility_unittest.cc
index ecd0baa..94abc0f 100644
--- a/webrtc/voice_engine/utility_unittest.cc
+++ b/webrtc/voice_engine/utility_unittest.cc
@@ -16,6 +16,7 @@
 #include "webrtc/test/gtest.h"
 #include "webrtc/voice_engine/utility.h"
 #include "webrtc/voice_engine/voice_engine_defines.h"
+#include "webrtc/base/arraysize.h"
 
 namespace webrtc {
 namespace voe {
@@ -45,29 +46,31 @@
 // Sets the signal value to increase by |data| with every sample. Floats are
 // used so non-integer values result in rounding error, but not an accumulating
 // error.
-void SetMonoFrame(AudioFrame* frame, float data, int sample_rate_hz) {
+void SetMonoFrame(float data, int sample_rate_hz, AudioFrame* frame) {
   memset(frame->data_, 0, sizeof(frame->data_));
   frame->num_channels_ = 1;
   frame->sample_rate_hz_ = sample_rate_hz;
-  frame->samples_per_channel_ = sample_rate_hz / 100;
+  frame->samples_per_channel_ = rtc::CheckedDivExact(sample_rate_hz, 100);
   for (size_t i = 0; i < frame->samples_per_channel_; i++) {
     frame->data_[i] = static_cast<int16_t>(data * i);
   }
 }
 
 // Keep the existing sample rate.
-void SetMonoFrame(AudioFrame* frame, float data) {
-  SetMonoFrame(frame, data, frame->sample_rate_hz_);
+void SetMonoFrame(float data, AudioFrame* frame) {
+  SetMonoFrame(data, frame->sample_rate_hz_, frame);
 }
 
 // Sets the signal value to increase by |left| and |right| with every sample in
 // each channel respectively.
-void SetStereoFrame(AudioFrame* frame, float left, float right,
-                    int sample_rate_hz) {
+void SetStereoFrame(float left,
+                    float right,
+                    int sample_rate_hz,
+                    AudioFrame* frame) {
   memset(frame->data_, 0, sizeof(frame->data_));
   frame->num_channels_ = 2;
   frame->sample_rate_hz_ = sample_rate_hz;
-  frame->samples_per_channel_ = sample_rate_hz / 100;
+  frame->samples_per_channel_ = rtc::CheckedDivExact(sample_rate_hz, 100);
   for (size_t i = 0; i < frame->samples_per_channel_; i++) {
     frame->data_[i * 2] = static_cast<int16_t>(left * i);
     frame->data_[i * 2 + 1] = static_cast<int16_t>(right * i);
@@ -75,8 +78,28 @@
 }
 
 // Keep the existing sample rate.
-void SetStereoFrame(AudioFrame* frame, float left, float right) {
-  SetStereoFrame(frame, left, right, frame->sample_rate_hz_);
+void SetStereoFrame(float left, float right, AudioFrame* frame) {
+  SetStereoFrame(left, right, frame->sample_rate_hz_, frame);
+}
+
+// Sets the signal value to increase by |ch1|, |ch2|, |ch3|, |ch4| with every
+// sample in each channel respectively.
+void SetQuadFrame(float ch1,
+                  float ch2,
+                  float ch3,
+                  float ch4,
+                  int sample_rate_hz,
+                  AudioFrame* frame) {
+  memset(frame->data_, 0, sizeof(frame->data_));
+  frame->num_channels_ = 4;
+  frame->sample_rate_hz_ = sample_rate_hz;
+  frame->samples_per_channel_ = rtc::CheckedDivExact(sample_rate_hz, 100);
+  for (size_t i = 0; i < frame->samples_per_channel_; i++) {
+    frame->data_[i * 4] = static_cast<int16_t>(ch1 * i);
+    frame->data_[i * 4 + 1] = static_cast<int16_t>(ch2 * i);
+    frame->data_[i * 4 + 2] = static_cast<int16_t>(ch3 * i);
+    frame->data_[i * 4 + 3] = static_cast<int16_t>(ch4 * i);
+  }
 }
 
 void VerifyParams(const AudioFrame& ref_frame, const AudioFrame& test_frame) {
@@ -128,30 +151,45 @@
                                   int dst_channels,
                                   int dst_sample_rate_hz) {
   PushResampler<int16_t> resampler;  // Create a new one with every test.
-  const int16_t kSrcLeft = 30;  // Shouldn't overflow for any used sample rate.
-  const int16_t kSrcRight = 15;
+  const int16_t kSrcCh1 = 30;  // Shouldn't overflow for any used sample rate.
+  const int16_t kSrcCh2 = 15;
+  const int16_t kSrcCh3 = 22;
+  const int16_t kSrcCh4 = 8;
   const float resampling_factor = (1.0 * src_sample_rate_hz) /
       dst_sample_rate_hz;
-  const float dst_left = resampling_factor * kSrcLeft;
-  const float dst_right = resampling_factor * kSrcRight;
-  const float dst_mono = (dst_left + dst_right) / 2;
+  const float dst_ch1 = resampling_factor * kSrcCh1;
+  const float dst_ch2 = resampling_factor * kSrcCh2;
+  const float dst_ch3 = resampling_factor * kSrcCh3;
+  const float dst_ch4 = resampling_factor * kSrcCh4;
+  const float dst_stereo_to_mono = (dst_ch1 + dst_ch2) / 2;
+  const float dst_quad_to_mono = (dst_ch1 + dst_ch2 + dst_ch3 + dst_ch4) / 4;
+  const float dst_quad_to_stereo_ch1 = (dst_ch1 + dst_ch2) / 2;
+  const float dst_quad_to_stereo_ch2 = (dst_ch3 + dst_ch4) / 2;
   if (src_channels == 1)
-    SetMonoFrame(&src_frame_, kSrcLeft, src_sample_rate_hz);
+    SetMonoFrame(kSrcCh1, src_sample_rate_hz, &src_frame_);
+  else if (src_channels == 2)
+    SetStereoFrame(kSrcCh1, kSrcCh2, src_sample_rate_hz, &src_frame_);
   else
-    SetStereoFrame(&src_frame_, kSrcLeft, kSrcRight, src_sample_rate_hz);
+    SetQuadFrame(kSrcCh1, kSrcCh2, kSrcCh3, kSrcCh4, src_sample_rate_hz,
+                 &src_frame_);
 
   if (dst_channels == 1) {
-    SetMonoFrame(&dst_frame_, 0, dst_sample_rate_hz);
+    SetMonoFrame(0, dst_sample_rate_hz, &dst_frame_);
     if (src_channels == 1)
-      SetMonoFrame(&golden_frame_, dst_left, dst_sample_rate_hz);
+      SetMonoFrame(dst_ch1, dst_sample_rate_hz, &golden_frame_);
+    else if (src_channels == 2)
+      SetMonoFrame(dst_stereo_to_mono, dst_sample_rate_hz, &golden_frame_);
     else
-      SetMonoFrame(&golden_frame_, dst_mono, dst_sample_rate_hz);
+      SetMonoFrame(dst_quad_to_mono, dst_sample_rate_hz, &golden_frame_);
   } else {
-    SetStereoFrame(&dst_frame_, 0, 0, dst_sample_rate_hz);
+    SetStereoFrame(0, 0, dst_sample_rate_hz, &dst_frame_);
     if (src_channels == 1)
-      SetStereoFrame(&golden_frame_, dst_left, dst_left, dst_sample_rate_hz);
+      SetStereoFrame(dst_ch1, dst_ch1, dst_sample_rate_hz, &golden_frame_);
+    else if (src_channels == 2)
+      SetStereoFrame(dst_ch1, dst_ch2, dst_sample_rate_hz, &golden_frame_);
     else
-      SetStereoFrame(&golden_frame_, dst_left, dst_right, dst_sample_rate_hz);
+      SetStereoFrame(dst_quad_to_stereo_ch1, dst_quad_to_stereo_ch2,
+                     dst_sample_rate_hz, &golden_frame_);
   }
 
   // The sinc resampler has a known delay, which we compute here. Multiplying by
@@ -176,45 +214,50 @@
 
 TEST_F(UtilityTest, RemixAndResampleCopyFrameSucceeds) {
   // Stereo -> stereo.
-  SetStereoFrame(&src_frame_, 10, 10);
-  SetStereoFrame(&dst_frame_, 0, 0);
+  SetStereoFrame(10, 10, &src_frame_);
+  SetStereoFrame(0, 0, &dst_frame_);
   RemixAndResample(src_frame_, &resampler_, &dst_frame_);
   VerifyFramesAreEqual(src_frame_, dst_frame_);
 
   // Mono -> mono.
-  SetMonoFrame(&src_frame_, 20);
-  SetMonoFrame(&dst_frame_, 0);
+  SetMonoFrame(20, &src_frame_);
+  SetMonoFrame(0, &dst_frame_);
   RemixAndResample(src_frame_, &resampler_, &dst_frame_);
   VerifyFramesAreEqual(src_frame_, dst_frame_);
 }
 
 TEST_F(UtilityTest, RemixAndResampleMixingOnlySucceeds) {
   // Stereo -> mono.
-  SetStereoFrame(&dst_frame_, 0, 0);
-  SetMonoFrame(&src_frame_, 10);
-  SetStereoFrame(&golden_frame_, 10, 10);
+  SetStereoFrame(0, 0, &dst_frame_);
+  SetMonoFrame(10, &src_frame_);
+  SetStereoFrame(10, 10, &golden_frame_);
   RemixAndResample(src_frame_, &resampler_, &dst_frame_);
   VerifyFramesAreEqual(dst_frame_, golden_frame_);
 
   // Mono -> stereo.
-  SetMonoFrame(&dst_frame_, 0);
-  SetStereoFrame(&src_frame_, 10, 20);
-  SetMonoFrame(&golden_frame_, 15);
+  SetMonoFrame(0, &dst_frame_);
+  SetStereoFrame(10, 20, &src_frame_);
+  SetMonoFrame(15, &golden_frame_);
   RemixAndResample(src_frame_, &resampler_, &dst_frame_);
   VerifyFramesAreEqual(golden_frame_, dst_frame_);
 }
 
 TEST_F(UtilityTest, RemixAndResampleSucceeds) {
   const int kSampleRates[] = {8000, 16000, 32000, 44100, 48000, 96000};
-  const int kSampleRatesSize = sizeof(kSampleRates) / sizeof(*kSampleRates);
-  const int kChannels[] = {1, 2};
-  const int kChannelsSize = sizeof(kChannels) / sizeof(*kChannels);
+  const int kSampleRatesSize = arraysize(kSampleRates);
+  const int kSrcChannels[] = {1, 2, 4};
+  const int kSrcChannelsSize = arraysize(kSrcChannels);
+  const int kDstChannels[] = {1, 2};
+  const int kDstChannelsSize = arraysize(kDstChannels);
+
   for (int src_rate = 0; src_rate < kSampleRatesSize; src_rate++) {
     for (int dst_rate = 0; dst_rate < kSampleRatesSize; dst_rate++) {
-      for (int src_channel = 0; src_channel < kChannelsSize; src_channel++) {
-        for (int dst_channel = 0; dst_channel < kChannelsSize; dst_channel++) {
-          RunResampleTest(kChannels[src_channel], kSampleRates[src_rate],
-                          kChannels[dst_channel], kSampleRates[dst_rate]);
+      for (int src_channel = 0; src_channel < kSrcChannelsSize;
+           src_channel++) {
+        for (int dst_channel = 0; dst_channel < kDstChannelsSize;
+             dst_channel++) {
+          RunResampleTest(kSrcChannels[src_channel], kSampleRates[src_rate],
+                          kDstChannels[dst_channel], kSampleRates[dst_rate]);
         }
       }
     }