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// Unit test for VideoCaptureManager. 6 7#include <string> 8 9#include "base/bind.h" 10#include "base/memory/ref_counted.h" 11#include "base/memory/scoped_ptr.h" 12#include "base/message_loop/message_loop.h" 13#include "base/run_loop.h" 14#include "content/browser/browser_thread_impl.h" 15#include "content/browser/renderer_host/media/media_stream_provider.h" 16#include "content/browser/renderer_host/media/video_capture_controller_event_handler.h" 17#include "content/browser/renderer_host/media/video_capture_manager.h" 18#include "content/common/media/media_stream_options.h" 19#include "media/video/capture/fake_video_capture_device_factory.h" 20#include "testing/gmock/include/gmock/gmock.h" 21#include "testing/gtest/include/gtest/gtest.h" 22 23using ::testing::_; 24using ::testing::AnyNumber; 25using ::testing::InSequence; 26using ::testing::Return; 27using ::testing::SaveArg; 28 29namespace content { 30 31// Listener class used to track progress of VideoCaptureManager test. 32class MockMediaStreamProviderListener : public MediaStreamProviderListener { 33 public: 34 MockMediaStreamProviderListener() {} 35 ~MockMediaStreamProviderListener() {} 36 37 MOCK_METHOD2(Opened, void(MediaStreamType, int)); 38 MOCK_METHOD2(Closed, void(MediaStreamType, int)); 39 MOCK_METHOD2(DevicesEnumerated, void(MediaStreamType, 40 const StreamDeviceInfoArray&)); 41 MOCK_METHOD2(Aborted, void(MediaStreamType, int)); 42}; // class MockMediaStreamProviderListener 43 44// Needed as an input argument to StartCaptureForClient(). 45class MockFrameObserver : public VideoCaptureControllerEventHandler { 46 public: 47 MOCK_METHOD1(OnError, void(const VideoCaptureControllerID& id)); 48 49 virtual void OnBufferCreated(const VideoCaptureControllerID& id, 50 base::SharedMemoryHandle handle, 51 int length, int buffer_id) OVERRIDE {} 52 virtual void OnBufferDestroyed(const VideoCaptureControllerID& id, 53 int buffer_id) OVERRIDE {} 54 virtual void OnBufferReady(const VideoCaptureControllerID& id, 55 int buffer_id, 56 const media::VideoCaptureFormat& format, 57 const gfx::Rect& visible_rect, 58 base::TimeTicks timestamp) OVERRIDE {} 59 virtual void OnMailboxBufferReady(const VideoCaptureControllerID& id, 60 int buffer_id, 61 const gpu::MailboxHolder& mailbox_holder, 62 const media::VideoCaptureFormat& format, 63 base::TimeTicks timestamp) OVERRIDE {} 64 virtual void OnEnded(const VideoCaptureControllerID& id) OVERRIDE {} 65 66 void OnGotControllerCallback(VideoCaptureControllerID) {} 67}; 68 69// Test class 70class VideoCaptureManagerTest : public testing::Test { 71 public: 72 VideoCaptureManagerTest() : next_client_id_(1) {} 73 virtual ~VideoCaptureManagerTest() {} 74 75 protected: 76 virtual void SetUp() OVERRIDE { 77 listener_.reset(new MockMediaStreamProviderListener()); 78 message_loop_.reset(new base::MessageLoopForIO); 79 io_thread_.reset(new BrowserThreadImpl(BrowserThread::IO, 80 message_loop_.get())); 81 vcm_ = new VideoCaptureManager(scoped_ptr<media::VideoCaptureDeviceFactory>( 82 new media::FakeVideoCaptureDeviceFactory())); 83 video_capture_device_factory_ = 84 static_cast<media::FakeVideoCaptureDeviceFactory*>( 85 vcm_->video_capture_device_factory()); 86 const int32 kNumberOfFakeDevices = 2; 87 video_capture_device_factory_->set_number_of_devices(kNumberOfFakeDevices); 88 vcm_->Register(listener_.get(), message_loop_->message_loop_proxy().get()); 89 frame_observer_.reset(new MockFrameObserver()); 90 } 91 92 virtual void TearDown() OVERRIDE {} 93 94 void OnGotControllerCallback( 95 VideoCaptureControllerID id, 96 base::Closure quit_closure, 97 bool expect_success, 98 const base::WeakPtr<VideoCaptureController>& controller) { 99 if (expect_success) { 100 ASSERT_TRUE(controller); 101 ASSERT_TRUE(0 == controllers_.count(id)); 102 controllers_[id] = controller.get(); 103 } else { 104 ASSERT_TRUE(NULL == controller); 105 } 106 quit_closure.Run(); 107 } 108 109 VideoCaptureControllerID StartClient(int session_id, bool expect_success) { 110 media::VideoCaptureParams params; 111 params.requested_format = media::VideoCaptureFormat( 112 gfx::Size(320, 240), 30, media::PIXEL_FORMAT_I420); 113 114 VideoCaptureControllerID client_id(next_client_id_++); 115 base::RunLoop run_loop; 116 vcm_->StartCaptureForClient( 117 session_id, 118 params, 119 base::kNullProcessHandle, 120 client_id, 121 frame_observer_.get(), 122 base::Bind(&VideoCaptureManagerTest::OnGotControllerCallback, 123 base::Unretained(this), 124 client_id, 125 run_loop.QuitClosure(), 126 expect_success)); 127 run_loop.Run(); 128 return client_id; 129 } 130 131 void StopClient(VideoCaptureControllerID client_id) { 132 ASSERT_TRUE(1 == controllers_.count(client_id)); 133 vcm_->StopCaptureForClient(controllers_[client_id], client_id, 134 frame_observer_.get(), false); 135 controllers_.erase(client_id); 136 } 137 138 int next_client_id_; 139 std::map<VideoCaptureControllerID, VideoCaptureController*> controllers_; 140 scoped_refptr<VideoCaptureManager> vcm_; 141 scoped_ptr<MockMediaStreamProviderListener> listener_; 142 scoped_ptr<base::MessageLoop> message_loop_; 143 scoped_ptr<BrowserThreadImpl> io_thread_; 144 scoped_ptr<MockFrameObserver> frame_observer_; 145 media::FakeVideoCaptureDeviceFactory* video_capture_device_factory_; 146 147 private: 148 DISALLOW_COPY_AND_ASSIGN(VideoCaptureManagerTest); 149}; 150 151// Test cases 152 153// Try to open, start, stop and close a device. 154TEST_F(VideoCaptureManagerTest, CreateAndClose) { 155 StreamDeviceInfoArray devices; 156 157 InSequence s; 158 EXPECT_CALL(*listener_, DevicesEnumerated(MEDIA_DEVICE_VIDEO_CAPTURE, _)) 159 .WillOnce(SaveArg<1>(&devices)); 160 EXPECT_CALL(*listener_, Opened(MEDIA_DEVICE_VIDEO_CAPTURE, _)); 161 EXPECT_CALL(*listener_, Closed(MEDIA_DEVICE_VIDEO_CAPTURE, _)); 162 163 vcm_->EnumerateDevices(MEDIA_DEVICE_VIDEO_CAPTURE); 164 165 // Wait to get device callback. 166 message_loop_->RunUntilIdle(); 167 168 int video_session_id = vcm_->Open(devices.front()); 169 VideoCaptureControllerID client_id = StartClient(video_session_id, true); 170 171 StopClient(client_id); 172 vcm_->Close(video_session_id); 173 174 // Wait to check callbacks before removing the listener. 175 message_loop_->RunUntilIdle(); 176 vcm_->Unregister(); 177} 178 179// Try to open, start, and abort a device. 180TEST_F(VideoCaptureManagerTest, CreateAndAbort) { 181 StreamDeviceInfoArray devices; 182 183 InSequence s; 184 EXPECT_CALL(*listener_, DevicesEnumerated(MEDIA_DEVICE_VIDEO_CAPTURE, _)) 185 .WillOnce(SaveArg<1>(&devices)); 186 EXPECT_CALL(*listener_, Opened(MEDIA_DEVICE_VIDEO_CAPTURE, _)); 187 EXPECT_CALL(*listener_, Aborted(MEDIA_DEVICE_VIDEO_CAPTURE, _)); 188 189 vcm_->EnumerateDevices(MEDIA_DEVICE_VIDEO_CAPTURE); 190 191 // Wait to get device callback. 192 message_loop_->RunUntilIdle(); 193 194 int video_session_id = vcm_->Open(devices.front()); 195 VideoCaptureControllerID client_id = StartClient(video_session_id, true); 196 197 // Wait for device opened. 198 message_loop_->RunUntilIdle(); 199 200 vcm_->StopCaptureForClient(controllers_[client_id], client_id, 201 frame_observer_.get(), true); 202 203 // Wait to check callbacks before removing the listener. 204 message_loop_->RunUntilIdle(); 205 vcm_->Unregister(); 206} 207 208// Open the same device twice. 209TEST_F(VideoCaptureManagerTest, OpenTwice) { 210 StreamDeviceInfoArray devices; 211 212 InSequence s; 213 EXPECT_CALL(*listener_, DevicesEnumerated(MEDIA_DEVICE_VIDEO_CAPTURE, _)) 214 .WillOnce(SaveArg<1>(&devices)); 215 EXPECT_CALL(*listener_, Opened(MEDIA_DEVICE_VIDEO_CAPTURE, _)).Times(2); 216 EXPECT_CALL(*listener_, Closed(MEDIA_DEVICE_VIDEO_CAPTURE, _)).Times(2); 217 218 vcm_->EnumerateDevices(MEDIA_DEVICE_VIDEO_CAPTURE); 219 220 // Wait to get device callback. 221 message_loop_->RunUntilIdle(); 222 223 int video_session_id_first = vcm_->Open(devices.front()); 224 225 // This should trigger an error callback with error code 226 // 'kDeviceAlreadyInUse'. 227 int video_session_id_second = vcm_->Open(devices.front()); 228 EXPECT_NE(video_session_id_first, video_session_id_second); 229 230 vcm_->Close(video_session_id_first); 231 vcm_->Close(video_session_id_second); 232 233 // Wait to check callbacks before removing the listener. 234 message_loop_->RunUntilIdle(); 235 vcm_->Unregister(); 236} 237 238// Connect and disconnect devices. 239TEST_F(VideoCaptureManagerTest, ConnectAndDisconnectDevices) { 240 StreamDeviceInfoArray devices; 241 int number_of_devices_keep = 242 video_capture_device_factory_->number_of_devices(); 243 244 InSequence s; 245 EXPECT_CALL(*listener_, DevicesEnumerated(MEDIA_DEVICE_VIDEO_CAPTURE, _)) 246 .WillOnce(SaveArg<1>(&devices)); 247 vcm_->EnumerateDevices(MEDIA_DEVICE_VIDEO_CAPTURE); 248 message_loop_->RunUntilIdle(); 249 ASSERT_EQ(devices.size(), 2u); 250 251 // Simulate we remove 1 fake device. 252 video_capture_device_factory_->set_number_of_devices(1); 253 EXPECT_CALL(*listener_, DevicesEnumerated(MEDIA_DEVICE_VIDEO_CAPTURE, _)) 254 .WillOnce(SaveArg<1>(&devices)); 255 vcm_->EnumerateDevices(MEDIA_DEVICE_VIDEO_CAPTURE); 256 message_loop_->RunUntilIdle(); 257 ASSERT_EQ(devices.size(), 1u); 258 259 // Simulate we add 2 fake devices. 260 video_capture_device_factory_->set_number_of_devices(3); 261 EXPECT_CALL(*listener_, DevicesEnumerated(MEDIA_DEVICE_VIDEO_CAPTURE, _)) 262 .WillOnce(SaveArg<1>(&devices)); 263 vcm_->EnumerateDevices(MEDIA_DEVICE_VIDEO_CAPTURE); 264 message_loop_->RunUntilIdle(); 265 ASSERT_EQ(devices.size(), 3u); 266 267 vcm_->Unregister(); 268 video_capture_device_factory_->set_number_of_devices(number_of_devices_keep); 269} 270 271// Enumerate devices and open the first, then check the list of supported 272// formats. Then start the opened device. The capability list should stay the 273// same. Finally stop the device and check that the capabilities stay unchanged. 274TEST_F(VideoCaptureManagerTest, ManipulateDeviceAndCheckCapabilities) { 275 StreamDeviceInfoArray devices; 276 277 // Before enumerating the devices, requesting formats should return false. 278 int video_session_id = 0; 279 media::VideoCaptureFormats supported_formats; 280 supported_formats.clear(); 281 EXPECT_FALSE( 282 vcm_->GetDeviceSupportedFormats(video_session_id, &supported_formats)); 283 284 InSequence s; 285 EXPECT_CALL(*listener_, DevicesEnumerated(MEDIA_DEVICE_VIDEO_CAPTURE, _)) 286 .WillOnce(SaveArg<1>(&devices)); 287 vcm_->EnumerateDevices(MEDIA_DEVICE_VIDEO_CAPTURE); 288 message_loop_->RunUntilIdle(); 289 ASSERT_GE(devices.size(), 2u); 290 291 EXPECT_CALL(*listener_, Opened(MEDIA_DEVICE_VIDEO_CAPTURE, _)); 292 video_session_id = vcm_->Open(devices.front()); 293 message_loop_->RunUntilIdle(); 294 295 // Right after opening the device, we should see all its formats. 296 supported_formats.clear(); 297 EXPECT_TRUE( 298 vcm_->GetDeviceSupportedFormats(video_session_id, &supported_formats)); 299 ASSERT_GT(supported_formats.size(), 1u); 300 EXPECT_GT(supported_formats[0].frame_size.width(), 1); 301 EXPECT_GT(supported_formats[0].frame_size.height(), 1); 302 EXPECT_GT(supported_formats[0].frame_rate, 1); 303 EXPECT_GT(supported_formats[1].frame_size.width(), 1); 304 EXPECT_GT(supported_formats[1].frame_size.height(), 1); 305 EXPECT_GT(supported_formats[1].frame_rate, 1); 306 307 VideoCaptureControllerID client_id = StartClient(video_session_id, true); 308 message_loop_->RunUntilIdle(); 309 // After StartClient(), device's supported formats should stay the same. 310 supported_formats.clear(); 311 EXPECT_TRUE( 312 vcm_->GetDeviceSupportedFormats(video_session_id, &supported_formats)); 313 ASSERT_GE(supported_formats.size(), 2u); 314 EXPECT_GT(supported_formats[0].frame_size.width(), 1); 315 EXPECT_GT(supported_formats[0].frame_size.height(), 1); 316 EXPECT_GT(supported_formats[0].frame_rate, 1); 317 EXPECT_GT(supported_formats[1].frame_size.width(), 1); 318 EXPECT_GT(supported_formats[1].frame_size.height(), 1); 319 EXPECT_GT(supported_formats[1].frame_rate, 1); 320 321 EXPECT_CALL(*listener_, Closed(MEDIA_DEVICE_VIDEO_CAPTURE, _)); 322 StopClient(client_id); 323 supported_formats.clear(); 324 EXPECT_TRUE( 325 vcm_->GetDeviceSupportedFormats(video_session_id, &supported_formats)); 326 ASSERT_GE(supported_formats.size(), 2u); 327 EXPECT_GT(supported_formats[0].frame_size.width(), 1); 328 EXPECT_GT(supported_formats[0].frame_size.height(), 1); 329 EXPECT_GT(supported_formats[0].frame_rate, 1); 330 EXPECT_GT(supported_formats[1].frame_size.width(), 1); 331 EXPECT_GT(supported_formats[1].frame_size.height(), 1); 332 EXPECT_GT(supported_formats[1].frame_rate, 1); 333 334 vcm_->Close(video_session_id); 335 message_loop_->RunUntilIdle(); 336 vcm_->Unregister(); 337} 338 339// Enumerate devices and open the first, then check the formats currently in 340// use, which should be an empty vector. Then start the opened device. The 341// format(s) in use should be just one format (the one used when configuring- 342// starting the device). Finally stop the device and check that the formats in 343// use is an empty vector. 344TEST_F(VideoCaptureManagerTest, StartDeviceAndGetDeviceFormatInUse) { 345 StreamDeviceInfoArray devices; 346 347 InSequence s; 348 EXPECT_CALL(*listener_, DevicesEnumerated(MEDIA_DEVICE_VIDEO_CAPTURE, _)) 349 .WillOnce(SaveArg<1>(&devices)); 350 vcm_->EnumerateDevices(MEDIA_DEVICE_VIDEO_CAPTURE); 351 message_loop_->RunUntilIdle(); 352 ASSERT_GE(devices.size(), 2u); 353 354 EXPECT_CALL(*listener_, Opened(MEDIA_DEVICE_VIDEO_CAPTURE, _)); 355 int video_session_id = vcm_->Open(devices.front()); 356 message_loop_->RunUntilIdle(); 357 358 // Right after opening the device, we should see no format in use. 359 media::VideoCaptureFormats formats_in_use; 360 EXPECT_TRUE(vcm_->GetDeviceFormatsInUse(video_session_id, &formats_in_use)); 361 EXPECT_TRUE(formats_in_use.empty()); 362 363 VideoCaptureControllerID client_id = StartClient(video_session_id, true); 364 message_loop_->RunUntilIdle(); 365 // After StartClient(), |formats_in_use| should contain one valid format. 366 EXPECT_TRUE(vcm_->GetDeviceFormatsInUse(video_session_id, &formats_in_use)); 367 EXPECT_EQ(formats_in_use.size(), 1u); 368 if (formats_in_use.size()) { 369 media::VideoCaptureFormat& format_in_use = formats_in_use.front(); 370 EXPECT_TRUE(format_in_use.IsValid()); 371 EXPECT_GT(format_in_use.frame_size.width(), 1); 372 EXPECT_GT(format_in_use.frame_size.height(), 1); 373 EXPECT_GT(format_in_use.frame_rate, 1); 374 } 375 formats_in_use.clear(); 376 377 EXPECT_CALL(*listener_, Closed(MEDIA_DEVICE_VIDEO_CAPTURE, _)); 378 StopClient(client_id); 379 message_loop_->RunUntilIdle(); 380 // After StopClient(), the device's formats in use should be empty again. 381 EXPECT_TRUE(vcm_->GetDeviceFormatsInUse(video_session_id, &formats_in_use)); 382 EXPECT_TRUE(formats_in_use.empty()); 383 384 vcm_->Close(video_session_id); 385 message_loop_->RunUntilIdle(); 386 vcm_->Unregister(); 387} 388 389// Open two different devices. 390TEST_F(VideoCaptureManagerTest, OpenTwo) { 391 StreamDeviceInfoArray devices; 392 393 InSequence s; 394 EXPECT_CALL(*listener_, DevicesEnumerated(MEDIA_DEVICE_VIDEO_CAPTURE, _)) 395 .WillOnce(SaveArg<1>(&devices)); 396 EXPECT_CALL(*listener_, Opened(MEDIA_DEVICE_VIDEO_CAPTURE, _)).Times(2); 397 EXPECT_CALL(*listener_, Closed(MEDIA_DEVICE_VIDEO_CAPTURE, _)).Times(2); 398 399 vcm_->EnumerateDevices(MEDIA_DEVICE_VIDEO_CAPTURE); 400 401 // Wait to get device callback. 402 message_loop_->RunUntilIdle(); 403 404 StreamDeviceInfoArray::iterator it = devices.begin(); 405 406 int video_session_id_first = vcm_->Open(*it); 407 ++it; 408 int video_session_id_second = vcm_->Open(*it); 409 410 vcm_->Close(video_session_id_first); 411 vcm_->Close(video_session_id_second); 412 413 // Wait to check callbacks before removing the listener. 414 message_loop_->RunUntilIdle(); 415 vcm_->Unregister(); 416} 417 418// Try open a non-existing device. 419TEST_F(VideoCaptureManagerTest, OpenNotExisting) { 420 StreamDeviceInfoArray devices; 421 422 InSequence s; 423 EXPECT_CALL(*listener_, DevicesEnumerated(MEDIA_DEVICE_VIDEO_CAPTURE, _)) 424 .WillOnce(SaveArg<1>(&devices)); 425 EXPECT_CALL(*listener_, Opened(MEDIA_DEVICE_VIDEO_CAPTURE, _)); 426 EXPECT_CALL(*frame_observer_, OnError(_)); 427 EXPECT_CALL(*listener_, Closed(MEDIA_DEVICE_VIDEO_CAPTURE, _)); 428 429 vcm_->EnumerateDevices(MEDIA_DEVICE_VIDEO_CAPTURE); 430 431 // Wait to get device callback. 432 message_loop_->RunUntilIdle(); 433 434 MediaStreamType stream_type = MEDIA_DEVICE_VIDEO_CAPTURE; 435 std::string device_name("device_doesnt_exist"); 436 std::string device_id("id_doesnt_exist"); 437 StreamDeviceInfo dummy_device(stream_type, device_name, device_id); 438 439 // This should fail with an error to the controller. 440 int session_id = vcm_->Open(dummy_device); 441 VideoCaptureControllerID client_id = StartClient(session_id, true); 442 message_loop_->RunUntilIdle(); 443 444 StopClient(client_id); 445 vcm_->Close(session_id); 446 message_loop_->RunUntilIdle(); 447 448 vcm_->Unregister(); 449} 450 451// Start a device without calling Open, using a non-magic ID. 452TEST_F(VideoCaptureManagerTest, StartInvalidSession) { 453 StartClient(22, false); 454 455 // Wait to check callbacks before removing the listener. 456 message_loop_->RunUntilIdle(); 457 vcm_->Unregister(); 458} 459 460// Open and start a device, close it before calling Stop. 461TEST_F(VideoCaptureManagerTest, CloseWithoutStop) { 462 StreamDeviceInfoArray devices; 463 464 InSequence s; 465 EXPECT_CALL(*listener_, DevicesEnumerated(MEDIA_DEVICE_VIDEO_CAPTURE, _)) 466 .WillOnce(SaveArg<1>(&devices)); 467 EXPECT_CALL(*listener_, Opened(MEDIA_DEVICE_VIDEO_CAPTURE, _)); 468 EXPECT_CALL(*listener_, Closed(MEDIA_DEVICE_VIDEO_CAPTURE, _)); 469 470 vcm_->EnumerateDevices(MEDIA_DEVICE_VIDEO_CAPTURE); 471 472 // Wait to get device callback. 473 message_loop_->RunUntilIdle(); 474 475 int video_session_id = vcm_->Open(devices.front()); 476 477 VideoCaptureControllerID client_id = StartClient(video_session_id, true); 478 479 // Close will stop the running device, an assert will be triggered in 480 // VideoCaptureManager destructor otherwise. 481 vcm_->Close(video_session_id); 482 StopClient(client_id); 483 484 // Wait to check callbacks before removing the listener 485 message_loop_->RunUntilIdle(); 486 vcm_->Unregister(); 487} 488 489// TODO(mcasas): Add a test to check consolidation of the supported formats 490// provided by the device when http://crbug.com/323913 is closed. 491 492} // namespace content 493