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_PI. 6 #define _USE_MATH_DEFINES 7 8 #include <cmath> 9 10 #include "base/memory/scoped_ptr.h" 11 #include "base/memory/scoped_vector.h" 12 #include "base/strings/string_number_conversions.h" 13 #include "media/base/audio_converter.h" 14 #include "media/base/fake_audio_render_callback.h" 15 #include "testing/gmock/include/gmock/gmock.h" 16 #include "testing/gtest/include/gtest/gtest.h" 17 18 namespace media { 19 20 // Parameters which control the many input case tests. 21 static const int kConvertInputs = 8; 22 static const int kConvertCycles = 3; 23 24 // Parameters used for testing. 25 static const int kBitsPerChannel = 32; 26 static const ChannelLayout kChannelLayout = CHANNEL_LAYOUT_STEREO; 27 static const int kHighLatencyBufferSize = 2048; 28 static const int kLowLatencyBufferSize = 256; 29 static const int kSampleRate = 48000; 30 31 // Number of full sine wave cycles for each Render() call. 32 static const int kSineCycles = 4; 33 34 // Tuple of <input rate, output rate, output channel layout, epsilon>. 35 typedef std::tr1::tuple<int, int, ChannelLayout, double> AudioConverterTestData; 36 class AudioConverterTest 37 : public testing::TestWithParam<AudioConverterTestData> { 38 public: 39 AudioConverterTest() 40 : epsilon_(std::tr1::get<3>(GetParam())) { 41 // Create input and output parameters based on test parameters. 42 input_parameters_ = AudioParameters( 43 AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout, 44 std::tr1::get<0>(GetParam()), kBitsPerChannel, kHighLatencyBufferSize); 45 output_parameters_ = AudioParameters( 46 AudioParameters::AUDIO_PCM_LOW_LATENCY, std::tr1::get<2>(GetParam()), 47 std::tr1::get<1>(GetParam()), 16, kLowLatencyBufferSize); 48 49 converter_.reset(new AudioConverter( 50 input_parameters_, output_parameters_, false)); 51 52 audio_bus_ = AudioBus::Create(output_parameters_); 53 expected_audio_bus_ = AudioBus::Create(output_parameters_); 54 55 // Allocate one callback for generating expected results. 56 double step = kSineCycles / static_cast<double>( 57 output_parameters_.frames_per_buffer()); 58 expected_callback_.reset(new FakeAudioRenderCallback(step)); 59 } 60 61 // Creates |count| input callbacks to be used for conversion testing. 62 void InitializeInputs(int count) { 63 // Setup FakeAudioRenderCallback step to compensate for resampling. 64 double scale_factor = input_parameters_.sample_rate() / 65 static_cast<double>(output_parameters_.sample_rate()); 66 double step = kSineCycles / (scale_factor * 67 static_cast<double>(output_parameters_.frames_per_buffer())); 68 69 for (int i = 0; i < count; ++i) { 70 fake_callbacks_.push_back(new FakeAudioRenderCallback(step)); 71 converter_->AddInput(fake_callbacks_[i]); 72 } 73 } 74 75 // Resets all input callbacks to a pristine state. 76 void Reset() { 77 converter_->Reset(); 78 for (size_t i = 0; i < fake_callbacks_.size(); ++i) 79 fake_callbacks_[i]->reset(); 80 expected_callback_->reset(); 81 } 82 83 // Sets the volume on all input callbacks to |volume|. 84 void SetVolume(float volume) { 85 for (size_t i = 0; i < fake_callbacks_.size(); ++i) 86 fake_callbacks_[i]->set_volume(volume); 87 } 88 89 // Validates audio data between |audio_bus_| and |expected_audio_bus_| from 90 // |index|..|frames| after |scale| is applied to the expected audio data. 91 bool ValidateAudioData(int index, int frames, float scale) { 92 for (int i = 0; i < audio_bus_->channels(); ++i) { 93 for (int j = index; j < frames; ++j) { 94 double error = fabs(audio_bus_->channel(i)[j] - 95 expected_audio_bus_->channel(i)[j] * scale); 96 if (error > epsilon_) { 97 EXPECT_NEAR(expected_audio_bus_->channel(i)[j] * scale, 98 audio_bus_->channel(i)[j], epsilon_) 99 << " i=" << i << ", j=" << j; 100 return false; 101 } 102 } 103 } 104 return true; 105 } 106 107 // Runs a single Convert() stage, fills |expected_audio_bus_| appropriately, 108 // and validates equality with |audio_bus_| after |scale| is applied. 109 bool RenderAndValidateAudioData(float scale) { 110 // Render actual audio data. 111 converter_->Convert(audio_bus_.get()); 112 113 // Render expected audio data. 114 expected_callback_->Render(expected_audio_bus_.get(), 0); 115 116 // Zero out unused channels in the expected AudioBus just as AudioConverter 117 // would during channel mixing. 118 for (int i = input_parameters_.channels(); 119 i < output_parameters_.channels(); ++i) { 120 memset(expected_audio_bus_->channel(i), 0, 121 audio_bus_->frames() * sizeof(*audio_bus_->channel(i))); 122 } 123 124 return ValidateAudioData(0, audio_bus_->frames(), scale); 125 } 126 127 // Fills |audio_bus_| fully with |value|. 128 void FillAudioData(float value) { 129 for (int i = 0; i < audio_bus_->channels(); ++i) { 130 std::fill(audio_bus_->channel(i), 131 audio_bus_->channel(i) + audio_bus_->frames(), value); 132 } 133 } 134 135 // Verifies converter output with a |inputs| number of transform inputs. 136 void RunTest(int inputs) { 137 InitializeInputs(inputs); 138 139 SetVolume(0); 140 for (int i = 0; i < kConvertCycles; ++i) 141 ASSERT_TRUE(RenderAndValidateAudioData(0)); 142 143 Reset(); 144 145 // Set a different volume for each input and verify the results. 146 float total_scale = 0; 147 for (size_t i = 0; i < fake_callbacks_.size(); ++i) { 148 float volume = static_cast<float>(i) / fake_callbacks_.size(); 149 total_scale += volume; 150 fake_callbacks_[i]->set_volume(volume); 151 } 152 for (int i = 0; i < kConvertCycles; ++i) 153 ASSERT_TRUE(RenderAndValidateAudioData(total_scale)); 154 155 Reset(); 156 157 // Remove every other input. 158 for (size_t i = 1; i < fake_callbacks_.size(); i += 2) 159 converter_->RemoveInput(fake_callbacks_[i]); 160 161 SetVolume(1); 162 float scale = inputs > 1 ? inputs / 2.0f : inputs; 163 for (int i = 0; i < kConvertCycles; ++i) 164 ASSERT_TRUE(RenderAndValidateAudioData(scale)); 165 } 166 167 protected: 168 virtual ~AudioConverterTest() {} 169 170 // Converter under test. 171 scoped_ptr<AudioConverter> converter_; 172 173 // Input and output parameters used for AudioConverter construction. 174 AudioParameters input_parameters_; 175 AudioParameters output_parameters_; 176 177 // Destination AudioBus for AudioConverter output. 178 scoped_ptr<AudioBus> audio_bus_; 179 180 // AudioBus containing expected results for comparison with |audio_bus_|. 181 scoped_ptr<AudioBus> expected_audio_bus_; 182 183 // Vector of all input callbacks used to drive AudioConverter::Convert(). 184 ScopedVector<FakeAudioRenderCallback> fake_callbacks_; 185 186 // Parallel input callback which generates the expected output. 187 scoped_ptr<FakeAudioRenderCallback> expected_callback_; 188 189 // Epsilon value with which to perform comparisons between |audio_bus_| and 190 // |expected_audio_bus_|. 191 double epsilon_; 192 193 DISALLOW_COPY_AND_ASSIGN(AudioConverterTest); 194 }; 195 196 // Ensure the buffer delay provided by AudioConverter is accurate. 197 TEST(AudioConverterTest, AudioDelay) { 198 // Choose input and output parameters such that the transform must make 199 // multiple calls to fill the buffer. 200 AudioParameters input_parameters = AudioParameters( 201 AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout, kSampleRate, 202 kBitsPerChannel, kLowLatencyBufferSize); 203 AudioParameters output_parameters = AudioParameters( 204 AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout, kSampleRate * 2, 205 kBitsPerChannel, kHighLatencyBufferSize); 206 207 AudioConverter converter(input_parameters, output_parameters, false); 208 FakeAudioRenderCallback callback(0.2); 209 scoped_ptr<AudioBus> audio_bus = AudioBus::Create(output_parameters); 210 converter.AddInput(&callback); 211 converter.Convert(audio_bus.get()); 212 213 // Calculate the expected buffer delay for given AudioParameters. 214 double input_sample_rate = input_parameters.sample_rate(); 215 int fill_count = 216 (output_parameters.frames_per_buffer() * input_sample_rate / 217 output_parameters.sample_rate()) / input_parameters.frames_per_buffer(); 218 219 base::TimeDelta input_frame_duration = base::TimeDelta::FromMicroseconds( 220 base::Time::kMicrosecondsPerSecond / input_sample_rate); 221 222 int expected_last_delay_milliseconds = 223 fill_count * input_parameters.frames_per_buffer() * 224 input_frame_duration.InMillisecondsF(); 225 226 EXPECT_EQ(expected_last_delay_milliseconds, 227 callback.last_audio_delay_milliseconds()); 228 } 229 230 TEST_P(AudioConverterTest, ArbitraryOutputRequestSize) { 231 // Resize output bus to be half of |output_parameters_|'s frames_per_buffer(). 232 audio_bus_ = AudioBus::Create(output_parameters_.channels(), 233 output_parameters_.frames_per_buffer() / 2); 234 RunTest(1); 235 } 236 237 TEST_P(AudioConverterTest, NoInputs) { 238 FillAudioData(1.0f); 239 EXPECT_TRUE(RenderAndValidateAudioData(0.0f)); 240 } 241 242 TEST_P(AudioConverterTest, OneInput) { 243 RunTest(1); 244 } 245 246 TEST_P(AudioConverterTest, ManyInputs) { 247 RunTest(kConvertInputs); 248 } 249 250 INSTANTIATE_TEST_CASE_P( 251 AudioConverterTest, AudioConverterTest, testing::Values( 252 // No resampling. No channel mixing. 253 std::tr1::make_tuple(44100, 44100, CHANNEL_LAYOUT_STEREO, 0.00000048), 254 255 // Upsampling. Channel upmixing. 256 std::tr1::make_tuple(44100, 48000, CHANNEL_LAYOUT_QUAD, 0.033), 257 258 // Downsampling. Channel downmixing. 259 std::tr1::make_tuple(48000, 41000, CHANNEL_LAYOUT_MONO, 0.042))); 260 261 } // namespace media 262