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.
7 #include "base/memory/ref_counted.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "content/common/media/media_stream_messages.h"
12 #include "content/public/common/media_stream_request.h"
13 #include "content/renderer/media/media_stream_dispatcher.h"
14 #include "content/renderer/media/media_stream_dispatcher_eventhandler.h"
15 #include "media/audio/audio_parameters.h"
16 #include "testing/gtest/include/gtest/gtest.h"
22 const int kRouteId
= 0;
23 const int kAudioSessionId
= 3;
24 const int kVideoSessionId
= 5;
25 const int kRequestId1
= 10;
26 const int kRequestId2
= 20;
27 const int kRequestId3
= 30;
28 const int kRequestId4
= 40;
30 const MediaStreamType kAudioType
= MEDIA_DEVICE_AUDIO_CAPTURE
;
31 const MediaStreamType kVideoType
= MEDIA_DEVICE_VIDEO_CAPTURE
;
33 class MockMediaStreamDispatcherEventHandler
34 : public MediaStreamDispatcherEventHandler
,
35 public base::SupportsWeakPtr
<MockMediaStreamDispatcherEventHandler
> {
37 MockMediaStreamDispatcherEventHandler()
40 void OnStreamGenerated(
42 const std::string
& label
,
43 const StreamDeviceInfoArray
& audio_device_array
,
44 const StreamDeviceInfoArray
& video_device_array
) override
{
45 request_id_
= request_id
;
47 if (audio_device_array
.size()) {
48 DCHECK(audio_device_array
.size() == 1);
49 audio_device_
= audio_device_array
[0];
51 if (video_device_array
.size()) {
52 DCHECK(video_device_array
.size() == 1);
53 video_device_
= video_device_array
[0];
57 void OnStreamGenerationFailed(
59 content::MediaStreamRequestResult result
) override
{
60 request_id_
= request_id
;
63 void OnDeviceStopped(const std::string
& label
,
64 const StreamDeviceInfo
& device_info
) override
{
65 device_stopped_label_
= label
;
66 if (IsVideoMediaType(device_info
.device
.type
)) {
67 EXPECT_TRUE(StreamDeviceInfo::IsEqual(video_device_
, device_info
));
69 if (IsAudioInputMediaType(device_info
.device
.type
)) {
70 EXPECT_TRUE(StreamDeviceInfo::IsEqual(audio_device_
, device_info
));
74 void OnDevicesEnumerated(int request_id
,
75 const StreamDeviceInfoArray
& device_array
) override
{
76 request_id_
= request_id
;
79 void OnDeviceOpened(int request_id
,
80 const std::string
& label
,
81 const StreamDeviceInfo
& video_device
) override
{
82 request_id_
= request_id
;
86 void OnDeviceOpenFailed(int request_id
) override
{ request_id_
= request_id
; }
88 void ResetStoredParameters() {
91 device_stopped_label_
= "";
92 audio_device_
= StreamDeviceInfo();
93 video_device_
= StreamDeviceInfo();
98 std::string device_stopped_label_
;
99 StreamDeviceInfo audio_device_
;
100 StreamDeviceInfo video_device_
;
103 class MediaStreamDispatcherUnderTest
: public MediaStreamDispatcher
{
105 MediaStreamDispatcherUnderTest() : MediaStreamDispatcher(NULL
) {}
107 using MediaStreamDispatcher::GetNextIpcIdForTest
;
108 using RenderFrameObserver::OnMessageReceived
;
111 class MediaStreamDispatcherTest
: public ::testing::Test
{
113 MediaStreamDispatcherTest()
114 : dispatcher_(new MediaStreamDispatcherUnderTest()),
115 handler_(new MockMediaStreamDispatcherEventHandler
),
116 security_origin_("http://test.com"),
120 // Generates a request for a MediaStream and returns the request id that is
121 // used in IPC. Use this returned id in CompleteGenerateStream to identify
123 int GenerateStream(const StreamOptions
& options
, int request_id
) {
124 int next_ipc_id
= dispatcher_
->GetNextIpcIdForTest();
125 dispatcher_
->GenerateStream(request_id
, handler_
.get()->AsWeakPtr(),
126 options
, security_origin_
);
130 // CompleteGenerateStream create a MediaStreamMsg_StreamGenerated instance
131 // and call the MediaStreamDispathcer::OnMessageReceived. |ipc_id| must be the
132 // the id returned by GenerateStream.
133 std::string
CompleteGenerateStream(int ipc_id
, const StreamOptions
& options
,
135 StreamDeviceInfoArray
audio_device_array(options
.audio_requested
? 1 : 0);
136 if (options
.audio_requested
) {
137 StreamDeviceInfo audio_device_info
;
138 audio_device_info
.device
.name
= "Microphone";
139 audio_device_info
.device
.type
= kAudioType
;
140 audio_device_info
.session_id
= kAudioSessionId
;
141 audio_device_array
[0] = audio_device_info
;
144 StreamDeviceInfoArray
video_device_array(options
.video_requested
? 1 : 0);
145 if (options
.video_requested
) {
146 StreamDeviceInfo video_device_info
;
147 video_device_info
.device
.name
= "Camera";
148 video_device_info
.device
.type
= kVideoType
;
149 video_device_info
.session_id
= kVideoSessionId
;
150 video_device_array
[0] = video_device_info
;
153 std::string label
= "stream" + base::IntToString(ipc_id
);
155 handler_
->ResetStoredParameters();
156 dispatcher_
->OnMessageReceived(MediaStreamMsg_StreamGenerated(
157 kRouteId
, ipc_id
, label
,
158 audio_device_array
, video_device_array
));
160 EXPECT_EQ(handler_
->request_id_
, request_id
);
161 EXPECT_EQ(handler_
->label_
, label
);
163 if (options
.audio_requested
)
164 EXPECT_EQ(dispatcher_
->audio_session_id(label
, 0), kAudioSessionId
);
166 if (options
.video_requested
)
167 EXPECT_EQ(dispatcher_
->video_session_id(label
, 0), kVideoSessionId
);
173 base::MessageLoop message_loop_
;
174 scoped_ptr
<MediaStreamDispatcherUnderTest
> dispatcher_
;
175 scoped_ptr
<MockMediaStreamDispatcherEventHandler
> handler_
;
176 GURL security_origin_
;
182 TEST_F(MediaStreamDispatcherTest
, GenerateStreamAndStopDevices
) {
183 StreamOptions
options(true, true);
185 int ipc_request_id1
= GenerateStream(options
, kRequestId1
);
186 int ipc_request_id2
= GenerateStream(options
, kRequestId2
);
187 EXPECT_NE(ipc_request_id1
, ipc_request_id2
);
189 // Complete the creation of stream1.
190 const std::string
& label1
= CompleteGenerateStream(ipc_request_id1
, options
,
193 // Complete the creation of stream2.
194 const std::string
& label2
= CompleteGenerateStream(ipc_request_id2
, options
,
197 // Stop the actual audio device and verify that there is no valid
199 dispatcher_
->StopStreamDevice(handler_
->audio_device_
);
200 EXPECT_EQ(dispatcher_
->audio_session_id(label1
, 0),
201 StreamDeviceInfo::kNoId
);
202 EXPECT_EQ(dispatcher_
->audio_session_id(label2
, 0),
203 StreamDeviceInfo::kNoId
);
205 // Stop the actual video device and verify that there is no valid
207 dispatcher_
->StopStreamDevice(handler_
->video_device_
);
208 EXPECT_EQ(dispatcher_
->video_session_id(label1
, 0),
209 StreamDeviceInfo::kNoId
);
210 EXPECT_EQ(dispatcher_
->video_session_id(label2
, 0),
211 StreamDeviceInfo::kNoId
);
214 TEST_F(MediaStreamDispatcherTest
, BasicVideoDevice
) {
215 scoped_ptr
<MediaStreamDispatcher
> dispatcher(new MediaStreamDispatcher(NULL
));
216 scoped_ptr
<MockMediaStreamDispatcherEventHandler
>
217 handler1(new MockMediaStreamDispatcherEventHandler
);
218 scoped_ptr
<MockMediaStreamDispatcherEventHandler
>
219 handler2(new MockMediaStreamDispatcherEventHandler
);
220 GURL security_origin
;
222 int ipc_request_id1
= dispatcher
->next_ipc_id_
;
223 dispatcher
->EnumerateDevices(
224 kRequestId1
, handler1
.get()->AsWeakPtr(),
227 int ipc_request_id2
= dispatcher
->next_ipc_id_
;
228 EXPECT_NE(ipc_request_id1
, ipc_request_id2
);
229 dispatcher
->EnumerateDevices(
230 kRequestId2
, handler2
.get()->AsWeakPtr(),
233 EXPECT_EQ(dispatcher
->requests_
.size(), size_t(2));
235 StreamDeviceInfoArray
video_device_array(1);
236 StreamDeviceInfo video_device_info
;
237 video_device_info
.device
.name
= "Camera";
238 video_device_info
.device
.id
= "device_path";
239 video_device_info
.device
.type
= kVideoType
;
240 video_device_info
.session_id
= kVideoSessionId
;
241 video_device_array
[0] = video_device_info
;
243 // Complete the first enumeration request.
244 dispatcher
->OnMessageReceived(MediaStreamMsg_DevicesEnumerated(
245 kRouteId
, ipc_request_id1
, video_device_array
));
246 EXPECT_EQ(handler1
->request_id_
, kRequestId1
);
248 dispatcher
->OnMessageReceived(MediaStreamMsg_DevicesEnumerated(
249 kRouteId
, ipc_request_id2
, video_device_array
));
250 EXPECT_EQ(handler2
->request_id_
, kRequestId2
);
252 EXPECT_EQ(dispatcher
->requests_
.size(), size_t(2));
253 EXPECT_EQ(dispatcher
->label_stream_map_
.size(), size_t(0));
255 int ipc_request_id3
= dispatcher
->next_ipc_id_
;
256 dispatcher
->OpenDevice(kRequestId3
, handler1
.get()->AsWeakPtr(),
257 video_device_info
.device
.id
,
260 int ipc_request_id4
= dispatcher
->next_ipc_id_
;
261 EXPECT_NE(ipc_request_id3
, ipc_request_id4
);
262 dispatcher
->OpenDevice(kRequestId4
, handler1
.get()->AsWeakPtr(),
263 video_device_info
.device
.id
,
266 EXPECT_EQ(dispatcher
->requests_
.size(), size_t(4));
268 // Complete the OpenDevice of request 1.
269 std::string stream_label1
= std::string("stream1");
270 dispatcher
->OnMessageReceived(MediaStreamMsg_DeviceOpened(
271 kRouteId
, ipc_request_id3
, stream_label1
, video_device_info
));
272 EXPECT_EQ(handler1
->request_id_
, kRequestId3
);
274 // Complete the OpenDevice of request 2.
275 std::string stream_label2
= std::string("stream2");
276 dispatcher
->OnMessageReceived(MediaStreamMsg_DeviceOpened(
277 kRouteId
, ipc_request_id4
, stream_label2
, video_device_info
));
278 EXPECT_EQ(handler1
->request_id_
, kRequestId4
);
280 EXPECT_EQ(dispatcher
->requests_
.size(), size_t(2));
281 EXPECT_EQ(dispatcher
->label_stream_map_
.size(), size_t(2));
283 // Check the video_session_id.
284 EXPECT_EQ(dispatcher
->video_session_id(stream_label1
, 0), kVideoSessionId
);
285 EXPECT_EQ(dispatcher
->video_session_id(stream_label2
, 0), kVideoSessionId
);
287 // Close the device from request 2.
288 dispatcher
->CloseDevice(stream_label2
);
289 EXPECT_EQ(dispatcher
->video_session_id(stream_label2
, 0),
290 StreamDeviceInfo::kNoId
);
292 // Close the device from request 1.
293 dispatcher
->CloseDevice(stream_label1
);
294 EXPECT_EQ(dispatcher
->video_session_id(stream_label1
, 0),
295 StreamDeviceInfo::kNoId
);
296 EXPECT_EQ(dispatcher
->label_stream_map_
.size(), size_t(0));
298 // Verify that the request have been completed.
299 EXPECT_EQ(dispatcher
->label_stream_map_
.size(), size_t(0));
300 EXPECT_EQ(dispatcher
->requests_
.size(), size_t(2));
303 TEST_F(MediaStreamDispatcherTest
, TestFailure
) {
304 scoped_ptr
<MediaStreamDispatcher
> dispatcher(new MediaStreamDispatcher(NULL
));
305 scoped_ptr
<MockMediaStreamDispatcherEventHandler
>
306 handler(new MockMediaStreamDispatcherEventHandler
);
307 StreamOptions
components(true, true);
308 GURL security_origin
;
310 // Test failure when creating a stream.
311 int ipc_request_id1
= dispatcher
->next_ipc_id_
;
312 dispatcher
->GenerateStream(kRequestId1
, handler
.get()->AsWeakPtr(),
313 components
, security_origin
);
314 dispatcher
->OnMessageReceived(MediaStreamMsg_StreamGenerationFailed(
315 kRouteId
, ipc_request_id1
, MEDIA_DEVICE_PERMISSION_DENIED
));
317 // Verify that the request have been completed.
318 EXPECT_EQ(handler
->request_id_
, kRequestId1
);
319 EXPECT_EQ(dispatcher
->requests_
.size(), size_t(0));
321 // Create a new stream.
322 ipc_request_id1
= dispatcher
->next_ipc_id_
;
323 dispatcher
->GenerateStream(kRequestId1
, handler
.get()->AsWeakPtr(),
324 components
, security_origin
);
326 StreamDeviceInfoArray
audio_device_array(1);
327 StreamDeviceInfo audio_device_info
;
328 audio_device_info
.device
.name
= "Microphone";
329 audio_device_info
.device
.type
= kAudioType
;
330 audio_device_info
.session_id
= kAudioSessionId
;
331 audio_device_array
[0] = audio_device_info
;
333 StreamDeviceInfoArray
video_device_array(1);
334 StreamDeviceInfo video_device_info
;
335 video_device_info
.device
.name
= "Camera";
336 video_device_info
.device
.type
= kVideoType
;
337 video_device_info
.session_id
= kVideoSessionId
;
338 video_device_array
[0] = video_device_info
;
340 // Complete the creation of stream1.
341 std::string stream_label1
= std::string("stream1");
342 dispatcher
->OnMessageReceived(MediaStreamMsg_StreamGenerated(
343 kRouteId
, ipc_request_id1
, stream_label1
,
344 audio_device_array
, video_device_array
));
345 EXPECT_EQ(handler
->request_id_
, kRequestId1
);
346 EXPECT_EQ(handler
->label_
, stream_label1
);
347 EXPECT_EQ(dispatcher
->video_session_id(stream_label1
, 0), kVideoSessionId
);
350 TEST_F(MediaStreamDispatcherTest
, CancelGenerateStream
) {
351 scoped_ptr
<MediaStreamDispatcher
> dispatcher(new MediaStreamDispatcher(NULL
));
352 scoped_ptr
<MockMediaStreamDispatcherEventHandler
>
353 handler(new MockMediaStreamDispatcherEventHandler
);
354 StreamOptions
components(true, true);
355 int ipc_request_id1
= dispatcher
->next_ipc_id_
;
357 dispatcher
->GenerateStream(kRequestId1
, handler
.get()->AsWeakPtr(),
359 dispatcher
->GenerateStream(kRequestId2
, handler
.get()->AsWeakPtr(),
362 EXPECT_EQ(2u, dispatcher
->requests_
.size());
363 dispatcher
->CancelGenerateStream(kRequestId2
, handler
.get()->AsWeakPtr());
364 EXPECT_EQ(1u, dispatcher
->requests_
.size());
366 // Complete the creation of stream1.
367 StreamDeviceInfo audio_device_info
;
368 audio_device_info
.device
.name
= "Microphone";
369 audio_device_info
.device
.type
= kAudioType
;
370 audio_device_info
.session_id
= kAudioSessionId
;
371 StreamDeviceInfoArray
audio_device_array(1);
372 audio_device_array
[0] = audio_device_info
;
374 StreamDeviceInfo video_device_info
;
375 video_device_info
.device
.name
= "Camera";
376 video_device_info
.device
.type
= kVideoType
;
377 video_device_info
.session_id
= kVideoSessionId
;
378 StreamDeviceInfoArray
video_device_array(1);
379 video_device_array
[0] = video_device_info
;
381 std::string stream_label1
= "stream1";
382 dispatcher
->OnMessageReceived(MediaStreamMsg_StreamGenerated(
383 kRouteId
, ipc_request_id1
, stream_label1
,
384 audio_device_array
, video_device_array
));
385 EXPECT_EQ(handler
->request_id_
, kRequestId1
);
386 EXPECT_EQ(handler
->label_
, stream_label1
);
387 EXPECT_EQ(0u, dispatcher
->requests_
.size());
390 // Test that the MediaStreamDispatcherEventHandler is notified when the message
391 // MediaStreamMsg_DeviceStopped is received.
392 TEST_F(MediaStreamDispatcherTest
, DeviceClosed
) {
393 StreamOptions
options(true, true);
395 int ipc_request_id
= GenerateStream(options
, kRequestId1
);
396 const std::string
& label
= CompleteGenerateStream(ipc_request_id
, options
,
399 dispatcher_
->OnMessageReceived(
400 MediaStreamMsg_DeviceStopped(kRouteId
, label
, handler_
->video_device_
));
401 // Verify that MediaStreamDispatcherEventHandler::OnDeviceStopped has been
403 EXPECT_EQ(label
, handler_
->device_stopped_label_
);
404 EXPECT_EQ(dispatcher_
->video_session_id(label
, 0),
405 StreamDeviceInfo::kNoId
);
408 TEST_F(MediaStreamDispatcherTest
, CheckDuckingState
) {
409 scoped_ptr
<MediaStreamDispatcher
> dispatcher(new MediaStreamDispatcher(NULL
));
410 scoped_ptr
<MockMediaStreamDispatcherEventHandler
>
411 handler(new MockMediaStreamDispatcherEventHandler
);
412 StreamOptions
components(true, false); // audio only.
413 int ipc_request_id1
= dispatcher
->next_ipc_id_
;
415 dispatcher
->GenerateStream(kRequestId1
, handler
.get()->AsWeakPtr(),
417 EXPECT_EQ(1u, dispatcher
->requests_
.size());
419 // Ducking isn't active at this point.
420 EXPECT_FALSE(dispatcher
->IsAudioDuckingActive());
422 // Complete the creation of stream1 with a single audio track that has
424 StreamDeviceInfoArray
audio_device_array(1);
425 StreamDeviceInfo
& audio_device_info
= audio_device_array
[0];
426 audio_device_info
.device
.name
= "Microphone";
427 audio_device_info
.device
.type
= kAudioType
;
428 audio_device_info
.session_id
= kAudioSessionId
;
429 audio_device_info
.device
.input
.effects
= media::AudioParameters::DUCKING
;
431 StreamDeviceInfoArray video_device_array
; // Empty for this test.
433 const char kStreamLabel
[] = "stream1";
434 dispatcher
->OnMessageReceived(MediaStreamMsg_StreamGenerated(
435 kRouteId
, ipc_request_id1
, kStreamLabel
,
436 audio_device_array
, video_device_array
));
437 EXPECT_EQ(handler
->request_id_
, kRequestId1
);
438 EXPECT_EQ(0u, dispatcher
->requests_
.size());
440 // Ducking should now be reported as active.
441 EXPECT_TRUE(dispatcher
->IsAudioDuckingActive());
443 // Stop the device (removes the stream).
444 dispatcher
->OnMessageReceived(
445 MediaStreamMsg_DeviceStopped(kRouteId
, kStreamLabel
,
446 handler
->audio_device_
));
448 // Ducking should now be reported as inactive again.
449 EXPECT_FALSE(dispatcher
->IsAudioDuckingActive());
451 // Now do the same sort of test with the DUCKING flag off.
452 audio_device_info
.device
.input
.effects
=
453 media::AudioParameters::ECHO_CANCELLER
;
455 dispatcher
->OnMessageReceived(MediaStreamMsg_StreamGenerated(
456 kRouteId
, ipc_request_id1
, kStreamLabel
,
457 audio_device_array
, video_device_array
));
458 EXPECT_EQ(handler
->request_id_
, kRequestId1
);
459 EXPECT_EQ(0u, dispatcher
->requests_
.size());
461 // Ducking should still be reported as not active.
462 EXPECT_FALSE(dispatcher
->IsAudioDuckingActive());
464 // Stop the device (removes the stream).
465 dispatcher
->OnMessageReceived(
466 MediaStreamMsg_DeviceStopped(kRouteId
, kStreamLabel
,
467 handler
->audio_device_
));
470 } // namespace content