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/command_line.h"
7 #include "base/memory/scoped_ptr.h"
8 #include "base/run_loop.h"
9 #include "base/sync_socket.h"
10 #include "content/browser/media/capture/audio_mirroring_manager.h"
11 #include "content/browser/media/media_internals.h"
12 #include "content/browser/renderer_host/media/audio_input_device_manager.h"
13 #include "content/browser/renderer_host/media/audio_renderer_host.h"
14 #include "content/browser/renderer_host/media/media_stream_manager.h"
15 #include "content/common/media/audio_messages.h"
16 #include "content/public/common/content_switches.h"
17 #include "content/public/test/test_browser_thread_bundle.h"
18 #include "ipc/ipc_message_utils.h"
19 #include "media/audio/audio_manager.h"
20 #include "media/base/bind_to_current_loop.h"
21 #include "media/base/media_switches.h"
22 #include "testing/gmock/include/gmock/gmock.h"
23 #include "testing/gtest/include/gtest/gtest.h"
26 using ::testing::Assign
;
27 using ::testing::DoAll
;
28 using ::testing::NotNull
;
31 const int kRenderProcessId
= 1;
32 const int kRenderViewId
= 4;
33 const int kRenderFrameId
= 5;
34 const int kStreamId
= 50;
39 class MockAudioMirroringManager
: public AudioMirroringManager
{
41 MockAudioMirroringManager() {}
42 virtual ~MockAudioMirroringManager() {}
44 MOCK_METHOD3(AddDiverter
,
45 void(int render_process_id
,
48 MOCK_METHOD3(RemoveDiverter
,
49 void(int render_process_id
,
54 DISALLOW_COPY_AND_ASSIGN(MockAudioMirroringManager
);
57 class MockAudioRendererHost
: public AudioRendererHost
{
59 MockAudioRendererHost(media::AudioManager
* audio_manager
,
60 AudioMirroringManager
* mirroring_manager
,
61 MediaInternals
* media_internals
,
62 MediaStreamManager
* media_stream_manager
)
63 : AudioRendererHost(kRenderProcessId
,
67 media_stream_manager
),
68 shared_memory_length_(0) {}
70 // A list of mock methods.
71 MOCK_METHOD2(OnStreamCreated
, void(int stream_id
, int length
));
72 MOCK_METHOD1(OnStreamPlaying
, void(int stream_id
));
73 MOCK_METHOD1(OnStreamPaused
, void(int stream_id
));
74 MOCK_METHOD1(OnStreamError
, void(int stream_id
));
77 virtual ~MockAudioRendererHost() {
78 // Make sure all audio streams have been deleted.
79 EXPECT_TRUE(audio_entries_
.empty());
82 // This method is used to dispatch IPC messages to the renderer. We intercept
83 // these messages here and dispatch to our mock methods to verify the
84 // conversation between this object and the renderer.
85 virtual bool Send(IPC::Message
* message
) {
88 // In this method we dispatch the messages to the according handlers as if
89 // we are the renderer.
91 IPC_BEGIN_MESSAGE_MAP(MockAudioRendererHost
, *message
)
92 IPC_MESSAGE_HANDLER(AudioMsg_NotifyStreamCreated
,
93 OnNotifyStreamCreated
)
94 IPC_MESSAGE_HANDLER(AudioMsg_NotifyStreamStateChanged
,
95 OnNotifyStreamStateChanged
)
96 IPC_MESSAGE_UNHANDLED(handled
= false)
104 void OnNotifyStreamCreated(int stream_id
,
105 base::SharedMemoryHandle handle
,
107 base::SyncSocket::Handle socket_handle
,
109 base::FileDescriptor socket_descriptor
,
112 // Maps the shared memory.
113 shared_memory_
.reset(new base::SharedMemory(handle
, false));
114 CHECK(shared_memory_
->Map(length
));
115 CHECK(shared_memory_
->memory());
116 shared_memory_length_
= length
;
118 // Create the SyncSocket using the handle.
119 base::SyncSocket::Handle sync_socket_handle
;
121 sync_socket_handle
= socket_handle
;
123 sync_socket_handle
= socket_descriptor
.fd
;
125 sync_socket_
.reset(new base::SyncSocket(sync_socket_handle
));
127 // And then delegate the call to the mock method.
128 OnStreamCreated(stream_id
, length
);
131 void OnNotifyStreamStateChanged(int stream_id
,
132 media::AudioOutputIPCDelegate::State state
) {
134 case media::AudioOutputIPCDelegate::kPlaying
:
135 OnStreamPlaying(stream_id
);
137 case media::AudioOutputIPCDelegate::kPaused
:
138 OnStreamPaused(stream_id
);
140 case media::AudioOutputIPCDelegate::kError
:
141 OnStreamError(stream_id
);
144 FAIL() << "Unknown stream state";
149 scoped_ptr
<base::SharedMemory
> shared_memory_
;
150 scoped_ptr
<base::SyncSocket
> sync_socket_
;
151 uint32 shared_memory_length_
;
153 DISALLOW_COPY_AND_ASSIGN(MockAudioRendererHost
);
156 class AudioRendererHostTest
: public testing::Test
{
158 AudioRendererHostTest() {
159 audio_manager_
.reset(media::AudioManager::CreateForTesting());
160 base::CommandLine::ForCurrentProcess()->AppendSwitch(
161 switches::kUseFakeDeviceForMediaStream
);
162 media_stream_manager_
.reset(new MediaStreamManager(audio_manager_
.get()));
163 host_
= new MockAudioRendererHost(audio_manager_
.get(),
165 MediaInternals::GetInstance(),
166 media_stream_manager_
.get());
168 // Simulate IPC channel connected.
169 host_
->set_peer_pid_for_testing(base::GetCurrentProcId());
172 virtual ~AudioRendererHostTest() {
173 // Simulate closing the IPC channel and give the audio thread time to close
174 // the underlying streams.
175 host_
->OnChannelClosing();
176 SyncWithAudioThread();
178 // Release the reference to the mock object. The object will be destructed
184 void Create(bool unified_stream
) {
185 EXPECT_CALL(*host_
.get(), OnStreamCreated(kStreamId
, _
));
187 EXPECT_CALL(mirroring_manager_
,
188 AddDiverter(kRenderProcessId
, kRenderViewId
, NotNull()))
189 .RetiresOnSaturation();
191 // Send a create stream message to the audio output stream and wait until
192 // we receive the created message.
194 media::AudioParameters params
;
195 if (unified_stream
) {
196 // Use AudioInputDeviceManager::kFakeOpenSessionId as the session id to
197 // pass the permission check.
198 session_id
= AudioInputDeviceManager::kFakeOpenSessionId
;
199 params
= media::AudioParameters(
200 media::AudioParameters::AUDIO_FAKE
,
201 media::CHANNEL_LAYOUT_STEREO
,
203 media::AudioParameters::kAudioCDSampleRate
, 16,
204 media::AudioParameters::kAudioCDSampleRate
/ 10,
205 media::AudioParameters::NO_EFFECTS
);
208 params
= media::AudioParameters(
209 media::AudioParameters::AUDIO_FAKE
,
210 media::CHANNEL_LAYOUT_STEREO
,
211 media::AudioParameters::kAudioCDSampleRate
, 16,
212 media::AudioParameters::kAudioCDSampleRate
/ 10);
214 host_
->OnCreateStream(kStreamId
, kRenderViewId
, kRenderFrameId
, session_id
,
217 // At some point in the future, a corresponding RemoveDiverter() call must
219 EXPECT_CALL(mirroring_manager_
,
220 RemoveDiverter(kRenderProcessId
, kRenderViewId
, NotNull()))
221 .RetiresOnSaturation();
222 SyncWithAudioThread();
226 // Send a message to AudioRendererHost to tell it we want to close the
228 host_
->OnCloseStream(kStreamId
);
229 SyncWithAudioThread();
233 EXPECT_CALL(*host_
.get(), OnStreamPlaying(kStreamId
));
234 host_
->OnPlayStream(kStreamId
);
235 SyncWithAudioThread();
239 EXPECT_CALL(*host_
.get(), OnStreamPaused(kStreamId
));
240 host_
->OnPauseStream(kStreamId
);
241 SyncWithAudioThread();
244 void SetVolume(double volume
) {
245 host_
->OnSetVolume(kStreamId
, volume
);
246 SyncWithAudioThread();
249 void SimulateError() {
250 EXPECT_EQ(1u, host_
->audio_entries_
.size())
251 << "Calls Create() before calling this method";
253 // Expect an error signal sent through IPC.
254 EXPECT_CALL(*host_
.get(), OnStreamError(kStreamId
));
256 // Simulate an error sent from the audio device.
257 host_
->ReportErrorAndClose(kStreamId
);
258 SyncWithAudioThread();
260 // Expect the audio stream record is removed.
261 EXPECT_EQ(0u, host_
->audio_entries_
.size());
264 // SyncWithAudioThread() waits until all pending tasks on the audio thread
265 // are executed while also processing pending task in message_loop_ on the
266 // current thread. It is used to synchronize with the audio thread when we are
267 // closing an audio stream.
268 void SyncWithAudioThread() {
269 base::RunLoop().RunUntilIdle();
271 base::RunLoop run_loop
;
272 audio_manager_
->GetTaskRunner()->PostTask(
273 FROM_HERE
, media::BindToCurrentLoop(run_loop
.QuitClosure()));
278 // MediaStreamManager uses a DestructionObserver, so it must outlive the
279 // TestBrowserThreadBundle.
280 scoped_ptr
<MediaStreamManager
> media_stream_manager_
;
281 TestBrowserThreadBundle thread_bundle_
;
282 scoped_ptr
<media::AudioManager
> audio_manager_
;
283 MockAudioMirroringManager mirroring_manager_
;
284 scoped_refptr
<MockAudioRendererHost
> host_
;
286 DISALLOW_COPY_AND_ASSIGN(AudioRendererHostTest
);
289 TEST_F(AudioRendererHostTest
, CreateAndClose
) {
294 // Simulate the case where a stream is not properly closed.
295 TEST_F(AudioRendererHostTest
, CreateAndShutdown
) {
299 TEST_F(AudioRendererHostTest
, CreatePlayAndClose
) {
305 TEST_F(AudioRendererHostTest
, CreatePlayPauseAndClose
) {
312 TEST_F(AudioRendererHostTest
, SetVolume
) {
320 // Simulate the case where a stream is not properly closed.
321 TEST_F(AudioRendererHostTest
, CreatePlayAndShutdown
) {
326 // Simulate the case where a stream is not properly closed.
327 TEST_F(AudioRendererHostTest
, CreatePlayPauseAndShutdown
) {
333 TEST_F(AudioRendererHostTest
, SimulateError
) {
339 // Simulate the case when an error is generated on the browser process,
340 // the audio device is closed but the render process try to close the
341 // audio stream again.
342 TEST_F(AudioRendererHostTest
, SimulateErrorAndClose
) {
349 TEST_F(AudioRendererHostTest
, CreateUnifiedStreamAndClose
) {
354 // TODO(hclam): Add tests for data conversation in low latency mode.
356 } // namespace content