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. 4 5 #include <string> 6 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" 17 #include "url/gurl.h" 18 19 namespace content { 20 namespace { 21 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; 29 30 const MediaStreamType kAudioType = MEDIA_DEVICE_AUDIO_CAPTURE; 31 const MediaStreamType kVideoType = MEDIA_DEVICE_VIDEO_CAPTURE; 32 33 class MockMediaStreamDispatcherEventHandler 34 : public MediaStreamDispatcherEventHandler, 35 public base::SupportsWeakPtr<MockMediaStreamDispatcherEventHandler> { 36 public: 37 MockMediaStreamDispatcherEventHandler() 38 : request_id_(-1) {} 39 40 virtual void OnStreamGenerated( 41 int request_id, 42 const std::string &label, 43 const StreamDeviceInfoArray& audio_device_array, 44 const StreamDeviceInfoArray& video_device_array) OVERRIDE { 45 request_id_ = request_id; 46 label_ = label; 47 if (audio_device_array.size()) { 48 DCHECK(audio_device_array.size() == 1); 49 audio_device_ = audio_device_array[0]; 50 } 51 if (video_device_array.size()) { 52 DCHECK(video_device_array.size() == 1); 53 video_device_ = video_device_array[0]; 54 } 55 } 56 57 virtual void OnStreamGenerationFailed( 58 int request_id, 59 content::MediaStreamRequestResult result) OVERRIDE { 60 request_id_ = request_id; 61 } 62 63 virtual 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)); 68 } 69 if (IsAudioInputMediaType(device_info.device.type)) { 70 EXPECT_TRUE(StreamDeviceInfo::IsEqual(audio_device_, device_info)); 71 } 72 } 73 74 virtual void OnDevicesEnumerated( 75 int request_id, 76 const StreamDeviceInfoArray& device_array) OVERRIDE { 77 request_id_ = request_id; 78 } 79 80 virtual void OnDeviceOpened( 81 int request_id, 82 const std::string& label, 83 const StreamDeviceInfo& video_device) OVERRIDE { 84 request_id_ = request_id; 85 label_ = label; 86 } 87 88 virtual void OnDeviceOpenFailed(int request_id) OVERRIDE { 89 request_id_ = request_id; 90 } 91 92 void ResetStoredParameters() { 93 request_id_ = -1; 94 label_ = ""; 95 device_stopped_label_ = ""; 96 audio_device_ = StreamDeviceInfo(); 97 video_device_ = StreamDeviceInfo(); 98 } 99 100 int request_id_; 101 std::string label_; 102 std::string device_stopped_label_; 103 StreamDeviceInfo audio_device_; 104 StreamDeviceInfo video_device_; 105 }; 106 107 class MediaStreamDispatcherUnderTest : public MediaStreamDispatcher { 108 public: 109 MediaStreamDispatcherUnderTest() : MediaStreamDispatcher(NULL) {} 110 111 using MediaStreamDispatcher::GetNextIpcIdForTest; 112 using RenderFrameObserver::OnMessageReceived; 113 }; 114 115 class MediaStreamDispatcherTest : public ::testing::Test { 116 public: 117 MediaStreamDispatcherTest() 118 : dispatcher_(new MediaStreamDispatcherUnderTest()), 119 handler_(new MockMediaStreamDispatcherEventHandler), 120 security_origin_("http://test.com"), 121 request_id_(10) { 122 } 123 124 // Generates a request for a MediaStream and returns the request id that is 125 // used in IPC. Use this returned id in CompleteGenerateStream to identify 126 // the request. 127 int GenerateStream(const StreamOptions& options, int request_id) { 128 int next_ipc_id = dispatcher_->GetNextIpcIdForTest(); 129 dispatcher_->GenerateStream(request_id, handler_.get()->AsWeakPtr(), 130 options, security_origin_); 131 return next_ipc_id; 132 } 133 134 // CompleteGenerateStream create a MediaStreamMsg_StreamGenerated instance 135 // and call the MediaStreamDispathcer::OnMessageReceived. |ipc_id| must be the 136 // the id returned by GenerateStream. 137 std::string CompleteGenerateStream(int ipc_id, const StreamOptions& options, 138 int request_id) { 139 StreamDeviceInfoArray audio_device_array(options.audio_requested ? 1 : 0); 140 if (options.audio_requested) { 141 StreamDeviceInfo audio_device_info; 142 audio_device_info.device.name = "Microphone"; 143 audio_device_info.device.type = kAudioType; 144 audio_device_info.session_id = kAudioSessionId; 145 audio_device_array[0] = audio_device_info; 146 } 147 148 StreamDeviceInfoArray video_device_array(options.video_requested ? 1 : 0); 149 if (options.video_requested) { 150 StreamDeviceInfo video_device_info; 151 video_device_info.device.name = "Camera"; 152 video_device_info.device.type = kVideoType; 153 video_device_info.session_id = kVideoSessionId; 154 video_device_array[0] = video_device_info; 155 } 156 157 std::string label = "stream" + base::IntToString(ipc_id); 158 159 handler_->ResetStoredParameters(); 160 dispatcher_->OnMessageReceived(MediaStreamMsg_StreamGenerated( 161 kRouteId, ipc_id, label, 162 audio_device_array, video_device_array)); 163 164 EXPECT_EQ(handler_->request_id_, request_id); 165 EXPECT_EQ(handler_->label_, label); 166 167 if (options.audio_requested) 168 EXPECT_EQ(dispatcher_->audio_session_id(label, 0), kAudioSessionId); 169 170 if (options.video_requested) 171 EXPECT_EQ(dispatcher_->video_session_id(label, 0), kVideoSessionId); 172 173 return label; 174 } 175 176 protected: 177 base::MessageLoop message_loop_; 178 scoped_ptr<MediaStreamDispatcherUnderTest> dispatcher_; 179 scoped_ptr<MockMediaStreamDispatcherEventHandler> handler_; 180 GURL security_origin_; 181 int request_id_; 182 }; 183 184 } // namespace 185 186 TEST_F(MediaStreamDispatcherTest, GenerateStreamAndStopDevices) { 187 StreamOptions options(true, true); 188 189 int ipc_request_id1 = GenerateStream(options, kRequestId1); 190 int ipc_request_id2 = GenerateStream(options, kRequestId2); 191 EXPECT_NE(ipc_request_id1, ipc_request_id2); 192 193 // Complete the creation of stream1. 194 const std::string& label1 = CompleteGenerateStream(ipc_request_id1, options, 195 kRequestId1); 196 197 // Complete the creation of stream2. 198 const std::string& label2 = CompleteGenerateStream(ipc_request_id2, options, 199 kRequestId2); 200 201 // Stop the actual audio device and verify that there is no valid 202 // |session_id|. 203 dispatcher_->StopStreamDevice(handler_->audio_device_); 204 EXPECT_EQ(dispatcher_->audio_session_id(label1, 0), 205 StreamDeviceInfo::kNoId); 206 EXPECT_EQ(dispatcher_->audio_session_id(label2, 0), 207 StreamDeviceInfo::kNoId); 208 209 // Stop the actual video device and verify that there is no valid 210 // |session_id|. 211 dispatcher_->StopStreamDevice(handler_->video_device_); 212 EXPECT_EQ(dispatcher_->video_session_id(label1, 0), 213 StreamDeviceInfo::kNoId); 214 EXPECT_EQ(dispatcher_->video_session_id(label2, 0), 215 StreamDeviceInfo::kNoId); 216 } 217 218 TEST_F(MediaStreamDispatcherTest, BasicVideoDevice) { 219 scoped_ptr<MediaStreamDispatcher> dispatcher(new MediaStreamDispatcher(NULL)); 220 scoped_ptr<MockMediaStreamDispatcherEventHandler> 221 handler1(new MockMediaStreamDispatcherEventHandler); 222 scoped_ptr<MockMediaStreamDispatcherEventHandler> 223 handler2(new MockMediaStreamDispatcherEventHandler); 224 GURL security_origin; 225 226 int ipc_request_id1 = dispatcher->next_ipc_id_; 227 dispatcher->EnumerateDevices( 228 kRequestId1, handler1.get()->AsWeakPtr(), 229 kVideoType, 230 security_origin); 231 int ipc_request_id2 = dispatcher->next_ipc_id_; 232 EXPECT_NE(ipc_request_id1, ipc_request_id2); 233 dispatcher->EnumerateDevices( 234 kRequestId2, handler2.get()->AsWeakPtr(), 235 kVideoType, 236 security_origin); 237 EXPECT_EQ(dispatcher->requests_.size(), size_t(2)); 238 239 StreamDeviceInfoArray video_device_array(1); 240 StreamDeviceInfo video_device_info; 241 video_device_info.device.name = "Camera"; 242 video_device_info.device.id = "device_path"; 243 video_device_info.device.type = kVideoType; 244 video_device_info.session_id = kVideoSessionId; 245 video_device_array[0] = video_device_info; 246 247 // Complete the first enumeration request. 248 dispatcher->OnMessageReceived(MediaStreamMsg_DevicesEnumerated( 249 kRouteId, ipc_request_id1, video_device_array)); 250 EXPECT_EQ(handler1->request_id_, kRequestId1); 251 252 dispatcher->OnMessageReceived(MediaStreamMsg_DevicesEnumerated( 253 kRouteId, ipc_request_id2, video_device_array)); 254 EXPECT_EQ(handler2->request_id_, kRequestId2); 255 256 EXPECT_EQ(dispatcher->requests_.size(), size_t(2)); 257 EXPECT_EQ(dispatcher->label_stream_map_.size(), size_t(0)); 258 259 int ipc_request_id3 = dispatcher->next_ipc_id_; 260 dispatcher->OpenDevice(kRequestId3, handler1.get()->AsWeakPtr(), 261 video_device_info.device.id, 262 kVideoType, 263 security_origin); 264 int ipc_request_id4 = dispatcher->next_ipc_id_; 265 EXPECT_NE(ipc_request_id3, ipc_request_id4); 266 dispatcher->OpenDevice(kRequestId4, handler1.get()->AsWeakPtr(), 267 video_device_info.device.id, 268 kVideoType, 269 security_origin); 270 EXPECT_EQ(dispatcher->requests_.size(), size_t(4)); 271 272 // Complete the OpenDevice of request 1. 273 std::string stream_label1 = std::string("stream1"); 274 dispatcher->OnMessageReceived(MediaStreamMsg_DeviceOpened( 275 kRouteId, ipc_request_id3, stream_label1, video_device_info)); 276 EXPECT_EQ(handler1->request_id_, kRequestId3); 277 278 // Complete the OpenDevice of request 2. 279 std::string stream_label2 = std::string("stream2"); 280 dispatcher->OnMessageReceived(MediaStreamMsg_DeviceOpened( 281 kRouteId, ipc_request_id4, stream_label2, video_device_info)); 282 EXPECT_EQ(handler1->request_id_, kRequestId4); 283 284 EXPECT_EQ(dispatcher->requests_.size(), size_t(2)); 285 EXPECT_EQ(dispatcher->label_stream_map_.size(), size_t(2)); 286 287 // Check the video_session_id. 288 EXPECT_EQ(dispatcher->video_session_id(stream_label1, 0), kVideoSessionId); 289 EXPECT_EQ(dispatcher->video_session_id(stream_label2, 0), kVideoSessionId); 290 291 // Close the device from request 2. 292 dispatcher->CloseDevice(stream_label2); 293 EXPECT_EQ(dispatcher->video_session_id(stream_label2, 0), 294 StreamDeviceInfo::kNoId); 295 296 // Close the device from request 1. 297 dispatcher->CloseDevice(stream_label1); 298 EXPECT_EQ(dispatcher->video_session_id(stream_label1, 0), 299 StreamDeviceInfo::kNoId); 300 EXPECT_EQ(dispatcher->label_stream_map_.size(), size_t(0)); 301 302 // Verify that the request have been completed. 303 EXPECT_EQ(dispatcher->label_stream_map_.size(), size_t(0)); 304 EXPECT_EQ(dispatcher->requests_.size(), size_t(2)); 305 } 306 307 TEST_F(MediaStreamDispatcherTest, TestFailure) { 308 scoped_ptr<MediaStreamDispatcher> dispatcher(new MediaStreamDispatcher(NULL)); 309 scoped_ptr<MockMediaStreamDispatcherEventHandler> 310 handler(new MockMediaStreamDispatcherEventHandler); 311 StreamOptions components(true, true); 312 GURL security_origin; 313 314 // Test failure when creating a stream. 315 int ipc_request_id1 = dispatcher->next_ipc_id_; 316 dispatcher->GenerateStream(kRequestId1, handler.get()->AsWeakPtr(), 317 components, security_origin); 318 dispatcher->OnMessageReceived(MediaStreamMsg_StreamGenerationFailed( 319 kRouteId, ipc_request_id1, MEDIA_DEVICE_PERMISSION_DENIED)); 320 321 // Verify that the request have been completed. 322 EXPECT_EQ(handler->request_id_, kRequestId1); 323 EXPECT_EQ(dispatcher->requests_.size(), size_t(0)); 324 325 // Create a new stream. 326 ipc_request_id1 = dispatcher->next_ipc_id_; 327 dispatcher->GenerateStream(kRequestId1, handler.get()->AsWeakPtr(), 328 components, security_origin); 329 330 StreamDeviceInfoArray audio_device_array(1); 331 StreamDeviceInfo audio_device_info; 332 audio_device_info.device.name = "Microphone"; 333 audio_device_info.device.type = kAudioType; 334 audio_device_info.session_id = kAudioSessionId; 335 audio_device_array[0] = audio_device_info; 336 337 StreamDeviceInfoArray video_device_array(1); 338 StreamDeviceInfo video_device_info; 339 video_device_info.device.name = "Camera"; 340 video_device_info.device.type = kVideoType; 341 video_device_info.session_id = kVideoSessionId; 342 video_device_array[0] = video_device_info; 343 344 // Complete the creation of stream1. 345 std::string stream_label1 = std::string("stream1"); 346 dispatcher->OnMessageReceived(MediaStreamMsg_StreamGenerated( 347 kRouteId, ipc_request_id1, stream_label1, 348 audio_device_array, video_device_array)); 349 EXPECT_EQ(handler->request_id_, kRequestId1); 350 EXPECT_EQ(handler->label_, stream_label1); 351 EXPECT_EQ(dispatcher->video_session_id(stream_label1, 0), kVideoSessionId); 352 } 353 354 TEST_F(MediaStreamDispatcherTest, CancelGenerateStream) { 355 scoped_ptr<MediaStreamDispatcher> dispatcher(new MediaStreamDispatcher(NULL)); 356 scoped_ptr<MockMediaStreamDispatcherEventHandler> 357 handler(new MockMediaStreamDispatcherEventHandler); 358 StreamOptions components(true, true); 359 int ipc_request_id1 = dispatcher->next_ipc_id_; 360 361 dispatcher->GenerateStream(kRequestId1, handler.get()->AsWeakPtr(), 362 components, GURL()); 363 dispatcher->GenerateStream(kRequestId2, handler.get()->AsWeakPtr(), 364 components, GURL()); 365 366 EXPECT_EQ(2u, dispatcher->requests_.size()); 367 dispatcher->CancelGenerateStream(kRequestId2, handler.get()->AsWeakPtr()); 368 EXPECT_EQ(1u, dispatcher->requests_.size()); 369 370 // Complete the creation of stream1. 371 StreamDeviceInfo audio_device_info; 372 audio_device_info.device.name = "Microphone"; 373 audio_device_info.device.type = kAudioType; 374 audio_device_info.session_id = kAudioSessionId; 375 StreamDeviceInfoArray audio_device_array(1); 376 audio_device_array[0] = audio_device_info; 377 378 StreamDeviceInfo video_device_info; 379 video_device_info.device.name = "Camera"; 380 video_device_info.device.type = kVideoType; 381 video_device_info.session_id = kVideoSessionId; 382 StreamDeviceInfoArray video_device_array(1); 383 video_device_array[0] = video_device_info; 384 385 std::string stream_label1 = "stream1"; 386 dispatcher->OnMessageReceived(MediaStreamMsg_StreamGenerated( 387 kRouteId, ipc_request_id1, stream_label1, 388 audio_device_array, video_device_array)); 389 EXPECT_EQ(handler->request_id_, kRequestId1); 390 EXPECT_EQ(handler->label_, stream_label1); 391 EXPECT_EQ(0u, dispatcher->requests_.size()); 392 } 393 394 // Test that the MediaStreamDispatcherEventHandler is notified when the message 395 // MediaStreamMsg_DeviceStopped is received. 396 TEST_F(MediaStreamDispatcherTest, DeviceClosed) { 397 StreamOptions options(true, true); 398 399 int ipc_request_id = GenerateStream(options, kRequestId1); 400 const std::string& label = CompleteGenerateStream(ipc_request_id, options, 401 kRequestId1); 402 403 dispatcher_->OnMessageReceived( 404 MediaStreamMsg_DeviceStopped(kRouteId, label, handler_->video_device_)); 405 // Verify that MediaStreamDispatcherEventHandler::OnDeviceStopped has been 406 // called. 407 EXPECT_EQ(label, handler_->device_stopped_label_); 408 EXPECT_EQ(dispatcher_->video_session_id(label, 0), 409 StreamDeviceInfo::kNoId); 410 } 411 412 TEST_F(MediaStreamDispatcherTest, CheckDuckingState) { 413 scoped_ptr<MediaStreamDispatcher> dispatcher(new MediaStreamDispatcher(NULL)); 414 scoped_ptr<MockMediaStreamDispatcherEventHandler> 415 handler(new MockMediaStreamDispatcherEventHandler); 416 StreamOptions components(true, false); // audio only. 417 int ipc_request_id1 = dispatcher->next_ipc_id_; 418 419 dispatcher->GenerateStream(kRequestId1, handler.get()->AsWeakPtr(), 420 components, GURL()); 421 EXPECT_EQ(1u, dispatcher->requests_.size()); 422 423 // Ducking isn't active at this point. 424 EXPECT_FALSE(dispatcher->IsAudioDuckingActive()); 425 426 // Complete the creation of stream1 with a single audio track that has 427 // ducking enabled. 428 StreamDeviceInfoArray audio_device_array(1); 429 StreamDeviceInfo& audio_device_info = audio_device_array[0]; 430 audio_device_info.device.name = "Microphone"; 431 audio_device_info.device.type = kAudioType; 432 audio_device_info.session_id = kAudioSessionId; 433 audio_device_info.device.input.effects = media::AudioParameters::DUCKING; 434 435 StreamDeviceInfoArray video_device_array; // Empty for this test. 436 437 const char kStreamLabel[] = "stream1"; 438 dispatcher->OnMessageReceived(MediaStreamMsg_StreamGenerated( 439 kRouteId, ipc_request_id1, kStreamLabel, 440 audio_device_array, video_device_array)); 441 EXPECT_EQ(handler->request_id_, kRequestId1); 442 EXPECT_EQ(0u, dispatcher->requests_.size()); 443 444 // Ducking should now be reported as active. 445 EXPECT_TRUE(dispatcher->IsAudioDuckingActive()); 446 447 // Stop the device (removes the stream). 448 dispatcher->OnMessageReceived( 449 MediaStreamMsg_DeviceStopped(kRouteId, kStreamLabel, 450 handler->audio_device_)); 451 452 // Ducking should now be reported as inactive again. 453 EXPECT_FALSE(dispatcher->IsAudioDuckingActive()); 454 455 // Now do the same sort of test with the DUCKING flag off. 456 audio_device_info.device.input.effects = 457 media::AudioParameters::ECHO_CANCELLER; 458 459 dispatcher->OnMessageReceived(MediaStreamMsg_StreamGenerated( 460 kRouteId, ipc_request_id1, kStreamLabel, 461 audio_device_array, video_device_array)); 462 EXPECT_EQ(handler->request_id_, kRequestId1); 463 EXPECT_EQ(0u, dispatcher->requests_.size()); 464 465 // Ducking should still be reported as not active. 466 EXPECT_FALSE(dispatcher->IsAudioDuckingActive()); 467 468 // Stop the device (removes the stream). 469 dispatcher->OnMessageReceived( 470 MediaStreamMsg_DeviceStopped(kRouteId, kStreamLabel, 471 handler->audio_device_)); 472 } 473 474 } // namespace content 475