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