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.
9 #include "base/callback_helpers.h"
10 #include "base/message_loop/message_loop.h"
11 #include "base/run_loop.h"
12 #include "content/browser/browser_thread_impl.h"
13 #include "content/browser/renderer_host/media/media_stream_dispatcher_host.h"
14 #include "content/browser/renderer_host/media/media_stream_manager.h"
15 #include "content/browser/renderer_host/media/media_stream_ui_proxy.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));
55 MOCK_METHOD1(OnStopGeneratedStreamFromBrowser,
56 void(int routing_id));
57 MOCK_METHOD2(OnDeviceOpened,
58 void(int routing_id, int request_id));
60 // Accessor to private functions.
61 void OnGenerateStream(int render_view_id,
63 const StreamOptions& components,
64 const base::Closure& quit_closure) {
65 quit_closures_.push(quit_closure);
66 MediaStreamDispatcherHost::OnGenerateStream(
67 render_view_id, page_request_id, components, GURL());
70 void OnStopStreamDevice(int render_view_id,
71 const std::string& device_id) {
72 MediaStreamDispatcherHost::OnStopStreamDevice(render_view_id, device_id);
75 void OnOpenDevice(int render_view_id,
77 const std::string& device_id,
79 const base::Closure& quit_closure) {
80 quit_closures_.push(quit_closure);
81 MediaStreamDispatcherHost::OnOpenDevice(
82 render_view_id, page_request_id, device_id, type, GURL());
85 bool FindExistingRequestedDeviceInfo(const std::string& device_id,
86 MediaStreamRequestType request_type,
87 StreamDeviceInfo* device_info) {
88 MediaRequestState request_state;
89 return media_stream_manager_->FindExistingRequestedDeviceInfo(
90 kProcessId, kRenderId, request_type, device_id, device_info,
95 StreamDeviceInfoArray audio_devices_;
96 StreamDeviceInfoArray video_devices_;
97 StreamDeviceInfo opened_device_;
100 virtual ~MockMediaStreamDispatcherHost() {}
102 // This method is used to dispatch IPC messages to the renderer. We intercept
103 // these messages here and dispatch to our mock methods to verify the
104 // conversation between this object and the renderer.
105 virtual bool Send(IPC::Message* message) OVERRIDE {
108 // In this method we dispatch the messages to the according handlers as if
109 // we are the renderer.
111 IPC_BEGIN_MESSAGE_MAP(MockMediaStreamDispatcherHost, *message)
112 IPC_MESSAGE_HANDLER(MediaStreamMsg_StreamGenerated, OnStreamGenerated)
113 IPC_MESSAGE_HANDLER(MediaStreamMsg_StreamGenerationFailed,
114 OnStreamGenerationFailed)
115 IPC_MESSAGE_HANDLER(MediaStreamMsg_StopGeneratedStream,
116 OnStopGeneratedStreamFromBrowser)
117 IPC_MESSAGE_HANDLER(MediaStreamMsg_DeviceOpened, OnDeviceOpened)
118 IPC_MESSAGE_UNHANDLED(handled = false)
119 IPC_END_MESSAGE_MAP()
120 EXPECT_TRUE(handled);
126 // These handler methods do minimal things and delegate to the mock methods.
127 void OnStreamGenerated(
128 const IPC::Message& msg,
131 StreamDeviceInfoArray audio_device_list,
132 StreamDeviceInfoArray video_device_list) {
133 OnStreamGenerated(msg.routing_id(), request_id, audio_device_list.size(),
134 video_device_list.size());
135 // Notify that the event have occurred.
136 base::Closure quit_closure = quit_closures_.front();
137 quit_closures_.pop();
138 message_loop_->PostTask(FROM_HERE, base::ResetAndReturn(&quit_closure));
141 audio_devices_ = audio_device_list;
142 video_devices_ = video_device_list;
145 void OnStreamGenerationFailed(const IPC::Message& msg, int request_id) {
146 OnStreamGenerationFailed(msg.routing_id(), request_id);
147 if (!quit_closures_.empty()) {
148 base::Closure quit_closure = quit_closures_.front();
149 quit_closures_.pop();
150 message_loop_->PostTask(FROM_HERE, base::ResetAndReturn(&quit_closure));
156 void OnStopGeneratedStreamFromBrowser(const IPC::Message& msg,
157 const std::string& label) {
158 OnStopGeneratedStreamFromBrowser(msg.routing_id());
159 // Notify that the event have occurred.
160 if (!quit_closures_.empty()) {
161 base::Closure quit_closure = quit_closures_.front();
162 quit_closures_.pop();
163 message_loop_->PostTask(FROM_HERE, base::ResetAndReturn(&quit_closure));
168 void OnDeviceOpened(const IPC::Message& msg,
170 const std::string& label,
171 const StreamDeviceInfo& device) {
172 base::Closure quit_closure = quit_closures_.front();
173 quit_closures_.pop();
174 message_loop_->PostTask(FROM_HERE, base::ResetAndReturn(&quit_closure));
176 opened_device_ = device;
179 scoped_refptr<base::MessageLoopProxy> message_loop_;
181 std::queue<base::Closure> quit_closures_;
184 class MockMediaStreamUIProxy : public FakeMediaStreamUIProxy {
186 MOCK_METHOD1(OnStarted, void(const base::Closure& stop));
189 class MediaStreamDispatcherHostTest : public testing::Test {
191 MediaStreamDispatcherHostTest()
192 : old_browser_client_(NULL),
193 thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP) {
194 // Create our own MediaStreamManager.
195 audio_manager_.reset(media::AudioManager::Create());
196 media_stream_manager_.reset(new MediaStreamManager(audio_manager_.get()));
197 // Make sure we use fake devices to avoid long delays.
198 media_stream_manager_->UseFakeDevice();
200 host_ = new MockMediaStreamDispatcherHost(base::MessageLoopProxy::current(),
201 media_stream_manager_.get());
203 // Use the fake content client and browser.
204 content_client_.reset(new TestContentClient());
205 SetContentClient(content_client_.get());
206 old_browser_client_ = SetBrowserClientForTesting(host_.get());
209 virtual ~MediaStreamDispatcherHostTest() {
210 // Recover the old browser client and content client.
211 SetBrowserClientForTesting(old_browser_client_);
212 content_client_.reset();
213 media_stream_manager_->WillDestroyCurrentMessageLoop();
216 virtual void TearDown() OVERRIDE {
217 host_->OnChannelClosing();
221 virtual void SetupFakeUI(bool expect_started) {
222 scoped_ptr<MockMediaStreamUIProxy> stream_ui(new MockMediaStreamUIProxy());
223 if (expect_started) {
224 EXPECT_CALL(*stream_ui, OnStarted(_));
226 media_stream_manager_->UseFakeUI(
227 stream_ui.PassAs<FakeMediaStreamUIProxy>());
230 void GenerateStreamAndWaitForResult(int render_view_id,
232 const StreamOptions& options) {
233 base::RunLoop run_loop;
234 host_->OnGenerateStream(render_view_id, page_request_id, options,
235 run_loop.QuitClosure());
239 void OpenVideoDeviceAndWaitForResult(int render_view_id,
241 const std::string& device_id) {
242 base::RunLoop run_loop;
243 host_->OnOpenDevice(render_view_id, page_request_id, device_id,
244 MEDIA_DEVICE_VIDEO_CAPTURE,
245 run_loop.QuitClosure());
249 scoped_refptr<MockMediaStreamDispatcherHost> host_;
250 scoped_ptr<media::AudioManager> audio_manager_;
251 scoped_ptr<MediaStreamManager> media_stream_manager_;
252 ContentBrowserClient* old_browser_client_;
253 scoped_ptr<ContentClient> content_client_;
254 content::TestBrowserThreadBundle thread_bundle_;
257 TEST_F(MediaStreamDispatcherHostTest, GenerateStreamWithVideoOnly) {
258 StreamOptions options(MEDIA_NO_SERVICE, MEDIA_DEVICE_VIDEO_CAPTURE);
261 EXPECT_CALL(*host_.get(), OnStreamGenerated(kRenderId, kPageRequestId, 0, 1));
262 GenerateStreamAndWaitForResult(kRenderId, kPageRequestId, options);
264 EXPECT_EQ(host_->audio_devices_.size(), 0u);
265 EXPECT_EQ(host_->video_devices_.size(), 1u);
268 // This test generates two streams with video only using the same render view
269 // id. The same capture device with the same device and session id is expected
271 TEST_F(MediaStreamDispatcherHostTest, GenerateStreamsFromSameRenderId) {
272 StreamOptions options(MEDIA_NO_SERVICE, MEDIA_DEVICE_VIDEO_CAPTURE);
274 // Generate first stream.
276 EXPECT_CALL(*host_.get(), OnStreamGenerated(kRenderId, kPageRequestId, 0, 1));
277 GenerateStreamAndWaitForResult(kRenderId, kPageRequestId, options);
279 // Check the latest generated stream.
280 EXPECT_EQ(host_->audio_devices_.size(), 0u);
281 EXPECT_EQ(host_->video_devices_.size(), 1u);
282 const std::string label1 = host_->label_;
283 const std::string device_id1 = host_->video_devices_.front().device.id;
284 const int session_id1 = host_->video_devices_.front().session_id;
286 // Generate second stream.
288 EXPECT_CALL(*host_.get(),
289 OnStreamGenerated(kRenderId, kPageRequestId + 1, 0, 1));
290 GenerateStreamAndWaitForResult(kRenderId, kPageRequestId + 1, options);
292 // Check the latest generated stream.
293 EXPECT_EQ(host_->audio_devices_.size(), 0u);
294 EXPECT_EQ(host_->video_devices_.size(), 1u);
295 const std::string label2 = host_->label_;
296 const std::string device_id2 = host_->video_devices_.front().device.id;
297 int session_id2 = host_->video_devices_.front().session_id;
298 EXPECT_EQ(device_id1, device_id2);
299 EXPECT_EQ(session_id1, session_id2);
300 EXPECT_NE(label1, label2);
303 TEST_F(MediaStreamDispatcherHostTest,
304 GenerateStreamAndOpenDeviceFromSameRenderId) {
305 StreamOptions options(MEDIA_NO_SERVICE, MEDIA_DEVICE_VIDEO_CAPTURE);
307 // Generate first stream.
309 EXPECT_CALL(*host_.get(), OnStreamGenerated(kRenderId, kPageRequestId, 0, 1));
310 GenerateStreamAndWaitForResult(kRenderId, kPageRequestId, options);
312 EXPECT_EQ(host_->audio_devices_.size(), 0u);
313 EXPECT_EQ(host_->video_devices_.size(), 1u);
314 const std::string label1 = host_->label_;
315 const std::string device_id1 = host_->video_devices_.front().device.id;
316 const int session_id1 = host_->video_devices_.front().session_id;
318 // Generate second stream.
319 OpenVideoDeviceAndWaitForResult(kRenderId, kPageRequestId, device_id1);
321 const std::string device_id2 = host_->opened_device_.device.id;
322 const int session_id2 = host_->opened_device_.session_id;
323 const std::string label2 = host_->label_;
325 EXPECT_EQ(device_id1, device_id2);
326 EXPECT_NE(session_id1, session_id2);
327 EXPECT_NE(label1, label2);
331 // This test generates two streams with video only using two separate render
332 // view ids. The same device id but different session ids are expected.
333 TEST_F(MediaStreamDispatcherHostTest, GenerateStreamsDifferentRenderId) {
334 StreamOptions options(MEDIA_NO_SERVICE, MEDIA_DEVICE_VIDEO_CAPTURE);
336 // Generate first stream.
338 EXPECT_CALL(*host_.get(), OnStreamGenerated(kRenderId, kPageRequestId, 0, 1));
339 GenerateStreamAndWaitForResult(kRenderId, kPageRequestId, options);
341 // Check the latest generated stream.
342 EXPECT_EQ(host_->audio_devices_.size(), 0u);
343 EXPECT_EQ(host_->video_devices_.size(), 1u);
344 const std::string label1 = host_->label_;
345 const std::string device_id1 = host_->video_devices_.front().device.id;
346 const int session_id1 = host_->video_devices_.front().session_id;
348 // Generate second stream from another render view.
350 EXPECT_CALL(*host_.get(),
351 OnStreamGenerated(kRenderId+1, kPageRequestId + 1, 0, 1));
352 GenerateStreamAndWaitForResult(kRenderId+1, kPageRequestId + 1, options);
354 // Check the latest generated stream.
355 EXPECT_EQ(host_->audio_devices_.size(), 0u);
356 EXPECT_EQ(host_->video_devices_.size(), 1u);
357 const std::string label2 = host_->label_;
358 const std::string device_id2 = host_->video_devices_.front().device.id;
359 const int session_id2 = host_->video_devices_.front().session_id;
360 EXPECT_EQ(device_id1, device_id2);
361 EXPECT_NE(session_id1, session_id2);
362 EXPECT_NE(label1, label2);
365 // This test request two streams with video only without waiting for the first
366 // stream to be generated before requesting the second.
367 // The same device id and session ids are expected.
368 TEST_F(MediaStreamDispatcherHostTest, GenerateStreamsWithoutWaiting) {
369 StreamOptions options(MEDIA_NO_SERVICE, MEDIA_DEVICE_VIDEO_CAPTURE);
371 // Generate first stream.
373 EXPECT_CALL(*host_.get(), OnStreamGenerated(kRenderId, kPageRequestId, 0, 1));
375 // Generate second stream.
376 EXPECT_CALL(*host_.get(),
377 OnStreamGenerated(kRenderId, kPageRequestId + 1, 0, 1));
379 base::RunLoop run_loop1;
380 base::RunLoop run_loop2;
381 host_->OnGenerateStream(kRenderId, kPageRequestId, options,
382 run_loop1.QuitClosure());
383 host_->OnGenerateStream(kRenderId, kPageRequestId + 1, options,
384 run_loop2.QuitClosure());
390 TEST_F(MediaStreamDispatcherHostTest, StopDeviceInStream) {
391 StreamOptions options(MEDIA_NO_SERVICE, MEDIA_DEVICE_VIDEO_CAPTURE);
394 EXPECT_CALL(*host_.get(), OnStreamGenerated(kRenderId, kPageRequestId, 0, 1));
395 GenerateStreamAndWaitForResult(kRenderId, kPageRequestId, options);
397 const std::string device_id = host_->video_devices_.front().device.id;
398 const int session_id = host_->video_devices_.front().session_id;
399 StreamDeviceInfo video_device_info;
400 EXPECT_TRUE(host_->FindExistingRequestedDeviceInfo(device_id,
401 MEDIA_GENERATE_STREAM,
402 &video_device_info));
403 EXPECT_EQ(video_device_info.device.id, device_id);
404 EXPECT_EQ(video_device_info.session_id, session_id);
406 OpenVideoDeviceAndWaitForResult(kRenderId, kPageRequestId, device_id);
408 host_->OnStopStreamDevice(kRenderId, device_id);
410 EXPECT_FALSE(host_->FindExistingRequestedDeviceInfo(device_id,
411 MEDIA_GENERATE_STREAM,
412 &video_device_info));
413 EXPECT_TRUE(host_->FindExistingRequestedDeviceInfo(device_id,
415 &video_device_info));
418 TEST_F(MediaStreamDispatcherHostTest, CancelPendingStreamsOnChannelClosing) {
419 StreamOptions options(MEDIA_NO_SERVICE, MEDIA_DEVICE_VIDEO_CAPTURE);
421 base::RunLoop run_loop;
423 // Create multiple GenerateStream requests.
425 for (size_t i = 1; i <= streams; ++i) {
426 host_->OnGenerateStream(kRenderId, kPageRequestId + i, options,
427 run_loop.QuitClosure());
430 // Calling OnChannelClosing() to cancel all the pending requests.
431 host_->OnChannelClosing();
432 run_loop.RunUntilIdle();
435 TEST_F(MediaStreamDispatcherHostTest, StopGeneratedStreamsOnChannelClosing) {
436 StreamOptions options(MEDIA_NO_SERVICE, MEDIA_DEVICE_VIDEO_CAPTURE);
438 // Create first group of streams.
439 size_t generated_streams = 3;
440 for (size_t i = 0; i < generated_streams; ++i) {
442 EXPECT_CALL(*host_.get(),
443 OnStreamGenerated(kRenderId, kPageRequestId + i, 0, 1));
444 GenerateStreamAndWaitForResult(kRenderId, kPageRequestId + i, options);
447 // Calling OnChannelClosing() to cancel all the pending/generated streams.
448 host_->OnChannelClosing();
449 base::RunLoop().RunUntilIdle();
452 TEST_F(MediaStreamDispatcherHostTest, CloseFromUI) {
453 StreamOptions options(MEDIA_NO_SERVICE, MEDIA_DEVICE_VIDEO_CAPTURE);
455 base::Closure close_callback;
456 scoped_ptr<MockMediaStreamUIProxy> stream_ui(new MockMediaStreamUIProxy());
457 EXPECT_CALL(*stream_ui, OnStarted(_))
458 .WillOnce(SaveArg<0>(&close_callback));
459 media_stream_manager_->UseFakeUI(stream_ui.PassAs<FakeMediaStreamUIProxy>());
461 EXPECT_CALL(*host_.get(), OnStreamGenerated(kRenderId, kPageRequestId, 0, 1));
462 EXPECT_CALL(*host_.get(), OnStopGeneratedStreamFromBrowser(kRenderId));
463 GenerateStreamAndWaitForResult(kRenderId, kPageRequestId, options);
465 EXPECT_EQ(host_->audio_devices_.size(), 0u);
466 EXPECT_EQ(host_->video_devices_.size(), 1u);
468 ASSERT_FALSE(close_callback.is_null());
469 close_callback.Run();
470 base::RunLoop().RunUntilIdle();
473 }; // namespace content