xref: /aosp_15_r20/external/webrtc/audio/utility/channel_mixer_unittest.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1*d9f75844SAndroid Build Coastguard Worker /*
2*d9f75844SAndroid Build Coastguard Worker  *  Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
3*d9f75844SAndroid Build Coastguard Worker  *
4*d9f75844SAndroid Build Coastguard Worker  *  Use of this source code is governed by a BSD-style license
5*d9f75844SAndroid Build Coastguard Worker  *  that can be found in the LICENSE file in the root of the source
6*d9f75844SAndroid Build Coastguard Worker  *  tree. An additional intellectual property rights grant can be found
7*d9f75844SAndroid Build Coastguard Worker  *  in the file PATENTS.  All contributing project authors may
8*d9f75844SAndroid Build Coastguard Worker  *  be found in the AUTHORS file in the root of the source tree.
9*d9f75844SAndroid Build Coastguard Worker  */
10*d9f75844SAndroid Build Coastguard Worker 
11*d9f75844SAndroid Build Coastguard Worker #include "audio/utility/channel_mixer.h"
12*d9f75844SAndroid Build Coastguard Worker 
13*d9f75844SAndroid Build Coastguard Worker #include <memory>
14*d9f75844SAndroid Build Coastguard Worker 
15*d9f75844SAndroid Build Coastguard Worker #include "api/audio/audio_frame.h"
16*d9f75844SAndroid Build Coastguard Worker #include "api/audio/channel_layout.h"
17*d9f75844SAndroid Build Coastguard Worker #include "audio/utility/channel_mixing_matrix.h"
18*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/arraysize.h"
19*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/strings/string_builder.h"
20*d9f75844SAndroid Build Coastguard Worker #include "test/gtest.h"
21*d9f75844SAndroid Build Coastguard Worker 
22*d9f75844SAndroid Build Coastguard Worker namespace webrtc {
23*d9f75844SAndroid Build Coastguard Worker 
24*d9f75844SAndroid Build Coastguard Worker namespace {
25*d9f75844SAndroid Build Coastguard Worker 
26*d9f75844SAndroid Build Coastguard Worker constexpr uint32_t kTimestamp = 27;
27*d9f75844SAndroid Build Coastguard Worker constexpr int kSampleRateHz = 16000;
28*d9f75844SAndroid Build Coastguard Worker constexpr size_t kSamplesPerChannel = kSampleRateHz / 100;
29*d9f75844SAndroid Build Coastguard Worker 
30*d9f75844SAndroid Build Coastguard Worker class ChannelMixerTest : public ::testing::Test {
31*d9f75844SAndroid Build Coastguard Worker  protected:
ChannelMixerTest()32*d9f75844SAndroid Build Coastguard Worker   ChannelMixerTest() {
33*d9f75844SAndroid Build Coastguard Worker     // Use 10ms audio frames by default. Don't set values yet.
34*d9f75844SAndroid Build Coastguard Worker     frame_.samples_per_channel_ = kSamplesPerChannel;
35*d9f75844SAndroid Build Coastguard Worker     frame_.sample_rate_hz_ = kSampleRateHz;
36*d9f75844SAndroid Build Coastguard Worker     EXPECT_TRUE(frame_.muted());
37*d9f75844SAndroid Build Coastguard Worker   }
38*d9f75844SAndroid Build Coastguard Worker 
~ChannelMixerTest()39*d9f75844SAndroid Build Coastguard Worker   virtual ~ChannelMixerTest() {}
40*d9f75844SAndroid Build Coastguard Worker 
41*d9f75844SAndroid Build Coastguard Worker   AudioFrame frame_;
42*d9f75844SAndroid Build Coastguard Worker };
43*d9f75844SAndroid Build Coastguard Worker 
SetFrameData(int16_t data,AudioFrame * frame)44*d9f75844SAndroid Build Coastguard Worker void SetFrameData(int16_t data, AudioFrame* frame) {
45*d9f75844SAndroid Build Coastguard Worker   int16_t* frame_data = frame->mutable_data();
46*d9f75844SAndroid Build Coastguard Worker   for (size_t i = 0; i < frame->samples_per_channel() * frame->num_channels();
47*d9f75844SAndroid Build Coastguard Worker        i++) {
48*d9f75844SAndroid Build Coastguard Worker     frame_data[i] = data;
49*d9f75844SAndroid Build Coastguard Worker   }
50*d9f75844SAndroid Build Coastguard Worker }
51*d9f75844SAndroid Build Coastguard Worker 
SetMonoData(int16_t center,AudioFrame * frame)52*d9f75844SAndroid Build Coastguard Worker void SetMonoData(int16_t center, AudioFrame* frame) {
53*d9f75844SAndroid Build Coastguard Worker   frame->num_channels_ = 1;
54*d9f75844SAndroid Build Coastguard Worker   int16_t* frame_data = frame->mutable_data();
55*d9f75844SAndroid Build Coastguard Worker   for (size_t i = 0; i < frame->samples_per_channel(); ++i) {
56*d9f75844SAndroid Build Coastguard Worker     frame_data[i] = center;
57*d9f75844SAndroid Build Coastguard Worker   }
58*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(frame->muted());
59*d9f75844SAndroid Build Coastguard Worker }
60*d9f75844SAndroid Build Coastguard Worker 
SetStereoData(int16_t left,int16_t right,AudioFrame * frame)61*d9f75844SAndroid Build Coastguard Worker void SetStereoData(int16_t left, int16_t right, AudioFrame* frame) {
62*d9f75844SAndroid Build Coastguard Worker   ASSERT_LE(2 * frame->samples_per_channel(), frame->max_16bit_samples());
63*d9f75844SAndroid Build Coastguard Worker   frame->num_channels_ = 2;
64*d9f75844SAndroid Build Coastguard Worker   int16_t* frame_data = frame->mutable_data();
65*d9f75844SAndroid Build Coastguard Worker   for (size_t i = 0; i < frame->samples_per_channel() * 2; i += 2) {
66*d9f75844SAndroid Build Coastguard Worker     frame_data[i] = left;
67*d9f75844SAndroid Build Coastguard Worker     frame_data[i + 1] = right;
68*d9f75844SAndroid Build Coastguard Worker   }
69*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(frame->muted());
70*d9f75844SAndroid Build Coastguard Worker }
71*d9f75844SAndroid Build Coastguard Worker 
SetFiveOneData(int16_t front_left,int16_t front_right,int16_t center,int16_t lfe,int16_t side_left,int16_t side_right,AudioFrame * frame)72*d9f75844SAndroid Build Coastguard Worker void SetFiveOneData(int16_t front_left,
73*d9f75844SAndroid Build Coastguard Worker                     int16_t front_right,
74*d9f75844SAndroid Build Coastguard Worker                     int16_t center,
75*d9f75844SAndroid Build Coastguard Worker                     int16_t lfe,
76*d9f75844SAndroid Build Coastguard Worker                     int16_t side_left,
77*d9f75844SAndroid Build Coastguard Worker                     int16_t side_right,
78*d9f75844SAndroid Build Coastguard Worker                     AudioFrame* frame) {
79*d9f75844SAndroid Build Coastguard Worker   ASSERT_LE(6 * frame->samples_per_channel(), frame->max_16bit_samples());
80*d9f75844SAndroid Build Coastguard Worker   frame->num_channels_ = 6;
81*d9f75844SAndroid Build Coastguard Worker   int16_t* frame_data = frame->mutable_data();
82*d9f75844SAndroid Build Coastguard Worker   for (size_t i = 0; i < frame->samples_per_channel() * 6; i += 6) {
83*d9f75844SAndroid Build Coastguard Worker     frame_data[i] = front_left;
84*d9f75844SAndroid Build Coastguard Worker     frame_data[i + 1] = front_right;
85*d9f75844SAndroid Build Coastguard Worker     frame_data[i + 2] = center;
86*d9f75844SAndroid Build Coastguard Worker     frame_data[i + 3] = lfe;
87*d9f75844SAndroid Build Coastguard Worker     frame_data[i + 4] = side_left;
88*d9f75844SAndroid Build Coastguard Worker     frame_data[i + 5] = side_right;
89*d9f75844SAndroid Build Coastguard Worker   }
90*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(frame->muted());
91*d9f75844SAndroid Build Coastguard Worker }
92*d9f75844SAndroid Build Coastguard Worker 
SetSevenOneData(int16_t front_left,int16_t front_right,int16_t center,int16_t lfe,int16_t side_left,int16_t side_right,int16_t back_left,int16_t back_right,AudioFrame * frame)93*d9f75844SAndroid Build Coastguard Worker void SetSevenOneData(int16_t front_left,
94*d9f75844SAndroid Build Coastguard Worker                      int16_t front_right,
95*d9f75844SAndroid Build Coastguard Worker                      int16_t center,
96*d9f75844SAndroid Build Coastguard Worker                      int16_t lfe,
97*d9f75844SAndroid Build Coastguard Worker                      int16_t side_left,
98*d9f75844SAndroid Build Coastguard Worker                      int16_t side_right,
99*d9f75844SAndroid Build Coastguard Worker                      int16_t back_left,
100*d9f75844SAndroid Build Coastguard Worker                      int16_t back_right,
101*d9f75844SAndroid Build Coastguard Worker                      AudioFrame* frame) {
102*d9f75844SAndroid Build Coastguard Worker   ASSERT_LE(8 * frame->samples_per_channel(), frame->max_16bit_samples());
103*d9f75844SAndroid Build Coastguard Worker   frame->num_channels_ = 8;
104*d9f75844SAndroid Build Coastguard Worker   int16_t* frame_data = frame->mutable_data();
105*d9f75844SAndroid Build Coastguard Worker   for (size_t i = 0; i < frame->samples_per_channel() * 8; i += 8) {
106*d9f75844SAndroid Build Coastguard Worker     frame_data[i] = front_left;
107*d9f75844SAndroid Build Coastguard Worker     frame_data[i + 1] = front_right;
108*d9f75844SAndroid Build Coastguard Worker     frame_data[i + 2] = center;
109*d9f75844SAndroid Build Coastguard Worker     frame_data[i + 3] = lfe;
110*d9f75844SAndroid Build Coastguard Worker     frame_data[i + 4] = side_left;
111*d9f75844SAndroid Build Coastguard Worker     frame_data[i + 5] = side_right;
112*d9f75844SAndroid Build Coastguard Worker     frame_data[i + 6] = back_left;
113*d9f75844SAndroid Build Coastguard Worker     frame_data[i + 7] = back_right;
114*d9f75844SAndroid Build Coastguard Worker   }
115*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(frame->muted());
116*d9f75844SAndroid Build Coastguard Worker }
117*d9f75844SAndroid Build Coastguard Worker 
AllSamplesEquals(int16_t sample,const AudioFrame * frame)118*d9f75844SAndroid Build Coastguard Worker bool AllSamplesEquals(int16_t sample, const AudioFrame* frame) {
119*d9f75844SAndroid Build Coastguard Worker   const int16_t* frame_data = frame->data();
120*d9f75844SAndroid Build Coastguard Worker   for (size_t i = 0; i < frame->samples_per_channel() * frame->num_channels();
121*d9f75844SAndroid Build Coastguard Worker        i++) {
122*d9f75844SAndroid Build Coastguard Worker     if (frame_data[i] != sample) {
123*d9f75844SAndroid Build Coastguard Worker       return false;
124*d9f75844SAndroid Build Coastguard Worker     }
125*d9f75844SAndroid Build Coastguard Worker   }
126*d9f75844SAndroid Build Coastguard Worker   return true;
127*d9f75844SAndroid Build Coastguard Worker }
128*d9f75844SAndroid Build Coastguard Worker 
VerifyFramesAreEqual(const AudioFrame & frame1,const AudioFrame & frame2)129*d9f75844SAndroid Build Coastguard Worker void VerifyFramesAreEqual(const AudioFrame& frame1, const AudioFrame& frame2) {
130*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(frame1.num_channels(), frame2.num_channels());
131*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(frame1.samples_per_channel(), frame2.samples_per_channel());
132*d9f75844SAndroid Build Coastguard Worker   const int16_t* frame1_data = frame1.data();
133*d9f75844SAndroid Build Coastguard Worker   const int16_t* frame2_data = frame2.data();
134*d9f75844SAndroid Build Coastguard Worker   for (size_t i = 0; i < frame1.samples_per_channel() * frame1.num_channels();
135*d9f75844SAndroid Build Coastguard Worker        i++) {
136*d9f75844SAndroid Build Coastguard Worker     EXPECT_EQ(frame1_data[i], frame2_data[i]);
137*d9f75844SAndroid Build Coastguard Worker   }
138*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(frame1.muted(), frame2.muted());
139*d9f75844SAndroid Build Coastguard Worker }
140*d9f75844SAndroid Build Coastguard Worker 
141*d9f75844SAndroid Build Coastguard Worker }  // namespace
142*d9f75844SAndroid Build Coastguard Worker 
143*d9f75844SAndroid Build Coastguard Worker // Test all possible layout conversions can be constructed and mixed. Don't
144*d9f75844SAndroid Build Coastguard Worker // care about the actual content, simply run through all mixing combinations
145*d9f75844SAndroid Build Coastguard Worker // and ensure that nothing fails.
TEST_F(ChannelMixerTest,ConstructAllPossibleLayouts)146*d9f75844SAndroid Build Coastguard Worker TEST_F(ChannelMixerTest, ConstructAllPossibleLayouts) {
147*d9f75844SAndroid Build Coastguard Worker   for (ChannelLayout input_layout = CHANNEL_LAYOUT_MONO;
148*d9f75844SAndroid Build Coastguard Worker        input_layout <= CHANNEL_LAYOUT_MAX;
149*d9f75844SAndroid Build Coastguard Worker        input_layout = static_cast<ChannelLayout>(input_layout + 1)) {
150*d9f75844SAndroid Build Coastguard Worker     for (ChannelLayout output_layout = CHANNEL_LAYOUT_MONO;
151*d9f75844SAndroid Build Coastguard Worker          output_layout <= CHANNEL_LAYOUT_MAX;
152*d9f75844SAndroid Build Coastguard Worker          output_layout = static_cast<ChannelLayout>(output_layout + 1)) {
153*d9f75844SAndroid Build Coastguard Worker       // DISCRETE, BITSTREAM can't be tested here based on the current approach.
154*d9f75844SAndroid Build Coastguard Worker       // CHANNEL_LAYOUT_STEREO_AND_KEYBOARD_MIC is not mixable.
155*d9f75844SAndroid Build Coastguard Worker       // Stereo down mix should never be the output layout.
156*d9f75844SAndroid Build Coastguard Worker       if (input_layout == CHANNEL_LAYOUT_BITSTREAM ||
157*d9f75844SAndroid Build Coastguard Worker           input_layout == CHANNEL_LAYOUT_DISCRETE ||
158*d9f75844SAndroid Build Coastguard Worker           input_layout == CHANNEL_LAYOUT_STEREO_AND_KEYBOARD_MIC ||
159*d9f75844SAndroid Build Coastguard Worker           output_layout == CHANNEL_LAYOUT_BITSTREAM ||
160*d9f75844SAndroid Build Coastguard Worker           output_layout == CHANNEL_LAYOUT_DISCRETE ||
161*d9f75844SAndroid Build Coastguard Worker           output_layout == CHANNEL_LAYOUT_STEREO_AND_KEYBOARD_MIC ||
162*d9f75844SAndroid Build Coastguard Worker           output_layout == CHANNEL_LAYOUT_STEREO_DOWNMIX) {
163*d9f75844SAndroid Build Coastguard Worker         continue;
164*d9f75844SAndroid Build Coastguard Worker       }
165*d9f75844SAndroid Build Coastguard Worker 
166*d9f75844SAndroid Build Coastguard Worker       rtc::StringBuilder ss;
167*d9f75844SAndroid Build Coastguard Worker       ss << "Input Layout: " << input_layout
168*d9f75844SAndroid Build Coastguard Worker          << ", Output Layout: " << output_layout;
169*d9f75844SAndroid Build Coastguard Worker       SCOPED_TRACE(ss.str());
170*d9f75844SAndroid Build Coastguard Worker       ChannelMixer mixer(input_layout, output_layout);
171*d9f75844SAndroid Build Coastguard Worker 
172*d9f75844SAndroid Build Coastguard Worker       frame_.UpdateFrame(kTimestamp, nullptr, kSamplesPerChannel, kSampleRateHz,
173*d9f75844SAndroid Build Coastguard Worker                          AudioFrame::kNormalSpeech, AudioFrame::kVadActive,
174*d9f75844SAndroid Build Coastguard Worker                          ChannelLayoutToChannelCount(input_layout));
175*d9f75844SAndroid Build Coastguard Worker       EXPECT_TRUE(frame_.muted());
176*d9f75844SAndroid Build Coastguard Worker       mixer.Transform(&frame_);
177*d9f75844SAndroid Build Coastguard Worker     }
178*d9f75844SAndroid Build Coastguard Worker   }
179*d9f75844SAndroid Build Coastguard Worker }
180*d9f75844SAndroid Build Coastguard Worker 
181*d9f75844SAndroid Build Coastguard Worker // Ensure that the audio frame is untouched when input and output channel
182*d9f75844SAndroid Build Coastguard Worker // layouts are identical, i.e., the transformation should have no effect.
183*d9f75844SAndroid Build Coastguard Worker // Exclude invalid mixing combinations.
TEST_F(ChannelMixerTest,NoMixingForIdenticalChannelLayouts)184*d9f75844SAndroid Build Coastguard Worker TEST_F(ChannelMixerTest, NoMixingForIdenticalChannelLayouts) {
185*d9f75844SAndroid Build Coastguard Worker   for (ChannelLayout input_layout = CHANNEL_LAYOUT_MONO;
186*d9f75844SAndroid Build Coastguard Worker        input_layout <= CHANNEL_LAYOUT_MAX;
187*d9f75844SAndroid Build Coastguard Worker        input_layout = static_cast<ChannelLayout>(input_layout + 1)) {
188*d9f75844SAndroid Build Coastguard Worker     for (ChannelLayout output_layout = CHANNEL_LAYOUT_MONO;
189*d9f75844SAndroid Build Coastguard Worker          output_layout <= CHANNEL_LAYOUT_MAX;
190*d9f75844SAndroid Build Coastguard Worker          output_layout = static_cast<ChannelLayout>(output_layout + 1)) {
191*d9f75844SAndroid Build Coastguard Worker       if (input_layout != output_layout ||
192*d9f75844SAndroid Build Coastguard Worker           input_layout == CHANNEL_LAYOUT_BITSTREAM ||
193*d9f75844SAndroid Build Coastguard Worker           input_layout == CHANNEL_LAYOUT_DISCRETE ||
194*d9f75844SAndroid Build Coastguard Worker           input_layout == CHANNEL_LAYOUT_STEREO_AND_KEYBOARD_MIC ||
195*d9f75844SAndroid Build Coastguard Worker           output_layout == CHANNEL_LAYOUT_STEREO_DOWNMIX) {
196*d9f75844SAndroid Build Coastguard Worker         continue;
197*d9f75844SAndroid Build Coastguard Worker       }
198*d9f75844SAndroid Build Coastguard Worker       ChannelMixer mixer(input_layout, output_layout);
199*d9f75844SAndroid Build Coastguard Worker       frame_.num_channels_ = ChannelLayoutToChannelCount(input_layout);
200*d9f75844SAndroid Build Coastguard Worker       SetFrameData(99, &frame_);
201*d9f75844SAndroid Build Coastguard Worker       mixer.Transform(&frame_);
202*d9f75844SAndroid Build Coastguard Worker       EXPECT_EQ(ChannelLayoutToChannelCount(input_layout),
203*d9f75844SAndroid Build Coastguard Worker                 static_cast<int>(frame_.num_channels()));
204*d9f75844SAndroid Build Coastguard Worker       EXPECT_TRUE(AllSamplesEquals(99, &frame_));
205*d9f75844SAndroid Build Coastguard Worker     }
206*d9f75844SAndroid Build Coastguard Worker   }
207*d9f75844SAndroid Build Coastguard Worker }
208*d9f75844SAndroid Build Coastguard Worker 
TEST_F(ChannelMixerTest,StereoToMono)209*d9f75844SAndroid Build Coastguard Worker TEST_F(ChannelMixerTest, StereoToMono) {
210*d9f75844SAndroid Build Coastguard Worker   ChannelMixer mixer(CHANNEL_LAYOUT_STEREO, CHANNEL_LAYOUT_MONO);
211*d9f75844SAndroid Build Coastguard Worker   //
212*d9f75844SAndroid Build Coastguard Worker   //                      Input: stereo
213*d9f75844SAndroid Build Coastguard Worker   //                      LEFT  RIGHT
214*d9f75844SAndroid Build Coastguard Worker   // Output: mono CENTER  0.5   0.5
215*d9f75844SAndroid Build Coastguard Worker   //
216*d9f75844SAndroid Build Coastguard Worker   SetStereoData(7, 3, &frame_);
217*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(2u, frame_.num_channels());
218*d9f75844SAndroid Build Coastguard Worker   mixer.Transform(&frame_);
219*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(1u, frame_.num_channels());
220*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(CHANNEL_LAYOUT_MONO, frame_.channel_layout());
221*d9f75844SAndroid Build Coastguard Worker 
222*d9f75844SAndroid Build Coastguard Worker   AudioFrame mono_frame;
223*d9f75844SAndroid Build Coastguard Worker   mono_frame.samples_per_channel_ = frame_.samples_per_channel();
224*d9f75844SAndroid Build Coastguard Worker   SetMonoData(5, &mono_frame);
225*d9f75844SAndroid Build Coastguard Worker   VerifyFramesAreEqual(mono_frame, frame_);
226*d9f75844SAndroid Build Coastguard Worker 
227*d9f75844SAndroid Build Coastguard Worker   SetStereoData(-32768, -32768, &frame_);
228*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(2u, frame_.num_channels());
229*d9f75844SAndroid Build Coastguard Worker   mixer.Transform(&frame_);
230*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(1u, frame_.num_channels());
231*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(CHANNEL_LAYOUT_MONO, frame_.channel_layout());
232*d9f75844SAndroid Build Coastguard Worker   SetMonoData(-32768, &mono_frame);
233*d9f75844SAndroid Build Coastguard Worker   VerifyFramesAreEqual(mono_frame, frame_);
234*d9f75844SAndroid Build Coastguard Worker }
235*d9f75844SAndroid Build Coastguard Worker 
TEST_F(ChannelMixerTest,StereoToMonoMuted)236*d9f75844SAndroid Build Coastguard Worker TEST_F(ChannelMixerTest, StereoToMonoMuted) {
237*d9f75844SAndroid Build Coastguard Worker   ASSERT_TRUE(frame_.muted());
238*d9f75844SAndroid Build Coastguard Worker   ChannelMixer mixer(CHANNEL_LAYOUT_STEREO, CHANNEL_LAYOUT_MONO);
239*d9f75844SAndroid Build Coastguard Worker   mixer.Transform(&frame_);
240*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(1u, frame_.num_channels());
241*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(CHANNEL_LAYOUT_MONO, frame_.channel_layout());
242*d9f75844SAndroid Build Coastguard Worker   EXPECT_TRUE(frame_.muted());
243*d9f75844SAndroid Build Coastguard Worker }
244*d9f75844SAndroid Build Coastguard Worker 
TEST_F(ChannelMixerTest,FiveOneToSevenOneMuted)245*d9f75844SAndroid Build Coastguard Worker TEST_F(ChannelMixerTest, FiveOneToSevenOneMuted) {
246*d9f75844SAndroid Build Coastguard Worker   ASSERT_TRUE(frame_.muted());
247*d9f75844SAndroid Build Coastguard Worker   ChannelMixer mixer(CHANNEL_LAYOUT_5_1, CHANNEL_LAYOUT_7_1);
248*d9f75844SAndroid Build Coastguard Worker   mixer.Transform(&frame_);
249*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(8u, frame_.num_channels());
250*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(CHANNEL_LAYOUT_7_1, frame_.channel_layout());
251*d9f75844SAndroid Build Coastguard Worker   EXPECT_TRUE(frame_.muted());
252*d9f75844SAndroid Build Coastguard Worker }
253*d9f75844SAndroid Build Coastguard Worker 
TEST_F(ChannelMixerTest,FiveOneToMono)254*d9f75844SAndroid Build Coastguard Worker TEST_F(ChannelMixerTest, FiveOneToMono) {
255*d9f75844SAndroid Build Coastguard Worker   ChannelMixer mixer(CHANNEL_LAYOUT_5_1, CHANNEL_LAYOUT_MONO);
256*d9f75844SAndroid Build Coastguard Worker   //
257*d9f75844SAndroid Build Coastguard Worker   //                      Input: 5.1
258*d9f75844SAndroid Build Coastguard Worker   //                      LEFT   RIGHT  CENTER  LFE    SIDE_LEFT  SIDE_RIGHT
259*d9f75844SAndroid Build Coastguard Worker   // Output: mono CENTER  0.707  0.707  1       0.707  0.707      0.707
260*d9f75844SAndroid Build Coastguard Worker   //
261*d9f75844SAndroid Build Coastguard Worker   // a = [10, 20, 15, 2, 5, 5]
262*d9f75844SAndroid Build Coastguard Worker   // b = [1/sqrt(2), 1/sqrt(2), 1.0, 1/sqrt(2), 1/sqrt(2), 1/sqrt(2)] =>
263*d9f75844SAndroid Build Coastguard Worker   // a * b (dot product) = 44.69848480983499,
264*d9f75844SAndroid Build Coastguard Worker   // which is truncated into 44 using 16 bit representation.
265*d9f75844SAndroid Build Coastguard Worker   //
266*d9f75844SAndroid Build Coastguard Worker   SetFiveOneData(10, 20, 15, 2, 5, 5, &frame_);
267*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(6u, frame_.num_channels());
268*d9f75844SAndroid Build Coastguard Worker   mixer.Transform(&frame_);
269*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(1u, frame_.num_channels());
270*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(CHANNEL_LAYOUT_MONO, frame_.channel_layout());
271*d9f75844SAndroid Build Coastguard Worker 
272*d9f75844SAndroid Build Coastguard Worker   AudioFrame mono_frame;
273*d9f75844SAndroid Build Coastguard Worker   mono_frame.samples_per_channel_ = frame_.samples_per_channel();
274*d9f75844SAndroid Build Coastguard Worker   SetMonoData(44, &mono_frame);
275*d9f75844SAndroid Build Coastguard Worker   VerifyFramesAreEqual(mono_frame, frame_);
276*d9f75844SAndroid Build Coastguard Worker 
277*d9f75844SAndroid Build Coastguard Worker   SetFiveOneData(-32768, -32768, -32768, -32768, -32768, -32768, &frame_);
278*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(6u, frame_.num_channels());
279*d9f75844SAndroid Build Coastguard Worker   mixer.Transform(&frame_);
280*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(1u, frame_.num_channels());
281*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(CHANNEL_LAYOUT_MONO, frame_.channel_layout());
282*d9f75844SAndroid Build Coastguard Worker   SetMonoData(-32768, &mono_frame);
283*d9f75844SAndroid Build Coastguard Worker   VerifyFramesAreEqual(mono_frame, frame_);
284*d9f75844SAndroid Build Coastguard Worker }
285*d9f75844SAndroid Build Coastguard Worker 
TEST_F(ChannelMixerTest,FiveOneToSevenOne)286*d9f75844SAndroid Build Coastguard Worker TEST_F(ChannelMixerTest, FiveOneToSevenOne) {
287*d9f75844SAndroid Build Coastguard Worker   ChannelMixer mixer(CHANNEL_LAYOUT_5_1, CHANNEL_LAYOUT_7_1);
288*d9f75844SAndroid Build Coastguard Worker   //
289*d9f75844SAndroid Build Coastguard Worker   //                        Input: 5.1
290*d9f75844SAndroid Build Coastguard Worker   //                        LEFT   RIGHT  CENTER  LFE    SIDE_LEFT  SIDE_RIGHT
291*d9f75844SAndroid Build Coastguard Worker   // Output: 7.1 LEFT       1      0      0       0      0          0
292*d9f75844SAndroid Build Coastguard Worker   //             RIGHT      0      1      0       0      0          0
293*d9f75844SAndroid Build Coastguard Worker   //             CENTER     0      0      1       0      0          0
294*d9f75844SAndroid Build Coastguard Worker   //             LFE        0      0      0       1      0          0
295*d9f75844SAndroid Build Coastguard Worker   //             SIDE_LEFT  0      0      0       0      1          0
296*d9f75844SAndroid Build Coastguard Worker   //             SIDE_RIGHT 0      0      0       0      0          1
297*d9f75844SAndroid Build Coastguard Worker   //             BACK_LEFT  0      0      0       0      0          0
298*d9f75844SAndroid Build Coastguard Worker   //             BACK_RIGHT 0      0      0       0      0          0
299*d9f75844SAndroid Build Coastguard Worker   //
300*d9f75844SAndroid Build Coastguard Worker   SetFiveOneData(10, 20, 15, 2, 5, 5, &frame_);
301*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(6u, frame_.num_channels());
302*d9f75844SAndroid Build Coastguard Worker   mixer.Transform(&frame_);
303*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(8u, frame_.num_channels());
304*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(CHANNEL_LAYOUT_7_1, frame_.channel_layout());
305*d9f75844SAndroid Build Coastguard Worker 
306*d9f75844SAndroid Build Coastguard Worker   AudioFrame seven_one_frame;
307*d9f75844SAndroid Build Coastguard Worker   seven_one_frame.samples_per_channel_ = frame_.samples_per_channel();
308*d9f75844SAndroid Build Coastguard Worker   SetSevenOneData(10, 20, 15, 2, 5, 5, 0, 0, &seven_one_frame);
309*d9f75844SAndroid Build Coastguard Worker   VerifyFramesAreEqual(seven_one_frame, frame_);
310*d9f75844SAndroid Build Coastguard Worker 
311*d9f75844SAndroid Build Coastguard Worker   SetFiveOneData(-32768, 32767, -32768, 32767, -32768, 32767, &frame_);
312*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(6u, frame_.num_channels());
313*d9f75844SAndroid Build Coastguard Worker   mixer.Transform(&frame_);
314*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(8u, frame_.num_channels());
315*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(CHANNEL_LAYOUT_7_1, frame_.channel_layout());
316*d9f75844SAndroid Build Coastguard Worker   SetSevenOneData(-32768, 32767, -32768, 32767, -32768, 32767, 0, 0,
317*d9f75844SAndroid Build Coastguard Worker                   &seven_one_frame);
318*d9f75844SAndroid Build Coastguard Worker   VerifyFramesAreEqual(seven_one_frame, frame_);
319*d9f75844SAndroid Build Coastguard Worker }
320*d9f75844SAndroid Build Coastguard Worker 
TEST_F(ChannelMixerTest,FiveOneBackToStereo)321*d9f75844SAndroid Build Coastguard Worker TEST_F(ChannelMixerTest, FiveOneBackToStereo) {
322*d9f75844SAndroid Build Coastguard Worker   ChannelMixer mixer(CHANNEL_LAYOUT_5_1_BACK, CHANNEL_LAYOUT_STEREO);
323*d9f75844SAndroid Build Coastguard Worker   //
324*d9f75844SAndroid Build Coastguard Worker   //                      Input: 5.1
325*d9f75844SAndroid Build Coastguard Worker   //                      LEFT   RIGHT  CENTER  LFE    BACK_LEFT  BACK_RIGHT
326*d9f75844SAndroid Build Coastguard Worker   // Output: stereo LEFT  1      0      0.707   0.707  0.707      0
327*d9f75844SAndroid Build Coastguard Worker   //                RIGHT 0      1      0.707   0.707  0          0.707
328*d9f75844SAndroid Build Coastguard Worker   //
329*d9f75844SAndroid Build Coastguard Worker   SetFiveOneData(20, 30, 15, 2, 5, 5, &frame_);
330*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(6u, frame_.num_channels());
331*d9f75844SAndroid Build Coastguard Worker   mixer.Transform(&frame_);
332*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(2u, frame_.num_channels());
333*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(CHANNEL_LAYOUT_STEREO, frame_.channel_layout());
334*d9f75844SAndroid Build Coastguard Worker 
335*d9f75844SAndroid Build Coastguard Worker   AudioFrame stereo_frame;
336*d9f75844SAndroid Build Coastguard Worker   stereo_frame.samples_per_channel_ = frame_.samples_per_channel();
337*d9f75844SAndroid Build Coastguard Worker   SetStereoData(35, 45, &stereo_frame);
338*d9f75844SAndroid Build Coastguard Worker   VerifyFramesAreEqual(stereo_frame, frame_);
339*d9f75844SAndroid Build Coastguard Worker 
340*d9f75844SAndroid Build Coastguard Worker   SetFiveOneData(-32768, -32768, -32768, -32768, -32768, -32768, &frame_);
341*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(6u, frame_.num_channels());
342*d9f75844SAndroid Build Coastguard Worker   mixer.Transform(&frame_);
343*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(2u, frame_.num_channels());
344*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(CHANNEL_LAYOUT_STEREO, frame_.channel_layout());
345*d9f75844SAndroid Build Coastguard Worker   SetStereoData(-32768, -32768, &stereo_frame);
346*d9f75844SAndroid Build Coastguard Worker   VerifyFramesAreEqual(stereo_frame, frame_);
347*d9f75844SAndroid Build Coastguard Worker }
348*d9f75844SAndroid Build Coastguard Worker 
TEST_F(ChannelMixerTest,MonoToStereo)349*d9f75844SAndroid Build Coastguard Worker TEST_F(ChannelMixerTest, MonoToStereo) {
350*d9f75844SAndroid Build Coastguard Worker   ChannelMixer mixer(CHANNEL_LAYOUT_MONO, CHANNEL_LAYOUT_STEREO);
351*d9f75844SAndroid Build Coastguard Worker   //
352*d9f75844SAndroid Build Coastguard Worker   //                       Input: mono
353*d9f75844SAndroid Build Coastguard Worker   //                       CENTER
354*d9f75844SAndroid Build Coastguard Worker   // Output: stereo LEFT   1
355*d9f75844SAndroid Build Coastguard Worker   //                RIGHT  1
356*d9f75844SAndroid Build Coastguard Worker   //
357*d9f75844SAndroid Build Coastguard Worker   SetMonoData(44, &frame_);
358*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(1u, frame_.num_channels());
359*d9f75844SAndroid Build Coastguard Worker   mixer.Transform(&frame_);
360*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(2u, frame_.num_channels());
361*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(CHANNEL_LAYOUT_STEREO, frame_.channel_layout());
362*d9f75844SAndroid Build Coastguard Worker 
363*d9f75844SAndroid Build Coastguard Worker   AudioFrame stereo_frame;
364*d9f75844SAndroid Build Coastguard Worker   stereo_frame.samples_per_channel_ = frame_.samples_per_channel();
365*d9f75844SAndroid Build Coastguard Worker   SetStereoData(44, 44, &stereo_frame);
366*d9f75844SAndroid Build Coastguard Worker   VerifyFramesAreEqual(stereo_frame, frame_);
367*d9f75844SAndroid Build Coastguard Worker }
368*d9f75844SAndroid Build Coastguard Worker 
TEST_F(ChannelMixerTest,StereoToFiveOne)369*d9f75844SAndroid Build Coastguard Worker TEST_F(ChannelMixerTest, StereoToFiveOne) {
370*d9f75844SAndroid Build Coastguard Worker   ChannelMixer mixer(CHANNEL_LAYOUT_STEREO, CHANNEL_LAYOUT_5_1);
371*d9f75844SAndroid Build Coastguard Worker   //
372*d9f75844SAndroid Build Coastguard Worker   //                         Input: Stereo
373*d9f75844SAndroid Build Coastguard Worker   //                         LEFT   RIGHT
374*d9f75844SAndroid Build Coastguard Worker   // Output: 5.1 LEFT        1      0
375*d9f75844SAndroid Build Coastguard Worker   //             RIGHT       0      1
376*d9f75844SAndroid Build Coastguard Worker   //             CENTER      0      0
377*d9f75844SAndroid Build Coastguard Worker   //             LFE         0      0
378*d9f75844SAndroid Build Coastguard Worker   //             SIDE_LEFT   0      0
379*d9f75844SAndroid Build Coastguard Worker   //             SIDE_RIGHT  0      0
380*d9f75844SAndroid Build Coastguard Worker   //
381*d9f75844SAndroid Build Coastguard Worker   SetStereoData(50, 60, &frame_);
382*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(2u, frame_.num_channels());
383*d9f75844SAndroid Build Coastguard Worker   mixer.Transform(&frame_);
384*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(6u, frame_.num_channels());
385*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(CHANNEL_LAYOUT_5_1, frame_.channel_layout());
386*d9f75844SAndroid Build Coastguard Worker 
387*d9f75844SAndroid Build Coastguard Worker   AudioFrame five_one_frame;
388*d9f75844SAndroid Build Coastguard Worker   five_one_frame.samples_per_channel_ = frame_.samples_per_channel();
389*d9f75844SAndroid Build Coastguard Worker   SetFiveOneData(50, 60, 0, 0, 0, 0, &five_one_frame);
390*d9f75844SAndroid Build Coastguard Worker   VerifyFramesAreEqual(five_one_frame, frame_);
391*d9f75844SAndroid Build Coastguard Worker }
392*d9f75844SAndroid Build Coastguard Worker 
393*d9f75844SAndroid Build Coastguard Worker }  // namespace webrtc
394