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 3// found in the LICENSE file. 4 5#include "base/logging.h" 6#include "base/memory/ref_counted.h" 7#include "base/memory/scoped_ptr.h" 8#include "content/renderer/media/audio_renderer_mixer_manager.h" 9#include "ipc/ipc_message.h" 10#include "media/audio/audio_parameters.h" 11#include "media/base/audio_hardware_config.h" 12#include "media/base/audio_renderer_mixer.h" 13#include "media/base/audio_renderer_mixer_input.h" 14#include "media/base/fake_audio_render_callback.h" 15#include "media/base/mock_audio_renderer_sink.h" 16#include "testing/gmock/include/gmock/gmock.h" 17#include "testing/gtest/include/gtest/gtest.h" 18 19namespace content { 20 21static const int kBitsPerChannel = 16; 22static const int kSampleRate = 48000; 23static const int kBufferSize = 8192; 24static const media::ChannelLayout kChannelLayout = media::CHANNEL_LAYOUT_STEREO; 25 26static const int kRenderViewId = 123; 27static const int kRenderFrameId = 124; 28static const int kAnotherRenderViewId = 456; 29static const int kAnotherRenderFrameId = 678; 30 31using media::AudioParameters; 32 33class AudioRendererMixerManagerTest : public testing::Test { 34 public: 35 AudioRendererMixerManagerTest() 36 : fake_config_(AudioParameters(), AudioParameters()) { 37 AudioParameters output_params( 38 AudioParameters::AUDIO_PCM_LOW_LATENCY, 39 media::CHANNEL_LAYOUT_STEREO, 40 kSampleRate, 41 16, 42 kBufferSize); 43 fake_config_.UpdateOutputConfig(output_params); 44 45 manager_.reset(new AudioRendererMixerManager(&fake_config_)); 46 47 // We don't want to deal with instantiating a real AudioOutputDevice since 48 // it's not important to our testing, so we inject a mock. 49 mock_sink_ = new media::MockAudioRendererSink(); 50 manager_->SetAudioRendererSinkForTesting(mock_sink_.get()); 51 } 52 53 media::AudioRendererMixer* GetMixer(int source_render_view_id, 54 const media::AudioParameters& params) { 55 return manager_->GetMixer(source_render_view_id, MSG_ROUTING_NONE, params); 56 } 57 58 void RemoveMixer(int source_render_view_id, 59 const media::AudioParameters& params) { 60 return manager_->RemoveMixer(source_render_view_id, params); 61 } 62 63 // Number of instantiated mixers. 64 int mixer_count() { 65 return manager_->mixers_.size(); 66 } 67 68 protected: 69 media::AudioHardwareConfig fake_config_; 70 scoped_ptr<AudioRendererMixerManager> manager_; 71 scoped_refptr<media::MockAudioRendererSink> mock_sink_; 72 73 DISALLOW_COPY_AND_ASSIGN(AudioRendererMixerManagerTest); 74}; 75 76// Verify GetMixer() and RemoveMixer() both work as expected; particularly with 77// respect to the explicit ref counting done. 78TEST_F(AudioRendererMixerManagerTest, GetRemoveMixer) { 79 // Since we're testing two different sets of parameters, we expect 80 // AudioRendererMixerManager to call Start and Stop on our mock twice. 81 EXPECT_CALL(*mock_sink_.get(), Start()).Times(2); 82 EXPECT_CALL(*mock_sink_.get(), Stop()).Times(2); 83 84 // There should be no mixers outstanding to start with. 85 EXPECT_EQ(mixer_count(), 0); 86 87 media::AudioParameters params1( 88 AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout, kSampleRate, 89 kBitsPerChannel, kBufferSize); 90 91 media::AudioRendererMixer* mixer1 = GetMixer(kRenderViewId, params1); 92 ASSERT_TRUE(mixer1); 93 EXPECT_EQ(mixer_count(), 1); 94 95 // The same parameters should return the same mixer1. 96 EXPECT_EQ(mixer1, GetMixer(kRenderViewId, params1)); 97 EXPECT_EQ(mixer_count(), 1); 98 99 // Remove the extra mixer we just acquired. 100 RemoveMixer(kRenderViewId, params1); 101 EXPECT_EQ(mixer_count(), 1); 102 103 media::AudioParameters params2( 104 AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout, kSampleRate * 2, 105 kBitsPerChannel, kBufferSize * 2); 106 media::AudioRendererMixer* mixer2 = GetMixer(kRenderViewId, params2); 107 ASSERT_TRUE(mixer2); 108 EXPECT_EQ(mixer_count(), 2); 109 110 // Different parameters should result in a different mixer1. 111 EXPECT_NE(mixer1, mixer2); 112 113 // Remove both outstanding mixers. 114 RemoveMixer(kRenderViewId, params1); 115 EXPECT_EQ(mixer_count(), 1); 116 RemoveMixer(kRenderViewId, params2); 117 EXPECT_EQ(mixer_count(), 0); 118} 119 120// Verify GetMixer() correctly deduplicates mixer with irrelevant AudioParameter 121// differences. 122TEST_F(AudioRendererMixerManagerTest, MixerReuse) { 123 EXPECT_CALL(*mock_sink_.get(), Start()).Times(2); 124 EXPECT_CALL(*mock_sink_.get(), Stop()).Times(2); 125 EXPECT_EQ(mixer_count(), 0); 126 127 media::AudioParameters params1(AudioParameters::AUDIO_PCM_LINEAR, 128 kChannelLayout, 129 kSampleRate, 130 kBitsPerChannel, 131 kBufferSize); 132 media::AudioRendererMixer* mixer1 = GetMixer(kRenderViewId, params1); 133 ASSERT_TRUE(mixer1); 134 EXPECT_EQ(mixer_count(), 1); 135 136 // Different formats, bit depths, and buffer sizes should not result in a 137 // different mixer. 138 media::AudioParameters params2(AudioParameters::AUDIO_PCM_LOW_LATENCY, 139 kChannelLayout, 140 kSampleRate, 141 kBitsPerChannel * 2, 142 kBufferSize * 2, 143 AudioParameters::NO_EFFECTS); 144 EXPECT_EQ(mixer1, GetMixer(kRenderViewId, params2)); 145 EXPECT_EQ(mixer_count(), 1); 146 RemoveMixer(kRenderViewId, params2); 147 EXPECT_EQ(mixer_count(), 1); 148 149 // Modify some parameters that do matter. 150 media::AudioParameters params3(AudioParameters::AUDIO_PCM_LOW_LATENCY, 151 media::CHANNEL_LAYOUT_MONO, 152 kSampleRate * 2, 153 kBitsPerChannel, 154 kBufferSize, 155 AudioParameters::NO_EFFECTS); 156 ASSERT_NE(params3.channel_layout(), params1.channel_layout()); 157 158 EXPECT_NE(mixer1, GetMixer(kRenderViewId, params3)); 159 EXPECT_EQ(mixer_count(), 2); 160 RemoveMixer(kRenderViewId, params3); 161 EXPECT_EQ(mixer_count(), 1); 162 163 // Remove final mixer. 164 RemoveMixer(kRenderViewId, params1); 165 EXPECT_EQ(mixer_count(), 0); 166} 167 168// Verify CreateInput() provides AudioRendererMixerInput with the appropriate 169// callbacks and they are working as expected. Also, verify that separate 170// mixers are created for separate render views, even though the AudioParameters 171// are the same. 172TEST_F(AudioRendererMixerManagerTest, CreateInput) { 173 // Expect AudioRendererMixerManager to call Start and Stop on our mock twice 174 // each. Note: Under normal conditions, each mixer would get its own sink! 175 EXPECT_CALL(*mock_sink_.get(), Start()).Times(2); 176 EXPECT_CALL(*mock_sink_.get(), Stop()).Times(2); 177 178 media::AudioParameters params( 179 AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout, kSampleRate, 180 kBitsPerChannel, kBufferSize); 181 182 // Create two mixer inputs and ensure this doesn't instantiate any mixers yet. 183 EXPECT_EQ(mixer_count(), 0); 184 media::FakeAudioRenderCallback callback(0); 185 scoped_refptr<media::AudioRendererMixerInput> input( 186 manager_->CreateInput(kRenderViewId, kRenderFrameId)); 187 input->Initialize(params, &callback); 188 EXPECT_EQ(mixer_count(), 0); 189 media::FakeAudioRenderCallback another_callback(1); 190 scoped_refptr<media::AudioRendererMixerInput> another_input( 191 manager_->CreateInput(kAnotherRenderViewId, kAnotherRenderFrameId)); 192 another_input->Initialize(params, &another_callback); 193 EXPECT_EQ(mixer_count(), 0); 194 195 // Implicitly test that AudioRendererMixerInput was provided with the expected 196 // callbacks needed to acquire an AudioRendererMixer and remove it. 197 input->Start(); 198 EXPECT_EQ(mixer_count(), 1); 199 another_input->Start(); 200 EXPECT_EQ(mixer_count(), 2); 201 202 // Destroying the inputs should destroy the mixers. 203 input->Stop(); 204 input = NULL; 205 EXPECT_EQ(mixer_count(), 1); 206 another_input->Stop(); 207 another_input = NULL; 208 EXPECT_EQ(mixer_count(), 0); 209} 210 211} // namespace content 212