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