audio_converter_unittest.cc revision 868fa2fe829687343ffae624259930155e16dbd8
12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// MSVC++ requires this to be set before any other includes to get M_PI.
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#define _USE_MATH_DEFINES
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <cmath>
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/command_line.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/logging.h"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/memory/scoped_ptr.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/memory/scoped_vector.h"
14868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_number_conversions.h"
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/time.h"
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "media/base/audio_converter.h"
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "media/base/fake_audio_render_callback.h"
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "testing/gmock/include/gmock/gmock.h"
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "testing/gtest/include/gtest/gtest.h"
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace media {
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Command line switch for runtime adjustment of benchmark iterations.
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static const char kBenchmarkIterations[] = "audio-converter-iterations";
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static const int kDefaultIterations = 10;
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Parameters which control the many input case tests.
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static const int kConvertInputs = 8;
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static const int kConvertCycles = 3;
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Parameters used for testing.
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static const int kBitsPerChannel = 32;
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static const ChannelLayout kChannelLayout = CHANNEL_LAYOUT_STEREO;
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static const int kHighLatencyBufferSize = 2048;
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static const int kLowLatencyBufferSize = 256;
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static const int kSampleRate = 48000;
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Number of full sine wave cycles for each Render() call.
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static const int kSineCycles = 4;
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
41c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Tuple of <input rate, output rate, output channel layout, epsilon>.
42c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)typedef std::tr1::tuple<int, int, ChannelLayout, double> AudioConverterTestData;
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class AudioConverterTest
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : public testing::TestWithParam<AudioConverterTestData> {
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public:
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  AudioConverterTest()
47c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      : epsilon_(std::tr1::get<3>(GetParam())) {
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Create input and output parameters based on test parameters.
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    input_parameters_ = AudioParameters(
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout,
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        std::tr1::get<0>(GetParam()), kBitsPerChannel, kHighLatencyBufferSize);
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    output_parameters_ = AudioParameters(
53c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        AudioParameters::AUDIO_PCM_LOW_LATENCY, std::tr1::get<2>(GetParam()),
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        std::tr1::get<1>(GetParam()), 16, kLowLatencyBufferSize);
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    converter_.reset(new AudioConverter(
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        input_parameters_, output_parameters_, false));
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    audio_bus_ = AudioBus::Create(output_parameters_);
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    expected_audio_bus_ = AudioBus::Create(output_parameters_);
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Allocate one callback for generating expected results.
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    double step = kSineCycles / static_cast<double>(
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        output_parameters_.frames_per_buffer());
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    expected_callback_.reset(new FakeAudioRenderCallback(step));
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
68c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Creates |count| input callbacks to be used for conversion testing.
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void InitializeInputs(int count) {
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Setup FakeAudioRenderCallback step to compensate for resampling.
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    double scale_factor = input_parameters_.sample_rate() /
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        static_cast<double>(output_parameters_.sample_rate());
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    double step = kSineCycles / (scale_factor *
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        static_cast<double>(output_parameters_.frames_per_buffer()));
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (int i = 0; i < count; ++i) {
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      fake_callbacks_.push_back(new FakeAudioRenderCallback(step));
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      converter_->AddInput(fake_callbacks_[i]);
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
82c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Resets all input callbacks to a pristine state.
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void Reset() {
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    converter_->Reset();
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (size_t i = 0; i < fake_callbacks_.size(); ++i)
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      fake_callbacks_[i]->reset();
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    expected_callback_->reset();
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
90c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Sets the volume on all input callbacks to |volume|.
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void SetVolume(float volume) {
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (size_t i = 0; i < fake_callbacks_.size(); ++i)
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      fake_callbacks_[i]->set_volume(volume);
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
96c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Validates audio data between |audio_bus_| and |expected_audio_bus_| from
97c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // |index|..|frames| after |scale| is applied to the expected audio data.
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool ValidateAudioData(int index, int frames, float scale) {
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (int i = 0; i < audio_bus_->channels(); ++i) {
100c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      for (int j = index; j < frames; ++j) {
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        double error = fabs(audio_bus_->channel(i)[j] -
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            expected_audio_bus_->channel(i)[j] * scale);
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        if (error > epsilon_) {
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          EXPECT_NEAR(expected_audio_bus_->channel(i)[j] * scale,
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                      audio_bus_->channel(i)[j], epsilon_)
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)              << " i=" << i << ", j=" << j;
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          return false;
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        }
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return true;
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
114c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Runs a single Convert() stage, fills |expected_audio_bus_| appropriately,
115c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // and validates equality with |audio_bus_| after |scale| is applied.
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool RenderAndValidateAudioData(float scale) {
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Render actual audio data.
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    converter_->Convert(audio_bus_.get());
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Render expected audio data.
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    expected_callback_->Render(expected_audio_bus_.get(), 0);
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
123c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // Zero out unused channels in the expected AudioBus just as AudioConverter
124c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // would during channel mixing.
125c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    for (int i = input_parameters_.channels();
126c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)         i < output_parameters_.channels(); ++i) {
127c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      memset(expected_audio_bus_->channel(i), 0,
128c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)             audio_bus_->frames() * sizeof(*audio_bus_->channel(i)));
129c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
130c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return ValidateAudioData(0, audio_bus_->frames(), scale);
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
134c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Fills |audio_bus_| fully with |value|.
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void FillAudioData(float value) {
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (int i = 0; i < audio_bus_->channels(); ++i) {
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      std::fill(audio_bus_->channel(i),
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                audio_bus_->channel(i) + audio_bus_->frames(), value);
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
142c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Verifies converter output with a |inputs| number of transform inputs.
1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void RunTest(int inputs) {
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    InitializeInputs(inputs);
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SetVolume(0);
1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (int i = 0; i < kConvertCycles; ++i)
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      ASSERT_TRUE(RenderAndValidateAudioData(0));
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Reset();
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Set a different volume for each input and verify the results.
1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    float total_scale = 0;
1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (size_t i = 0; i < fake_callbacks_.size(); ++i) {
1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      float volume = static_cast<float>(i) / fake_callbacks_.size();
1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      total_scale += volume;
1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      fake_callbacks_[i]->set_volume(volume);
1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (int i = 0; i < kConvertCycles; ++i)
1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      ASSERT_TRUE(RenderAndValidateAudioData(total_scale));
1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Reset();
1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Remove every other input.
1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (size_t i = 1; i < fake_callbacks_.size(); i += 2)
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      converter_->RemoveInput(fake_callbacks_[i]);
1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SetVolume(1);
1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    float scale = inputs > 1 ? inputs / 2.0f : inputs;
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (int i = 0; i < kConvertCycles; ++i)
1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      ASSERT_TRUE(RenderAndValidateAudioData(scale));
1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) protected:
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual ~AudioConverterTest() {}
1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
177c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Converter under test.
1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<AudioConverter> converter_;
179c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
180c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Input and output parameters used for AudioConverter construction.
1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  AudioParameters input_parameters_;
1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  AudioParameters output_parameters_;
183c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
184c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Destination AudioBus for AudioConverter output.
1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<AudioBus> audio_bus_;
186c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
187c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // AudioBus containing expected results for comparison with |audio_bus_|.
1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<AudioBus> expected_audio_bus_;
189c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
190c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Vector of all input callbacks used to drive AudioConverter::Convert().
1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ScopedVector<FakeAudioRenderCallback> fake_callbacks_;
192c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
193c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Parallel input callback which generates the expected output.
1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<FakeAudioRenderCallback> expected_callback_;
195c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
196c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Epsilon value with which to perform comparisons between |audio_bus_| and
197c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // |expected_audio_bus_|.
1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  double epsilon_;
1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(AudioConverterTest);
2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Ensure the buffer delay provided by AudioConverter is accurate.
2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)TEST(AudioConverterTest, AudioDelay) {
2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Choose input and output parameters such that the transform must make
2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // multiple calls to fill the buffer.
2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  AudioParameters input_parameters = AudioParameters(
2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout, kSampleRate,
2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      kBitsPerChannel, kLowLatencyBufferSize);
2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  AudioParameters output_parameters = AudioParameters(
2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout, kSampleRate * 2,
2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      kBitsPerChannel, kHighLatencyBufferSize);
2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  AudioConverter converter(input_parameters, output_parameters, false);
2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  FakeAudioRenderCallback callback(0.2);
2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<AudioBus> audio_bus = AudioBus::Create(output_parameters);
2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  converter.AddInput(&callback);
2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  converter.Convert(audio_bus.get());
2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Calculate the expected buffer delay for given AudioParameters.
2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  double input_sample_rate = input_parameters.sample_rate();
2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int fill_count =
2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      (output_parameters.frames_per_buffer() * input_sample_rate /
2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       output_parameters.sample_rate()) / input_parameters.frames_per_buffer();
2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::TimeDelta input_frame_duration = base::TimeDelta::FromMicroseconds(
2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Time::kMicrosecondsPerSecond / input_sample_rate);
2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int expected_last_delay_milliseconds =
2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      fill_count * input_parameters.frames_per_buffer() *
2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      input_frame_duration.InMillisecondsF();
2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EXPECT_EQ(expected_last_delay_milliseconds,
2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            callback.last_audio_delay_milliseconds());
2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
237b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)// InputCallback that zero's out the provided AudioBus.  Used for benchmarking.
238b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)class NullInputProvider : public AudioConverter::InputCallback {
239b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) public:
240b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  NullInputProvider() {}
241b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  virtual ~NullInputProvider() {}
242b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
243b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  virtual double ProvideInput(AudioBus* audio_bus,
244b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                              base::TimeDelta buffer_delay) OVERRIDE {
245b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    audio_bus->Zero();
246b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    return 1;
247b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  }
248b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)};
249b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
2502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Benchmark for audio conversion.  Original benchmarks were run with
2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// --audio-converter-iterations=50000.
2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)TEST(AudioConverterTest, ConvertBenchmark) {
2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int benchmark_iterations = kDefaultIterations;
2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string iterations(CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      kBenchmarkIterations));
2562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::StringToInt(iterations, &benchmark_iterations);
2572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (benchmark_iterations < kDefaultIterations)
2582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    benchmark_iterations = kDefaultIterations;
2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
260b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  NullInputProvider fake_input1;
261b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  NullInputProvider fake_input2;
262b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  NullInputProvider fake_input3;
263b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
264b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  printf("Benchmarking %d iterations:\n", benchmark_iterations);
265b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
266b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  {
267b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    // Create input and output parameters to convert between the two most common
268b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    // sets of parameters (as indicated via UMA data).
269b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    AudioParameters input_params(
270b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)        AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO,
271b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)        48000, 16, 2048);
272b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    AudioParameters output_params(
273b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)        AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_STEREO,
274b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)        44100, 16, 440);
275b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    scoped_ptr<AudioBus> output_bus = AudioBus::Create(output_params);
276b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
277b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    scoped_ptr<AudioConverter> converter(
278b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)        new AudioConverter(input_params, output_params, true));
279b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    converter->AddInput(&fake_input1);
280b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    converter->AddInput(&fake_input2);
281b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    converter->AddInput(&fake_input3);
282b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
283b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    // Benchmark Convert() w/ FIFO.
284b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    base::TimeTicks start = base::TimeTicks::HighResNow();
285b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    for (int i = 0; i < benchmark_iterations; ++i) {
286b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      converter->Convert(output_bus.get());
287b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    }
288b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    double total_time_ms =
289b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)        (base::TimeTicks::HighResNow() - start).InMillisecondsF();
290b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    printf("Convert() w/ Resampling took %.2fms.\n", total_time_ms);
291b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  }
292b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
293b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  // Create input and output parameters to convert between common buffer sizes
294b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  // without any resampling for the FIFO vs no FIFO benchmarks.
2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  AudioParameters input_params(
296b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_STEREO,
297b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      44100, 16, 2048);
2982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  AudioParameters output_params(
299b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_STEREO,
300b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      44100, 16, 440);
3012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<AudioBus> output_bus = AudioBus::Create(output_params);
3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
303b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  {
304b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    scoped_ptr<AudioConverter> converter(
305b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)        new AudioConverter(input_params, output_params, false));
306b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    converter->AddInput(&fake_input1);
307b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    converter->AddInput(&fake_input2);
308b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    converter->AddInput(&fake_input3);
309b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
310b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    // Benchmark Convert() w/ FIFO.
311b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    base::TimeTicks start = base::TimeTicks::HighResNow();
312b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    for (int i = 0; i < benchmark_iterations; ++i) {
313b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      converter->Convert(output_bus.get());
314b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    }
315b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    double total_time_ms =
316b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)        (base::TimeTicks::HighResNow() - start).InMillisecondsF();
317b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    printf("Convert() w/ FIFO took %.2fms.\n", total_time_ms);
3182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
319b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
320b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  {
321b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    scoped_ptr<AudioConverter> converter(
322b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)        new AudioConverter(input_params, output_params, true));
323b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    converter->AddInput(&fake_input1);
324b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    converter->AddInput(&fake_input2);
325b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    converter->AddInput(&fake_input3);
326b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
327b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    // Benchmark Convert() w/o FIFO.
328b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    base::TimeTicks start = base::TimeTicks::HighResNow();
329b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    for (int i = 0; i < benchmark_iterations; ++i) {
330b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      converter->Convert(output_bus.get());
331b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    }
332b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    double total_time_ms =
333b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)        (base::TimeTicks::HighResNow() - start).InMillisecondsF();
334b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    printf("Convert() w/o FIFO took %.2fms.\n", total_time_ms);
3352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)TEST_P(AudioConverterTest, NoInputs) {
3392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  FillAudioData(1.0f);
3402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EXPECT_TRUE(RenderAndValidateAudioData(0.0f));
3412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)TEST_P(AudioConverterTest, OneInput) {
3442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RunTest(1);
3452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)TEST_P(AudioConverterTest, ManyInputs) {
3482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RunTest(kConvertInputs);
3492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)INSTANTIATE_TEST_CASE_P(
3522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    AudioConverterTest, AudioConverterTest, testing::Values(
353c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        // No resampling. No channel mixing.
354c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        std::tr1::make_tuple(44100, 44100, CHANNEL_LAYOUT_STEREO, 0.00000048),
3552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
356c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        // Upsampling. Channel upmixing.
357c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        std::tr1::make_tuple(44100, 48000, CHANNEL_LAYOUT_QUAD, 0.033),
3582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
359c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        // Downsampling. Channel downmixing.
360c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        std::tr1::make_tuple(48000, 41000, CHANNEL_LAYOUT_MONO, 0.042)));
3612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace media
363