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.
5 // MSVC++ requires this to be set before any other includes to get M_SQRT1_2.
6 #define _USE_MATH_DEFINES
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"
18 // Number of frames to test with.
19 enum { kFrames
= 16 };
21 // Test all possible layout conversions can be constructed and mixed.
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_MAX
;
28 output_layout
= static_cast<ChannelLayout
>(output_layout
+ 1)) {
29 // DISCRETE can't be tested here based on the current approach.
30 // CHANNEL_LAYOUT_STEREO_AND_KEYBOARD_MIC is not mixable.
31 // Stereo down mix should never be the output layout.
32 if (input_layout
== CHANNEL_LAYOUT_DISCRETE
||
33 input_layout
== CHANNEL_LAYOUT_STEREO_AND_KEYBOARD_MIC
||
34 output_layout
== CHANNEL_LAYOUT_DISCRETE
||
35 output_layout
== CHANNEL_LAYOUT_STEREO_AND_KEYBOARD_MIC
||
36 output_layout
== CHANNEL_LAYOUT_STEREO_DOWNMIX
) {
40 SCOPED_TRACE(base::StringPrintf(
41 "Input Layout: %d, Output Layout: %d", input_layout
, output_layout
));
42 ChannelMixer
mixer(input_layout
, output_layout
);
43 scoped_ptr
<AudioBus
> input_bus
= AudioBus::Create(
44 ChannelLayoutToChannelCount(input_layout
), kFrames
);
45 scoped_ptr
<AudioBus
> output_bus
= AudioBus::Create(
46 ChannelLayoutToChannelCount(output_layout
), kFrames
);
47 for (int ch
= 0; ch
< input_bus
->channels(); ++ch
)
48 std::fill(input_bus
->channel(ch
), input_bus
->channel(ch
) + kFrames
, 1);
50 mixer
.Transform(input_bus
.get(), output_bus
.get());
55 struct ChannelMixerTestData
{
56 ChannelMixerTestData(ChannelLayout input_layout
, ChannelLayout output_layout
,
57 const float* channel_values
, int num_channel_values
,
59 : input_layout(input_layout
),
60 output_layout(output_layout
),
61 channel_values(channel_values
),
62 num_channel_values(num_channel_values
),
64 input_channels
= ChannelLayoutToChannelCount(input_layout
);
65 output_channels
= ChannelLayoutToChannelCount(output_layout
);
68 ChannelMixerTestData(ChannelLayout input_layout
, int input_channels
,
69 ChannelLayout output_layout
, int output_channels
,
70 const float* channel_values
, int num_channel_values
)
71 : input_layout(input_layout
),
72 input_channels(input_channels
),
73 output_layout(output_layout
),
74 output_channels(output_channels
),
75 channel_values(channel_values
),
76 num_channel_values(num_channel_values
),
80 std::string
DebugString() const {
81 return base::StringPrintf(
82 "Input Layout: %d, Output Layout %d, Scale: %f", input_layout
,
83 output_layout
, scale
);
86 ChannelLayout input_layout
;
88 ChannelLayout output_layout
;
90 const float* channel_values
;
91 int num_channel_values
;
95 std::ostream
& operator<<(std::ostream
& os
, const ChannelMixerTestData
& data
) {
96 return os
<< data
.DebugString();
99 class ChannelMixerTest
: public testing::TestWithParam
<ChannelMixerTestData
> {};
101 // Verify channels are mixed and scaled correctly. The test only works if all
102 // output channels have the same value.
103 TEST_P(ChannelMixerTest
, Mixing
) {
104 ChannelLayout input_layout
= GetParam().input_layout
;
105 int input_channels
= GetParam().input_channels
;
106 scoped_ptr
<AudioBus
> input_bus
= AudioBus::Create(input_channels
, kFrames
);
107 AudioParameters
input_audio(AudioParameters::AUDIO_PCM_LINEAR
, input_layout
,
108 AudioParameters::kAudioCDSampleRate
, 16, kFrames
);
109 if (input_layout
== CHANNEL_LAYOUT_DISCRETE
)
110 input_audio
.set_channels_for_discrete(input_channels
);
112 ChannelLayout output_layout
= GetParam().output_layout
;
113 int output_channels
= GetParam().output_channels
;
114 scoped_ptr
<AudioBus
> output_bus
= AudioBus::Create(output_channels
, kFrames
);
115 AudioParameters
output_audio(AudioParameters::AUDIO_PCM_LINEAR
, output_layout
,
116 AudioParameters::kAudioCDSampleRate
, 16,
118 if (output_layout
== CHANNEL_LAYOUT_DISCRETE
)
119 output_audio
.set_channels_for_discrete(output_channels
);
121 const float* channel_values
= GetParam().channel_values
;
122 ASSERT_EQ(input_bus
->channels(), GetParam().num_channel_values
);
124 float expected_value
= 0;
125 float scale
= GetParam().scale
;
126 for (int ch
= 0; ch
< input_bus
->channels(); ++ch
) {
127 std::fill(input_bus
->channel(ch
), input_bus
->channel(ch
) + kFrames
,
129 expected_value
+= channel_values
[ch
] * scale
;
132 ChannelMixer
mixer(input_audio
, output_audio
);
133 mixer
.Transform(input_bus
.get(), output_bus
.get());
135 // Validate the output channel
136 if (input_layout
!= CHANNEL_LAYOUT_DISCRETE
) {
137 for (int ch
= 0; ch
< output_bus
->channels(); ++ch
) {
138 for (int frame
= 0; frame
< output_bus
->frames(); ++frame
) {
139 ASSERT_FLOAT_EQ(expected_value
, output_bus
->channel(ch
)[frame
]);
143 // Processing discrete mixing. If there is a matching input channel,
144 // then the output channel should be set. If no input channel,
145 // output channel should be 0
146 for (int ch
= 0; ch
< output_bus
->channels(); ++ch
) {
147 expected_value
= (ch
< input_channels
) ? channel_values
[ch
] : 0;
148 for (int frame
= 0; frame
< output_bus
->frames(); ++frame
) {
149 ASSERT_FLOAT_EQ(expected_value
, output_bus
->channel(ch
)[frame
]);
155 static float kStereoToMonoValues
[] = { 0.5f
, 0.75f
};
156 static float kMonoToStereoValues
[] = { 0.5f
};
157 // Zero the center channel since it will be mixed at scale 1 vs M_SQRT1_2.
158 static float kFiveOneToMonoValues
[] = { 0.1f
, 0.2f
, 0.0f
, 0.4f
, 0.5f
, 0.6f
};
159 static float kFiveDiscreteValues
[] = { 0.1f
, 0.2f
, 0.3f
, 0.4f
, 0.5f
};
161 // Run through basic sanity tests for some common conversions.
162 INSTANTIATE_TEST_CASE_P(ChannelMixerTest
, ChannelMixerTest
, testing::Values(
163 ChannelMixerTestData(CHANNEL_LAYOUT_STEREO
, CHANNEL_LAYOUT_MONO
,
164 kStereoToMonoValues
, arraysize(kStereoToMonoValues
),
166 ChannelMixerTestData(CHANNEL_LAYOUT_MONO
, CHANNEL_LAYOUT_STEREO
,
167 kMonoToStereoValues
, arraysize(kMonoToStereoValues
),
169 ChannelMixerTestData(CHANNEL_LAYOUT_5_1
, CHANNEL_LAYOUT_MONO
,
170 kFiveOneToMonoValues
, arraysize(kFiveOneToMonoValues
),
171 static_cast<float>(M_SQRT1_2
)),
172 ChannelMixerTestData(CHANNEL_LAYOUT_DISCRETE
, 2,
173 CHANNEL_LAYOUT_DISCRETE
, 2,
174 kStereoToMonoValues
, arraysize(kStereoToMonoValues
)),
175 ChannelMixerTestData(CHANNEL_LAYOUT_DISCRETE
, 2,
176 CHANNEL_LAYOUT_DISCRETE
, 5,
177 kStereoToMonoValues
, arraysize(kStereoToMonoValues
)),
178 ChannelMixerTestData(CHANNEL_LAYOUT_DISCRETE
, 5,
179 CHANNEL_LAYOUT_DISCRETE
, 2,
180 kFiveDiscreteValues
, arraysize(kFiveDiscreteValues
))