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 VideoCaptureController. 6 7 #include <string> 8 9 #include "base/bind.h" 10 #include "base/bind_helpers.h" 11 #include "base/memory/ref_counted.h" 12 #include "base/memory/scoped_ptr.h" 13 #include "base/message_loop/message_loop.h" 14 #include "base/run_loop.h" 15 #include "content/browser/renderer_host/media/media_stream_provider.h" 16 #include "content/browser/renderer_host/media/video_capture_controller.h" 17 #include "content/browser/renderer_host/media/video_capture_controller_event_handler.h" 18 #include "content/browser/renderer_host/media/video_capture_manager.h" 19 #include "content/common/media/media_stream_options.h" 20 #include "content/public/test/test_browser_thread_bundle.h" 21 #include "gpu/command_buffer/common/mailbox_holder.h" 22 #include "media/base/video_util.h" 23 #include "media/video/capture/video_capture_types.h" 24 #include "testing/gmock/include/gmock/gmock.h" 25 #include "testing/gtest/include/gtest/gtest.h" 26 27 using ::testing::InSequence; 28 using ::testing::Mock; 29 30 namespace content { 31 32 class MockVideoCaptureControllerEventHandler 33 : public VideoCaptureControllerEventHandler { 34 public: 35 explicit MockVideoCaptureControllerEventHandler( 36 VideoCaptureController* controller) 37 : controller_(controller) {} 38 virtual ~MockVideoCaptureControllerEventHandler() {} 39 40 // These mock methods are delegated to by our fake implementation of 41 // VideoCaptureControllerEventHandler, to be used in EXPECT_CALL(). 42 MOCK_METHOD1(DoBufferCreated, void(const VideoCaptureControllerID&)); 43 MOCK_METHOD1(DoBufferDestroyed, void(const VideoCaptureControllerID&)); 44 MOCK_METHOD1(DoBufferReady, void(const VideoCaptureControllerID&)); 45 MOCK_METHOD1(DoMailboxBufferReady, void(const VideoCaptureControllerID&)); 46 MOCK_METHOD1(DoEnded, void(const VideoCaptureControllerID&)); 47 MOCK_METHOD1(DoError, void(const VideoCaptureControllerID&)); 48 49 virtual void OnError(const VideoCaptureControllerID& id) OVERRIDE { 50 DoError(id); 51 } 52 virtual void OnBufferCreated(const VideoCaptureControllerID& id, 53 base::SharedMemoryHandle handle, 54 int length, int buffer_id) OVERRIDE { 55 DoBufferCreated(id); 56 } 57 virtual void OnBufferDestroyed(const VideoCaptureControllerID& id, 58 int buffer_id) OVERRIDE { 59 DoBufferDestroyed(id); 60 } 61 virtual void OnBufferReady(const VideoCaptureControllerID& id, 62 int buffer_id, 63 const media::VideoCaptureFormat& format, 64 base::TimeTicks timestamp) OVERRIDE { 65 DoBufferReady(id); 66 base::MessageLoop::current()->PostTask( 67 FROM_HERE, 68 base::Bind(&VideoCaptureController::ReturnBuffer, 69 base::Unretained(controller_), 70 id, 71 this, 72 buffer_id, 73 std::vector<uint32>())); 74 } 75 virtual void OnMailboxBufferReady(const VideoCaptureControllerID& id, 76 int buffer_id, 77 const gpu::MailboxHolder& mailbox_holder, 78 const media::VideoCaptureFormat& format, 79 base::TimeTicks timestamp) OVERRIDE { 80 DoMailboxBufferReady(id); 81 // Use a very different syncpoint value when returning a new syncpoint. 82 std::vector<uint32> release_sync_points; 83 release_sync_points.push_back(~mailbox_holder.sync_point); 84 base::MessageLoop::current()->PostTask( 85 FROM_HERE, 86 base::Bind(&VideoCaptureController::ReturnBuffer, 87 base::Unretained(controller_), 88 id, 89 this, 90 buffer_id, 91 release_sync_points)); 92 } 93 virtual void OnEnded(const VideoCaptureControllerID& id) OVERRIDE { 94 DoEnded(id); 95 // OnEnded() must respond by (eventually) unregistering the client. 96 base::MessageLoop::current()->PostTask(FROM_HERE, 97 base::Bind(base::IgnoreResult(&VideoCaptureController::RemoveClient), 98 base::Unretained(controller_), id, this)); 99 } 100 101 VideoCaptureController* controller_; 102 }; 103 104 // Test class. 105 class VideoCaptureControllerTest : public testing::Test { 106 public: 107 VideoCaptureControllerTest() {} 108 virtual ~VideoCaptureControllerTest() {} 109 110 protected: 111 static const int kPoolSize = 3; 112 113 virtual void SetUp() OVERRIDE { 114 controller_.reset(new VideoCaptureController()); 115 device_ = controller_->NewDeviceClient().Pass(); 116 client_a_.reset(new MockVideoCaptureControllerEventHandler( 117 controller_.get())); 118 client_b_.reset(new MockVideoCaptureControllerEventHandler( 119 controller_.get())); 120 } 121 122 virtual void TearDown() OVERRIDE { 123 base::RunLoop().RunUntilIdle(); 124 } 125 126 scoped_refptr<media::VideoFrame> WrapI420Buffer( 127 const scoped_refptr<media::VideoCaptureDevice::Client::Buffer>& buffer, 128 gfx::Size dimensions) { 129 return media::VideoFrame::WrapExternalPackedMemory( 130 media::VideoFrame::I420, 131 dimensions, 132 gfx::Rect(dimensions), 133 dimensions, 134 reinterpret_cast<uint8*>(buffer->data()), 135 media::VideoFrame::AllocationSize(media::VideoFrame::I420, dimensions), 136 base::SharedMemory::NULLHandle(), 137 base::TimeDelta(), 138 base::Closure()); 139 } 140 141 scoped_refptr<media::VideoFrame> WrapMailboxBuffer( 142 const scoped_refptr<media::VideoCaptureDevice::Client::Buffer>& buffer, 143 scoped_ptr<gpu::MailboxHolder> holder, 144 const media::VideoFrame::ReleaseMailboxCB& release_cb, 145 gfx::Size dimensions) { 146 return media::VideoFrame::WrapNativeTexture( 147 holder.Pass(), 148 release_cb, 149 dimensions, 150 gfx::Rect(dimensions), 151 dimensions, 152 base::TimeDelta(), 153 media::VideoFrame::ReadPixelsCB()); 154 } 155 156 TestBrowserThreadBundle bundle_; 157 scoped_ptr<MockVideoCaptureControllerEventHandler> client_a_; 158 scoped_ptr<MockVideoCaptureControllerEventHandler> client_b_; 159 scoped_ptr<VideoCaptureController> controller_; 160 scoped_ptr<media::VideoCaptureDevice::Client> device_; 161 162 private: 163 DISALLOW_COPY_AND_ASSIGN(VideoCaptureControllerTest); 164 }; 165 166 // A simple test of VideoCaptureController's ability to add, remove, and keep 167 // track of clients. 168 TEST_F(VideoCaptureControllerTest, AddAndRemoveClients) { 169 media::VideoCaptureParams session_100; 170 session_100.requested_format = media::VideoCaptureFormat( 171 gfx::Size(320, 240), 30, media::PIXEL_FORMAT_I420); 172 media::VideoCaptureParams session_200 = session_100; 173 174 media::VideoCaptureParams session_300 = session_100; 175 176 media::VideoCaptureParams session_400 = session_100; 177 178 // Intentionally use the same route ID for two of the clients: the device_ids 179 // are a per-VideoCaptureHost namespace, and can overlap across hosts. 180 const VideoCaptureControllerID client_a_route_1(44); 181 const VideoCaptureControllerID client_a_route_2(30); 182 const VideoCaptureControllerID client_b_route_1(30); 183 const VideoCaptureControllerID client_b_route_2(1); 184 185 // Clients in controller: [] 186 ASSERT_EQ(0, controller_->GetClientCount()) 187 << "Client count should initially be zero."; 188 controller_->AddClient(client_a_route_1, 189 client_a_.get(), 190 base::kNullProcessHandle, 191 100, 192 session_100); 193 // Clients in controller: [A/1] 194 ASSERT_EQ(1, controller_->GetClientCount()) 195 << "Adding client A/1 should bump client count."; 196 controller_->AddClient(client_a_route_2, 197 client_a_.get(), 198 base::kNullProcessHandle, 199 200, 200 session_200); 201 // Clients in controller: [A/1, A/2] 202 ASSERT_EQ(2, controller_->GetClientCount()) 203 << "Adding client A/2 should bump client count."; 204 controller_->AddClient(client_b_route_1, 205 client_b_.get(), 206 base::kNullProcessHandle, 207 300, 208 session_300); 209 // Clients in controller: [A/1, A/2, B/1] 210 ASSERT_EQ(3, controller_->GetClientCount()) 211 << "Adding client B/1 should bump client count."; 212 ASSERT_EQ(200, 213 controller_->RemoveClient(client_a_route_2, client_a_.get())) 214 << "Removing client A/1 should return its session_id."; 215 // Clients in controller: [A/1, B/1] 216 ASSERT_EQ(2, controller_->GetClientCount()); 217 ASSERT_EQ(static_cast<int>(kInvalidMediaCaptureSessionId), 218 controller_->RemoveClient(client_a_route_2, client_a_.get())) 219 << "Removing a nonexistant client should fail."; 220 // Clients in controller: [A/1, B/1] 221 ASSERT_EQ(2, controller_->GetClientCount()); 222 ASSERT_EQ(300, 223 controller_->RemoveClient(client_b_route_1, client_b_.get())) 224 << "Removing client B/1 should return its session_id."; 225 // Clients in controller: [A/1] 226 ASSERT_EQ(1, controller_->GetClientCount()); 227 controller_->AddClient(client_b_route_2, 228 client_b_.get(), 229 base::kNullProcessHandle, 230 400, 231 session_400); 232 // Clients in controller: [A/1, B/2] 233 234 EXPECT_CALL(*client_a_, DoEnded(client_a_route_1)).Times(1); 235 controller_->StopSession(100); // Session 100 == client A/1 236 Mock::VerifyAndClearExpectations(client_a_.get()); 237 ASSERT_EQ(2, controller_->GetClientCount()) 238 << "Client should be closed but still exist after StopSession."; 239 // Clients in controller: [A/1 (closed, removal pending), B/2] 240 base::RunLoop().RunUntilIdle(); 241 // Clients in controller: [B/2] 242 ASSERT_EQ(1, controller_->GetClientCount()) 243 << "Client A/1 should be deleted by now."; 244 controller_->StopSession(200); // Session 200 does not exist anymore 245 // Clients in controller: [B/2] 246 ASSERT_EQ(1, controller_->GetClientCount()) 247 << "Stopping non-existant session 200 should be a no-op."; 248 controller_->StopSession(256); // Session 256 never existed. 249 // Clients in controller: [B/2] 250 ASSERT_EQ(1, controller_->GetClientCount()) 251 << "Stopping non-existant session 256 should be a no-op."; 252 ASSERT_EQ(static_cast<int>(kInvalidMediaCaptureSessionId), 253 controller_->RemoveClient(client_a_route_1, client_a_.get())) 254 << "Removing already-removed client A/1 should fail."; 255 // Clients in controller: [B/2] 256 ASSERT_EQ(1, controller_->GetClientCount()) 257 << "Removing non-existant session 200 should be a no-op."; 258 ASSERT_EQ(400, 259 controller_->RemoveClient(client_b_route_2, client_b_.get())) 260 << "Removing client B/2 should return its session_id."; 261 // Clients in controller: [] 262 ASSERT_EQ(0, controller_->GetClientCount()) 263 << "Client count should return to zero after all clients are gone."; 264 } 265 266 static void CacheSyncPoint(std::vector<uint32>* called_release_sync_points, 267 const std::vector<uint32>& release_sync_points) { 268 DCHECK(called_release_sync_points->empty()); 269 called_release_sync_points->assign(release_sync_points.begin(), 270 release_sync_points.end()); 271 } 272 273 // This test will connect and disconnect several clients while simulating an 274 // active capture device being started and generating frames. It runs on one 275 // thread and is intended to behave deterministically. 276 TEST_F(VideoCaptureControllerTest, NormalCaptureMultipleClients) { 277 media::VideoCaptureParams session_100; 278 session_100.requested_format = media::VideoCaptureFormat( 279 gfx::Size(320, 240), 30, media::PIXEL_FORMAT_I420); 280 281 media::VideoCaptureParams session_200 = session_100; 282 283 media::VideoCaptureParams session_300 = session_100; 284 285 media::VideoCaptureParams session_1 = session_100; 286 287 gfx::Size capture_resolution(444, 200); 288 289 // The device format needn't match the VideoCaptureParams (the camera can do 290 // what it wants). Pick something random. 291 media::VideoCaptureFormat device_format( 292 gfx::Size(10, 10), 25, media::PIXEL_FORMAT_RGB24); 293 294 const VideoCaptureControllerID client_a_route_1(0xa1a1a1a1); 295 const VideoCaptureControllerID client_a_route_2(0xa2a2a2a2); 296 const VideoCaptureControllerID client_b_route_1(0xb1b1b1b1); 297 const VideoCaptureControllerID client_b_route_2(0xb2b2b2b2); 298 299 // Start with two clients. 300 controller_->AddClient(client_a_route_1, 301 client_a_.get(), 302 base::kNullProcessHandle, 303 100, 304 session_100); 305 controller_->AddClient(client_b_route_1, 306 client_b_.get(), 307 base::kNullProcessHandle, 308 300, 309 session_300); 310 controller_->AddClient(client_a_route_2, 311 client_a_.get(), 312 base::kNullProcessHandle, 313 200, 314 session_200); 315 ASSERT_EQ(3, controller_->GetClientCount()); 316 317 // Now, simulate an incoming captured buffer from the capture device. As a 318 // side effect this will cause the first buffer to be shared with clients. 319 uint8 buffer_no = 1; 320 scoped_refptr<media::VideoCaptureDevice::Client::Buffer> buffer; 321 buffer = 322 device_->ReserveOutputBuffer(media::VideoFrame::I420, capture_resolution); 323 ASSERT_TRUE(buffer); 324 memset(buffer->data(), buffer_no++, buffer->size()); 325 { 326 InSequence s; 327 EXPECT_CALL(*client_a_, DoBufferCreated(client_a_route_1)).Times(1); 328 EXPECT_CALL(*client_a_, DoBufferReady(client_a_route_1)).Times(1); 329 } 330 { 331 InSequence s; 332 EXPECT_CALL(*client_b_, DoBufferCreated(client_b_route_1)).Times(1); 333 EXPECT_CALL(*client_b_, DoBufferReady(client_b_route_1)).Times(1); 334 } 335 { 336 InSequence s; 337 EXPECT_CALL(*client_a_, DoBufferCreated(client_a_route_2)).Times(1); 338 EXPECT_CALL(*client_a_, DoBufferReady(client_a_route_2)).Times(1); 339 } 340 device_->OnIncomingCapturedVideoFrame( 341 buffer, 342 media::VideoCaptureFormat(capture_resolution, 343 device_format.frame_rate, 344 media::PIXEL_FORMAT_I420), 345 WrapI420Buffer(buffer, capture_resolution), 346 base::TimeTicks()); 347 buffer = NULL; 348 349 base::RunLoop().RunUntilIdle(); 350 Mock::VerifyAndClearExpectations(client_a_.get()); 351 Mock::VerifyAndClearExpectations(client_b_.get()); 352 353 // Second buffer which ought to use the same shared memory buffer. In this 354 // case pretend that the Buffer pointer is held by the device for a long 355 // delay. This shouldn't affect anything. 356 buffer = 357 device_->ReserveOutputBuffer(media::VideoFrame::I420, capture_resolution); 358 ASSERT_TRUE(buffer); 359 memset(buffer->data(), buffer_no++, buffer->size()); 360 device_->OnIncomingCapturedVideoFrame( 361 buffer, 362 media::VideoCaptureFormat(capture_resolution, 363 device_format.frame_rate, 364 media::PIXEL_FORMAT_I420), 365 WrapI420Buffer(buffer, capture_resolution), 366 base::TimeTicks()); 367 buffer = NULL; 368 369 // The buffer should be delivered to the clients in any order. 370 EXPECT_CALL(*client_a_, DoBufferReady(client_a_route_1)).Times(1); 371 EXPECT_CALL(*client_b_, DoBufferReady(client_b_route_1)).Times(1); 372 EXPECT_CALL(*client_a_, DoBufferReady(client_a_route_2)).Times(1); 373 base::RunLoop().RunUntilIdle(); 374 Mock::VerifyAndClearExpectations(client_a_.get()); 375 Mock::VerifyAndClearExpectations(client_b_.get()); 376 377 // Add a fourth client now that some buffers have come through. 378 controller_->AddClient(client_b_route_2, 379 client_b_.get(), 380 base::kNullProcessHandle, 381 1, 382 session_1); 383 Mock::VerifyAndClearExpectations(client_b_.get()); 384 385 // Third, fourth, and fifth buffers. Pretend they all arrive at the same time. 386 for (int i = 0; i < kPoolSize; i++) { 387 buffer = device_->ReserveOutputBuffer(media::VideoFrame::I420, 388 capture_resolution); 389 ASSERT_TRUE(buffer); 390 memset(buffer->data(), buffer_no++, buffer->size()); 391 device_->OnIncomingCapturedVideoFrame( 392 buffer, 393 media::VideoCaptureFormat(capture_resolution, 394 device_format.frame_rate, 395 media::PIXEL_FORMAT_I420), 396 WrapI420Buffer(buffer, capture_resolution), 397 base::TimeTicks()); 398 buffer = NULL; 399 } 400 // ReserveOutputBuffer ought to fail now, because the pool is depleted. 401 ASSERT_FALSE(device_->ReserveOutputBuffer(media::VideoFrame::I420, 402 capture_resolution)); 403 404 // The new client needs to be told of 3 buffers; the old clients only 2. 405 EXPECT_CALL(*client_b_, DoBufferCreated(client_b_route_2)).Times(kPoolSize); 406 EXPECT_CALL(*client_b_, DoBufferReady(client_b_route_2)).Times(kPoolSize); 407 EXPECT_CALL(*client_a_, DoBufferCreated(client_a_route_1)) 408 .Times(kPoolSize - 1); 409 EXPECT_CALL(*client_a_, DoBufferReady(client_a_route_1)).Times(kPoolSize); 410 EXPECT_CALL(*client_a_, DoBufferCreated(client_a_route_2)) 411 .Times(kPoolSize - 1); 412 EXPECT_CALL(*client_a_, DoBufferReady(client_a_route_2)).Times(kPoolSize); 413 EXPECT_CALL(*client_b_, DoBufferCreated(client_b_route_1)) 414 .Times(kPoolSize - 1); 415 EXPECT_CALL(*client_b_, DoBufferReady(client_b_route_1)).Times(kPoolSize); 416 base::RunLoop().RunUntilIdle(); 417 Mock::VerifyAndClearExpectations(client_a_.get()); 418 Mock::VerifyAndClearExpectations(client_b_.get()); 419 420 // Now test the interaction of client shutdown and buffer delivery. 421 // Kill A1 via renderer disconnect (synchronous). 422 controller_->RemoveClient(client_a_route_1, client_a_.get()); 423 // Kill B1 via session close (posts a task to disconnect). 424 EXPECT_CALL(*client_b_, DoEnded(client_b_route_1)).Times(1); 425 controller_->StopSession(300); 426 // Queue up another buffer. 427 buffer = 428 device_->ReserveOutputBuffer(media::VideoFrame::I420, capture_resolution); 429 ASSERT_TRUE(buffer); 430 memset(buffer->data(), buffer_no++, buffer->size()); 431 device_->OnIncomingCapturedVideoFrame( 432 buffer, 433 media::VideoCaptureFormat(capture_resolution, 434 device_format.frame_rate, 435 media::PIXEL_FORMAT_I420), 436 WrapI420Buffer(buffer, capture_resolution), 437 base::TimeTicks()); 438 buffer = NULL; 439 buffer = 440 device_->ReserveOutputBuffer(media::VideoFrame::I420, capture_resolution); 441 { 442 // Kill A2 via session close (posts a task to disconnect, but A2 must not 443 // be sent either of these two buffers). 444 EXPECT_CALL(*client_a_, DoEnded(client_a_route_2)).Times(1); 445 controller_->StopSession(200); 446 } 447 ASSERT_TRUE(buffer); 448 memset(buffer->data(), buffer_no++, buffer->size()); 449 device_->OnIncomingCapturedVideoFrame( 450 buffer, 451 media::VideoCaptureFormat(capture_resolution, 452 device_format.frame_rate, 453 media::PIXEL_FORMAT_I420), 454 WrapI420Buffer(buffer, capture_resolution), 455 base::TimeTicks()); 456 buffer = NULL; 457 // B2 is the only client left, and is the only one that should 458 // get the buffer. 459 EXPECT_CALL(*client_b_, DoBufferReady(client_b_route_2)).Times(2); 460 base::RunLoop().RunUntilIdle(); 461 Mock::VerifyAndClearExpectations(client_a_.get()); 462 Mock::VerifyAndClearExpectations(client_b_.get()); 463 464 // Allocate all buffers from the buffer pool, half as SHM buffer and half as 465 // mailbox buffers. Make sure of different counts though. 466 int shm_buffers = kPoolSize / 2; 467 int mailbox_buffers = kPoolSize - shm_buffers; 468 if (shm_buffers == mailbox_buffers) { 469 shm_buffers--; 470 mailbox_buffers++; 471 } 472 473 for (int i = 0; i < shm_buffers; ++i) { 474 buffer = device_->ReserveOutputBuffer(media::VideoFrame::I420, 475 capture_resolution); 476 ASSERT_TRUE(buffer); 477 device_->OnIncomingCapturedVideoFrame( 478 buffer, 479 media::VideoCaptureFormat(capture_resolution, 480 device_format.frame_rate, 481 media::PIXEL_FORMAT_I420), 482 WrapI420Buffer(buffer, capture_resolution), 483 base::TimeTicks()); 484 buffer = NULL; 485 } 486 std::vector<uint32> mailbox_syncpoints(mailbox_buffers); 487 std::vector<std::vector<uint32> > release_syncpoint_vectors(mailbox_buffers); 488 for (int i = 0; i < mailbox_buffers; ++i) { 489 buffer = device_->ReserveOutputBuffer(media::VideoFrame::NATIVE_TEXTURE, 490 gfx::Size(0, 0)); 491 ASSERT_TRUE(buffer); 492 mailbox_syncpoints[i] = i; 493 device_->OnIncomingCapturedVideoFrame( 494 buffer, 495 media::VideoCaptureFormat(capture_resolution, 496 device_format.frame_rate, 497 media::PIXEL_FORMAT_TEXTURE), 498 WrapMailboxBuffer( 499 buffer, 500 make_scoped_ptr(new gpu::MailboxHolder( 501 gpu::Mailbox(), 0, mailbox_syncpoints[i])), 502 base::Bind(&CacheSyncPoint, &release_syncpoint_vectors[i]), 503 capture_resolution), 504 base::TimeTicks()); 505 buffer = NULL; 506 } 507 // ReserveOutputBuffers ought to fail now regardless of buffer format, because 508 // the pool is depleted. 509 ASSERT_FALSE(device_->ReserveOutputBuffer(media::VideoFrame::I420, 510 capture_resolution)); 511 ASSERT_FALSE(device_->ReserveOutputBuffer(media::VideoFrame::NATIVE_TEXTURE, 512 gfx::Size(0, 0))); 513 EXPECT_CALL(*client_b_, DoBufferReady(client_b_route_2)).Times(shm_buffers); 514 EXPECT_CALL(*client_b_, DoMailboxBufferReady(client_b_route_2)) 515 .Times(mailbox_buffers); 516 base::RunLoop().RunUntilIdle(); 517 for (size_t i = 0; i < mailbox_syncpoints.size(); ++i) { 518 // See: MockVideoCaptureControllerEventHandler::OnMailboxBufferReady() 519 ASSERT_EQ(1u, release_syncpoint_vectors[i].size()); 520 ASSERT_EQ(mailbox_syncpoints[i], ~release_syncpoint_vectors[i][0]); 521 } 522 Mock::VerifyAndClearExpectations(client_b_.get()); 523 } 524 525 // Exercises the OnError() codepath of VideoCaptureController, and tests the 526 // behavior of various operations after the error state has been signalled. 527 TEST_F(VideoCaptureControllerTest, ErrorBeforeDeviceCreation) { 528 media::VideoCaptureParams session_100; 529 session_100.requested_format = media::VideoCaptureFormat( 530 gfx::Size(320, 240), 30, media::PIXEL_FORMAT_I420); 531 532 media::VideoCaptureParams session_200 = session_100; 533 534 const gfx::Size capture_resolution(320, 240); 535 536 const VideoCaptureControllerID route_id(0x99); 537 538 // Start with one client. 539 controller_->AddClient( 540 route_id, client_a_.get(), base::kNullProcessHandle, 100, session_100); 541 device_->OnError("Test Error"); 542 EXPECT_CALL(*client_a_, DoError(route_id)).Times(1); 543 base::RunLoop().RunUntilIdle(); 544 Mock::VerifyAndClearExpectations(client_a_.get()); 545 546 // Second client connects after the error state. It also should get told of 547 // the error. 548 EXPECT_CALL(*client_b_, DoError(route_id)).Times(1); 549 controller_->AddClient( 550 route_id, client_b_.get(), base::kNullProcessHandle, 200, session_200); 551 base::RunLoop().RunUntilIdle(); 552 Mock::VerifyAndClearExpectations(client_b_.get()); 553 554 scoped_refptr<media::VideoCaptureDevice::Client::Buffer> buffer = 555 device_->ReserveOutputBuffer(media::VideoFrame::I420, capture_resolution); 556 ASSERT_TRUE(buffer); 557 558 device_->OnIncomingCapturedVideoFrame( 559 buffer, 560 media::VideoCaptureFormat( 561 capture_resolution, 30, media::PIXEL_FORMAT_I420), 562 WrapI420Buffer(buffer, capture_resolution), 563 base::TimeTicks()); 564 buffer = NULL; 565 566 base::RunLoop().RunUntilIdle(); 567 } 568 569 // Exercises the OnError() codepath of VideoCaptureController, and tests the 570 // behavior of various operations after the error state has been signalled. 571 TEST_F(VideoCaptureControllerTest, ErrorAfterDeviceCreation) { 572 media::VideoCaptureParams session_100; 573 session_100.requested_format = media::VideoCaptureFormat( 574 gfx::Size(320, 240), 30, media::PIXEL_FORMAT_I420); 575 576 media::VideoCaptureParams session_200 = session_100; 577 578 const VideoCaptureControllerID route_id(0x99); 579 580 // Start with one client. 581 controller_->AddClient( 582 route_id, client_a_.get(), base::kNullProcessHandle, 100, session_100); 583 media::VideoCaptureFormat device_format( 584 gfx::Size(10, 10), 25, media::PIXEL_FORMAT_ARGB); 585 586 // Start the device. Then, before the first buffer, signal an error and 587 // deliver the buffer. The error should be propagated to clients; the buffer 588 // should not be. 589 base::RunLoop().RunUntilIdle(); 590 Mock::VerifyAndClearExpectations(client_a_.get()); 591 592 const gfx::Size dims(320, 240); 593 scoped_refptr<media::VideoCaptureDevice::Client::Buffer> buffer = 594 device_->ReserveOutputBuffer(media::VideoFrame::I420, dims); 595 ASSERT_TRUE(buffer); 596 597 device_->OnError("Test error"); 598 device_->OnIncomingCapturedVideoFrame( 599 buffer, 600 media::VideoCaptureFormat( 601 dims, device_format.frame_rate, media::PIXEL_FORMAT_I420), 602 WrapI420Buffer(buffer, dims), 603 base::TimeTicks()); 604 buffer = NULL; 605 606 EXPECT_CALL(*client_a_, DoError(route_id)).Times(1); 607 base::RunLoop().RunUntilIdle(); 608 Mock::VerifyAndClearExpectations(client_a_.get()); 609 610 // Second client connects after the error state. It also should get told of 611 // the error. 612 EXPECT_CALL(*client_b_, DoError(route_id)).Times(1); 613 controller_->AddClient( 614 route_id, client_b_.get(), base::kNullProcessHandle, 200, session_200); 615 Mock::VerifyAndClearExpectations(client_b_.get()); 616 } 617 618 } // namespace content 619