• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 // MSVC++ requires this to be set before any other includes to get M_SQRT1_2.
6 #define _USE_MATH_DEFINES
7 
8 #include <cmath>
9 
10 #include "base/strings/stringprintf.h"
11 #include "media/audio/audio_parameters.h"
12 #include "media/base/audio_bus.h"
13 #include "media/base/channel_mixer.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15 
16 namespace media {
17 
18 // Number of frames to test with.
19 enum { kFrames = 16 };
20 
21 // Test all possible layout conversions can be constructed and mixed.
TEST(ChannelMixerTest,ConstructAllPossibleLayouts)22 TEST(ChannelMixerTest, ConstructAllPossibleLayouts) {
23   for (ChannelLayout input_layout = CHANNEL_LAYOUT_MONO;
24        input_layout < CHANNEL_LAYOUT_MAX;
25        input_layout = static_cast<ChannelLayout>(input_layout + 1)) {
26     for (ChannelLayout output_layout = CHANNEL_LAYOUT_MONO;
27          output_layout < CHANNEL_LAYOUT_STEREO_DOWNMIX;
28          output_layout = static_cast<ChannelLayout>(output_layout + 1)) {
29       // DISCRETE can't be tested here based on the current approach.
30       if (input_layout == CHANNEL_LAYOUT_DISCRETE ||
31           output_layout == CHANNEL_LAYOUT_DISCRETE)
32         continue;
33 
34       SCOPED_TRACE(base::StringPrintf(
35           "Input Layout: %d, Output Layout: %d", input_layout, output_layout));
36       ChannelMixer mixer(input_layout, output_layout);
37       scoped_ptr<AudioBus> input_bus = AudioBus::Create(
38           ChannelLayoutToChannelCount(input_layout), kFrames);
39       scoped_ptr<AudioBus> output_bus = AudioBus::Create(
40           ChannelLayoutToChannelCount(output_layout), kFrames);
41       for (int ch = 0; ch < input_bus->channels(); ++ch)
42         std::fill(input_bus->channel(ch), input_bus->channel(ch) + kFrames, 1);
43 
44       mixer.Transform(input_bus.get(), output_bus.get());
45     }
46   }
47 }
48 
49 struct ChannelMixerTestData {
ChannelMixerTestDatamedia::ChannelMixerTestData50   ChannelMixerTestData(ChannelLayout input_layout, ChannelLayout output_layout,
51                        float* channel_values, int num_channel_values,
52                        float scale)
53       : input_layout(input_layout),
54         output_layout(output_layout),
55         channel_values(channel_values),
56         num_channel_values(num_channel_values),
57         scale(scale) {
58     input_channels = ChannelLayoutToChannelCount(input_layout);
59     output_channels = ChannelLayoutToChannelCount(output_layout);
60   }
61 
ChannelMixerTestDatamedia::ChannelMixerTestData62   ChannelMixerTestData(ChannelLayout input_layout, int input_channels,
63                        ChannelLayout output_layout, int output_channels,
64                        float* channel_values, int num_channel_values)
65       : input_layout(input_layout),
66         input_channels(input_channels),
67         output_layout(output_layout),
68         output_channels(output_channels),
69         channel_values(channel_values),
70         num_channel_values(num_channel_values),
71         scale(1.0f) {
72   }
73 
DebugStringmedia::ChannelMixerTestData74   std::string DebugString() const {
75     return base::StringPrintf(
76         "Input Layout: %d, Output Layout %d, Scale: %f", input_layout,
77         output_layout, scale);
78   }
79 
80   ChannelLayout input_layout;
81   int input_channels;
82   ChannelLayout output_layout;
83   int output_channels;
84   float* channel_values;
85   int num_channel_values;
86   float scale;
87 };
88 
operator <<(std::ostream & os,const ChannelMixerTestData & data)89 std::ostream& operator<<(std::ostream& os, const ChannelMixerTestData& data) {
90   return os << data.DebugString();
91 }
92 
93 class ChannelMixerTest : public testing::TestWithParam<ChannelMixerTestData> {};
94 
95 // Verify channels are mixed and scaled correctly.  The test only works if all
96 // output channels have the same value.
TEST_P(ChannelMixerTest,Mixing)97 TEST_P(ChannelMixerTest, Mixing) {
98   ChannelLayout input_layout = GetParam().input_layout;
99   int input_channels = GetParam().input_channels;
100   scoped_ptr<AudioBus> input_bus = AudioBus::Create(input_channels, kFrames);
101   AudioParameters input_audio(AudioParameters::AUDIO_PCM_LINEAR,
102                               input_layout,
103                               input_layout == CHANNEL_LAYOUT_DISCRETE ?
104                                   input_channels :
105                                   ChannelLayoutToChannelCount(input_layout),
106                               0,
107                               AudioParameters::kAudioCDSampleRate, 16,
108                               kFrames,
109                               AudioParameters::NO_EFFECTS);
110 
111   ChannelLayout output_layout = GetParam().output_layout;
112   int output_channels = GetParam().output_channels;
113   scoped_ptr<AudioBus> output_bus = AudioBus::Create(output_channels, kFrames);
114   AudioParameters output_audio(AudioParameters::AUDIO_PCM_LINEAR,
115                                output_layout,
116                                output_layout == CHANNEL_LAYOUT_DISCRETE ?
117                                   output_channels :
118                                   ChannelLayoutToChannelCount(output_layout),
119                                0,
120                                AudioParameters::kAudioCDSampleRate, 16,
121                                kFrames,
122                                AudioParameters::NO_EFFECTS);
123 
124   const float* channel_values = GetParam().channel_values;
125   ASSERT_EQ(input_bus->channels(), GetParam().num_channel_values);
126 
127   float expected_value = 0;
128   float scale = GetParam().scale;
129   for (int ch = 0; ch < input_bus->channels(); ++ch) {
130     std::fill(input_bus->channel(ch), input_bus->channel(ch) + kFrames,
131               channel_values[ch]);
132     expected_value += channel_values[ch] * scale;
133   }
134 
135   ChannelMixer mixer(input_audio, output_audio);
136   mixer.Transform(input_bus.get(), output_bus.get());
137 
138   // Validate the output channel
139   if (input_layout != CHANNEL_LAYOUT_DISCRETE) {
140     for (int ch = 0; ch < output_bus->channels(); ++ch) {
141       for (int frame = 0; frame < output_bus->frames(); ++frame) {
142         ASSERT_FLOAT_EQ(output_bus->channel(ch)[frame], expected_value);
143       }
144     }
145   } else {
146     // Processing discrete mixing. If there is a matching input channel,
147     // then the output channel should be set. If no input channel,
148     // output channel should be 0
149     for (int ch = 0; ch < output_bus->channels(); ++ch) {
150       expected_value = (ch < input_channels) ? channel_values[ch] : 0;
151       for (int frame = 0; frame < output_bus->frames(); ++frame) {
152         ASSERT_FLOAT_EQ(output_bus->channel(ch)[frame], expected_value);
153       }
154     }
155   }
156 }
157 
158 static float kStereoToMonoValues[] = { 0.5f, 0.75f };
159 static float kMonoToStereoValues[] = { 0.5f };
160 // Zero the center channel since it will be mixed at scale 1 vs M_SQRT1_2.
161 static float kFiveOneToMonoValues[] = { 0.1f, 0.2f, 0.0f, 0.4f, 0.5f, 0.6f };
162 static float kFiveDiscreteValues[] = { 0.1f, 0.2f, 0.3f, 0.4f, 0.5f };
163 
164 // Run through basic sanity tests for some common conversions.
165 INSTANTIATE_TEST_CASE_P(ChannelMixerTest, ChannelMixerTest, testing::Values(
166     ChannelMixerTestData(CHANNEL_LAYOUT_STEREO, CHANNEL_LAYOUT_MONO,
167                          kStereoToMonoValues, arraysize(kStereoToMonoValues),
168                          0.5f),
169     ChannelMixerTestData(CHANNEL_LAYOUT_MONO, CHANNEL_LAYOUT_STEREO,
170                          kMonoToStereoValues, arraysize(kMonoToStereoValues),
171                          1.0f),
172     ChannelMixerTestData(CHANNEL_LAYOUT_5_1, CHANNEL_LAYOUT_MONO,
173                          kFiveOneToMonoValues, arraysize(kFiveOneToMonoValues),
174                          static_cast<float>(M_SQRT1_2)),
175     ChannelMixerTestData(CHANNEL_LAYOUT_DISCRETE, 2,
176                          CHANNEL_LAYOUT_DISCRETE, 2,
177                          kStereoToMonoValues, arraysize(kStereoToMonoValues)),
178     ChannelMixerTestData(CHANNEL_LAYOUT_DISCRETE, 2,
179                          CHANNEL_LAYOUT_DISCRETE, 5,
180                          kStereoToMonoValues, arraysize(kStereoToMonoValues)),
181     ChannelMixerTestData(CHANNEL_LAYOUT_DISCRETE, 5,
182                          CHANNEL_LAYOUT_DISCRETE, 2,
183                          kFiveDiscreteValues, arraysize(kFiveDiscreteValues))
184 ));
185 
186 }  // namespace media
187