| Index: media/base/audio_renderer_mixer_unittest.cc
|
| diff --git a/media/base/audio_renderer_mixer_unittest.cc b/media/base/audio_renderer_mixer_unittest.cc
|
| index b218fa0410070d9d2c765f49bff06453eaa48f1f..8d2b5d43a80309f44e24b75ac5a3493ee96c3ea5 100644
|
| --- a/media/base/audio_renderer_mixer_unittest.cc
|
| +++ b/media/base/audio_renderer_mixer_unittest.cc
|
| @@ -23,6 +23,7 @@ namespace media {
|
|
|
| // Parameters which control the many input case tests.
|
| const int kMixerInputs = 8;
|
| +const int kOddMixerInputs = 7;
|
| const int kMixerCycles = 3;
|
|
|
| // Parameters used for testing.
|
| @@ -34,22 +35,37 @@ const int kLowLatencyBufferSize = 256;
|
| // Number of full sine wave cycles for each Render() call.
|
| const int kSineCycles = 4;
|
|
|
| -// Default device ID
|
| +// Default device ID.
|
| const std::string kDefaultDeviceId;
|
| const url::Origin kDefaultSecurityOrigin;
|
|
|
| -// Tuple of <input sampling rate, output sampling rate, epsilon>.
|
| -typedef std::tr1::tuple<int, int, double> AudioRendererMixerTestData;
|
| +// Input sample frequencies for testing.
|
| +std::vector<int> kTestInputLower(1, 44100);
|
| +std::vector<int> kTestInputHigher(1, 48000);
|
| +const int kSampleRates[] = {22050, 44100, 48000};
|
| +std::vector<int> kTestInput3Rates(kSampleRates,
|
| + kSampleRates +
|
| + sizeof(kSampleRates) /
|
| + sizeof(kSampleRates[0]));
|
| +
|
| +// Tuple of <input sampling rates, output sampling rate, epsilon>.
|
| +typedef std::tr1::tuple<std::vector<int>, int, double>
|
| + AudioRendererMixerTestData;
|
| +
|
| class AudioRendererMixerTest
|
| : public testing::TestWithParam<AudioRendererMixerTestData> {
|
| public:
|
| AudioRendererMixerTest()
|
| : epsilon_(std::tr1::get<2>(GetParam())),
|
| half_fill_(false) {
|
| - // Create input and output parameters based on test parameters.
|
| - input_parameters_ = AudioParameters(
|
| - AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout,
|
| - std::tr1::get<0>(GetParam()), kBitsPerChannel, kHighLatencyBufferSize);
|
| + // Create input parameters based on test parameters.
|
| + const std::vector<int>& sample_rates(std::tr1::get<0>(GetParam()));
|
| + for (size_t i = 0; i < sample_rates.size(); ++i)
|
| + input_parameters_.push_back(AudioParameters(
|
| + AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout, sample_rates[i],
|
| + kBitsPerChannel, kHighLatencyBufferSize));
|
| +
|
| + // Create output parameters based on test parameters.
|
| output_parameters_ = AudioParameters(
|
| AudioParameters::AUDIO_PCM_LOW_LATENCY, kChannelLayout,
|
| std::tr1::get<1>(GetParam()), 16, kLowLatencyBufferSize);
|
| @@ -58,8 +74,7 @@ class AudioRendererMixerTest
|
| EXPECT_CALL(*sink_.get(), Start());
|
| EXPECT_CALL(*sink_.get(), Stop());
|
|
|
| - mixer_.reset(new AudioRendererMixer(
|
| - input_parameters_, output_parameters_, sink_));
|
| + mixer_.reset(new AudioRendererMixer(output_parameters_, sink_));
|
| mixer_callback_ = sink_->callback();
|
|
|
| audio_bus_ = AudioBus::Create(output_parameters_);
|
| @@ -83,28 +98,35 @@ class AudioRendererMixerTest
|
| const std::string&,
|
| const url::Origin&));
|
|
|
| - void InitializeInputs(int count) {
|
| - mixer_inputs_.reserve(count);
|
| - fake_callbacks_.reserve(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));
|
| - mixer_inputs_.push_back(new AudioRendererMixerInput(
|
| - base::Bind(&AudioRendererMixerTest::GetMixer, base::Unretained(this)),
|
| - base::Bind(&AudioRendererMixerTest::RemoveMixer,
|
| - base::Unretained(this)),
|
| - kDefaultDeviceId, kDefaultSecurityOrigin));
|
| - mixer_inputs_[i]->Initialize(input_parameters_, fake_callbacks_[i]);
|
| - mixer_inputs_[i]->SetVolume(1.0f);
|
| + void InitializeInputs(int inputs_per_sample_rate) {
|
| + mixer_inputs_.reserve(inputs_per_sample_rate * input_parameters_.size());
|
| + fake_callbacks_.reserve(inputs_per_sample_rate * input_parameters_.size());
|
| +
|
| + for (size_t i = 0, input = 0; i < input_parameters_.size(); ++i) {
|
| + // Setup FakeAudioRenderCallback step to compensate for resampling.
|
| + double scale_factor =
|
| + input_parameters_[i].sample_rate() /
|
| + static_cast<double>(output_parameters_.sample_rate());
|
| + double step =
|
| + kSineCycles /
|
| + (scale_factor *
|
| + static_cast<double>(output_parameters_.frames_per_buffer()));
|
| +
|
| + for (int j = 0; j < inputs_per_sample_rate; ++j, ++input) {
|
| + fake_callbacks_.push_back(new FakeAudioRenderCallback(step));
|
| + mixer_inputs_.push_back(new AudioRendererMixerInput(
|
| + base::Bind(&AudioRendererMixerTest::GetMixer,
|
| + base::Unretained(this)),
|
| + base::Bind(&AudioRendererMixerTest::RemoveMixer,
|
| + base::Unretained(this)),
|
| + kDefaultDeviceId, kDefaultSecurityOrigin));
|
| + mixer_inputs_[input]->Initialize(input_parameters_[i],
|
| + fake_callbacks_[input]);
|
| + mixer_inputs_[input]->SetVolume(1.0f);
|
| + }
|
| }
|
| EXPECT_CALL(*this, RemoveMixer(testing::_, testing::_, testing::_))
|
| - .Times(count);
|
| + .Times(mixer_inputs_.size());
|
| }
|
|
|
| bool ValidateAudioData(int index, int frames, float scale, double epsilon) {
|
| @@ -112,9 +134,11 @@ class AudioRendererMixerTest
|
| 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) {
|
| + // The second comparison is for the case when scale is set to 0
|
| + // (and less that 1 in general)
|
| + if ((error > epsilon * scale) && (error > epsilon)) {
|
| EXPECT_NEAR(expected_audio_bus_->channel(i)[j] * scale,
|
| - audio_bus_->channel(i)[j], epsilon)
|
| + audio_bus_->channel(i)[j], epsilon * scale)
|
| << " i=" << i << ", j=" << j;
|
| return false;
|
| }
|
| @@ -279,13 +303,40 @@ class AudioRendererMixerTest
|
| EXPECT_TRUE(RenderAndValidateAudioData(0.0f));
|
| }
|
|
|
| + // Verify output when mixer inputs in mixed post-Stop() and post-Play()
|
| + // states.
|
| + void MixedStopPlayTest(int inputs) {
|
| + InitializeInputs(inputs);
|
| +
|
| + // Start() all inputs.
|
| + for (size_t i = 0; i < mixer_inputs_.size(); ++i)
|
| + mixer_inputs_[i]->Start();
|
| +
|
| + // Stop() all even numbered mixer inputs and Play() all odd numbered inputs
|
| + // and ensure we get the right value.
|
| + for (size_t i = 1; i < mixer_inputs_.size(); i += 2) {
|
| + mixer_inputs_[i - 1]->Stop();
|
| + mixer_inputs_[i]->Play();
|
| + }
|
| +
|
| + // Stop the last input in case the number of inputs is odd
|
| + if (mixer_inputs_.size() % 2)
|
| + mixer_inputs_[mixer_inputs_.size() - 1]->Stop();
|
| +
|
| + ASSERT_TRUE(RenderAndValidateAudioData(
|
| + std::max(1.f, static_cast<float>(floor(mixer_inputs_.size() / 2.f)))));
|
| +
|
| + for (size_t i = 1; i < mixer_inputs_.size(); i += 2)
|
| + mixer_inputs_[i]->Stop();
|
| + }
|
| +
|
| protected:
|
| virtual ~AudioRendererMixerTest() {}
|
|
|
| scoped_refptr<MockAudioRendererSink> sink_;
|
| scoped_ptr<AudioRendererMixer> mixer_;
|
| AudioRendererSink::RenderCallback* mixer_callback_;
|
| - AudioParameters input_parameters_;
|
| + std::vector<AudioParameters> input_parameters_;
|
| AudioParameters output_parameters_;
|
| scoped_ptr<AudioBus> audio_bus_;
|
| scoped_ptr<AudioBus> expected_audio_bus_;
|
| @@ -373,23 +424,13 @@ TEST_P(AudioRendererMixerTest, ManyInputStop) {
|
|
|
| // Test mixer with many inputs in mixed post-Stop() and post-Play() states.
|
| TEST_P(AudioRendererMixerTest, ManyInputMixedStopPlay) {
|
| - InitializeInputs(kMixerInputs);
|
| -
|
| - // Start() all inputs.
|
| - for (size_t i = 0; i < mixer_inputs_.size(); ++i)
|
| - mixer_inputs_[i]->Start();
|
| -
|
| - // Stop() all even numbered mixer inputs and Play() all odd numbered inputs
|
| - // and ensure we get the right value.
|
| - for (size_t i = 1; i < mixer_inputs_.size(); i += 2) {
|
| - mixer_inputs_[i - 1]->Stop();
|
| - mixer_inputs_[i]->Play();
|
| - }
|
| - ASSERT_TRUE(RenderAndValidateAudioData(std::max(
|
| - mixer_inputs_.size() / 2, static_cast<size_t>(1))));
|
| + MixedStopPlayTest(kMixerInputs);
|
| +}
|
|
|
| - for (size_t i = 1; i < mixer_inputs_.size(); i += 2)
|
| - mixer_inputs_[i]->Stop();
|
| +// Test mixer with many inputs in mixed post-Stop() and post-Play() states.
|
| +TEST_P(AudioRendererMixerTest, ManyInputMixedStopPlayOdd) {
|
| + // Odd number of inputs per sample rate, to stop them unevenly.
|
| + MixedStopPlayTest(kOddMixerInputs);
|
| }
|
|
|
| TEST_P(AudioRendererMixerBehavioralTest, OnRenderError) {
|
| @@ -474,22 +515,36 @@ TEST_P(AudioRendererMixerBehavioralTest, MixerPausesStream) {
|
| }
|
|
|
| INSTANTIATE_TEST_CASE_P(
|
| - AudioRendererMixerTest, AudioRendererMixerTest, testing::Values(
|
| - // No resampling.
|
| - std::tr1::make_tuple(44100, 44100, 0.00000048),
|
| + AudioRendererMixerTest,
|
| + AudioRendererMixerTest,
|
| + testing::Values(
|
| + // No resampling, 1 input sample rate.
|
| + std::tr1::make_tuple(kTestInputLower, kTestInputLower[0], 0.00000048),
|
|
|
| - // Upsampling.
|
| - std::tr1::make_tuple(44100, 48000, 0.033),
|
| + // Upsampling, 1 input sample rate.
|
| + std::tr1::make_tuple(kTestInputLower, kTestInputHigher[0], 0.01),
|
|
|
| - // Downsampling.
|
| - std::tr1::make_tuple(48000, 41000, 0.042)));
|
| + // Downsampling, 1 input sample rate.
|
| + std::tr1::make_tuple(kTestInputHigher, kTestInputLower[0], 0.01),
|
| +
|
| + // Downsampling, multuple input sample rates.
|
| + std::tr1::make_tuple(kTestInput3Rates, kTestInput3Rates[0], 0.01),
|
| +
|
| + // Upsampling, multiple sinput sample rates.
|
| + std::tr1::make_tuple(kTestInput3Rates, kTestInput3Rates[2], 0.01),
|
| +
|
| + // Both downsampling and upsampling, multiple input sample rates
|
| + std::tr1::make_tuple(kTestInput3Rates, kTestInput3Rates[1], 0.01)));
|
|
|
| // Test cases for behavior which is independent of parameters. Values() doesn't
|
| // support single item lists and we don't want these test cases to run for every
|
| // parameter set.
|
| INSTANTIATE_TEST_CASE_P(
|
| - AudioRendererMixerBehavioralTest, AudioRendererMixerBehavioralTest,
|
| + AudioRendererMixerBehavioralTest,
|
| + AudioRendererMixerBehavioralTest,
|
| testing::ValuesIn(std::vector<AudioRendererMixerTestData>(
|
| - 1, std::tr1::make_tuple(44100, 44100, 0))));
|
| -
|
| + 1,
|
| + std::tr1::make_tuple(kTestInputLower,
|
| + kTestInputLower[0],
|
| + 0.00000048))));
|
| } // namespace media
|
|
|