| OLD | NEW |
| (Empty) | |
| 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/logging.h" |
| 11 #include "base/memory/scoped_ptr.h" |
| 12 #include "base/memory/scoped_vector.h" |
| 13 #include "media/base/audio_transform.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 kTransformInputs = 8; |
| 22 static const int kTransformCycles = 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 sampling rate, output sampling rate, epsilon>. |
| 35 typedef std::tr1::tuple<int, int, double> AudioTransformTestData; |
| 36 class AudioTransformTest |
| 37 : public testing::TestWithParam<AudioTransformTestData> { |
| 38 public: |
| 39 AudioTransformTest() |
| 40 : epsilon_(std::tr1::get<2>(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, kChannelLayout, |
| 47 std::tr1::get<1>(GetParam()), 16, kLowLatencyBufferSize); |
| 48 |
| 49 transform_.reset(new AudioTransform(input_parameters_, output_parameters_)); |
| 50 |
| 51 audio_bus_ = AudioBus::Create(output_parameters_); |
| 52 expected_audio_bus_ = AudioBus::Create(output_parameters_); |
| 53 |
| 54 // Allocate one callback for generating expected results. |
| 55 double step = kSineCycles / static_cast<double>( |
| 56 output_parameters_.frames_per_buffer()); |
| 57 expected_callback_.reset(new FakeAudioRenderCallback(step)); |
| 58 } |
| 59 |
| 60 void InitializeInputs(int count) { |
| 61 // Setup FakeAudioRenderCallback step to compensate for resampling. |
| 62 double scale_factor = input_parameters_.sample_rate() / |
| 63 static_cast<double>(output_parameters_.sample_rate()); |
| 64 double step = kSineCycles / (scale_factor * |
| 65 static_cast<double>(output_parameters_.frames_per_buffer())); |
| 66 |
| 67 for (int i = 0; i < count; ++i) { |
| 68 fake_callbacks_.push_back(new FakeAudioRenderCallback(step)); |
| 69 transform_->AddInput(fake_callbacks_[i]); |
| 70 } |
| 71 } |
| 72 |
| 73 void Reset() { |
| 74 transform_->Reset(); |
| 75 for (size_t i = 0; i < fake_callbacks_.size(); ++i) |
| 76 fake_callbacks_[i]->reset(); |
| 77 expected_callback_->reset(); |
| 78 } |
| 79 |
| 80 void SetVolume(float volume) { |
| 81 for (size_t i = 0; i < fake_callbacks_.size(); ++i) |
| 82 fake_callbacks_[i]->set_volume(volume); |
| 83 } |
| 84 |
| 85 bool ValidateAudioData(int index, int frames, float scale) { |
| 86 for (int i = 0; i < audio_bus_->channels(); ++i) { |
| 87 for (int j = index; j < frames; j++) { |
| 88 double error = fabs(audio_bus_->channel(i)[j] - |
| 89 expected_audio_bus_->channel(i)[j] * scale); |
| 90 if (error > epsilon_) { |
| 91 EXPECT_NEAR(expected_audio_bus_->channel(i)[j] * scale, |
| 92 audio_bus_->channel(i)[j], epsilon_) |
| 93 << " i=" << i << ", j=" << j; |
| 94 return false; |
| 95 } |
| 96 } |
| 97 } |
| 98 return true; |
| 99 } |
| 100 |
| 101 bool RenderAndValidateAudioData(float scale) { |
| 102 // Render actual audio data. |
| 103 transform_->Transform(audio_bus_.get()); |
| 104 |
| 105 // Render expected audio data. |
| 106 expected_callback_->Render(expected_audio_bus_.get(), 0); |
| 107 |
| 108 return ValidateAudioData(0, audio_bus_->frames(), scale); |
| 109 } |
| 110 |
| 111 // Fill |audio_bus_| fully with |value|. |
| 112 void FillAudioData(float value) { |
| 113 for (int i = 0; i < audio_bus_->channels(); ++i) { |
| 114 std::fill(audio_bus_->channel(i), |
| 115 audio_bus_->channel(i) + audio_bus_->frames(), value); |
| 116 } |
| 117 } |
| 118 |
| 119 // Verify output with a number of transform inputs. |
| 120 void RunTest(int inputs) { |
| 121 InitializeInputs(inputs); |
| 122 |
| 123 SetVolume(0); |
| 124 for (int i = 0; i < kTransformCycles; ++i) |
| 125 ASSERT_TRUE(RenderAndValidateAudioData(0)); |
| 126 |
| 127 Reset(); |
| 128 |
| 129 // Set a different volume for each input and verify the results. |
| 130 float total_scale = 0; |
| 131 for (size_t i = 0; i < fake_callbacks_.size(); ++i) { |
| 132 float volume = static_cast<float>(i) / fake_callbacks_.size(); |
| 133 total_scale += volume; |
| 134 fake_callbacks_[i]->set_volume(volume); |
| 135 } |
| 136 for (int i = 0; i < kTransformCycles; ++i) |
| 137 ASSERT_TRUE(RenderAndValidateAudioData(total_scale)); |
| 138 |
| 139 Reset(); |
| 140 |
| 141 // Remove every other input. |
| 142 for (size_t i = 1; i < fake_callbacks_.size(); i += 2) |
| 143 transform_->RemoveInput(fake_callbacks_[i]); |
| 144 |
| 145 SetVolume(1); |
| 146 float scale = inputs > 1 ? inputs / 2.0f : inputs; |
| 147 for (int i = 0; i < kTransformCycles; ++i) |
| 148 ASSERT_TRUE(RenderAndValidateAudioData(scale)); |
| 149 } |
| 150 |
| 151 protected: |
| 152 virtual ~AudioTransformTest() {} |
| 153 |
| 154 scoped_ptr<AudioTransform> transform_; |
| 155 AudioParameters input_parameters_; |
| 156 AudioParameters output_parameters_; |
| 157 scoped_ptr<AudioBus> audio_bus_; |
| 158 scoped_ptr<AudioBus> expected_audio_bus_; |
| 159 ScopedVector<FakeAudioRenderCallback> fake_callbacks_; |
| 160 scoped_ptr<FakeAudioRenderCallback> expected_callback_; |
| 161 double epsilon_; |
| 162 |
| 163 DISALLOW_COPY_AND_ASSIGN(AudioTransformTest); |
| 164 }; |
| 165 |
| 166 // Ensure the buffer delay provided by AudioTransform is accurate. |
| 167 TEST(AudioTransformTest, AudioDelay) { |
| 168 // Choose input and output parameters such that the transform must make |
| 169 // multiple calls to fill the buffer. |
| 170 AudioParameters input_parameters = AudioParameters( |
| 171 AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout, kSampleRate, |
| 172 kBitsPerChannel, kLowLatencyBufferSize); |
| 173 AudioParameters output_parameters = AudioParameters( |
| 174 AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout, kSampleRate * 2, |
| 175 kBitsPerChannel, kHighLatencyBufferSize); |
| 176 |
| 177 AudioTransform transform(input_parameters, output_parameters); |
| 178 FakeAudioRenderCallback callback(0.2); |
| 179 scoped_ptr<AudioBus> audio_bus = AudioBus::Create(output_parameters); |
| 180 transform.AddInput(&callback); |
| 181 transform.Transform(audio_bus.get()); |
| 182 |
| 183 // Calculate the expected buffer delay for given AudioParameters. |
| 184 double input_sample_rate = input_parameters.sample_rate(); |
| 185 int fill_count = |
| 186 (output_parameters.frames_per_buffer() * input_sample_rate / |
| 187 output_parameters.sample_rate()) / input_parameters.frames_per_buffer(); |
| 188 |
| 189 base::TimeDelta input_frame_duration = base::TimeDelta::FromMicroseconds( |
| 190 base::Time::kMicrosecondsPerSecond / input_sample_rate); |
| 191 |
| 192 int expected_last_delay_milliseconds = |
| 193 fill_count * input_parameters.frames_per_buffer() * |
| 194 input_frame_duration.InMillisecondsF(); |
| 195 |
| 196 EXPECT_EQ(expected_last_delay_milliseconds, |
| 197 callback.last_audio_delay_milliseconds()); |
| 198 } |
| 199 |
| 200 TEST_P(AudioTransformTest, NoInputs) { |
| 201 FillAudioData(1.0f); |
| 202 EXPECT_TRUE(RenderAndValidateAudioData(0.0f)); |
| 203 } |
| 204 |
| 205 TEST_P(AudioTransformTest, OneInput) { |
| 206 RunTest(1); |
| 207 } |
| 208 |
| 209 TEST_P(AudioTransformTest, ManyInputs) { |
| 210 RunTest(kTransformInputs); |
| 211 } |
| 212 |
| 213 INSTANTIATE_TEST_CASE_P( |
| 214 // TODO(dalecurtis): Add test cases for channel transforms. |
| 215 AudioTransformTest, AudioTransformTest, testing::Values( |
| 216 // No resampling. |
| 217 std::tr1::make_tuple(44100, 44100, 0.00000048), |
| 218 |
| 219 // Upsampling. |
| 220 std::tr1::make_tuple(44100, 48000, 0.033), |
| 221 |
| 222 // Downsampling. |
| 223 std::tr1::make_tuple(48000, 41000, 0.042))); |
| 224 |
| 225 } // namespace media |
| OLD | NEW |