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.
6 #include "base/environment.h"
7 #include "base/memory/scoped_ptr.h"
8 #include "base/message_loop.h"
9 #include "base/process_util.h"
10 #include "base/sync_socket.h"
11 #include "content/browser/browser_thread_impl.h"
12 #include "content/browser/renderer_host/media/audio_input_device_manager.h"
13 #include "content/browser/renderer_host/media/audio_mirroring_manager.h"
14 #include "content/browser/renderer_host/media/audio_renderer_host.h"
15 #include "content/browser/renderer_host/media/media_stream_manager.h"
16 #include "content/browser/renderer_host/media/mock_media_observer.h"
17 #include "content/common/media/audio_messages.h"
18 #include "content/common/media/media_stream_options.h"
19 #include "ipc/ipc_message_utils.h"
20 #include "media/audio/audio_manager.h"
21 #include "media/audio/audio_manager_base.h"
22 #include "media/audio/fake_audio_output_stream.h"
23 #include "net/url_request/url_request_context.h"
24 #include "testing/gmock/include/gmock/gmock.h"
25 #include "testing/gtest/include/gtest/gtest.h"
28 using ::testing::AtLeast
;
29 using ::testing::DoAll
;
30 using ::testing::InSequence
;
31 using ::testing::NotNull
;
32 using ::testing::Return
;
33 using ::testing::SaveArg
;
34 using ::testing::SetArgumentPointee
;
38 static const int kRenderProcessId
= 1;
39 static const int kRenderViewId
= 4;
40 static const int kStreamId
= 50;
42 class MockAudioMirroringManager
: public AudioMirroringManager
{
44 MockAudioMirroringManager() {}
45 virtual ~MockAudioMirroringManager() {}
47 MOCK_METHOD3(AddDiverter
,
48 void(int render_process_id
, int render_view_id
,
50 MOCK_METHOD3(RemoveDiverter
,
51 void(int render_process_id
, int render_view_id
,
55 DISALLOW_COPY_AND_ASSIGN(MockAudioMirroringManager
);
58 class MockAudioRendererHost
: public AudioRendererHost
{
60 explicit MockAudioRendererHost(
61 media::AudioManager
* audio_manager
,
62 AudioMirroringManager
* mirroring_manager
,
63 MediaInternals
* media_internals
,
64 MediaStreamManager
* media_stream_manager
)
65 : AudioRendererHost(kRenderProcessId
,
69 media_stream_manager
),
70 shared_memory_length_(0) {
73 // A list of mock methods.
74 MOCK_METHOD2(OnStreamCreated
,
75 void(int stream_id
, int length
));
76 MOCK_METHOD1(OnStreamPlaying
, void(int stream_id
));
77 MOCK_METHOD1(OnStreamPaused
, void(int stream_id
));
78 MOCK_METHOD1(OnStreamError
, void(int stream_id
));
81 virtual ~MockAudioRendererHost() {
82 // Make sure all audio streams have been deleted.
83 EXPECT_TRUE(audio_entries_
.empty());
86 // This method is used to dispatch IPC messages to the renderer. We intercept
87 // these messages here and dispatch to our mock methods to verify the
88 // conversation between this object and the renderer.
89 virtual bool Send(IPC::Message
* message
) {
92 // In this method we dispatch the messages to the according handlers as if
93 // we are the renderer.
95 IPC_BEGIN_MESSAGE_MAP(MockAudioRendererHost
, *message
)
96 IPC_MESSAGE_HANDLER(AudioMsg_NotifyStreamCreated
,
98 IPC_MESSAGE_HANDLER(AudioMsg_NotifyStreamStateChanged
,
100 IPC_MESSAGE_UNHANDLED(handled
= false)
101 IPC_END_MESSAGE_MAP()
102 EXPECT_TRUE(handled
);
108 void OnStreamCreated(const IPC::Message
& msg
, int stream_id
,
109 base::SharedMemoryHandle handle
,
111 base::SyncSocket::Handle socket_handle
,
113 base::FileDescriptor socket_descriptor
,
116 // Maps the shared memory.
117 shared_memory_
.reset(new base::SharedMemory(handle
, false));
118 CHECK(shared_memory_
->Map(length
));
119 CHECK(shared_memory_
->memory());
120 shared_memory_length_
= length
;
122 // Create the SyncSocket using the handle.
123 base::SyncSocket::Handle sync_socket_handle
;
125 sync_socket_handle
= socket_handle
;
127 sync_socket_handle
= socket_descriptor
.fd
;
129 sync_socket_
.reset(new base::SyncSocket(sync_socket_handle
));
131 // And then delegate the call to the mock method.
132 OnStreamCreated(stream_id
, length
);
135 void OnStreamStateChanged(const IPC::Message
& msg
, int stream_id
,
136 media::AudioOutputIPCDelegate::State state
) {
138 case media::AudioOutputIPCDelegate::kPlaying
:
139 OnStreamPlaying(stream_id
);
141 case media::AudioOutputIPCDelegate::kPaused
:
142 OnStreamPaused(stream_id
);
144 case media::AudioOutputIPCDelegate::kError
:
145 OnStreamError(stream_id
);
148 FAIL() << "Unknown stream state";
153 scoped_ptr
<base::SharedMemory
> shared_memory_
;
154 scoped_ptr
<base::SyncSocket
> sync_socket_
;
155 uint32 shared_memory_length_
;
157 DISALLOW_COPY_AND_ASSIGN(MockAudioRendererHost
);
160 ACTION_P(QuitMessageLoop
, message_loop
) {
161 message_loop
->PostTask(FROM_HERE
, base::MessageLoop::QuitClosure());
164 class AudioRendererHostTest
: public testing::Test
{
166 AudioRendererHostTest() {}
169 virtual void SetUp() {
170 // Create a message loop so AudioRendererHost can use it.
171 message_loop_
.reset(new base::MessageLoop(base::MessageLoop::TYPE_IO
));
173 // Claim to be on both the UI and IO threads to pass all the DCHECKS.
174 io_thread_
.reset(new BrowserThreadImpl(BrowserThread::IO
,
175 message_loop_
.get()));
176 ui_thread_
.reset(new BrowserThreadImpl(BrowserThread::UI
,
177 message_loop_
.get()));
178 audio_manager_
.reset(media::AudioManager::Create());
179 media_stream_manager_
.reset(new MediaStreamManager(audio_manager_
.get()));
180 media_stream_manager_
->UseFakeDevice();
181 observer_
.reset(new MockMediaInternals());
182 host_
= new MockAudioRendererHost(
183 audio_manager_
.get(), &mirroring_manager_
, observer_
.get(),
184 media_stream_manager_
.get());
186 // Simulate IPC channel connected.
187 host_
->OnChannelConnected(base::GetCurrentProcId());
190 virtual void TearDown() {
191 // Simulate closing the IPC channel.
192 host_
->OnChannelClosing();
194 // Release the reference to the mock object. The object will be destructed
198 // We need to continue running message_loop_ to complete all destructions.
199 SyncWithAudioThread();
200 audio_manager_
.reset();
205 // Delete the IO message loop. This will cause the MediaStreamManager to be
206 // notified so it will stop its device thread and device managers.
207 message_loop_
.reset();
211 EXPECT_CALL(*observer_
,
212 OnSetAudioStreamStatus(_
, kStreamId
, "created"));
213 EXPECT_CALL(*host_
.get(), OnStreamCreated(kStreamId
, _
))
214 .WillOnce(QuitMessageLoop(message_loop_
.get()));
215 EXPECT_CALL(mirroring_manager_
,
216 AddDiverter(kRenderProcessId
, kRenderViewId
, NotNull()))
217 .RetiresOnSaturation();
219 // Send a create stream message to the audio output stream and wait until
220 // we receive the created message.
221 host_
->OnCreateStream(kStreamId
,
224 media::AudioParameters(
225 media::AudioParameters::AUDIO_FAKE
,
226 media::CHANNEL_LAYOUT_STEREO
,
227 media::AudioParameters::kAudioCDSampleRate
, 16,
228 media::AudioParameters::kAudioCDSampleRate
/ 10));
229 message_loop_
->Run();
231 // At some point in the future, a corresponding RemoveDiverter() call must
233 EXPECT_CALL(mirroring_manager_
,
234 RemoveDiverter(kRenderProcessId
, kRenderViewId
, NotNull()))
235 .RetiresOnSaturation();
237 // All created streams should ultimately be closed.
238 EXPECT_CALL(*observer_
,
239 OnSetAudioStreamStatus(_
, kStreamId
, "closed"));
241 // Expect the audio stream will be deleted at some later point.
242 EXPECT_CALL(*observer_
, OnDeleteAudioStream(_
, kStreamId
));
245 void CreateUnifiedStream() {
246 EXPECT_CALL(*observer_
,
247 OnSetAudioStreamStatus(_
, kStreamId
, "created"));
248 EXPECT_CALL(*host_
.get(), OnStreamCreated(kStreamId
, _
))
249 .WillOnce(QuitMessageLoop(message_loop_
.get()));
250 EXPECT_CALL(mirroring_manager_
,
251 AddDiverter(kRenderProcessId
, kRenderViewId
, NotNull()))
252 .RetiresOnSaturation();
253 // Send a create stream message to the audio output stream and wait until
254 // we receive the created message.
255 // Use AudioInputDeviceManager::kFakeOpenSessionId as the session id to
256 // pass the permission check.
257 host_
->OnCreateStream(kStreamId
,
259 AudioInputDeviceManager::kFakeOpenSessionId
,
260 media::AudioParameters(
261 media::AudioParameters::AUDIO_FAKE
,
262 media::CHANNEL_LAYOUT_STEREO
,
264 media::AudioParameters::kAudioCDSampleRate
, 16,
265 media::AudioParameters::kAudioCDSampleRate
/ 10));
266 message_loop_
->Run();
268 // At some point in the future, a corresponding RemoveDiverter() call must
270 EXPECT_CALL(mirroring_manager_
,
271 RemoveDiverter(kRenderProcessId
, kRenderViewId
, NotNull()))
272 .RetiresOnSaturation();
274 // All created streams should ultimately be closed.
275 EXPECT_CALL(*observer_
,
276 OnSetAudioStreamStatus(_
, kStreamId
, "closed"));
278 // Expect the audio stream will be deleted at some later point.
279 EXPECT_CALL(*observer_
, OnDeleteAudioStream(_
, kStreamId
));
283 // Send a message to AudioRendererHost to tell it we want to close the
285 host_
->OnCloseStream(kStreamId
);
286 message_loop_
->RunUntilIdle();
290 EXPECT_CALL(*observer_
,
291 OnSetAudioStreamPlaying(_
, kStreamId
, true));
292 EXPECT_CALL(*host_
.get(), OnStreamPlaying(kStreamId
))
293 .WillOnce(QuitMessageLoop(message_loop_
.get()));
295 host_
->OnPlayStream(kStreamId
);
296 message_loop_
->Run();
300 EXPECT_CALL(*observer_
,
301 OnSetAudioStreamPlaying(_
, kStreamId
, false));
302 EXPECT_CALL(*host_
.get(), OnStreamPaused(kStreamId
))
303 .WillOnce(QuitMessageLoop(message_loop_
.get()));
305 host_
->OnPauseStream(kStreamId
);
306 message_loop_
->Run();
309 void SetVolume(double volume
) {
310 EXPECT_CALL(*observer_
,
311 OnSetAudioStreamVolume(_
, kStreamId
, volume
));
313 host_
->OnSetVolume(kStreamId
, volume
);
314 message_loop_
->RunUntilIdle();
317 void SimulateError() {
318 EXPECT_CALL(*observer_
,
319 OnSetAudioStreamStatus(_
, kStreamId
, "error"));
320 EXPECT_EQ(1u, host_
->audio_entries_
.size())
321 << "Calls Create() before calling this method";
323 // Expect an error signal sent through IPC.
324 EXPECT_CALL(*host_
.get(), OnStreamError(kStreamId
));
326 // Simulate an error sent from the audio device.
327 host_
->ReportErrorAndClose(kStreamId
);
328 SyncWithAudioThread();
330 // Expect the audio stream record is removed.
331 EXPECT_EQ(0u, host_
->audio_entries_
.size());
334 // Called on the audio thread.
335 static void PostQuitMessageLoop(base::MessageLoop
* message_loop
) {
336 message_loop
->PostTask(FROM_HERE
, base::MessageLoop::QuitClosure());
339 // Called on the main thread.
340 static void PostQuitOnAudioThread(media::AudioManager
* audio_manager
,
341 base::MessageLoop
* message_loop
) {
342 audio_manager
->GetMessageLoop()->PostTask(FROM_HERE
,
343 base::Bind(&PostQuitMessageLoop
, message_loop
));
346 // SyncWithAudioThread() waits until all pending tasks on the audio thread
347 // are executed while also processing pending task in message_loop_ on the
348 // current thread. It is used to synchronize with the audio thread when we are
349 // closing an audio stream.
350 void SyncWithAudioThread() {
351 // Don't use scoped_refptr to addref the media::AudioManager when posting
352 // to the thread that itself owns.
353 message_loop_
->PostTask(
354 FROM_HERE
, base::Bind(&PostQuitOnAudioThread
,
355 base::Unretained(audio_manager_
.get()),
356 message_loop_
.get()));
357 message_loop_
->Run();
361 scoped_ptr
<MockMediaInternals
> observer_
;
362 MockAudioMirroringManager mirroring_manager_
;
363 scoped_refptr
<MockAudioRendererHost
> host_
;
364 scoped_ptr
<base::MessageLoop
> message_loop_
;
365 scoped_ptr
<BrowserThreadImpl
> io_thread_
;
366 scoped_ptr
<BrowserThreadImpl
> ui_thread_
;
367 scoped_ptr
<media::AudioManager
> audio_manager_
;
368 scoped_ptr
<MediaStreamManager
> media_stream_manager_
;
370 DISALLOW_COPY_AND_ASSIGN(AudioRendererHostTest
);
373 TEST_F(AudioRendererHostTest
, CreateAndClose
) {
378 // Simulate the case where a stream is not properly closed.
379 TEST_F(AudioRendererHostTest
, CreateAndShutdown
) {
383 TEST_F(AudioRendererHostTest
, CreatePlayAndClose
) {
389 TEST_F(AudioRendererHostTest
, CreatePlayPauseAndClose
) {
396 TEST_F(AudioRendererHostTest
, SetVolume
) {
404 // Simulate the case where a stream is not properly closed.
405 TEST_F(AudioRendererHostTest
, CreatePlayAndShutdown
) {
410 // Simulate the case where a stream is not properly closed.
411 TEST_F(AudioRendererHostTest
, CreatePlayPauseAndShutdown
) {
417 TEST_F(AudioRendererHostTest
, SimulateError
) {
423 // Simulate the case when an error is generated on the browser process,
424 // the audio device is closed but the render process try to close the
425 // audio stream again.
426 TEST_F(AudioRendererHostTest
, SimulateErrorAndClose
) {
433 TEST_F(AudioRendererHostTest
, CreateUnifiedStreamAndClose
) {
434 CreateUnifiedStream();
438 // TODO(hclam): Add tests for data conversation in low latency mode.
440 } // namespace content