| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include <cmath> | 5 #include <cmath> |
| 6 | 6 |
| 7 #include "base/memory/scoped_ptr.h" | 7 #include "base/memory/scoped_ptr.h" |
| 8 #include "media/audio/audio_util.h" | 8 #include "media/audio/audio_util.h" |
| 9 #include "media/base/audio_renderer_mixer.h" | 9 #include "media/base/audio_renderer_mixer.h" |
| 10 #include "media/base/audio_renderer_mixer_input.h" | 10 #include "media/base/audio_renderer_mixer_input.h" |
| 11 #include "media/base/fake_audio_render_callback.h" | 11 #include "media/base/fake_audio_render_callback.h" |
| 12 #include "testing/gmock/include/gmock/gmock.h" | 12 #include "testing/gmock/include/gmock/gmock.h" |
| 13 #include "testing/gtest/include/gtest/gtest.h" | 13 #include "testing/gtest/include/gtest/gtest.h" |
| 14 | 14 |
| 15 namespace media { | 15 namespace media { |
| 16 | 16 |
| 17 // Parameters which control the many input case tests. | 17 // Parameters which control the many input case tests. |
| 18 static const int kMixerInputs = 64; | 18 static const int kMixerInputs = 64; |
| 19 static const int kMixerCycles = 32; | 19 static const int kMixerCycles = 32; |
| 20 | 20 |
| 21 static const int kBitsPerChannel = 16; | 21 static const int kBitsPerChannel = 16; |
| 22 static const int kSampleRate = 48000; | 22 static const int kSampleRate = GetAudioHardwareSampleRate(); |
| 23 static const ChannelLayout kChannelLayout = CHANNEL_LAYOUT_STEREO; | 23 static const ChannelLayout kChannelLayout = CHANNEL_LAYOUT_STEREO; |
| 24 | 24 |
| 25 // Multiple rounds of addition result in precision loss with float values, so we | 25 // Multiple rounds of addition result in precision loss with float values, so we |
| 26 // need an epsilon such that if for all x f(x) = sum(x, m) and g(x) = m * x then | 26 // need an epsilon such that if for all x f(x) = sum(x, m) and g(x) = m * x then |
| 27 // fabs(f - g) < kEpsilon. The kEpsilon below has been tested with m < 128. | 27 // fabs(f - g) < kEpsilon. The kEpsilon below has been tested with m < 128. |
| 28 static const float kEpsilon = 0.00015f; | 28 static const float kEpsilon = 0.00015f; |
| 29 | 29 |
| 30 class MockAudioRendererSink : public AudioRendererSink { | 30 class MockAudioRendererSink : public AudioRendererSink { |
| 31 public: | 31 public: |
| 32 MOCK_METHOD0(Start, void()); | 32 MOCK_METHOD0(Start, void()); |
| 33 MOCK_METHOD0(Stop, void()); | 33 MOCK_METHOD0(Stop, void()); |
| 34 MOCK_METHOD1(Pause, void(bool flush)); | 34 MOCK_METHOD1(Pause, void(bool flush)); |
| 35 MOCK_METHOD0(Play, void()); | 35 MOCK_METHOD0(Play, void()); |
| 36 MOCK_METHOD1(SetPlaybackRate, void(float rate)); | 36 MOCK_METHOD1(SetPlaybackRate, void(float rate)); |
| 37 MOCK_METHOD1(SetVolume, bool(double volume)); | 37 MOCK_METHOD1(SetVolume, bool(double volume)); |
| 38 MOCK_METHOD1(GetVolume, void(double* volume)); | 38 MOCK_METHOD1(GetVolume, void(double* volume)); |
| 39 | 39 |
| 40 void Initialize(const media::AudioParameters& params, | 40 void Initialize(const AudioParameters& params, |
| 41 AudioRendererSink::RenderCallback* renderer) OVERRIDE { | 41 AudioRendererSink::RenderCallback* renderer) OVERRIDE { |
| 42 // TODO(dalecurtis): Once we have resampling we need to ensure we are given | 42 // TODO(dalecurtis): Once we have resampling we need to ensure we are given |
| 43 // an AudioParameters which reflects the hardware settings. | 43 // an AudioParameters which reflects the hardware settings. |
| 44 callback_ = renderer; | 44 callback_ = renderer; |
| 45 params_ = params; |
| 45 }; | 46 }; |
| 46 | 47 |
| 47 AudioRendererSink::RenderCallback* callback() { | 48 AudioRendererSink::RenderCallback* callback() { |
| 48 return callback_; | 49 return callback_; |
| 49 } | 50 } |
| 50 | 51 |
| 52 const AudioParameters& params() { |
| 53 return params_; |
| 54 } |
| 55 |
| 51 void SimulateRenderError() { | 56 void SimulateRenderError() { |
| 52 callback_->OnRenderError(); | 57 callback_->OnRenderError(); |
| 53 } | 58 } |
| 54 | 59 |
| 55 protected: | 60 protected: |
| 56 virtual ~MockAudioRendererSink() {} | 61 virtual ~MockAudioRendererSink() {} |
| 57 | 62 |
| 58 AudioRendererSink::RenderCallback* callback_; | 63 AudioRendererSink::RenderCallback* callback_; |
| 64 AudioParameters params_; |
| 59 }; | 65 }; |
| 60 | 66 |
| 61 class AudioRendererMixerTest : public ::testing::Test { | 67 class AudioRendererMixerTest : public ::testing::Test { |
| 62 public: | 68 public: |
| 63 AudioRendererMixerTest() { | 69 AudioRendererMixerTest() { |
| 64 audio_parameters_ = AudioParameters( | 70 input_parameters_ = AudioParameters( |
| 65 AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout, kSampleRate, | 71 AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout, kSampleRate, |
| 66 kBitsPerChannel, GetHighLatencyOutputBufferSize(kSampleRate)); | 72 kBitsPerChannel, GetHighLatencyOutputBufferSize(kSampleRate)); |
| 67 sink_ = new MockAudioRendererSink(); | 73 sink_ = new MockAudioRendererSink(); |
| 68 EXPECT_CALL(*sink_, Start()); | 74 EXPECT_CALL(*sink_, Start()); |
| 69 EXPECT_CALL(*sink_, Stop()); | 75 EXPECT_CALL(*sink_, Stop()); |
| 70 | 76 |
| 71 mixer_ = new AudioRendererMixer(audio_parameters_, sink_); | 77 mixer_ = new AudioRendererMixer(input_parameters_, sink_); |
| 72 mixer_callback_ = sink_->callback(); | 78 mixer_callback_ = sink_->callback(); |
| 79 output_parameters_ = sink_->params(); |
| 73 | 80 |
| 74 // TODO(dalecurtis): If we switch to AVX/SSE optimization, we'll need to | 81 // TODO(dalecurtis): If we switch to AVX/SSE optimization, we'll need to |
| 75 // allocate these on 32-byte boundaries and ensure they're sized % 32 bytes. | 82 // allocate these on 32-byte boundaries and ensure they're sized % 32 bytes. |
| 76 audio_data_.reserve(audio_parameters_.channels()); | 83 audio_data_.reserve(output_parameters_.channels()); |
| 77 for (int i = 0; i < audio_parameters_.channels(); ++i) | 84 for (int i = 0; i < output_parameters_.channels(); ++i) |
| 78 audio_data_.push_back(new float[audio_parameters_.frames_per_buffer()]); | 85 audio_data_.push_back(new float[output_parameters_.frames_per_buffer()]); |
| 79 | 86 |
| 80 fake_callback_.reset(new FakeAudioRenderCallback(audio_parameters_)); | 87 fake_callback_.reset(new FakeAudioRenderCallback(output_parameters_)); |
| 81 } | 88 } |
| 82 | 89 |
| 83 void InitializeInputs(int count) { | 90 void InitializeInputs(int count) { |
| 84 for (int i = 0; i < count; ++i) { | 91 for (int i = 0; i < count; ++i) { |
| 85 scoped_refptr<AudioRendererMixerInput> mixer_input( | 92 scoped_refptr<AudioRendererMixerInput> mixer_input( |
| 86 new AudioRendererMixerInput(mixer_)); | 93 new AudioRendererMixerInput(mixer_)); |
| 87 mixer_input->Initialize(audio_parameters_, fake_callback_.get()); | 94 mixer_input->Initialize(input_parameters_, fake_callback_.get()); |
| 88 mixer_input->SetVolume(1.0f); | 95 mixer_input->SetVolume(1.0f); |
| 89 mixer_inputs_.push_back(mixer_input); | 96 mixer_inputs_.push_back(mixer_input); |
| 90 } | 97 } |
| 91 } | 98 } |
| 92 | 99 |
| 93 bool ValidateAudioData(int start_index, int frames, float check_value) { | 100 bool ValidateAudioData(int start_index, int frames, float check_value) { |
| 94 for (size_t i = 0; i < audio_data_.size(); ++i) { | 101 for (size_t i = 0; i < audio_data_.size(); ++i) { |
| 95 for (int j = start_index; j < frames; j++) { | 102 for (int j = start_index; j < frames; j++) { |
| 96 if (fabs(audio_data_[i][j] - check_value) > kEpsilon) { | 103 if (fabs(audio_data_[i][j] - check_value) > kEpsilon) { |
| 97 EXPECT_NEAR(check_value, audio_data_[i][j], kEpsilon) | 104 EXPECT_NEAR(check_value, audio_data_[i][j], kEpsilon) |
| 98 << " i=" << i << ", j=" << j; | 105 << " i=" << i << ", j=" << j; |
| 99 return false; | 106 return false; |
| 100 } | 107 } |
| 101 } | 108 } |
| 102 } | 109 } |
| 103 return true; | 110 return true; |
| 104 } | 111 } |
| 105 | 112 |
| 106 // Render audio_parameters_.frames_per_buffer() frames into |audio_data_| and | 113 // Render input_parameters_.frames_per_buffer() frames into |audio_data_| and |
| 107 // verify the result against |check_value|. | 114 // verify the result against |check_value|. |
| 108 bool RenderAndValidateAudioData(float check_value) { | 115 bool RenderAndValidateAudioData(float check_value) { |
| 109 int frames = mixer_callback_->Render( | 116 int request_frames = output_parameters_.frames_per_buffer(); |
| 110 audio_data_, audio_parameters_.frames_per_buffer(), 0); | 117 int frames = mixer_callback_->Render(audio_data_, request_frames, 0); |
| 111 return frames == audio_parameters_.frames_per_buffer() && ValidateAudioData( | 118 return frames == request_frames && ValidateAudioData( |
| 112 0, audio_parameters_.frames_per_buffer(), check_value); | 119 0, request_frames, check_value); |
| 113 } | 120 } |
| 114 | 121 |
| 115 // Fill |audio_data_| fully with |value|. | 122 // Fill |audio_data_| fully with |value|. |
| 116 void FillAudioData(float value) { | 123 void FillAudioData(float value) { |
| 117 for (size_t i = 0; i < audio_data_.size(); ++i) | 124 for (size_t i = 0; i < audio_data_.size(); ++i) |
| 118 std::fill(audio_data_[i], | 125 std::fill(audio_data_[i], |
| 119 audio_data_[i] + audio_parameters_.frames_per_buffer(), value); | 126 audio_data_[i] + output_parameters_.frames_per_buffer(), value); |
| 120 } | 127 } |
| 121 | 128 |
| 122 // Verify silence when mixer inputs are in pre-Start() and post-Start(). | 129 // Verify silence when mixer inputs are in pre-Start() and post-Start(). |
| 123 void StartTest(int inputs) { | 130 void StartTest(int inputs) { |
| 124 InitializeInputs(inputs); | 131 InitializeInputs(inputs); |
| 125 | 132 |
| 126 // Verify silence before any inputs have been started. Fill the buffer | 133 // Verify silence before any inputs have been started. Fill the buffer |
| 127 // before hand with non-zero data to ensure we get zeros back. | 134 // before hand with non-zero data to ensure we get zeros back. |
| 128 FillAudioData(1.0f); | 135 FillAudioData(1.0f); |
| 129 EXPECT_TRUE(RenderAndValidateAudioData(0.0f)); | 136 EXPECT_TRUE(RenderAndValidateAudioData(0.0f)); |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 196 fake_callback_->fill_value() * total_scale)); | 203 fake_callback_->fill_value() * total_scale)); |
| 197 } | 204 } |
| 198 | 205 |
| 199 for (size_t i = 0; i < mixer_inputs_.size(); ++i) | 206 for (size_t i = 0; i < mixer_inputs_.size(); ++i) |
| 200 mixer_inputs_[i]->Stop(); | 207 mixer_inputs_[i]->Stop(); |
| 201 } | 208 } |
| 202 | 209 |
| 203 // Verify output when mixer inputs can only partially fulfill a Render(). | 210 // Verify output when mixer inputs can only partially fulfill a Render(). |
| 204 void PlayPartialRenderTest(int inputs) { | 211 void PlayPartialRenderTest(int inputs) { |
| 205 InitializeInputs(inputs); | 212 InitializeInputs(inputs); |
| 206 int frames = audio_parameters_.frames_per_buffer(); | 213 int frames = output_parameters_.frames_per_buffer(); |
| 207 | 214 |
| 208 for (size_t i = 0; i < mixer_inputs_.size(); ++i) { | 215 for (size_t i = 0; i < mixer_inputs_.size(); ++i) { |
| 209 mixer_inputs_[i]->Start(); | 216 mixer_inputs_[i]->Start(); |
| 210 mixer_inputs_[i]->Play(); | 217 mixer_inputs_[i]->Play(); |
| 211 } | 218 } |
| 212 | 219 |
| 213 // Verify a properly filled buffer when half filled (remainder zeroed). | 220 // Verify a properly filled buffer when half filled (remainder zeroed). |
| 214 fake_callback_->set_half_fill(true); | 221 fake_callback_->set_half_fill(true); |
| 215 for (int i = 0; i < kMixerCycles; ++i) { | 222 for (int i = 0; i < kMixerCycles; ++i) { |
| 216 fake_callback_->NextFillValue(); | 223 fake_callback_->NextFillValue(); |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 272 protected: | 279 protected: |
| 273 virtual ~AudioRendererMixerTest() { | 280 virtual ~AudioRendererMixerTest() { |
| 274 for (size_t i = 0; i < audio_data_.size(); ++i) | 281 for (size_t i = 0; i < audio_data_.size(); ++i) |
| 275 delete [] audio_data_[i]; | 282 delete [] audio_data_[i]; |
| 276 } | 283 } |
| 277 | 284 |
| 278 scoped_refptr<MockAudioRendererSink> sink_; | 285 scoped_refptr<MockAudioRendererSink> sink_; |
| 279 scoped_refptr<AudioRendererMixer> mixer_; | 286 scoped_refptr<AudioRendererMixer> mixer_; |
| 280 AudioRendererSink::RenderCallback* mixer_callback_; | 287 AudioRendererSink::RenderCallback* mixer_callback_; |
| 281 scoped_ptr<FakeAudioRenderCallback> fake_callback_; | 288 scoped_ptr<FakeAudioRenderCallback> fake_callback_; |
| 282 AudioParameters audio_parameters_; | 289 AudioParameters input_parameters_; |
| 290 AudioParameters output_parameters_; |
| 283 std::vector<float*> audio_data_; | 291 std::vector<float*> audio_data_; |
| 284 std::vector< scoped_refptr<AudioRendererMixerInput> > mixer_inputs_; | 292 std::vector< scoped_refptr<AudioRendererMixerInput> > mixer_inputs_; |
| 285 | 293 |
| 286 DISALLOW_COPY_AND_ASSIGN(AudioRendererMixerTest); | 294 DISALLOW_COPY_AND_ASSIGN(AudioRendererMixerTest); |
| 287 }; | 295 }; |
| 288 | 296 |
| 289 // Verify a mixer with no inputs returns silence for all requested frames. | 297 // Verify a mixer with no inputs returns silence for all requested frames. |
| 290 TEST_F(AudioRendererMixerTest, NoInputs) { | 298 TEST_F(AudioRendererMixerTest, NoInputs) { |
| 291 FillAudioData(1.0f); | 299 FillAudioData(1.0f); |
| 292 EXPECT_TRUE(RenderAndValidateAudioData(0.0f)); | 300 EXPECT_TRUE(RenderAndValidateAudioData(0.0f)); |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 375 | 383 |
| 376 for (size_t i = 1; i < mixer_inputs_.size(); i += 2) | 384 for (size_t i = 1; i < mixer_inputs_.size(); i += 2) |
| 377 mixer_inputs_[i]->Stop(); | 385 mixer_inputs_[i]->Stop(); |
| 378 } | 386 } |
| 379 | 387 |
| 380 TEST_F(AudioRendererMixerTest, OnRenderError) { | 388 TEST_F(AudioRendererMixerTest, OnRenderError) { |
| 381 std::vector< scoped_refptr<AudioRendererMixerInput> > mixer_inputs; | 389 std::vector< scoped_refptr<AudioRendererMixerInput> > mixer_inputs; |
| 382 for (int i = 0; i < kMixerInputs; ++i) { | 390 for (int i = 0; i < kMixerInputs; ++i) { |
| 383 scoped_refptr<AudioRendererMixerInput> mixer_input( | 391 scoped_refptr<AudioRendererMixerInput> mixer_input( |
| 384 new AudioRendererMixerInput(mixer_)); | 392 new AudioRendererMixerInput(mixer_)); |
| 385 mixer_input->Initialize(audio_parameters_, fake_callback_.get()); | 393 mixer_input->Initialize(input_parameters_, fake_callback_.get()); |
| 386 mixer_input->SetVolume(1.0f); | 394 mixer_input->SetVolume(1.0f); |
| 387 mixer_input->Start(); | 395 mixer_input->Start(); |
| 388 mixer_inputs_.push_back(mixer_input); | 396 mixer_inputs_.push_back(mixer_input); |
| 389 } | 397 } |
| 390 | 398 |
| 391 EXPECT_CALL(*fake_callback_, OnRenderError()).Times(kMixerInputs); | 399 EXPECT_CALL(*fake_callback_, OnRenderError()).Times(kMixerInputs); |
| 392 sink_->SimulateRenderError(); | 400 sink_->SimulateRenderError(); |
| 393 for (int i = 0; i < kMixerInputs; ++i) | 401 for (int i = 0; i < kMixerInputs; ++i) |
| 394 mixer_inputs_[i]->Stop(); | 402 mixer_inputs_[i]->Stop(); |
| 395 } | 403 } |
| 396 | 404 |
| 397 } // namespace media | 405 } // namespace media |
| OLD | NEW |