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. 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 // CHANNEL_LAYOUT_STEREO_AND_KEYBOARD_MIC is not mixable. 31 if (input_layout == CHANNEL_LAYOUT_DISCRETE || 32 input_layout == CHANNEL_LAYOUT_STEREO_AND_KEYBOARD_MIC || 33 output_layout == CHANNEL_LAYOUT_DISCRETE || 34 output_layout == CHANNEL_LAYOUT_STEREO_AND_KEYBOARD_MIC) { 35 continue; 36 } 37 38 SCOPED_TRACE(base::StringPrintf( 39 "Input Layout: %d, Output Layout: %d", input_layout, output_layout)); 40 ChannelMixer mixer(input_layout, output_layout); 41 scoped_ptr<AudioBus> input_bus = AudioBus::Create( 42 ChannelLayoutToChannelCount(input_layout), kFrames); 43 scoped_ptr<AudioBus> output_bus = AudioBus::Create( 44 ChannelLayoutToChannelCount(output_layout), kFrames); 45 for (int ch = 0; ch < input_bus->channels(); ++ch) 46 std::fill(input_bus->channel(ch), input_bus->channel(ch) + kFrames, 1); 47 48 mixer.Transform(input_bus.get(), output_bus.get()); 49 } 50 } 51 } 52 53 struct ChannelMixerTestData { 54 ChannelMixerTestData(ChannelLayout input_layout, ChannelLayout output_layout, 55 float* channel_values, int num_channel_values, 56 float scale) 57 : input_layout(input_layout), 58 output_layout(output_layout), 59 channel_values(channel_values), 60 num_channel_values(num_channel_values), 61 scale(scale) { 62 input_channels = ChannelLayoutToChannelCount(input_layout); 63 output_channels = ChannelLayoutToChannelCount(output_layout); 64 } 65 66 ChannelMixerTestData(ChannelLayout input_layout, int input_channels, 67 ChannelLayout output_layout, int output_channels, 68 float* channel_values, int num_channel_values) 69 : input_layout(input_layout), 70 input_channels(input_channels), 71 output_layout(output_layout), 72 output_channels(output_channels), 73 channel_values(channel_values), 74 num_channel_values(num_channel_values), 75 scale(1.0f) { 76 } 77 78 std::string DebugString() const { 79 return base::StringPrintf( 80 "Input Layout: %d, Output Layout %d, Scale: %f", input_layout, 81 output_layout, scale); 82 } 83 84 ChannelLayout input_layout; 85 int input_channels; 86 ChannelLayout output_layout; 87 int output_channels; 88 float* channel_values; 89 int num_channel_values; 90 float scale; 91 }; 92 93 std::ostream& operator<<(std::ostream& os, const ChannelMixerTestData& data) { 94 return os << data.DebugString(); 95 } 96 97 class ChannelMixerTest : public testing::TestWithParam<ChannelMixerTestData> {}; 98 99 // Verify channels are mixed and scaled correctly. The test only works if all 100 // output channels have the same value. 101 TEST_P(ChannelMixerTest, Mixing) { 102 ChannelLayout input_layout = GetParam().input_layout; 103 int input_channels = GetParam().input_channels; 104 scoped_ptr<AudioBus> input_bus = AudioBus::Create(input_channels, kFrames); 105 AudioParameters input_audio(AudioParameters::AUDIO_PCM_LINEAR, 106 input_layout, 107 input_layout == CHANNEL_LAYOUT_DISCRETE ? 108 input_channels : 109 ChannelLayoutToChannelCount(input_layout), 110 0, 111 AudioParameters::kAudioCDSampleRate, 16, 112 kFrames, 113 AudioParameters::NO_EFFECTS); 114 115 ChannelLayout output_layout = GetParam().output_layout; 116 int output_channels = GetParam().output_channels; 117 scoped_ptr<AudioBus> output_bus = AudioBus::Create(output_channels, kFrames); 118 AudioParameters output_audio(AudioParameters::AUDIO_PCM_LINEAR, 119 output_layout, 120 output_layout == CHANNEL_LAYOUT_DISCRETE ? 121 output_channels : 122 ChannelLayoutToChannelCount(output_layout), 123 0, 124 AudioParameters::kAudioCDSampleRate, 16, 125 kFrames, 126 AudioParameters::NO_EFFECTS); 127 128 const float* channel_values = GetParam().channel_values; 129 ASSERT_EQ(input_bus->channels(), GetParam().num_channel_values); 130 131 float expected_value = 0; 132 float scale = GetParam().scale; 133 for (int ch = 0; ch < input_bus->channels(); ++ch) { 134 std::fill(input_bus->channel(ch), input_bus->channel(ch) + kFrames, 135 channel_values[ch]); 136 expected_value += channel_values[ch] * scale; 137 } 138 139 ChannelMixer mixer(input_audio, output_audio); 140 mixer.Transform(input_bus.get(), output_bus.get()); 141 142 // Validate the output channel 143 if (input_layout != CHANNEL_LAYOUT_DISCRETE) { 144 for (int ch = 0; ch < output_bus->channels(); ++ch) { 145 for (int frame = 0; frame < output_bus->frames(); ++frame) { 146 ASSERT_FLOAT_EQ(output_bus->channel(ch)[frame], expected_value); 147 } 148 } 149 } else { 150 // Processing discrete mixing. If there is a matching input channel, 151 // then the output channel should be set. If no input channel, 152 // output channel should be 0 153 for (int ch = 0; ch < output_bus->channels(); ++ch) { 154 expected_value = (ch < input_channels) ? channel_values[ch] : 0; 155 for (int frame = 0; frame < output_bus->frames(); ++frame) { 156 ASSERT_FLOAT_EQ(output_bus->channel(ch)[frame], expected_value); 157 } 158 } 159 } 160 } 161 162 static float kStereoToMonoValues[] = { 0.5f, 0.75f }; 163 static float kMonoToStereoValues[] = { 0.5f }; 164 // Zero the center channel since it will be mixed at scale 1 vs M_SQRT1_2. 165 static float kFiveOneToMonoValues[] = { 0.1f, 0.2f, 0.0f, 0.4f, 0.5f, 0.6f }; 166 static float kFiveDiscreteValues[] = { 0.1f, 0.2f, 0.3f, 0.4f, 0.5f }; 167 168 // Run through basic sanity tests for some common conversions. 169 INSTANTIATE_TEST_CASE_P(ChannelMixerTest, ChannelMixerTest, testing::Values( 170 ChannelMixerTestData(CHANNEL_LAYOUT_STEREO, CHANNEL_LAYOUT_MONO, 171 kStereoToMonoValues, arraysize(kStereoToMonoValues), 172 0.5f), 173 ChannelMixerTestData(CHANNEL_LAYOUT_MONO, CHANNEL_LAYOUT_STEREO, 174 kMonoToStereoValues, arraysize(kMonoToStereoValues), 175 1.0f), 176 ChannelMixerTestData(CHANNEL_LAYOUT_5_1, CHANNEL_LAYOUT_MONO, 177 kFiveOneToMonoValues, arraysize(kFiveOneToMonoValues), 178 static_cast<float>(M_SQRT1_2)), 179 ChannelMixerTestData(CHANNEL_LAYOUT_DISCRETE, 2, 180 CHANNEL_LAYOUT_DISCRETE, 2, 181 kStereoToMonoValues, arraysize(kStereoToMonoValues)), 182 ChannelMixerTestData(CHANNEL_LAYOUT_DISCRETE, 2, 183 CHANNEL_LAYOUT_DISCRETE, 5, 184 kStereoToMonoValues, arraysize(kStereoToMonoValues)), 185 ChannelMixerTestData(CHANNEL_LAYOUT_DISCRETE, 5, 186 CHANNEL_LAYOUT_DISCRETE, 2, 187 kFiveDiscreteValues, arraysize(kFiveDiscreteValues)) 188 )); 189 190 } // namespace media 191