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 const gfx::Rect
& visible_rect
,
72 base::TimeTicks timestamp
) OVERRIDE
{
74 base::MessageLoop::current()->PostTask(
76 base::Bind(&VideoCaptureController::ReturnBuffer
,
77 base::Unretained(controller_
),
83 virtual void OnMailboxBufferReady(const VideoCaptureControllerID
& 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(
91 base::Bind(&VideoCaptureController::ReturnBuffer
,
92 base::Unretained(controller_
),
96 mailbox_holder
.sync_point
));
98 virtual void OnEnded(const VideoCaptureControllerID
& id
) OVERRIDE
{
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));
106 VideoCaptureController
* controller_
;
110 class VideoCaptureControllerTest
: public testing::Test
{
112 VideoCaptureControllerTest() {}
113 virtual ~VideoCaptureControllerTest() {}
116 static const int kPoolSize
= 3;
118 virtual void SetUp() OVERRIDE
{
119 controller_
.reset(new VideoCaptureController(kPoolSize
));
120 device_
= controller_
->NewDeviceClient().Pass();
121 client_a_
.reset(new MockVideoCaptureControllerEventHandler(
123 client_b_
.reset(new MockVideoCaptureControllerEventHandler(
127 virtual void TearDown() OVERRIDE
{
128 base::RunLoop().RunUntilIdle();
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
,
137 gfx::Rect(dimensions
),
139 reinterpret_cast<uint8
*>(buffer
->data()),
140 media::VideoFrame::AllocationSize(media::VideoFrame::I420
, dimensions
),
141 base::SharedMemory::NULLHandle(),
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(
155 gfx::Rect(dimensions
),
158 media::VideoFrame::ReadPixelsCB());
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_
;
168 DISALLOW_COPY_AND_ASSIGN(VideoCaptureControllerTest
);
171 // A simple test of VideoCaptureController's ability to add, remove, and keep
173 TEST_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
;
179 media::VideoCaptureParams session_300
= session_100
;
181 media::VideoCaptureParams session_400
= session_100
;
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);
190 // Clients in controller: []
191 ASSERT_EQ(0, controller_
->GetClientCount())
192 << "Client count should initially be zero.";
193 controller_
->AddClient(client_a_route_1
,
195 base::kNullProcessHandle
,
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
,
203 base::kNullProcessHandle
,
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
,
211 base::kNullProcessHandle
,
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.";
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());
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
,
234 base::kNullProcessHandle
,
237 // Clients in controller: [A/1, B/2]
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.";
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.";
271 static void CacheSyncPoint(uint32
* called_release_sync_point
,
272 uint32 release_sync_point
) {
273 *called_release_sync_point
= release_sync_point
;
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.
279 TEST_F(VideoCaptureControllerTest
, NormalCaptureMultipleClients
) {
280 // VideoCaptureController::ReturnBuffer() uses ImageTransportFactory.
281 #if defined(OS_ANDROID)
282 ImageTransportFactoryAndroid::InitializeForUnitTests(
283 scoped_ptr
<ImageTransportFactoryAndroid
>(
284 new NoTransportImageTransportFactoryAndroid
));
286 ImageTransportFactory::InitializeForUnitTests(
287 scoped_ptr
<ImageTransportFactory
>(new NoTransportImageTransportFactory
));
290 media::VideoCaptureParams session_100
;
291 session_100
.requested_format
= media::VideoCaptureFormat(
292 gfx::Size(320, 240), 30, media::PIXEL_FORMAT_I420
);
294 media::VideoCaptureParams session_200
= session_100
;
296 media::VideoCaptureParams session_300
= session_100
;
298 media::VideoCaptureParams session_1
= session_100
;
300 gfx::Size
capture_resolution(444, 200);
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
);
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);
312 // Start with two clients.
313 controller_
->AddClient(client_a_route_1
,
315 base::kNullProcessHandle
,
318 controller_
->AddClient(client_b_route_1
,
320 base::kNullProcessHandle
,
323 controller_
->AddClient(client_a_route_2
,
325 base::kNullProcessHandle
,
328 ASSERT_EQ(3, controller_
->GetClientCount());
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.
333 scoped_refptr
<media::VideoCaptureDevice::Client::Buffer
> buffer
;
335 device_
->ReserveOutputBuffer(media::VideoFrame::I420
, capture_resolution
);
336 ASSERT_TRUE(buffer
.get());
337 memset(buffer
->data(), buffer_no
++, buffer
->size());
340 EXPECT_CALL(*client_a_
, DoBufferCreated(client_a_route_1
)).Times(1);
341 EXPECT_CALL(*client_a_
, DoBufferReady(client_a_route_1
)).Times(1);
345 EXPECT_CALL(*client_b_
, DoBufferCreated(client_b_route_1
)).Times(1);
346 EXPECT_CALL(*client_b_
, DoBufferReady(client_b_route_1
)).Times(1);
350 EXPECT_CALL(*client_a_
, DoBufferCreated(client_a_route_2
)).Times(1);
351 EXPECT_CALL(*client_a_
, DoBufferReady(client_a_route_2
)).Times(1);
353 device_
->OnIncomingCapturedVideoFrame(
355 media::VideoCaptureFormat(capture_resolution
,
356 device_format
.frame_rate
,
357 media::PIXEL_FORMAT_I420
),
358 WrapI420Buffer(buffer
, capture_resolution
),
362 base::RunLoop().RunUntilIdle();
363 Mock::VerifyAndClearExpectations(client_a_
.get());
364 Mock::VerifyAndClearExpectations(client_b_
.get());
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.
370 device_
->ReserveOutputBuffer(media::VideoFrame::I420
, capture_resolution
);
371 ASSERT_TRUE(buffer
.get());
372 memset(buffer
->data(), buffer_no
++, buffer
->size());
373 device_
->OnIncomingCapturedVideoFrame(
375 media::VideoCaptureFormat(capture_resolution
,
376 device_format
.frame_rate
,
377 media::PIXEL_FORMAT_I420
),
378 WrapI420Buffer(buffer
, capture_resolution
),
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());
390 // Add a fourth client now that some buffers have come through.
391 controller_
->AddClient(client_b_route_2
,
393 base::kNullProcessHandle
,
396 Mock::VerifyAndClearExpectations(client_b_
.get());
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
,
402 ASSERT_TRUE(buffer
.get());
403 memset(buffer
->data(), buffer_no
++, buffer
->size());
404 device_
->OnIncomingCapturedVideoFrame(
406 media::VideoCaptureFormat(capture_resolution
,
407 device_format
.frame_rate
,
408 media::PIXEL_FORMAT_I420
),
409 WrapI420Buffer(buffer
, capture_resolution
),
413 // ReserveOutputBuffer ought to fail now, because the pool is depleted.
414 ASSERT_FALSE(device_
->ReserveOutputBuffer(media::VideoFrame::I420
,
415 capture_resolution
).get());
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());
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.
441 device_
->ReserveOutputBuffer(media::VideoFrame::I420
, capture_resolution
);
442 ASSERT_TRUE(buffer
.get());
443 memset(buffer
->data(), buffer_no
++, buffer
->size());
444 device_
->OnIncomingCapturedVideoFrame(
446 media::VideoCaptureFormat(capture_resolution
,
447 device_format
.frame_rate
,
448 media::PIXEL_FORMAT_I420
),
449 WrapI420Buffer(buffer
, capture_resolution
),
453 device_
->ReserveOutputBuffer(media::VideoFrame::I420
, capture_resolution
);
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);
460 ASSERT_TRUE(buffer
.get());
461 memset(buffer
->data(), buffer_no
++, buffer
->size());
462 device_
->OnIncomingCapturedVideoFrame(
464 media::VideoCaptureFormat(capture_resolution
,
465 device_format
.frame_rate
,
466 media::PIXEL_FORMAT_I420
),
467 WrapI420Buffer(buffer
, capture_resolution
),
470 // B2 is the only client left, and is the only one that should
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());
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
) {
486 for (int i
= 0; i
< shm_buffers
; ++i
) {
487 buffer
= device_
->ReserveOutputBuffer(media::VideoFrame::I420
,
489 ASSERT_TRUE(buffer
.get());
490 device_
->OnIncomingCapturedVideoFrame(
492 media::VideoCaptureFormat(capture_resolution
,
493 device_format
.frame_rate
,
494 media::PIXEL_FORMAT_I420
),
495 WrapI420Buffer(buffer
, capture_resolution
),
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();
505 GLHelper
* gl_helper
= ImageTransportFactory::GetInstance()->GetGLHelper();
507 for (int i
= 0; i
< mailbox_buffers
; ++i
) {
508 buffer
= device_
->ReserveOutputBuffer(media::VideoFrame::NATIVE_TEXTURE
,
510 ASSERT_TRUE(buffer
.get());
511 mailbox_syncpoints
[i
] = gl_helper
->InsertSyncPoint();
512 device_
->OnIncomingCapturedVideoFrame(
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
]),
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
]);
542 Mock::VerifyAndClearExpectations(client_b_
.get());
544 #if defined(OS_ANDROID)
545 ImageTransportFactoryAndroid::TerminateForUnitTests();
547 ImageTransportFactory::Terminate();
551 // Exercises the OnError() codepath of VideoCaptureController, and tests the
552 // behavior of various operations after the error state has been signalled.
553 TEST_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
);
558 media::VideoCaptureParams session_200
= session_100
;
560 const gfx::Size
capture_resolution(320, 240);
562 const VideoCaptureControllerID
route_id(0x99);
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());
572 // Second client connects after the error state. It also should get told of
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());
580 scoped_refptr
<media::VideoCaptureDevice::Client::Buffer
> buffer
=
581 device_
->ReserveOutputBuffer(media::VideoFrame::I420
, capture_resolution
);
582 ASSERT_TRUE(buffer
.get());
584 device_
->OnIncomingCapturedVideoFrame(
586 media::VideoCaptureFormat(
587 capture_resolution
, 30, media::PIXEL_FORMAT_I420
),
588 WrapI420Buffer(buffer
, capture_resolution
),
592 base::RunLoop().RunUntilIdle();
595 // Exercises the OnError() codepath of VideoCaptureController, and tests the
596 // behavior of various operations after the error state has been signalled.
597 TEST_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
);
602 media::VideoCaptureParams session_200
= session_100
;
604 const VideoCaptureControllerID
route_id(0x99);
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
);
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
615 base::RunLoop().RunUntilIdle();
616 Mock::VerifyAndClearExpectations(client_a_
.get());
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());
623 device_
->OnError("Test error");
624 device_
->OnIncomingCapturedVideoFrame(
626 media::VideoCaptureFormat(
627 dims
, device_format
.frame_rate
, media::PIXEL_FORMAT_I420
),
628 WrapI420Buffer(buffer
, dims
),
632 EXPECT_CALL(*client_a_
, DoError(route_id
)).Times(1);
633 base::RunLoop().RunUntilIdle();
634 Mock::VerifyAndClearExpectations(client_a_
.get());
636 // Second client connects after the error state. It also should get told of
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());
644 } // namespace content