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