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.
8 #include "base/callback_helpers.h"
9 #include "base/message_loop.h"
10 #include "base/run_loop.h"
11 #include "content/browser/browser_thread_impl.h"
12 #include "content/browser/renderer_host/media/media_stream_dispatcher_host.h"
13 #include "content/browser/renderer_host/media/media_stream_manager.h"
14 #include "content/browser/renderer_host/media/media_stream_ui_proxy.h"
15 #include "content/browser/renderer_host/media/video_capture_manager.h"
16 #include "content/common/media/media_stream_messages.h"
17 #include "content/common/media/media_stream_options.h"
18 #include "content/public/test/mock_resource_context.h"
19 #include "content/public/test/test_browser_thread_bundle.h"
20 #include "content/test/test_content_browser_client.h"
21 #include "content/test/test_content_client.h"
22 #include "ipc/ipc_message_macros.h"
23 #include "media/audio/audio_manager.h"
24 #include "media/video/capture/fake_video_capture_device.h"
25 #include "net/url_request/url_request_context.h"
26 #include "testing/gmock/include/gmock/gmock.h"
27 #include "testing/gtest/include/gtest/gtest.h"
30 using ::testing::DeleteArg
;
31 using ::testing::DoAll
;
32 using ::testing::Return
;
33 using ::testing::SaveArg
;
35 const int kProcessId
= 5;
36 const int kRenderId
= 6;
37 const int kPageRequestId
= 7;
41 class MockMediaStreamDispatcherHost
: public MediaStreamDispatcherHost
,
42 public TestContentBrowserClient
{
44 MockMediaStreamDispatcherHost(
45 const scoped_refptr
<base::MessageLoopProxy
>& message_loop
,
46 MediaStreamManager
* manager
)
47 : MediaStreamDispatcherHost(kProcessId
, manager
),
48 message_loop_(message_loop
) {}
50 // A list of mock methods.
51 MOCK_METHOD4(OnStreamGenerated
,
52 void(int routing_id
, int request_id
, int audio_array_size
,
53 int video_array_size
));
54 MOCK_METHOD2(OnStreamGenerationFailed
, void(int routing_id
, int request_id
));
56 // Accessor to private functions.
57 void OnGenerateStream(int page_request_id
,
58 const StreamOptions
& components
,
59 const base::Closure
& quit_closure
) {
60 quit_closure_
= quit_closure
;
61 MediaStreamDispatcherHost::OnGenerateStream(
62 kRenderId
, page_request_id
, components
, GURL());
65 void OnStopGeneratedStream(const std::string
& label
) {
66 MediaStreamDispatcherHost::OnStopGeneratedStream(kRenderId
, label
);
69 // Return the number of streams that have been opened or is being open.
70 size_t NumberOfStreams() {
71 return streams_
.size();
75 StreamDeviceInfoArray audio_devices_
;
76 StreamDeviceInfoArray video_devices_
;
79 virtual ~MockMediaStreamDispatcherHost() {}
81 // This method is used to dispatch IPC messages to the renderer. We intercept
82 // these messages here and dispatch to our mock methods to verify the
83 // conversation between this object and the renderer.
84 virtual bool Send(IPC::Message
* message
) OVERRIDE
{
87 // In this method we dispatch the messages to the according handlers as if
88 // we are the renderer.
90 IPC_BEGIN_MESSAGE_MAP(MockMediaStreamDispatcherHost
, *message
)
91 IPC_MESSAGE_HANDLER(MediaStreamMsg_StreamGenerated
, OnStreamGenerated
)
92 IPC_MESSAGE_HANDLER(MediaStreamMsg_StreamGenerationFailed
,
93 OnStreamGenerationFailed
)
94 IPC_MESSAGE_UNHANDLED(handled
= false)
102 // These handler methods do minimal things and delegate to the mock methods.
103 void OnStreamGenerated(
104 const IPC::Message
& msg
,
107 StreamDeviceInfoArray audio_device_list
,
108 StreamDeviceInfoArray video_device_list
) {
109 OnStreamGenerated(msg
.routing_id(), request_id
, audio_device_list
.size(),
110 video_device_list
.size());
111 // Notify that the event have occured.
112 message_loop_
->PostTask(FROM_HERE
, base::ResetAndReturn(&quit_closure_
));
114 audio_devices_
= audio_device_list
;
115 video_devices_
= video_device_list
;
118 void OnStreamGenerationFailed(const IPC::Message
& msg
, int request_id
) {
119 OnStreamGenerationFailed(msg
.routing_id(), request_id
);
120 if (!quit_closure_
.is_null())
121 message_loop_
->PostTask(FROM_HERE
, base::ResetAndReturn(&quit_closure_
));
125 scoped_refptr
<base::MessageLoopProxy
> message_loop_
;
126 base::Closure quit_closure_
;
129 class MockMediaStreamUIProxy
: public FakeMediaStreamUIProxy
{
131 MOCK_METHOD1(OnStarted
, void(const base::Closure
& stop
));
134 class MediaStreamDispatcherHostTest
: public testing::Test
{
136 MediaStreamDispatcherHostTest()
137 : old_browser_client_(NULL
),
138 thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP
) {
139 // Create our own MediaStreamManager.
140 audio_manager_
.reset(media::AudioManager::Create());
141 media_stream_manager_
.reset(new MediaStreamManager(audio_manager_
.get()));
142 // Make sure we use fake devices to avoid long delays.
143 media_stream_manager_
->UseFakeDevice();
145 host_
= new MockMediaStreamDispatcherHost(base::MessageLoopProxy::current(),
146 media_stream_manager_
.get());
148 // Use the fake content client and browser.
149 content_client_
.reset(new TestContentClient());
150 SetContentClient(content_client_
.get());
151 old_browser_client_
= SetBrowserClientForTesting(host_
.get());
154 virtual ~MediaStreamDispatcherHostTest() {
155 // Recover the old browser client and content client.
156 SetBrowserClientForTesting(old_browser_client_
);
157 content_client_
.reset();
161 virtual void SetupFakeUI(bool expect_started
) {
162 scoped_ptr
<MockMediaStreamUIProxy
> stream_ui(new MockMediaStreamUIProxy());
163 if (expect_started
) {
164 EXPECT_CALL(*stream_ui
, OnStarted(_
));
166 media_stream_manager_
->UseFakeUI(
167 stream_ui
.PassAs
<FakeMediaStreamUIProxy
>());
170 void GenerateStreamAndWaitForResult(int page_request_id
,
171 const StreamOptions
& options
) {
172 base::RunLoop run_loop
;
173 host_
->OnGenerateStream(page_request_id
, options
, run_loop
.QuitClosure());
177 scoped_refptr
<MockMediaStreamDispatcherHost
> host_
;
178 scoped_ptr
<media::AudioManager
> audio_manager_
;
179 scoped_ptr
<MediaStreamManager
> media_stream_manager_
;
180 ContentBrowserClient
* old_browser_client_
;
181 scoped_ptr
<ContentClient
> content_client_
;
182 content::TestBrowserThreadBundle thread_bundle_
;
185 TEST_F(MediaStreamDispatcherHostTest
, GenerateStream
) {
186 StreamOptions
options(MEDIA_NO_SERVICE
, MEDIA_DEVICE_VIDEO_CAPTURE
);
189 EXPECT_CALL(*host_
.get(), OnStreamGenerated(kRenderId
, kPageRequestId
, 0, 1));
190 GenerateStreamAndWaitForResult(kPageRequestId
, options
);
192 std::string label
= host_
->label_
;
194 EXPECT_EQ(host_
->audio_devices_
.size(), 0u);
195 EXPECT_EQ(host_
->video_devices_
.size(), 1u);
196 EXPECT_EQ(host_
->NumberOfStreams(), 1u);
198 host_
->OnStopGeneratedStream(label
);
199 EXPECT_EQ(host_
->NumberOfStreams(), 0u);
202 TEST_F(MediaStreamDispatcherHostTest
, GenerateThreeStreams
) {
203 // This test opens three video capture devices. Two fake devices exists and it
204 // is expected the last call to |Open()| will open the first device again, but
205 // with a different label.
206 StreamOptions
options(MEDIA_NO_SERVICE
, MEDIA_DEVICE_VIDEO_CAPTURE
);
208 // Generate first stream.
210 EXPECT_CALL(*host_
.get(), OnStreamGenerated(kRenderId
, kPageRequestId
, 0, 1));
211 GenerateStreamAndWaitForResult(kPageRequestId
, options
);
213 // Check the latest generated stream.
214 EXPECT_EQ(host_
->audio_devices_
.size(), 0u);
215 EXPECT_EQ(host_
->video_devices_
.size(), 1u);
216 std::string label1
= host_
->label_
;
217 std::string device_id1
= host_
->video_devices_
.front().device
.id
;
219 // Check that we now have one opened streams.
220 EXPECT_EQ(host_
->NumberOfStreams(), 1u);
222 // Generate second stream.
224 EXPECT_CALL(*host_
.get(),
225 OnStreamGenerated(kRenderId
, kPageRequestId
+ 1, 0, 1));
226 GenerateStreamAndWaitForResult(kPageRequestId
+ 1, options
);
228 // Check the latest generated stream.
229 EXPECT_EQ(host_
->audio_devices_
.size(), 0u);
230 EXPECT_EQ(host_
->video_devices_
.size(), 1u);
231 std::string label2
= host_
->label_
;
232 std::string device_id2
= host_
->video_devices_
.front().device
.id
;
233 EXPECT_EQ(device_id1
, device_id2
);
234 EXPECT_NE(label1
, label2
);
236 // Check that we now have two opened streams.
237 EXPECT_EQ(2u, host_
->NumberOfStreams());
239 // Generate third stream.
241 EXPECT_CALL(*host_
.get(),
242 OnStreamGenerated(kRenderId
, kPageRequestId
+ 2, 0, 1));
243 GenerateStreamAndWaitForResult(kPageRequestId
+ 2, options
);
245 // Check the latest generated stream.
246 EXPECT_EQ(host_
->audio_devices_
.size(), 0u);
247 EXPECT_EQ(host_
->video_devices_
.size(), 1u);
248 std::string label3
= host_
->label_
;
249 std::string device_id3
= host_
->video_devices_
.front().device
.id
;
250 EXPECT_EQ(device_id1
, device_id3
);
251 EXPECT_NE(label1
, label3
);
252 EXPECT_NE(label2
, label3
);
254 // Check that we now have three opened streams.
255 EXPECT_EQ(host_
->NumberOfStreams(), 3u);
257 host_
->OnStopGeneratedStream(label1
);
258 host_
->OnStopGeneratedStream(label2
);
259 host_
->OnStopGeneratedStream(label3
);
260 EXPECT_EQ(host_
->NumberOfStreams(), 0u);
263 TEST_F(MediaStreamDispatcherHostTest
, FailOpenVideoDevice
) {
264 StreamOptions
options(MEDIA_NO_SERVICE
, MEDIA_DEVICE_VIDEO_CAPTURE
);
266 media::FakeVideoCaptureDevice::SetFailNextCreate();
268 EXPECT_CALL(*host_
.get(),
269 OnStreamGenerationFailed(kRenderId
, kPageRequestId
));
270 GenerateStreamAndWaitForResult(kPageRequestId
, options
);
273 TEST_F(MediaStreamDispatcherHostTest
, CancelPendingStreamsOnChannelClosing
) {
274 StreamOptions
options(MEDIA_NO_SERVICE
, MEDIA_DEVICE_VIDEO_CAPTURE
);
276 base::RunLoop run_loop
;
278 // Create multiple GenerateStream requests.
280 for (size_t i
= 1; i
<= streams
; ++i
) {
281 host_
->OnGenerateStream(
282 kPageRequestId
+ i
, options
, run_loop
.QuitClosure());
283 EXPECT_EQ(host_
->NumberOfStreams(), i
);
286 // Calling OnChannelClosing() to cancel all the pending requests.
287 host_
->OnChannelClosing();
288 run_loop
.RunUntilIdle();
290 // Streams should have been cleaned up.
291 EXPECT_EQ(host_
->NumberOfStreams(), 0u);
294 TEST_F(MediaStreamDispatcherHostTest
, StopGeneratedStreamsOnChannelClosing
) {
295 StreamOptions
options(MEDIA_NO_SERVICE
, MEDIA_DEVICE_VIDEO_CAPTURE
);
297 // Create first group of streams.
298 size_t generated_streams
= 3;
299 for (size_t i
= 0; i
< generated_streams
; ++i
) {
301 EXPECT_CALL(*host_
.get(),
302 OnStreamGenerated(kRenderId
, kPageRequestId
+ i
, 0, 1));
303 GenerateStreamAndWaitForResult(kPageRequestId
+ i
, options
);
305 EXPECT_EQ(host_
->NumberOfStreams(), generated_streams
);
307 // Calling OnChannelClosing() to cancel all the pending/generated streams.
308 host_
->OnChannelClosing();
309 base::RunLoop().RunUntilIdle();
311 // Streams should have been cleaned up.
312 EXPECT_EQ(host_
->NumberOfStreams(), 0u);
315 TEST_F(MediaStreamDispatcherHostTest
, CloseFromUI
) {
316 StreamOptions
options(MEDIA_NO_SERVICE
, MEDIA_DEVICE_VIDEO_CAPTURE
);
318 base::Closure close_callback
;
319 scoped_ptr
<MockMediaStreamUIProxy
> stream_ui(new MockMediaStreamUIProxy());
320 EXPECT_CALL(*stream_ui
, OnStarted(_
))
321 .WillOnce(SaveArg
<0>(&close_callback
));
322 media_stream_manager_
->UseFakeUI(stream_ui
.PassAs
<FakeMediaStreamUIProxy
>());
324 EXPECT_CALL(*host_
.get(), OnStreamGenerated(kRenderId
, kPageRequestId
, 0, 1));
325 EXPECT_CALL(*host_
.get(),
326 OnStreamGenerationFailed(kRenderId
, kPageRequestId
));
327 GenerateStreamAndWaitForResult(kPageRequestId
, options
);
329 EXPECT_EQ(host_
->audio_devices_
.size(), 0u);
330 EXPECT_EQ(host_
->video_devices_
.size(), 1u);
331 EXPECT_EQ(host_
->NumberOfStreams(), 1u);
333 ASSERT_FALSE(close_callback
.is_null());
334 close_callback
.Run();
335 base::RunLoop().RunUntilIdle();
337 EXPECT_EQ(host_
->NumberOfStreams(), 0u);
340 }; // namespace content