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.
5 // Unit test for VideoCaptureController.
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"
28 #if defined(OS_ANDROID)
29 #include "content/browser/renderer_host/test/no_transport_image_transport_factory_android.h"
31 #include "content/browser/compositor/test/no_transport_image_transport_factory.h"
34 using ::testing::InSequence
;
35 using ::testing::Mock
;
39 class MockVideoCaptureControllerEventHandler
40 : public VideoCaptureControllerEventHandler
{
42 explicit MockVideoCaptureControllerEventHandler(
43 VideoCaptureController
* controller
)
44 : controller_(controller
) {}
45 virtual ~MockVideoCaptureControllerEventHandler() {}
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
&));
56 virtual void OnError(const VideoCaptureControllerID
& id
) OVERRIDE
{
59 virtual void OnBufferCreated(const VideoCaptureControllerID
& id
,
60 base::SharedMemoryHandle handle
,
61 int length
, int buffer_id
) OVERRIDE
{
64 virtual void OnBufferDestroyed(const VideoCaptureControllerID
& id
,
65 int buffer_id
) OVERRIDE
{
66 DoBufferDestroyed(id
);
68 virtual void OnBufferReady(const VideoCaptureControllerID
& id
,
70 const media::VideoCaptureFormat
& format
,
71 base::TimeTicks timestamp
) OVERRIDE
{
73 base::MessageLoop::current()->PostTask(
75 base::Bind(&VideoCaptureController::ReturnBuffer
,
76 base::Unretained(controller_
),
82 virtual void OnMailboxBufferReady(const VideoCaptureControllerID
& id
,
84 const gpu::MailboxHolder
& mailbox_holder
,
85 const media::VideoCaptureFormat
& format
,
86 base::TimeTicks timestamp
) OVERRIDE
{
87 DoMailboxBufferReady(id
);
88 base::MessageLoop::current()->PostTask(
90 base::Bind(&VideoCaptureController::ReturnBuffer
,
91 base::Unretained(controller_
),
95 mailbox_holder
.sync_point
));
97 virtual void OnEnded(const VideoCaptureControllerID
& id
) OVERRIDE
{
99 // OnEnded() must respond by (eventually) unregistering the client.
100 base::MessageLoop::current()->PostTask(FROM_HERE
,
101 base::Bind(base::IgnoreResult(&VideoCaptureController::RemoveClient
),
102 base::Unretained(controller_
), id
, this));
105 VideoCaptureController
* controller_
;
109 class VideoCaptureControllerTest
: public testing::Test
{
111 VideoCaptureControllerTest() {}
112 virtual ~VideoCaptureControllerTest() {}
115 static const int kPoolSize
= 3;
117 virtual void SetUp() OVERRIDE
{
118 controller_
.reset(new VideoCaptureController(kPoolSize
));
119 device_
= controller_
->NewDeviceClient().Pass();
120 client_a_
.reset(new MockVideoCaptureControllerEventHandler(
122 client_b_
.reset(new MockVideoCaptureControllerEventHandler(
126 virtual void TearDown() OVERRIDE
{
127 base::RunLoop().RunUntilIdle();
130 scoped_refptr
<media::VideoFrame
> WrapI420Buffer(
131 const scoped_refptr
<media::VideoCaptureDevice::Client::Buffer
>& buffer
,
132 gfx::Size dimensions
) {
133 return media::VideoFrame::WrapExternalPackedMemory(
134 media::VideoFrame::I420
,
136 gfx::Rect(dimensions
),
138 reinterpret_cast<uint8
*>(buffer
->data()),
139 media::VideoFrame::AllocationSize(media::VideoFrame::I420
, dimensions
),
140 base::SharedMemory::NULLHandle(),
145 scoped_refptr
<media::VideoFrame
> WrapMailboxBuffer(
146 const scoped_refptr
<media::VideoCaptureDevice::Client::Buffer
>& buffer
,
147 scoped_ptr
<gpu::MailboxHolder
> holder
,
148 const media::VideoFrame::ReleaseMailboxCB
& release_cb
,
149 gfx::Size dimensions
) {
150 return media::VideoFrame::WrapNativeTexture(
154 gfx::Rect(dimensions
),
157 media::VideoFrame::ReadPixelsCB());
160 TestBrowserThreadBundle bundle_
;
161 scoped_ptr
<MockVideoCaptureControllerEventHandler
> client_a_
;
162 scoped_ptr
<MockVideoCaptureControllerEventHandler
> client_b_
;
163 scoped_ptr
<VideoCaptureController
> controller_
;
164 scoped_ptr
<media::VideoCaptureDevice::Client
> device_
;
167 DISALLOW_COPY_AND_ASSIGN(VideoCaptureControllerTest
);
170 // A simple test of VideoCaptureController's ability to add, remove, and keep
172 TEST_F(VideoCaptureControllerTest
, AddAndRemoveClients
) {
173 media::VideoCaptureParams session_100
;
174 session_100
.requested_format
= media::VideoCaptureFormat(
175 gfx::Size(320, 240), 30, media::PIXEL_FORMAT_I420
);
176 media::VideoCaptureParams session_200
= session_100
;
178 media::VideoCaptureParams session_300
= session_100
;
180 media::VideoCaptureParams session_400
= session_100
;
182 // Intentionally use the same route ID for two of the clients: the device_ids
183 // are a per-VideoCaptureHost namespace, and can overlap across hosts.
184 const VideoCaptureControllerID
client_a_route_1(44);
185 const VideoCaptureControllerID
client_a_route_2(30);
186 const VideoCaptureControllerID
client_b_route_1(30);
187 const VideoCaptureControllerID
client_b_route_2(1);
189 // Clients in controller: []
190 ASSERT_EQ(0, controller_
->GetClientCount())
191 << "Client count should initially be zero.";
192 controller_
->AddClient(client_a_route_1
,
194 base::kNullProcessHandle
,
197 // Clients in controller: [A/1]
198 ASSERT_EQ(1, controller_
->GetClientCount())
199 << "Adding client A/1 should bump client count.";
200 controller_
->AddClient(client_a_route_2
,
202 base::kNullProcessHandle
,
205 // Clients in controller: [A/1, A/2]
206 ASSERT_EQ(2, controller_
->GetClientCount())
207 << "Adding client A/2 should bump client count.";
208 controller_
->AddClient(client_b_route_1
,
210 base::kNullProcessHandle
,
213 // Clients in controller: [A/1, A/2, B/1]
214 ASSERT_EQ(3, controller_
->GetClientCount())
215 << "Adding client B/1 should bump client count.";
217 controller_
->RemoveClient(client_a_route_2
, client_a_
.get()))
218 << "Removing client A/1 should return its session_id.";
219 // Clients in controller: [A/1, B/1]
220 ASSERT_EQ(2, controller_
->GetClientCount());
221 ASSERT_EQ(static_cast<int>(kInvalidMediaCaptureSessionId
),
222 controller_
->RemoveClient(client_a_route_2
, client_a_
.get()))
223 << "Removing a nonexistant client should fail.";
224 // Clients in controller: [A/1, B/1]
225 ASSERT_EQ(2, controller_
->GetClientCount());
227 controller_
->RemoveClient(client_b_route_1
, client_b_
.get()))
228 << "Removing client B/1 should return its session_id.";
229 // Clients in controller: [A/1]
230 ASSERT_EQ(1, controller_
->GetClientCount());
231 controller_
->AddClient(client_b_route_2
,
233 base::kNullProcessHandle
,
236 // Clients in controller: [A/1, B/2]
238 EXPECT_CALL(*client_a_
, DoEnded(client_a_route_1
)).Times(1);
239 controller_
->StopSession(100); // Session 100 == client A/1
240 Mock::VerifyAndClearExpectations(client_a_
.get());
241 ASSERT_EQ(2, controller_
->GetClientCount())
242 << "Client should be closed but still exist after StopSession.";
243 // Clients in controller: [A/1 (closed, removal pending), B/2]
244 base::RunLoop().RunUntilIdle();
245 // Clients in controller: [B/2]
246 ASSERT_EQ(1, controller_
->GetClientCount())
247 << "Client A/1 should be deleted by now.";
248 controller_
->StopSession(200); // Session 200 does not exist anymore
249 // Clients in controller: [B/2]
250 ASSERT_EQ(1, controller_
->GetClientCount())
251 << "Stopping non-existant session 200 should be a no-op.";
252 controller_
->StopSession(256); // Session 256 never existed.
253 // Clients in controller: [B/2]
254 ASSERT_EQ(1, controller_
->GetClientCount())
255 << "Stopping non-existant session 256 should be a no-op.";
256 ASSERT_EQ(static_cast<int>(kInvalidMediaCaptureSessionId
),
257 controller_
->RemoveClient(client_a_route_1
, client_a_
.get()))
258 << "Removing already-removed client A/1 should fail.";
259 // Clients in controller: [B/2]
260 ASSERT_EQ(1, controller_
->GetClientCount())
261 << "Removing non-existant session 200 should be a no-op.";
263 controller_
->RemoveClient(client_b_route_2
, client_b_
.get()))
264 << "Removing client B/2 should return its session_id.";
265 // Clients in controller: []
266 ASSERT_EQ(0, controller_
->GetClientCount())
267 << "Client count should return to zero after all clients are gone.";
270 static void CacheSyncPoint(uint32
* called_release_sync_point
,
271 uint32 release_sync_point
) {
272 *called_release_sync_point
= release_sync_point
;
275 // This test will connect and disconnect several clients while simulating an
276 // active capture device being started and generating frames. It runs on one
277 // thread and is intended to behave deterministically.
278 TEST_F(VideoCaptureControllerTest
, NormalCaptureMultipleClients
) {
279 // VideoCaptureController::ReturnBuffer() uses ImageTransportFactory.
280 #if defined(OS_ANDROID)
281 ImageTransportFactoryAndroid::InitializeForUnitTests(
282 scoped_ptr
<ImageTransportFactoryAndroid
>(
283 new NoTransportImageTransportFactoryAndroid
));
285 ImageTransportFactory::InitializeForUnitTests(
286 scoped_ptr
<ImageTransportFactory
>(new NoTransportImageTransportFactory
));
289 media::VideoCaptureParams session_100
;
290 session_100
.requested_format
= media::VideoCaptureFormat(
291 gfx::Size(320, 240), 30, media::PIXEL_FORMAT_I420
);
293 media::VideoCaptureParams session_200
= session_100
;
295 media::VideoCaptureParams session_300
= session_100
;
297 media::VideoCaptureParams session_1
= session_100
;
299 gfx::Size
capture_resolution(444, 200);
301 // The device format needn't match the VideoCaptureParams (the camera can do
302 // what it wants). Pick something random.
303 media::VideoCaptureFormat
device_format(
304 gfx::Size(10, 10), 25, media::PIXEL_FORMAT_RGB24
);
306 const VideoCaptureControllerID
client_a_route_1(0xa1a1a1a1);
307 const VideoCaptureControllerID
client_a_route_2(0xa2a2a2a2);
308 const VideoCaptureControllerID
client_b_route_1(0xb1b1b1b1);
309 const VideoCaptureControllerID
client_b_route_2(0xb2b2b2b2);
311 // Start with two clients.
312 controller_
->AddClient(client_a_route_1
,
314 base::kNullProcessHandle
,
317 controller_
->AddClient(client_b_route_1
,
319 base::kNullProcessHandle
,
322 controller_
->AddClient(client_a_route_2
,
324 base::kNullProcessHandle
,
327 ASSERT_EQ(3, controller_
->GetClientCount());
329 // Now, simulate an incoming captured buffer from the capture device. As a
330 // side effect this will cause the first buffer to be shared with clients.
332 scoped_refptr
<media::VideoCaptureDevice::Client::Buffer
> buffer
;
334 device_
->ReserveOutputBuffer(media::VideoFrame::I420
, capture_resolution
);
335 ASSERT_TRUE(buffer
.get());
336 memset(buffer
->data(), buffer_no
++, buffer
->size());
339 EXPECT_CALL(*client_a_
, DoBufferCreated(client_a_route_1
)).Times(1);
340 EXPECT_CALL(*client_a_
, DoBufferReady(client_a_route_1
)).Times(1);
344 EXPECT_CALL(*client_b_
, DoBufferCreated(client_b_route_1
)).Times(1);
345 EXPECT_CALL(*client_b_
, DoBufferReady(client_b_route_1
)).Times(1);
349 EXPECT_CALL(*client_a_
, DoBufferCreated(client_a_route_2
)).Times(1);
350 EXPECT_CALL(*client_a_
, DoBufferReady(client_a_route_2
)).Times(1);
352 device_
->OnIncomingCapturedVideoFrame(
354 media::VideoCaptureFormat(capture_resolution
,
355 device_format
.frame_rate
,
356 media::PIXEL_FORMAT_I420
),
357 WrapI420Buffer(buffer
, capture_resolution
),
361 base::RunLoop().RunUntilIdle();
362 Mock::VerifyAndClearExpectations(client_a_
.get());
363 Mock::VerifyAndClearExpectations(client_b_
.get());
365 // Second buffer which ought to use the same shared memory buffer. In this
366 // case pretend that the Buffer pointer is held by the device for a long
367 // delay. This shouldn't affect anything.
369 device_
->ReserveOutputBuffer(media::VideoFrame::I420
, capture_resolution
);
370 ASSERT_TRUE(buffer
.get());
371 memset(buffer
->data(), buffer_no
++, buffer
->size());
372 device_
->OnIncomingCapturedVideoFrame(
374 media::VideoCaptureFormat(capture_resolution
,
375 device_format
.frame_rate
,
376 media::PIXEL_FORMAT_I420
),
377 WrapI420Buffer(buffer
, capture_resolution
),
381 // The buffer should be delivered to the clients in any order.
382 EXPECT_CALL(*client_a_
, DoBufferReady(client_a_route_1
)).Times(1);
383 EXPECT_CALL(*client_b_
, DoBufferReady(client_b_route_1
)).Times(1);
384 EXPECT_CALL(*client_a_
, DoBufferReady(client_a_route_2
)).Times(1);
385 base::RunLoop().RunUntilIdle();
386 Mock::VerifyAndClearExpectations(client_a_
.get());
387 Mock::VerifyAndClearExpectations(client_b_
.get());
389 // Add a fourth client now that some buffers have come through.
390 controller_
->AddClient(client_b_route_2
,
392 base::kNullProcessHandle
,
395 Mock::VerifyAndClearExpectations(client_b_
.get());
397 // Third, fourth, and fifth buffers. Pretend they all arrive at the same time.
398 for (int i
= 0; i
< kPoolSize
; i
++) {
399 buffer
= device_
->ReserveOutputBuffer(media::VideoFrame::I420
,
401 ASSERT_TRUE(buffer
.get());
402 memset(buffer
->data(), buffer_no
++, buffer
->size());
403 device_
->OnIncomingCapturedVideoFrame(
405 media::VideoCaptureFormat(capture_resolution
,
406 device_format
.frame_rate
,
407 media::PIXEL_FORMAT_I420
),
408 WrapI420Buffer(buffer
, capture_resolution
),
412 // ReserveOutputBuffer ought to fail now, because the pool is depleted.
413 ASSERT_FALSE(device_
->ReserveOutputBuffer(media::VideoFrame::I420
,
414 capture_resolution
));
416 // The new client needs to be told of 3 buffers; the old clients only 2.
417 EXPECT_CALL(*client_b_
, DoBufferCreated(client_b_route_2
)).Times(kPoolSize
);
418 EXPECT_CALL(*client_b_
, DoBufferReady(client_b_route_2
)).Times(kPoolSize
);
419 EXPECT_CALL(*client_a_
, DoBufferCreated(client_a_route_1
))
420 .Times(kPoolSize
- 1);
421 EXPECT_CALL(*client_a_
, DoBufferReady(client_a_route_1
)).Times(kPoolSize
);
422 EXPECT_CALL(*client_a_
, DoBufferCreated(client_a_route_2
))
423 .Times(kPoolSize
- 1);
424 EXPECT_CALL(*client_a_
, DoBufferReady(client_a_route_2
)).Times(kPoolSize
);
425 EXPECT_CALL(*client_b_
, DoBufferCreated(client_b_route_1
))
426 .Times(kPoolSize
- 1);
427 EXPECT_CALL(*client_b_
, DoBufferReady(client_b_route_1
)).Times(kPoolSize
);
428 base::RunLoop().RunUntilIdle();
429 Mock::VerifyAndClearExpectations(client_a_
.get());
430 Mock::VerifyAndClearExpectations(client_b_
.get());
432 // Now test the interaction of client shutdown and buffer delivery.
433 // Kill A1 via renderer disconnect (synchronous).
434 controller_
->RemoveClient(client_a_route_1
, client_a_
.get());
435 // Kill B1 via session close (posts a task to disconnect).
436 EXPECT_CALL(*client_b_
, DoEnded(client_b_route_1
)).Times(1);
437 controller_
->StopSession(300);
438 // Queue up another buffer.
440 device_
->ReserveOutputBuffer(media::VideoFrame::I420
, capture_resolution
);
441 ASSERT_TRUE(buffer
.get());
442 memset(buffer
->data(), buffer_no
++, buffer
->size());
443 device_
->OnIncomingCapturedVideoFrame(
445 media::VideoCaptureFormat(capture_resolution
,
446 device_format
.frame_rate
,
447 media::PIXEL_FORMAT_I420
),
448 WrapI420Buffer(buffer
, capture_resolution
),
452 device_
->ReserveOutputBuffer(media::VideoFrame::I420
, capture_resolution
);
454 // Kill A2 via session close (posts a task to disconnect, but A2 must not
455 // be sent either of these two buffers).
456 EXPECT_CALL(*client_a_
, DoEnded(client_a_route_2
)).Times(1);
457 controller_
->StopSession(200);
459 ASSERT_TRUE(buffer
.get());
460 memset(buffer
->data(), buffer_no
++, buffer
->size());
461 device_
->OnIncomingCapturedVideoFrame(
463 media::VideoCaptureFormat(capture_resolution
,
464 device_format
.frame_rate
,
465 media::PIXEL_FORMAT_I420
),
466 WrapI420Buffer(buffer
, capture_resolution
),
469 // B2 is the only client left, and is the only one that should
471 EXPECT_CALL(*client_b_
, DoBufferReady(client_b_route_2
)).Times(2);
472 base::RunLoop().RunUntilIdle();
473 Mock::VerifyAndClearExpectations(client_a_
.get());
474 Mock::VerifyAndClearExpectations(client_b_
.get());
476 // Allocate all buffers from the buffer pool, half as SHM buffer and half as
477 // mailbox buffers. Make sure of different counts though.
478 int shm_buffers
= kPoolSize
/ 2;
479 int mailbox_buffers
= kPoolSize
- shm_buffers
;
480 if (shm_buffers
== mailbox_buffers
) {
485 for (int i
= 0; i
< shm_buffers
; ++i
) {
486 buffer
= device_
->ReserveOutputBuffer(media::VideoFrame::I420
,
488 ASSERT_TRUE(buffer
.get());
489 device_
->OnIncomingCapturedVideoFrame(
491 media::VideoCaptureFormat(capture_resolution
,
492 device_format
.frame_rate
,
493 media::PIXEL_FORMAT_I420
),
494 WrapI420Buffer(buffer
, capture_resolution
),
498 std::vector
<uint32
> mailbox_syncpoints(mailbox_buffers
);
499 std::vector
<uint32
> release_syncpoints(mailbox_buffers
);
500 #if defined(OS_ANDROID)
501 GLHelper
* gl_helper
=
502 ImageTransportFactoryAndroid::GetInstance()->GetGLHelper();
504 GLHelper
* gl_helper
= ImageTransportFactory::GetInstance()->GetGLHelper();
506 for (int i
= 0; i
< mailbox_buffers
; ++i
) {
507 buffer
= device_
->ReserveOutputBuffer(media::VideoFrame::NATIVE_TEXTURE
,
509 ASSERT_TRUE(buffer
.get());
510 mailbox_syncpoints
[i
] = gl_helper
->InsertSyncPoint();
511 device_
->OnIncomingCapturedVideoFrame(
513 media::VideoCaptureFormat(capture_resolution
,
514 device_format
.frame_rate
,
515 media::PIXEL_FORMAT_TEXTURE
),
516 WrapMailboxBuffer(buffer
,
517 make_scoped_ptr(new gpu::MailboxHolder(
518 gpu::Mailbox(), 0, mailbox_syncpoints
[i
])),
519 base::Bind(&CacheSyncPoint
, &release_syncpoints
[i
]),
524 // ReserveOutputBuffers ought to fail now regardless of buffer format, because
525 // the pool is depleted.
526 ASSERT_FALSE(device_
->ReserveOutputBuffer(media::VideoFrame::I420
,
527 capture_resolution
));
528 ASSERT_FALSE(device_
->ReserveOutputBuffer(media::VideoFrame::NATIVE_TEXTURE
,
530 EXPECT_CALL(*client_b_
, DoBufferReady(client_b_route_2
)).Times(shm_buffers
);
531 EXPECT_CALL(*client_b_
, DoMailboxBufferReady(client_b_route_2
))
532 .Times(mailbox_buffers
);
533 base::RunLoop().RunUntilIdle();
534 for (size_t i
= 0; i
< mailbox_syncpoints
.size(); ++i
) {
535 // A new release sync point must be inserted when the video frame is
536 // returned to the Browser process.
537 // See: MockVideoCaptureControllerEventHandler::OnMailboxBufferReady() and
538 // VideoCaptureController::ReturnBuffer()
539 ASSERT_NE(mailbox_syncpoints
[i
], release_syncpoints
[i
]);
541 Mock::VerifyAndClearExpectations(client_b_
.get());
543 #if defined(OS_ANDROID)
544 ImageTransportFactoryAndroid::TerminateForUnitTests();
546 ImageTransportFactory::Terminate();
550 // Exercises the OnError() codepath of VideoCaptureController, and tests the
551 // behavior of various operations after the error state has been signalled.
552 TEST_F(VideoCaptureControllerTest
, ErrorBeforeDeviceCreation
) {
553 media::VideoCaptureParams session_100
;
554 session_100
.requested_format
= media::VideoCaptureFormat(
555 gfx::Size(320, 240), 30, media::PIXEL_FORMAT_I420
);
557 media::VideoCaptureParams session_200
= session_100
;
559 const gfx::Size
capture_resolution(320, 240);
561 const VideoCaptureControllerID
route_id(0x99);
563 // Start with one client.
564 controller_
->AddClient(
565 route_id
, client_a_
.get(), base::kNullProcessHandle
, 100, session_100
);
566 device_
->OnError("Test Error");
567 EXPECT_CALL(*client_a_
, DoError(route_id
)).Times(1);
568 base::RunLoop().RunUntilIdle();
569 Mock::VerifyAndClearExpectations(client_a_
.get());
571 // Second client connects after the error state. It also should get told of
573 EXPECT_CALL(*client_b_
, DoError(route_id
)).Times(1);
574 controller_
->AddClient(
575 route_id
, client_b_
.get(), base::kNullProcessHandle
, 200, session_200
);
576 base::RunLoop().RunUntilIdle();
577 Mock::VerifyAndClearExpectations(client_b_
.get());
579 scoped_refptr
<media::VideoCaptureDevice::Client::Buffer
> buffer
=
580 device_
->ReserveOutputBuffer(media::VideoFrame::I420
, capture_resolution
);
581 ASSERT_TRUE(buffer
.get());
583 device_
->OnIncomingCapturedVideoFrame(
585 media::VideoCaptureFormat(
586 capture_resolution
, 30, media::PIXEL_FORMAT_I420
),
587 WrapI420Buffer(buffer
, capture_resolution
),
591 base::RunLoop().RunUntilIdle();
594 // Exercises the OnError() codepath of VideoCaptureController, and tests the
595 // behavior of various operations after the error state has been signalled.
596 TEST_F(VideoCaptureControllerTest
, ErrorAfterDeviceCreation
) {
597 media::VideoCaptureParams session_100
;
598 session_100
.requested_format
= media::VideoCaptureFormat(
599 gfx::Size(320, 240), 30, media::PIXEL_FORMAT_I420
);
601 media::VideoCaptureParams session_200
= session_100
;
603 const VideoCaptureControllerID
route_id(0x99);
605 // Start with one client.
606 controller_
->AddClient(
607 route_id
, client_a_
.get(), base::kNullProcessHandle
, 100, session_100
);
608 media::VideoCaptureFormat
device_format(
609 gfx::Size(10, 10), 25, media::PIXEL_FORMAT_ARGB
);
611 // Start the device. Then, before the first buffer, signal an error and
612 // deliver the buffer. The error should be propagated to clients; the buffer
614 base::RunLoop().RunUntilIdle();
615 Mock::VerifyAndClearExpectations(client_a_
.get());
617 const gfx::Size
dims(320, 240);
618 scoped_refptr
<media::VideoCaptureDevice::Client::Buffer
> buffer
=
619 device_
->ReserveOutputBuffer(media::VideoFrame::I420
, dims
);
620 ASSERT_TRUE(buffer
.get());
622 device_
->OnError("Test error");
623 device_
->OnIncomingCapturedVideoFrame(
625 media::VideoCaptureFormat(
626 dims
, device_format
.frame_rate
, media::PIXEL_FORMAT_I420
),
627 WrapI420Buffer(buffer
, dims
),
631 EXPECT_CALL(*client_a_
, DoError(route_id
)).Times(1);
632 base::RunLoop().RunUntilIdle();
633 Mock::VerifyAndClearExpectations(client_a_
.get());
635 // Second client connects after the error state. It also should get told of
637 EXPECT_CALL(*client_b_
, DoError(route_id
)).Times(1);
638 controller_
->AddClient(
639 route_id
, client_b_
.get(), base::kNullProcessHandle
, 200, session_200
);
640 Mock::VerifyAndClearExpectations(client_b_
.get());
643 } // namespace content