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