Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(715)

Side by Side Diff: media/base/audio_transform_unittest.cc

Issue 11410012: Collapse AudioRendererMixer and OnMoreDataResampler into AudioTransform. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Comments. Binding. Optional FIFO. Created 8 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(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/command_line.h"
11 #include "base/logging.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "base/memory/scoped_vector.h"
14 #include "base/string_number_conversions.h"
15 #include "base/time.h"
16 #include "media/base/audio_transform.h"
17 #include "media/base/fake_audio_render_callback.h"
18 #include "testing/gmock/include/gmock/gmock.h"
19 #include "testing/gtest/include/gtest/gtest.h"
20
21 namespace media {
22
23 // Command line switch for runtime adjustment of benchmark iterations.
24 static const char kBenchmarkIterations[] = "audio-converter-iterations";
25 static const int kDefaultIterations = 10;
26
27 // Parameters which control the many input case tests.
28 static const int kConvertInputs = 8;
29 static const int kConvertCycles = 3;
30
31 // Parameters used for testing.
32 static const int kBitsPerChannel = 32;
33 static const ChannelLayout kChannelLayout = CHANNEL_LAYOUT_STEREO;
34 static const int kHighLatencyBufferSize = 2048;
35 static const int kLowLatencyBufferSize = 256;
36 static const int kSampleRate = 48000;
37
38 // Number of full sine wave cycles for each Render() call.
39 static const int kSineCycles = 4;
40
41 // Tuple of <input sampling rate, output sampling rate, epsilon>.
42 typedef std::tr1::tuple<int, int, double> AudioConverterTestData;
43 class AudioConverterTest
44 : public testing::TestWithParam<AudioConverterTestData> {
45 public:
46 AudioConverterTest()
47 : epsilon_(std::tr1::get<2>(GetParam())) {
48 // Create input and output parameters based on test parameters.
49 input_parameters_ = AudioParameters(
50 AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout,
51 std::tr1::get<0>(GetParam()), kBitsPerChannel, kHighLatencyBufferSize);
52 output_parameters_ = AudioParameters(
53 AudioParameters::AUDIO_PCM_LOW_LATENCY, kChannelLayout,
54 std::tr1::get<1>(GetParam()), 16, kLowLatencyBufferSize);
55
56 converter_.reset(new AudioConverter(
57 input_parameters_, output_parameters_, false));
58
59 audio_bus_ = AudioBus::Create(output_parameters_);
60 expected_audio_bus_ = AudioBus::Create(output_parameters_);
61
62 // Allocate one callback for generating expected results.
63 double step = kSineCycles / static_cast<double>(
64 output_parameters_.frames_per_buffer());
65 expected_callback_.reset(new FakeAudioRenderCallback(step));
66 }
67
68 void InitializeInputs(int count) {
69 // Setup FakeAudioRenderCallback step to compensate for resampling.
70 double scale_factor = input_parameters_.sample_rate() /
71 static_cast<double>(output_parameters_.sample_rate());
72 double step = kSineCycles / (scale_factor *
73 static_cast<double>(output_parameters_.frames_per_buffer()));
74
75 for (int i = 0; i < count; ++i) {
76 fake_callbacks_.push_back(new FakeAudioRenderCallback(step));
77 converter_->AddInput(fake_callbacks_[i]);
78 }
79 }
80
81 void Reset() {
82 converter_->Reset();
83 for (size_t i = 0; i < fake_callbacks_.size(); ++i)
84 fake_callbacks_[i]->reset();
85 expected_callback_->reset();
86 }
87
88 void SetVolume(float volume) {
89 for (size_t i = 0; i < fake_callbacks_.size(); ++i)
90 fake_callbacks_[i]->set_volume(volume);
91 }
92
93 bool ValidateAudioData(int index, int frames, float scale) {
94 for (int i = 0; i < audio_bus_->channels(); ++i) {
95 for (int j = index; j < frames; j++) {
96 double error = fabs(audio_bus_->channel(i)[j] -
97 expected_audio_bus_->channel(i)[j] * scale);
98 if (error > epsilon_) {
99 EXPECT_NEAR(expected_audio_bus_->channel(i)[j] * scale,
100 audio_bus_->channel(i)[j], epsilon_)
101 << " i=" << i << ", j=" << j;
102 return false;
103 }
104 }
105 }
106 return true;
107 }
108
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 return ValidateAudioData(0, audio_bus_->frames(), scale);
117 }
118
119 // Fill |audio_bus_| fully with |value|.
120 void FillAudioData(float value) {
121 for (int i = 0; i < audio_bus_->channels(); ++i) {
122 std::fill(audio_bus_->channel(i),
123 audio_bus_->channel(i) + audio_bus_->frames(), value);
124 }
125 }
126
127 // Verify output with a number of transform inputs.
128 void RunTest(int inputs) {
129 InitializeInputs(inputs);
130
131 SetVolume(0);
132 for (int i = 0; i < kConvertCycles; ++i)
133 ASSERT_TRUE(RenderAndValidateAudioData(0));
134
135 Reset();
136
137 // Set a different volume for each input and verify the results.
138 float total_scale = 0;
139 for (size_t i = 0; i < fake_callbacks_.size(); ++i) {
140 float volume = static_cast<float>(i) / fake_callbacks_.size();
141 total_scale += volume;
142 fake_callbacks_[i]->set_volume(volume);
143 }
144 for (int i = 0; i < kConvertCycles; ++i)
145 ASSERT_TRUE(RenderAndValidateAudioData(total_scale));
146
147 Reset();
148
149 // Remove every other input.
150 for (size_t i = 1; i < fake_callbacks_.size(); i += 2)
151 converter_->RemoveInput(fake_callbacks_[i]);
152
153 SetVolume(1);
154 float scale = inputs > 1 ? inputs / 2.0f : inputs;
155 for (int i = 0; i < kConvertCycles; ++i)
156 ASSERT_TRUE(RenderAndValidateAudioData(scale));
157 }
158
159 protected:
160 virtual ~AudioConverterTest() {}
161
162 scoped_ptr<AudioConverter> converter_;
163 AudioParameters input_parameters_;
164 AudioParameters output_parameters_;
165 scoped_ptr<AudioBus> audio_bus_;
166 scoped_ptr<AudioBus> expected_audio_bus_;
167 ScopedVector<FakeAudioRenderCallback> fake_callbacks_;
168 scoped_ptr<FakeAudioRenderCallback> expected_callback_;
169 double epsilon_;
170
171 DISALLOW_COPY_AND_ASSIGN(AudioConverterTest);
172 };
173
174 // Ensure the buffer delay provided by AudioConverter is accurate.
175 TEST(AudioConverterTest, AudioDelay) {
176 // Choose input and output parameters such that the transform must make
177 // multiple calls to fill the buffer.
178 AudioParameters input_parameters = AudioParameters(
179 AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout, kSampleRate,
180 kBitsPerChannel, kLowLatencyBufferSize);
181 AudioParameters output_parameters = AudioParameters(
182 AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout, kSampleRate * 2,
183 kBitsPerChannel, kHighLatencyBufferSize);
184
185 AudioConverter converter(input_parameters, output_parameters, false);
186 FakeAudioRenderCallback callback(0.2);
187 scoped_ptr<AudioBus> audio_bus = AudioBus::Create(output_parameters);
188 converter.AddInput(&callback);
189 converter.Convert(audio_bus.get());
190
191 // Calculate the expected buffer delay for given AudioParameters.
192 double input_sample_rate = input_parameters.sample_rate();
193 int fill_count =
194 (output_parameters.frames_per_buffer() * input_sample_rate /
195 output_parameters.sample_rate()) / input_parameters.frames_per_buffer();
196
197 base::TimeDelta input_frame_duration = base::TimeDelta::FromMicroseconds(
198 base::Time::kMicrosecondsPerSecond / input_sample_rate);
199
200 int expected_last_delay_milliseconds =
201 fill_count * input_parameters.frames_per_buffer() *
202 input_frame_duration.InMillisecondsF();
203
204 EXPECT_EQ(expected_last_delay_milliseconds,
205 callback.last_audio_delay_milliseconds());
206 }
207
208 // Benchmark for audio conversion. Original benchmarks were run with
209 // --audio-converter-iterations=50000.
210 TEST(AudioConverterTest, ConvertBenchmark) {
scherkus (not reviewing) 2012/11/17 01:04:37 is this going to run every time and logspam to con
DaleCurtis 2012/11/17 01:07:14 Yes and yes it could be. fischman and I discussed
scherkus (not reviewing) 2012/11/20 00:51:10 I'll let it slide but this is some slippery-slope
211 int benchmark_iterations = kDefaultIterations;
212 std::string iterations(CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
213 kBenchmarkIterations));
214 base::StringToInt(iterations, &benchmark_iterations);
215 if (benchmark_iterations < kDefaultIterations)
216 benchmark_iterations = kDefaultIterations;
217
218 // Create input and output parameters to convert between the two most common
219 // sets of parameters (as indicated via UMA data).
220 AudioParameters input_params(
221 AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO, 48000, 16, 2048);
222 AudioParameters output_params(
223 AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_STEREO, 44100, 16, 440);
224 scoped_ptr<AudioConverter> converter(
225 new AudioConverter(input_params, output_params, false));
226
227 scoped_ptr<AudioBus> output_bus = AudioBus::Create(output_params);
228 FakeAudioRenderCallback fake_input1(0.2);
229 FakeAudioRenderCallback fake_input2(0.4);
230 FakeAudioRenderCallback fake_input3(0.6);
231 converter->AddInput(&fake_input1);
232 converter->AddInput(&fake_input2);
233 converter->AddInput(&fake_input3);
234
235 printf("Benchmarking %d iterations:\n", benchmark_iterations);
236
237 // Benchmark Convert() w/ FIFO.
238 base::TimeTicks start = base::TimeTicks::HighResNow();
239 for (int i = 0; i < benchmark_iterations; ++i) {
240 converter->Convert(output_bus.get());
241 }
242 double total_time_ms =
243 (base::TimeTicks::HighResNow() - start).InMillisecondsF();
244 printf("Convert() w/ FIFO took %.2fms.\n", total_time_ms);
245
246 converter.reset(new AudioConverter(input_params, output_params, true));
247 converter->AddInput(&fake_input1);
248 converter->AddInput(&fake_input2);
249 converter->AddInput(&fake_input3);
250
251 // Benchmark Convert() w/o FIFO.
252 start = base::TimeTicks::HighResNow();
253 for (int i = 0; i < benchmark_iterations; ++i) {
254 converter->Convert(output_bus.get());
255 }
256 total_time_ms =
257 (base::TimeTicks::HighResNow() - start).InMillisecondsF();
258 printf("Convert() w/o FIFO took %.2fms.\n", total_time_ms);
259 }
260
261 TEST_P(AudioConverterTest, NoInputs) {
262 FillAudioData(1.0f);
263 EXPECT_TRUE(RenderAndValidateAudioData(0.0f));
264 }
265
266 TEST_P(AudioConverterTest, OneInput) {
267 RunTest(1);
268 }
269
270 TEST_P(AudioConverterTest, ManyInputs) {
271 RunTest(kConvertInputs);
272 }
273
274 INSTANTIATE_TEST_CASE_P(
275 // TODO(dalecurtis): Add test cases for channel transforms.
276 AudioConverterTest, AudioConverterTest, testing::Values(
277 // No resampling.
278 std::tr1::make_tuple(44100, 44100, 0.00000048),
279
280 // Upsampling.
281 std::tr1::make_tuple(44100, 48000, 0.033),
282
283 // Downsampling.
284 std::tr1::make_tuple(48000, 41000, 0.042)));
285
286 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698