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.
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"
21 static const int kBitsPerChannel
= 16;
22 static const int kSampleRate
= 48000;
23 static const int kBufferSize
= 8192;
24 static const media::ChannelLayout kChannelLayout
= media::CHANNEL_LAYOUT_STEREO
;
26 static const int kRenderViewId
= 123;
27 static const int kRenderFrameId
= 124;
28 static const int kAnotherRenderViewId
= 456;
29 static const int kAnotherRenderFrameId
= 678;
31 using media::AudioParameters
;
33 class AudioRendererMixerManagerTest
: public testing::Test
{
35 AudioRendererMixerManagerTest()
36 : fake_config_(AudioParameters(), AudioParameters()) {
37 AudioParameters
output_params(
38 AudioParameters::AUDIO_PCM_LOW_LATENCY
,
39 media::CHANNEL_LAYOUT_STEREO
,
43 fake_config_
.UpdateOutputConfig(output_params
);
45 manager_
.reset(new AudioRendererMixerManager(&fake_config_
));
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());
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
);
58 void RemoveMixer(int source_render_view_id
,
59 const media::AudioParameters
& params
) {
60 return manager_
->RemoveMixer(source_render_view_id
, params
);
63 // Number of instantiated mixers.
65 return manager_
->mixers_
.size();
69 media::AudioHardwareConfig fake_config_
;
70 scoped_ptr
<AudioRendererMixerManager
> manager_
;
71 scoped_refptr
<media::MockAudioRendererSink
> mock_sink_
;
73 DISALLOW_COPY_AND_ASSIGN(AudioRendererMixerManagerTest
);
76 // Verify GetMixer() and RemoveMixer() both work as expected; particularly with
77 // respect to the explicit ref counting done.
78 TEST_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);
84 // There should be no mixers outstanding to start with.
85 EXPECT_EQ(mixer_count(), 0);
87 media::AudioParameters
params1(
88 AudioParameters::AUDIO_PCM_LINEAR
, kChannelLayout
, kSampleRate
,
89 kBitsPerChannel
, kBufferSize
);
91 media::AudioRendererMixer
* mixer1
= GetMixer(kRenderViewId
, params1
);
93 EXPECT_EQ(mixer_count(), 1);
95 // The same parameters should return the same mixer1.
96 EXPECT_EQ(mixer1
, GetMixer(kRenderViewId
, params1
));
97 EXPECT_EQ(mixer_count(), 1);
99 // Remove the extra mixer we just acquired.
100 RemoveMixer(kRenderViewId
, params1
);
101 EXPECT_EQ(mixer_count(), 1);
103 media::AudioParameters
params2(
104 AudioParameters::AUDIO_PCM_LINEAR
, kChannelLayout
, kSampleRate
* 2,
105 kBitsPerChannel
, kBufferSize
* 2);
106 media::AudioRendererMixer
* mixer2
= GetMixer(kRenderViewId
, params2
);
108 EXPECT_EQ(mixer_count(), 2);
110 // Different parameters should result in a different mixer1.
111 EXPECT_NE(mixer1
, mixer2
);
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);
120 // Verify GetMixer() correctly deduplicates mixer with irrelevant AudioParameter
122 TEST_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);
127 media::AudioParameters
params1(AudioParameters::AUDIO_PCM_LINEAR
,
132 media::AudioRendererMixer
* mixer1
= GetMixer(kRenderViewId
, params1
);
134 EXPECT_EQ(mixer_count(), 1);
136 // Different formats, bit depths, and buffer sizes should not result in a
138 media::AudioParameters
params2(AudioParameters::AUDIO_PCM_LOW_LATENCY
,
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);
149 // Modify some parameters that do matter.
150 media::AudioParameters
params3(AudioParameters::AUDIO_PCM_LOW_LATENCY
,
151 media::CHANNEL_LAYOUT_MONO
,
155 AudioParameters::NO_EFFECTS
);
156 ASSERT_NE(params3
.channel_layout(), params1
.channel_layout());
158 EXPECT_NE(mixer1
, GetMixer(kRenderViewId
, params3
));
159 EXPECT_EQ(mixer_count(), 2);
160 RemoveMixer(kRenderViewId
, params3
);
161 EXPECT_EQ(mixer_count(), 1);
163 // Remove final mixer.
164 RemoveMixer(kRenderViewId
, params1
);
165 EXPECT_EQ(mixer_count(), 0);
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
172 TEST_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);
178 media::AudioParameters
params(
179 AudioParameters::AUDIO_PCM_LINEAR
, kChannelLayout
, kSampleRate
,
180 kBitsPerChannel
, kBufferSize
);
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);
195 // Implicitly test that AudioRendererMixerInput was provided with the expected
196 // callbacks needed to acquire an AudioRendererMixer and remove it.
198 EXPECT_EQ(mixer_count(), 1);
199 another_input
->Start();
200 EXPECT_EQ(mixer_count(), 2);
202 // Destroying the inputs should destroy the mixers.
205 EXPECT_EQ(mixer_count(), 1);
206 another_input
->Stop();
207 another_input
= NULL
;
208 EXPECT_EQ(mixer_count(), 0);
211 } // namespace content