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

Unified Diff: media/base/audio_converter_unittest.cc

Issue 11410012: Collapse AudioRendererMixer and OnMoreDataResampler into AudioTransform. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rename. Comments. 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « media/base/audio_converter.cc ('k') | media/base/audio_pull_fifo.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: media/base/audio_converter_unittest.cc
diff --git a/media/base/audio_converter_unittest.cc b/media/base/audio_converter_unittest.cc
new file mode 100644
index 0000000000000000000000000000000000000000..0861222e5ef0eebb010479dbebee1e6cd27fe0a2
--- /dev/null
+++ b/media/base/audio_converter_unittest.cc
@@ -0,0 +1,286 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// MSVC++ requires this to be set before any other includes to get M_PI.
+#define _USE_MATH_DEFINES
+
+#include <cmath>
+
+#include "base/command_line.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/scoped_vector.h"
+#include "base/string_number_conversions.h"
+#include "base/time.h"
+#include "media/base/audio_converter.h"
+#include "media/base/fake_audio_render_callback.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace media {
+
+// Command line switch for runtime adjustment of benchmark iterations.
+static const char kBenchmarkIterations[] = "audio-converter-iterations";
+static const int kDefaultIterations = 10;
+
+// Parameters which control the many input case tests.
+static const int kConvertInputs = 8;
+static const int kConvertCycles = 3;
+
+// Parameters used for testing.
+static const int kBitsPerChannel = 32;
+static const ChannelLayout kChannelLayout = CHANNEL_LAYOUT_STEREO;
+static const int kHighLatencyBufferSize = 2048;
+static const int kLowLatencyBufferSize = 256;
+static const int kSampleRate = 48000;
+
+// Number of full sine wave cycles for each Render() call.
+static const int kSineCycles = 4;
+
+// Tuple of <input sampling rate, output sampling rate, epsilon>.
+typedef std::tr1::tuple<int, int, double> AudioConverterTestData;
+class AudioConverterTest
+ : public testing::TestWithParam<AudioConverterTestData> {
+ public:
+ AudioConverterTest()
+ : epsilon_(std::tr1::get<2>(GetParam())) {
+ // Create input and output parameters based on test parameters.
+ input_parameters_ = AudioParameters(
+ AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout,
+ std::tr1::get<0>(GetParam()), kBitsPerChannel, kHighLatencyBufferSize);
+ output_parameters_ = AudioParameters(
+ AudioParameters::AUDIO_PCM_LOW_LATENCY, kChannelLayout,
+ std::tr1::get<1>(GetParam()), 16, kLowLatencyBufferSize);
+
+ converter_.reset(new AudioConverter(
+ input_parameters_, output_parameters_, false));
+
+ audio_bus_ = AudioBus::Create(output_parameters_);
+ expected_audio_bus_ = AudioBus::Create(output_parameters_);
+
+ // Allocate one callback for generating expected results.
+ double step = kSineCycles / static_cast<double>(
+ output_parameters_.frames_per_buffer());
+ expected_callback_.reset(new FakeAudioRenderCallback(step));
+ }
+
+ void InitializeInputs(int count) {
+ // Setup FakeAudioRenderCallback step to compensate for resampling.
+ double scale_factor = input_parameters_.sample_rate() /
+ static_cast<double>(output_parameters_.sample_rate());
+ double step = kSineCycles / (scale_factor *
+ static_cast<double>(output_parameters_.frames_per_buffer()));
+
+ for (int i = 0; i < count; ++i) {
+ fake_callbacks_.push_back(new FakeAudioRenderCallback(step));
+ converter_->AddInput(fake_callbacks_[i]);
+ }
+ }
+
+ void Reset() {
+ converter_->Reset();
+ for (size_t i = 0; i < fake_callbacks_.size(); ++i)
+ fake_callbacks_[i]->reset();
+ expected_callback_->reset();
+ }
+
+ void SetVolume(float volume) {
+ for (size_t i = 0; i < fake_callbacks_.size(); ++i)
+ fake_callbacks_[i]->set_volume(volume);
+ }
+
+ bool ValidateAudioData(int index, int frames, float scale) {
+ for (int i = 0; i < audio_bus_->channels(); ++i) {
+ for (int j = index; j < frames; j++) {
+ double error = fabs(audio_bus_->channel(i)[j] -
+ expected_audio_bus_->channel(i)[j] * scale);
+ if (error > epsilon_) {
+ EXPECT_NEAR(expected_audio_bus_->channel(i)[j] * scale,
+ audio_bus_->channel(i)[j], epsilon_)
+ << " i=" << i << ", j=" << j;
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ bool RenderAndValidateAudioData(float scale) {
+ // Render actual audio data.
+ converter_->Convert(audio_bus_.get());
+
+ // Render expected audio data.
+ expected_callback_->Render(expected_audio_bus_.get(), 0);
+
+ return ValidateAudioData(0, audio_bus_->frames(), scale);
+ }
+
+ // Fill |audio_bus_| fully with |value|.
+ void FillAudioData(float value) {
+ for (int i = 0; i < audio_bus_->channels(); ++i) {
+ std::fill(audio_bus_->channel(i),
+ audio_bus_->channel(i) + audio_bus_->frames(), value);
+ }
+ }
+
+ // Verify output with a number of transform inputs.
+ void RunTest(int inputs) {
+ InitializeInputs(inputs);
+
+ SetVolume(0);
+ for (int i = 0; i < kConvertCycles; ++i)
+ ASSERT_TRUE(RenderAndValidateAudioData(0));
+
+ Reset();
+
+ // Set a different volume for each input and verify the results.
+ float total_scale = 0;
+ for (size_t i = 0; i < fake_callbacks_.size(); ++i) {
+ float volume = static_cast<float>(i) / fake_callbacks_.size();
+ total_scale += volume;
+ fake_callbacks_[i]->set_volume(volume);
+ }
+ for (int i = 0; i < kConvertCycles; ++i)
+ ASSERT_TRUE(RenderAndValidateAudioData(total_scale));
+
+ Reset();
+
+ // Remove every other input.
+ for (size_t i = 1; i < fake_callbacks_.size(); i += 2)
+ converter_->RemoveInput(fake_callbacks_[i]);
+
+ SetVolume(1);
+ float scale = inputs > 1 ? inputs / 2.0f : inputs;
+ for (int i = 0; i < kConvertCycles; ++i)
+ ASSERT_TRUE(RenderAndValidateAudioData(scale));
+ }
+
+ protected:
+ virtual ~AudioConverterTest() {}
+
+ scoped_ptr<AudioConverter> converter_;
+ AudioParameters input_parameters_;
+ AudioParameters output_parameters_;
+ scoped_ptr<AudioBus> audio_bus_;
+ scoped_ptr<AudioBus> expected_audio_bus_;
+ ScopedVector<FakeAudioRenderCallback> fake_callbacks_;
+ scoped_ptr<FakeAudioRenderCallback> expected_callback_;
+ double epsilon_;
+
+ DISALLOW_COPY_AND_ASSIGN(AudioConverterTest);
+};
+
+// Ensure the buffer delay provided by AudioConverter is accurate.
+TEST(AudioConverterTest, AudioDelay) {
+ // Choose input and output parameters such that the transform must make
+ // multiple calls to fill the buffer.
+ AudioParameters input_parameters = AudioParameters(
+ AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout, kSampleRate,
+ kBitsPerChannel, kLowLatencyBufferSize);
+ AudioParameters output_parameters = AudioParameters(
+ AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout, kSampleRate * 2,
+ kBitsPerChannel, kHighLatencyBufferSize);
+
+ AudioConverter converter(input_parameters, output_parameters, false);
+ FakeAudioRenderCallback callback(0.2);
+ scoped_ptr<AudioBus> audio_bus = AudioBus::Create(output_parameters);
+ converter.AddInput(&callback);
+ converter.Convert(audio_bus.get());
+
+ // Calculate the expected buffer delay for given AudioParameters.
+ double input_sample_rate = input_parameters.sample_rate();
+ int fill_count =
+ (output_parameters.frames_per_buffer() * input_sample_rate /
+ output_parameters.sample_rate()) / input_parameters.frames_per_buffer();
+
+ base::TimeDelta input_frame_duration = base::TimeDelta::FromMicroseconds(
+ base::Time::kMicrosecondsPerSecond / input_sample_rate);
+
+ int expected_last_delay_milliseconds =
+ fill_count * input_parameters.frames_per_buffer() *
+ input_frame_duration.InMillisecondsF();
+
+ EXPECT_EQ(expected_last_delay_milliseconds,
+ callback.last_audio_delay_milliseconds());
+}
+
+// Benchmark for audio conversion. Original benchmarks were run with
+// --audio-converter-iterations=50000.
+TEST(AudioConverterTest, ConvertBenchmark) {
+ int benchmark_iterations = kDefaultIterations;
+ std::string iterations(CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+ kBenchmarkIterations));
+ base::StringToInt(iterations, &benchmark_iterations);
+ if (benchmark_iterations < kDefaultIterations)
+ benchmark_iterations = kDefaultIterations;
+
+ // Create input and output parameters to convert between the two most common
+ // sets of parameters (as indicated via UMA data).
+ AudioParameters input_params(
+ AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO, 48000, 16, 2048);
+ AudioParameters output_params(
+ AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_STEREO, 44100, 16, 440);
+ scoped_ptr<AudioConverter> converter(
+ new AudioConverter(input_params, output_params, false));
+
+ scoped_ptr<AudioBus> output_bus = AudioBus::Create(output_params);
+ FakeAudioRenderCallback fake_input1(0.2);
+ FakeAudioRenderCallback fake_input2(0.4);
+ FakeAudioRenderCallback fake_input3(0.6);
+ converter->AddInput(&fake_input1);
+ converter->AddInput(&fake_input2);
+ converter->AddInput(&fake_input3);
+
+ printf("Benchmarking %d iterations:\n", benchmark_iterations);
+
+ // Benchmark Convert() w/ FIFO.
+ base::TimeTicks start = base::TimeTicks::HighResNow();
+ for (int i = 0; i < benchmark_iterations; ++i) {
+ converter->Convert(output_bus.get());
+ }
+ double total_time_ms =
+ (base::TimeTicks::HighResNow() - start).InMillisecondsF();
+ printf("Convert() w/ FIFO took %.2fms.\n", total_time_ms);
+
+ converter.reset(new AudioConverter(input_params, output_params, true));
+ converter->AddInput(&fake_input1);
+ converter->AddInput(&fake_input2);
+ converter->AddInput(&fake_input3);
+
+ // Benchmark Convert() w/o FIFO.
+ start = base::TimeTicks::HighResNow();
+ for (int i = 0; i < benchmark_iterations; ++i) {
+ converter->Convert(output_bus.get());
+ }
+ total_time_ms =
+ (base::TimeTicks::HighResNow() - start).InMillisecondsF();
+ printf("Convert() w/o FIFO took %.2fms.\n", total_time_ms);
+}
+
+TEST_P(AudioConverterTest, NoInputs) {
+ FillAudioData(1.0f);
+ EXPECT_TRUE(RenderAndValidateAudioData(0.0f));
+}
+
+TEST_P(AudioConverterTest, OneInput) {
+ RunTest(1);
+}
+
+TEST_P(AudioConverterTest, ManyInputs) {
+ RunTest(kConvertInputs);
+}
+
+INSTANTIATE_TEST_CASE_P(
+ // TODO(dalecurtis): Add test cases for channel transforms.
+ AudioConverterTest, AudioConverterTest, testing::Values(
+ // No resampling.
+ std::tr1::make_tuple(44100, 44100, 0.00000048),
+
+ // Upsampling.
+ std::tr1::make_tuple(44100, 48000, 0.033),
+
+ // Downsampling.
+ std::tr1::make_tuple(48000, 41000, 0.042)));
+
+} // namespace media
« no previous file with comments | « media/base/audio_converter.cc ('k') | media/base/audio_pull_fifo.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698