- add sources.
[platform/framework/web/crosswalk.git] / src / media / base / audio_converter_unittest.cc
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, NoInputs) {
231   FillAudioData(1.0f);
232   EXPECT_TRUE(RenderAndValidateAudioData(0.0f));
233 }
234
235 TEST_P(AudioConverterTest, OneInput) {
236   RunTest(1);
237 }
238
239 TEST_P(AudioConverterTest, ManyInputs) {
240   RunTest(kConvertInputs);
241 }
242
243 INSTANTIATE_TEST_CASE_P(
244     AudioConverterTest, AudioConverterTest, testing::Values(
245         // No resampling. No channel mixing.
246         std::tr1::make_tuple(44100, 44100, CHANNEL_LAYOUT_STEREO, 0.00000048),
247
248         // Upsampling. Channel upmixing.
249         std::tr1::make_tuple(44100, 48000, CHANNEL_LAYOUT_QUAD, 0.033),
250
251         // Downsampling. Channel downmixing.
252         std::tr1::make_tuple(48000, 41000, CHANNEL_LAYOUT_MONO, 0.042)));
253
254 }  // namespace media