| 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 e897bbf9399c8216fa94faf227c1d56a6e390a37..9f46dc1c2ab628e242b60bf94014dfac6d01c375 100644
|
| --- a/media/base/audio_renderer_mixer_unittest.cc
|
| +++ b/media/base/audio_renderer_mixer_unittest.cc
|
| @@ -2,99 +2,117 @@
|
| // 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/bind.h"
|
| +#include "base/bind_helpers.h"
|
| #include "base/memory/scoped_ptr.h"
|
| -#include "media/audio/audio_util.h"
|
| +#include "base/memory/scoped_vector.h"
|
| #include "media/base/audio_renderer_mixer.h"
|
| #include "media/base/audio_renderer_mixer_input.h"
|
| #include "media/base/fake_audio_render_callback.h"
|
| +#include "media/base/mock_audio_renderer_sink.h"
|
| #include "testing/gmock/include/gmock/gmock.h"
|
| #include "testing/gtest/include/gtest/gtest.h"
|
|
|
| namespace media {
|
|
|
| // Parameters which control the many input case tests.
|
| -static const int kMixerInputs = 64;
|
| -static const int kMixerCycles = 32;
|
| +static const int kMixerInputs = 8;
|
| +static const int kMixerCycles = 3;
|
|
|
| +// Parameters used for testing.
|
| static const int kBitsPerChannel = 16;
|
| -static const int kSampleRate = 48000;
|
| static const ChannelLayout kChannelLayout = CHANNEL_LAYOUT_STEREO;
|
| +static const int kHighLatencyBufferSize = 8192;
|
| +static const int kLowLatencyBufferSize = 256;
|
|
|
| -// Multiple rounds of addition result in precision loss with float values, so we
|
| -// need an epsilon such that if for all x f(x) = sum(x, m) and g(x) = m * x then
|
| -// fabs(f - g) < kEpsilon. The kEpsilon below has been tested with m < 128.
|
| -static const float kEpsilon = 0.00015f;
|
| +// Number of full sine wave cycles for each Render() call.
|
| +static const int kSineCycles = 4;
|
|
|
| -class MockAudioRendererSink : public AudioRendererSink {
|
| +// Tuple of <input sampling rate, output sampling rate, epsilon>.
|
| +typedef std::tr1::tuple<int, int, double> AudioRendererMixerTestData;
|
| +class AudioRendererMixerTest
|
| + : public testing::TestWithParam<AudioRendererMixerTestData> {
|
| public:
|
| - MOCK_METHOD0(Start, void());
|
| - MOCK_METHOD0(Stop, void());
|
| - MOCK_METHOD1(Pause, void(bool flush));
|
| - MOCK_METHOD0(Play, void());
|
| - MOCK_METHOD1(SetPlaybackRate, void(float rate));
|
| - MOCK_METHOD1(SetVolume, bool(double volume));
|
| - MOCK_METHOD1(GetVolume, void(double* volume));
|
| -
|
| - void Initialize(const media::AudioParameters& params,
|
| - AudioRendererSink::RenderCallback* renderer) OVERRIDE {
|
| - // TODO(dalecurtis): Once we have resampling we need to ensure we are given
|
| - // an AudioParameters which reflects the hardware settings.
|
| - callback_ = renderer;
|
| - };
|
| -
|
| - AudioRendererSink::RenderCallback* callback() {
|
| - return callback_;
|
| - }
|
| -
|
| - void SimulateRenderError() {
|
| - callback_->OnRenderError();
|
| - }
|
| + 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);
|
| + output_parameters_ = AudioParameters(
|
| + AudioParameters::AUDIO_PCM_LOW_LATENCY, kChannelLayout,
|
| + std::tr1::get<1>(GetParam()), 16, kLowLatencyBufferSize);
|
|
|
| - protected:
|
| - virtual ~MockAudioRendererSink() {}
|
| -
|
| - AudioRendererSink::RenderCallback* callback_;
|
| -};
|
| -
|
| -class AudioRendererMixerTest : public ::testing::Test {
|
| - public:
|
| - AudioRendererMixerTest() {
|
| - audio_parameters_ = AudioParameters(
|
| - AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout, kSampleRate,
|
| - kBitsPerChannel, GetHighLatencyOutputBufferSize(kSampleRate));
|
| sink_ = new MockAudioRendererSink();
|
| EXPECT_CALL(*sink_, Start());
|
| EXPECT_CALL(*sink_, Stop());
|
|
|
| - mixer_ = new AudioRendererMixer(audio_parameters_, sink_);
|
| + mixer_.reset(new AudioRendererMixer(
|
| + input_parameters_, output_parameters_, sink_));
|
| mixer_callback_ = sink_->callback();
|
|
|
| // TODO(dalecurtis): If we switch to AVX/SSE optimization, we'll need to
|
| // allocate these on 32-byte boundaries and ensure they're sized % 32 bytes.
|
| - audio_data_.reserve(audio_parameters_.channels());
|
| - for (int i = 0; i < audio_parameters_.channels(); ++i)
|
| - audio_data_.push_back(new float[audio_parameters_.frames_per_buffer()]);
|
| + audio_data_.reserve(output_parameters_.channels());
|
| + for (int i = 0; i < output_parameters_.channels(); ++i)
|
| + audio_data_.push_back(new float[output_parameters_.frames_per_buffer()]);
|
| +
|
| + // TODO(dalecurtis): If we switch to AVX/SSE optimization, we'll need to
|
| + // allocate these on 32-byte boundaries and ensure they're sized % 32 bytes.
|
| + expected_audio_data_.reserve(output_parameters_.channels());
|
| + for (int i = 0; i < output_parameters_.channels(); ++i) {
|
| + expected_audio_data_.push_back(
|
| + new float[output_parameters_.frames_per_buffer()]);
|
| + }
|
| +
|
| + // Allocate one callback for generating expected results.
|
| + double step = kSineCycles / static_cast<double>(
|
| + output_parameters_.frames_per_buffer());
|
| + expected_callback_.reset(new FakeAudioRenderCallback(step));
|
| + }
|
|
|
| - fake_callback_.reset(new FakeAudioRenderCallback(audio_parameters_));
|
| + AudioRendererMixer* GetMixer(const AudioParameters& params) {
|
| + return mixer_.get();
|
| }
|
|
|
| + MOCK_METHOD1(RemoveMixer, void(const AudioParameters&));
|
| +
|
| 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) {
|
| - scoped_refptr<AudioRendererMixerInput> mixer_input(
|
| - new AudioRendererMixerInput(mixer_));
|
| - mixer_input->Initialize(audio_parameters_, fake_callback_.get());
|
| - mixer_input->SetVolume(1.0f);
|
| - mixer_inputs_.push_back(mixer_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))));
|
| + mixer_inputs_[i]->Initialize(input_parameters_, fake_callbacks_[i]);
|
| + mixer_inputs_[i]->SetVolume(1.0f);
|
| }
|
| + EXPECT_CALL(*this, RemoveMixer(testing::_)).Times(count);
|
| }
|
|
|
| - bool ValidateAudioData(int start_index, int frames, float check_value) {
|
| + bool ValidateAudioData(int index, int frames, float scale) {
|
| for (size_t i = 0; i < audio_data_.size(); ++i) {
|
| - for (int j = start_index; j < frames; j++) {
|
| - if (fabs(audio_data_[i][j] - check_value) > kEpsilon) {
|
| - EXPECT_NEAR(check_value, audio_data_[i][j], kEpsilon)
|
| + for (int j = index; j < frames; j++) {
|
| + double error = fabs(
|
| + audio_data_[i][j] - expected_audio_data_[i][j] * scale);
|
| + if (error > epsilon_) {
|
| + EXPECT_NEAR(
|
| + expected_audio_data_[i][j] * scale, audio_data_[i][j], epsilon_)
|
| << " i=" << i << ", j=" << j;
|
| return false;
|
| }
|
| @@ -103,20 +121,47 @@ class AudioRendererMixerTest : public ::testing::Test {
|
| return true;
|
| }
|
|
|
| - // Render audio_parameters_.frames_per_buffer() frames into |audio_data_| and
|
| - // verify the result against |check_value|.
|
| - bool RenderAndValidateAudioData(float check_value) {
|
| - int frames = mixer_callback_->Render(
|
| - audio_data_, audio_parameters_.frames_per_buffer(), 0);
|
| - return frames == audio_parameters_.frames_per_buffer() && ValidateAudioData(
|
| - 0, audio_parameters_.frames_per_buffer(), check_value);
|
| + bool RenderAndValidateAudioData(float scale) {
|
| + int request_frames = output_parameters_.frames_per_buffer();
|
| +
|
| + // Half fill won't be exactly half when resampling since the resampler
|
| + // will have enough data to fill out more of the buffer based on its
|
| + // internal buffer and kernel size. So special case some of the checks.
|
| + bool resampling = input_parameters_.sample_rate()
|
| + != output_parameters_.sample_rate();
|
| +
|
| + if (half_fill_) {
|
| + for (size_t i = 0; i < fake_callbacks_.size(); ++i)
|
| + fake_callbacks_[i]->set_half_fill(true);
|
| + expected_callback_->set_half_fill(true);
|
| + }
|
| +
|
| + // Render actual audio data.
|
| + int frames = mixer_callback_->Render(audio_data_, request_frames, 0);
|
| + if (frames != request_frames)
|
| + return false;
|
| +
|
| + // Render expected audio data (without scaling).
|
| + expected_callback_->Render(expected_audio_data_, request_frames, 0);
|
| +
|
| + if (half_fill_) {
|
| + // Verify first half of audio data for both resampling and non-resampling.
|
| + if (!ValidateAudioData(0, frames / 2, scale))
|
| + return false;
|
| + // Verify silence in the second half if we're not resampling.
|
| + if (!resampling)
|
| + return ValidateAudioData(frames / 2, frames, 0);
|
| + return true;
|
| + } else {
|
| + return ValidateAudioData(0, frames, scale);
|
| + }
|
| }
|
|
|
| // Fill |audio_data_| fully with |value|.
|
| void FillAudioData(float value) {
|
| for (size_t i = 0; i < audio_data_.size(); ++i)
|
| std::fill(audio_data_[i],
|
| - audio_data_[i] + audio_parameters_.frames_per_buffer(), value);
|
| + audio_data_[i] + output_parameters_.frames_per_buffer(), value);
|
| }
|
|
|
| // Verify silence when mixer inputs are in pre-Start() and post-Start().
|
| @@ -148,27 +193,14 @@ class AudioRendererMixerTest : public ::testing::Test {
|
| void PlayTest(int inputs) {
|
| InitializeInputs(inputs);
|
|
|
| - for (size_t i = 0; i < mixer_inputs_.size(); ++i)
|
| + // Play() all mixer inputs and ensure we get the right values.
|
| + for (size_t i = 0; i < mixer_inputs_.size(); ++i) {
|
| mixer_inputs_[i]->Start();
|
| -
|
| - // Play() all even numbered mixer inputs and ensure we get the right value.
|
| - for (size_t i = 0; i < mixer_inputs_.size(); i += 2)
|
| mixer_inputs_[i]->Play();
|
| - for (int i = 0; i < kMixerCycles; ++i) {
|
| - fake_callback_->NextFillValue();
|
| - ASSERT_TRUE(RenderAndValidateAudioData(
|
| - fake_callback_->fill_value() * std::max(
|
| - mixer_inputs_.size() / 2, static_cast<size_t>(1))));
|
| }
|
|
|
| - // Play() all mixer inputs and ensure we still get the right values.
|
| - for (size_t i = 1; i < mixer_inputs_.size(); i += 2)
|
| - mixer_inputs_[i]->Play();
|
| - for (int i = 0; i < kMixerCycles; ++i) {
|
| - fake_callback_->NextFillValue();
|
| - ASSERT_TRUE(RenderAndValidateAudioData(
|
| - fake_callback_->fill_value() * mixer_inputs_.size()));
|
| - }
|
| + for (int i = 0; i < kMixerCycles; ++i)
|
| + ASSERT_TRUE(RenderAndValidateAudioData(mixer_inputs_.size()));
|
|
|
| for (size_t i = 0; i < mixer_inputs_.size(); ++i)
|
| mixer_inputs_[i]->Stop();
|
| @@ -190,11 +222,8 @@ class AudioRendererMixerTest : public ::testing::Test {
|
| total_scale += volume;
|
| EXPECT_TRUE(mixer_inputs_[i]->SetVolume(volume));
|
| }
|
| - for (int i = 0; i < kMixerCycles; ++i) {
|
| - fake_callback_->NextFillValue();
|
| - ASSERT_TRUE(RenderAndValidateAudioData(
|
| - fake_callback_->fill_value() * total_scale));
|
| - }
|
| + for (int i = 0; i < kMixerCycles; ++i)
|
| + ASSERT_TRUE(RenderAndValidateAudioData(total_scale));
|
|
|
| for (size_t i = 0; i < mixer_inputs_.size(); ++i)
|
| mixer_inputs_[i]->Stop();
|
| @@ -203,7 +232,6 @@ class AudioRendererMixerTest : public ::testing::Test {
|
| // Verify output when mixer inputs can only partially fulfill a Render().
|
| void PlayPartialRenderTest(int inputs) {
|
| InitializeInputs(inputs);
|
| - int frames = audio_parameters_.frames_per_buffer();
|
|
|
| for (size_t i = 0; i < mixer_inputs_.size(); ++i) {
|
| mixer_inputs_[i]->Start();
|
| @@ -211,16 +239,8 @@ class AudioRendererMixerTest : public ::testing::Test {
|
| }
|
|
|
| // Verify a properly filled buffer when half filled (remainder zeroed).
|
| - fake_callback_->set_half_fill(true);
|
| - for (int i = 0; i < kMixerCycles; ++i) {
|
| - fake_callback_->NextFillValue();
|
| - ASSERT_EQ(mixer_callback_->Render(audio_data_, frames, 0), frames);
|
| - ASSERT_TRUE(ValidateAudioData(
|
| - 0, frames / 2, fake_callback_->fill_value() * mixer_inputs_.size()));
|
| - ASSERT_TRUE(ValidateAudioData(
|
| - frames / 2, frames, 0.0f));
|
| - }
|
| - fake_callback_->set_half_fill(false);
|
| + half_fill_ = true;
|
| + ASSERT_TRUE(RenderAndValidateAudioData(mixer_inputs_.size()));
|
|
|
| for (size_t i = 0; i < mixer_inputs_.size(); ++i)
|
| mixer_inputs_[i]->Stop();
|
| @@ -238,17 +258,8 @@ class AudioRendererMixerTest : public ::testing::Test {
|
| // Pause() all even numbered mixer inputs and ensure we get the right value.
|
| for (size_t i = 0; i < mixer_inputs_.size(); i += 2)
|
| mixer_inputs_[i]->Pause(false);
|
| - for (int i = 0; i < kMixerCycles; ++i) {
|
| - fake_callback_->NextFillValue();
|
| - ASSERT_TRUE(RenderAndValidateAudioData(
|
| - fake_callback_->fill_value() * (mixer_inputs_.size() / 2)));
|
| - }
|
| -
|
| - // Pause() all the inputs and verify we get silence back.
|
| - for (size_t i = 1; i < mixer_inputs_.size(); i += 2)
|
| - mixer_inputs_[i]->Pause(false);
|
| - FillAudioData(1.0f);
|
| - EXPECT_TRUE(RenderAndValidateAudioData(0.0f));
|
| + for (int i = 0; i < kMixerCycles; ++i)
|
| + ASSERT_TRUE(RenderAndValidateAudioData(mixer_inputs_.size() / 2));
|
|
|
| for (size_t i = 0; i < mixer_inputs_.size(); ++i)
|
| mixer_inputs_[i]->Stop();
|
| @@ -276,84 +287,89 @@ class AudioRendererMixerTest : public ::testing::Test {
|
| }
|
|
|
| scoped_refptr<MockAudioRendererSink> sink_;
|
| - scoped_refptr<AudioRendererMixer> mixer_;
|
| + scoped_ptr<AudioRendererMixer> mixer_;
|
| AudioRendererSink::RenderCallback* mixer_callback_;
|
| - scoped_ptr<FakeAudioRenderCallback> fake_callback_;
|
| - AudioParameters audio_parameters_;
|
| + AudioParameters input_parameters_;
|
| + AudioParameters output_parameters_;
|
| std::vector<float*> audio_data_;
|
| + std::vector<float*> expected_audio_data_;
|
| std::vector< scoped_refptr<AudioRendererMixerInput> > mixer_inputs_;
|
| + ScopedVector<FakeAudioRenderCallback> fake_callbacks_;
|
| + scoped_ptr<FakeAudioRenderCallback> expected_callback_;
|
| + double epsilon_;
|
| + bool half_fill_;
|
|
|
| DISALLOW_COPY_AND_ASSIGN(AudioRendererMixerTest);
|
| };
|
|
|
| // Verify a mixer with no inputs returns silence for all requested frames.
|
| -TEST_F(AudioRendererMixerTest, NoInputs) {
|
| +TEST_P(AudioRendererMixerTest, NoInputs) {
|
| FillAudioData(1.0f);
|
| EXPECT_TRUE(RenderAndValidateAudioData(0.0f));
|
| }
|
|
|
| // Test mixer output with one input in the pre-Start() and post-Start() state.
|
| -TEST_F(AudioRendererMixerTest, OneInputStart) {
|
| +TEST_P(AudioRendererMixerTest, OneInputStart) {
|
| StartTest(1);
|
| }
|
|
|
| // Test mixer output with many inputs in the pre-Start() and post-Start() state.
|
| -TEST_F(AudioRendererMixerTest, ManyInputStart) {
|
| +TEST_P(AudioRendererMixerTest, ManyInputStart) {
|
| StartTest(kMixerInputs);
|
| }
|
|
|
| // Test mixer output with one input in the post-Play() state.
|
| -TEST_F(AudioRendererMixerTest, OneInputPlay) {
|
| +TEST_P(AudioRendererMixerTest, OneInputPlay) {
|
| PlayTest(1);
|
| }
|
|
|
| // Test mixer output with many inputs in the post-Play() state.
|
| -TEST_F(AudioRendererMixerTest, ManyInputPlay) {
|
| +TEST_P(AudioRendererMixerTest, ManyInputPlay) {
|
| PlayTest(kMixerInputs);
|
| }
|
|
|
| // Test volume adjusted mixer output with one input in the post-Play() state.
|
| -TEST_F(AudioRendererMixerTest, OneInputPlayVolumeAdjusted) {
|
| +TEST_P(AudioRendererMixerTest, OneInputPlayVolumeAdjusted) {
|
| PlayVolumeAdjustedTest(1);
|
| }
|
|
|
| // Test volume adjusted mixer output with many inputs in the post-Play() state.
|
| -TEST_F(AudioRendererMixerTest, ManyInputPlayVolumeAdjusted) {
|
| +TEST_P(AudioRendererMixerTest, ManyInputPlayVolumeAdjusted) {
|
| PlayVolumeAdjustedTest(kMixerInputs);
|
| }
|
|
|
| // Test mixer output with one input and partial Render() in post-Play() state.
|
| -TEST_F(AudioRendererMixerTest, OneInputPlayPartialRender) {
|
| +TEST_P(AudioRendererMixerTest, OneInputPlayPartialRender) {
|
| PlayPartialRenderTest(1);
|
| }
|
|
|
| // Test mixer output with many inputs and partial Render() in post-Play() state.
|
| -TEST_F(AudioRendererMixerTest, ManyInputPlayPartialRender) {
|
| +TEST_P(AudioRendererMixerTest, ManyInputPlayPartialRender) {
|
| PlayPartialRenderTest(kMixerInputs);
|
| }
|
|
|
| // Test mixer output with one input in the post-Pause() state.
|
| -TEST_F(AudioRendererMixerTest, OneInputPause) {
|
| +TEST_P(AudioRendererMixerTest, OneInputPause) {
|
| PauseTest(1);
|
| }
|
|
|
| // Test mixer output with many inputs in the post-Pause() state.
|
| -TEST_F(AudioRendererMixerTest, ManyInputPause) {
|
| +TEST_P(AudioRendererMixerTest, ManyInputPause) {
|
| PauseTest(kMixerInputs);
|
| }
|
|
|
| // Test mixer output with one input in the post-Stop() state.
|
| -TEST_F(AudioRendererMixerTest, OneInputStop) {
|
| +TEST_P(AudioRendererMixerTest, OneInputStop) {
|
| StopTest(1);
|
| }
|
|
|
| // Test mixer output with many inputs in the post-Stop() state.
|
| -TEST_F(AudioRendererMixerTest, ManyInputStop) {
|
| +TEST_P(AudioRendererMixerTest, ManyInputStop) {
|
| StopTest(kMixerInputs);
|
| }
|
|
|
| // Test mixer with many inputs in mixed post-Stop() and post-Play() states.
|
| -TEST_F(AudioRendererMixerTest, ManyInputMixedStopPlay) {
|
| +TEST_P(AudioRendererMixerTest, ManyInputMixedStopPlay) {
|
| InitializeInputs(kMixerInputs);
|
|
|
| // Start() all inputs.
|
| @@ -366,32 +382,34 @@ TEST_F(AudioRendererMixerTest, ManyInputMixedStopPlay) {
|
| mixer_inputs_[i - 1]->Stop();
|
| mixer_inputs_[i]->Play();
|
| }
|
| - for (int i = 0; i < kMixerCycles; ++i) {
|
| - fake_callback_->NextFillValue();
|
| - ASSERT_TRUE(RenderAndValidateAudioData(
|
| - fake_callback_->fill_value() * std::max(
|
| - mixer_inputs_.size() / 2, static_cast<size_t>(1))));
|
| - }
|
| + ASSERT_TRUE(RenderAndValidateAudioData(std::max(
|
| + mixer_inputs_.size() / 2, static_cast<size_t>(1))));
|
|
|
| for (size_t i = 1; i < mixer_inputs_.size(); i += 2)
|
| mixer_inputs_[i]->Stop();
|
| }
|
|
|
| -TEST_F(AudioRendererMixerTest, OnRenderError) {
|
| - std::vector< scoped_refptr<AudioRendererMixerInput> > mixer_inputs;
|
| - for (int i = 0; i < kMixerInputs; ++i) {
|
| - scoped_refptr<AudioRendererMixerInput> mixer_input(
|
| - new AudioRendererMixerInput(mixer_));
|
| - mixer_input->Initialize(audio_parameters_, fake_callback_.get());
|
| - mixer_input->SetVolume(1.0f);
|
| - mixer_input->Start();
|
| - mixer_inputs_.push_back(mixer_input);
|
| +TEST_P(AudioRendererMixerTest, OnRenderError) {
|
| + InitializeInputs(kMixerInputs);
|
| + for (size_t i = 0; i < mixer_inputs_.size(); ++i) {
|
| + mixer_inputs_[i]->Start();
|
| + EXPECT_CALL(*fake_callbacks_[i], OnRenderError()).Times(1);
|
| }
|
|
|
| - EXPECT_CALL(*fake_callback_, OnRenderError()).Times(kMixerInputs);
|
| - sink_->SimulateRenderError();
|
| - for (int i = 0; i < kMixerInputs; ++i)
|
| + mixer_callback_->OnRenderError();
|
| + for (size_t i = 0; i < mixer_inputs_.size(); ++i)
|
| mixer_inputs_[i]->Stop();
|
| }
|
|
|
| +INSTANTIATE_TEST_CASE_P(
|
| + AudioRendererMixerTest, AudioRendererMixerTest, testing::Values(
|
| + // No resampling.
|
| + std::tr1::make_tuple(44100, 44100, 0.000000477),
|
| +
|
| + // Upsampling.
|
| + std::tr1::make_tuple(44100, 48000, 0.0329405),
|
| +
|
| + // Downsampling.
|
| + std::tr1::make_tuple(48000, 41000, 0.0410239)));
|
| +
|
| } // namespace media
|
|
|