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_PI.
6 #define _USE_MATH_DEFINES
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"
20 // Parameters which control the many input case tests.
21 static const int kConvertInputs
= 8;
22 static const int kConvertCycles
= 3;
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;
31 // Number of full sine wave cycles for each Render() call.
32 static const int kSineCycles
= 4;
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
> {
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
);
49 converter_
.reset(new AudioConverter(
50 input_parameters_
, output_parameters_
, false));
52 audio_bus_
= AudioBus::Create(output_parameters_
);
53 expected_audio_bus_
= AudioBus::Create(output_parameters_
);
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
));
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()));
69 for (int i
= 0; i
< count
; ++i
) {
70 fake_callbacks_
.push_back(new FakeAudioRenderCallback(step
));
71 converter_
->AddInput(fake_callbacks_
[i
]);
75 // Resets all input callbacks to a pristine state.
78 for (size_t i
= 0; i
< fake_callbacks_
.size(); ++i
)
79 fake_callbacks_
[i
]->reset();
80 expected_callback_
->reset();
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
);
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
;
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());
113 // Render expected audio data.
114 expected_callback_
->Render(expected_audio_bus_
.get(), 0);
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
)));
124 return ValidateAudioData(0, audio_bus_
->frames(), scale
);
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
);
135 // Verifies converter output with a |inputs| number of transform inputs.
136 void RunTest(int inputs
) {
137 InitializeInputs(inputs
);
140 for (int i
= 0; i
< kConvertCycles
; ++i
)
141 ASSERT_TRUE(RenderAndValidateAudioData(0));
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
);
152 for (int i
= 0; i
< kConvertCycles
; ++i
)
153 ASSERT_TRUE(RenderAndValidateAudioData(total_scale
));
157 // Remove every other input.
158 for (size_t i
= 1; i
< fake_callbacks_
.size(); i
+= 2)
159 converter_
->RemoveInput(fake_callbacks_
[i
]);
162 float scale
= inputs
> 1 ? inputs
/ 2.0f
: inputs
;
163 for (int i
= 0; i
< kConvertCycles
; ++i
)
164 ASSERT_TRUE(RenderAndValidateAudioData(scale
));
168 virtual ~AudioConverterTest() {}
170 // Converter under test.
171 scoped_ptr
<AudioConverter
> converter_
;
173 // Input and output parameters used for AudioConverter construction.
174 AudioParameters input_parameters_
;
175 AudioParameters output_parameters_
;
177 // Destination AudioBus for AudioConverter output.
178 scoped_ptr
<AudioBus
> audio_bus_
;
180 // AudioBus containing expected results for comparison with |audio_bus_|.
181 scoped_ptr
<AudioBus
> expected_audio_bus_
;
183 // Vector of all input callbacks used to drive AudioConverter::Convert().
184 ScopedVector
<FakeAudioRenderCallback
> fake_callbacks_
;
186 // Parallel input callback which generates the expected output.
187 scoped_ptr
<FakeAudioRenderCallback
> expected_callback_
;
189 // Epsilon value with which to perform comparisons between |audio_bus_| and
190 // |expected_audio_bus_|.
193 DISALLOW_COPY_AND_ASSIGN(AudioConverterTest
);
196 // Ensure the buffer delay provided by AudioConverter is accurate.
197 TEST(AudioConverterTest
, AudioDelayAndDiscreteChannelCount
) {
198 // Choose input and output parameters such that the transform must make
199 // multiple calls to fill the buffer.
200 AudioParameters
input_parameters(AudioParameters::AUDIO_PCM_LINEAR
,
201 CHANNEL_LAYOUT_DISCRETE
, 10, kSampleRate
,
202 kBitsPerChannel
, kLowLatencyBufferSize
,
203 AudioParameters::NO_EFFECTS
);
204 AudioParameters
output_parameters(AudioParameters::AUDIO_PCM_LINEAR
,
205 CHANNEL_LAYOUT_DISCRETE
, 5, kSampleRate
* 2,
206 kBitsPerChannel
, kHighLatencyBufferSize
,
207 AudioParameters::NO_EFFECTS
);
209 AudioConverter
converter(input_parameters
, output_parameters
, false);
210 FakeAudioRenderCallback
callback(0.2);
211 scoped_ptr
<AudioBus
> audio_bus
= AudioBus::Create(output_parameters
);
212 converter
.AddInput(&callback
);
213 converter
.Convert(audio_bus
.get());
215 // Calculate the expected buffer delay for given AudioParameters.
216 double input_sample_rate
= input_parameters
.sample_rate();
218 (output_parameters
.frames_per_buffer() * input_sample_rate
/
219 output_parameters
.sample_rate()) / input_parameters
.frames_per_buffer();
221 base::TimeDelta input_frame_duration
= base::TimeDelta::FromMicroseconds(
222 base::Time::kMicrosecondsPerSecond
/ input_sample_rate
);
224 int expected_last_delay_milliseconds
=
225 fill_count
* input_parameters
.frames_per_buffer() *
226 input_frame_duration
.InMillisecondsF();
228 EXPECT_EQ(expected_last_delay_milliseconds
,
229 callback
.last_audio_delay_milliseconds());
230 EXPECT_EQ(input_parameters
.channels(), callback
.last_channel_count());
233 TEST_P(AudioConverterTest
, ArbitraryOutputRequestSize
) {
234 // Resize output bus to be half of |output_parameters_|'s frames_per_buffer().
235 audio_bus_
= AudioBus::Create(output_parameters_
.channels(),
236 output_parameters_
.frames_per_buffer() / 2);
240 TEST_P(AudioConverterTest
, NoInputs
) {
242 EXPECT_TRUE(RenderAndValidateAudioData(0.0f
));
245 TEST_P(AudioConverterTest
, OneInput
) {
249 TEST_P(AudioConverterTest
, ManyInputs
) {
250 RunTest(kConvertInputs
);
253 INSTANTIATE_TEST_CASE_P(
254 AudioConverterTest
, AudioConverterTest
, testing::Values(
255 // No resampling. No channel mixing.
256 std::tr1::make_tuple(44100, 44100, CHANNEL_LAYOUT_STEREO
, 0.00000048),
258 // Upsampling. Channel upmixing.
259 std::tr1::make_tuple(44100, 48000, CHANNEL_LAYOUT_QUAD
, 0.033),
261 // Downsampling. Channel downmixing.
262 std::tr1::make_tuple(48000, 41000, CHANNEL_LAYOUT_MONO
, 0.042)));