15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Unit test for VideoCaptureController.
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
10d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "base/bind_helpers.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/ref_counted.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_ptr.h"
139ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "base/message_loop/message_loop.h"
14d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "base/run_loop.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/browser/renderer_host/media/media_stream_provider.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/browser/renderer_host/media/video_capture_controller.h"
17d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "content/browser/renderer_host/media/video_capture_controller_event_handler.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/browser/renderer_host/media/video_capture_manager.h"
195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "content/common/gpu/client/gl_helper.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/common/media/media_stream_options.h"
21d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "content/public/test/test_browser_thread_bundle.h"
22a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "gpu/command_buffer/common/mailbox_holder.h"
23d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "media/base/video_util.h"
24d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "media/video/capture/video_capture_types.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "testing/gmock/include/gmock/gmock.h"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "testing/gtest/include/gtest/gtest.h"
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#if defined(OS_ANDROID)
295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "content/browser/renderer_host/test/no_transport_image_transport_factory_android.h"
305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#else
315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "content/browser/compositor/test/no_transport_image_transport_factory.h"
325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#endif
335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using ::testing::InSequence;
35d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)using ::testing::Mock;
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace content {
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class MockVideoCaptureControllerEventHandler
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : public VideoCaptureControllerEventHandler {
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
42d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  explicit MockVideoCaptureControllerEventHandler(
43d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      VideoCaptureController* controller)
44d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      : controller_(controller) {}
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~MockVideoCaptureControllerEventHandler() {}
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
47d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // These mock methods are delegated to by our fake implementation of
48d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // VideoCaptureControllerEventHandler, to be used in EXPECT_CALL().
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MOCK_METHOD1(DoBufferCreated, void(const VideoCaptureControllerID&));
501e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  MOCK_METHOD1(DoBufferDestroyed, void(const VideoCaptureControllerID&));
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MOCK_METHOD1(DoBufferReady, void(const VideoCaptureControllerID&));
52a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  MOCK_METHOD1(DoMailboxBufferReady, void(const VideoCaptureControllerID&));
53c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  MOCK_METHOD1(DoEnded, void(const VideoCaptureControllerID&));
54d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  MOCK_METHOD1(DoError, void(const VideoCaptureControllerID&));
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
56d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  virtual void OnError(const VideoCaptureControllerID& id) OVERRIDE {
57d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    DoError(id);
58d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  }
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void OnBufferCreated(const VideoCaptureControllerID& id,
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               base::SharedMemoryHandle handle,
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               int length, int buffer_id) OVERRIDE {
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DoBufferCreated(id);
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
641e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  virtual void OnBufferDestroyed(const VideoCaptureControllerID& id,
651e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                                 int buffer_id) OVERRIDE {
661e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    DoBufferDestroyed(id);
671e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  }
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void OnBufferReady(const VideoCaptureControllerID& id,
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             int buffer_id,
70a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                             const media::VideoCaptureFormat& format,
711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                             const gfx::Rect& visible_rect,
72a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                             base::TimeTicks timestamp) OVERRIDE {
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DoBufferReady(id);
74a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    base::MessageLoop::current()->PostTask(
75a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        FROM_HERE,
76a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        base::Bind(&VideoCaptureController::ReturnBuffer,
77a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                   base::Unretained(controller_),
78a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                   id,
79a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                   this,
80a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                   buffer_id,
815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                   0));
82a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
83a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  virtual void OnMailboxBufferReady(const VideoCaptureControllerID& id,
84a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                    int buffer_id,
85a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                    const gpu::MailboxHolder& mailbox_holder,
86a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                    const media::VideoCaptureFormat& format,
87a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                    base::TimeTicks timestamp) OVERRIDE {
88a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    DoMailboxBufferReady(id);
89a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    base::MessageLoop::current()->PostTask(
90a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        FROM_HERE,
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(&VideoCaptureController::ReturnBuffer,
92a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                   base::Unretained(controller_),
93a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                   id,
94a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                   this,
95a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                   buffer_id,
965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                   mailbox_holder.sync_point));
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
98c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  virtual void OnEnded(const VideoCaptureControllerID& id) OVERRIDE {
99c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    DoEnded(id);
100d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    // OnEnded() must respond by (eventually) unregistering the client.
101d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    base::MessageLoop::current()->PostTask(FROM_HERE,
102d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        base::Bind(base::IgnoreResult(&VideoCaptureController::RemoveClient),
103d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)                   base::Unretained(controller_), id, this));
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
106d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  VideoCaptureController* controller_;
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Test class.
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class VideoCaptureControllerTest : public testing::Test {
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VideoCaptureControllerTest() {}
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~VideoCaptureControllerTest() {}
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) protected:
116d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  static const int kPoolSize = 3;
117d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void SetUp() OVERRIDE {
1195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    controller_.reset(new VideoCaptureController(kPoolSize));
120d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    device_ = controller_->NewDeviceClient().Pass();
121d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    client_a_.reset(new MockVideoCaptureControllerEventHandler(
122d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        controller_.get()));
123d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    client_b_.reset(new MockVideoCaptureControllerEventHandler(
124d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        controller_.get()));
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
127d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  virtual void TearDown() OVERRIDE {
128d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    base::RunLoop().RunUntilIdle();
129d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  }
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
131a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  scoped_refptr<media::VideoFrame> WrapI420Buffer(
132a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      const scoped_refptr<media::VideoCaptureDevice::Client::Buffer>& buffer,
133a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      gfx::Size dimensions) {
134a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return media::VideoFrame::WrapExternalPackedMemory(
135a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        media::VideoFrame::I420,
136a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        dimensions,
137a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        gfx::Rect(dimensions),
138a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        dimensions,
139a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        reinterpret_cast<uint8*>(buffer->data()),
140a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        media::VideoFrame::AllocationSize(media::VideoFrame::I420, dimensions),
141a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        base::SharedMemory::NULLHandle(),
142a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        base::TimeDelta(),
143a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        base::Closure());
144a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
145a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
146a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  scoped_refptr<media::VideoFrame> WrapMailboxBuffer(
147a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      const scoped_refptr<media::VideoCaptureDevice::Client::Buffer>& buffer,
148a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      scoped_ptr<gpu::MailboxHolder> holder,
149a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      const media::VideoFrame::ReleaseMailboxCB& release_cb,
150a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      gfx::Size dimensions) {
151a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return media::VideoFrame::WrapNativeTexture(
152a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        holder.Pass(),
153a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        release_cb,
154a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        dimensions,
155a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        gfx::Rect(dimensions),
156a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        dimensions,
157a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        base::TimeDelta(),
158a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        media::VideoFrame::ReadPixelsCB());
159a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
160a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
161a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  TestBrowserThreadBundle bundle_;
162d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  scoped_ptr<MockVideoCaptureControllerEventHandler> client_a_;
163d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  scoped_ptr<MockVideoCaptureControllerEventHandler> client_b_;
164d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  scoped_ptr<VideoCaptureController> controller_;
16568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  scoped_ptr<media::VideoCaptureDevice::Client> device_;
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(VideoCaptureControllerTest);
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
171d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)// A simple test of VideoCaptureController's ability to add, remove, and keep
172d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)// track of clients.
173d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)TEST_F(VideoCaptureControllerTest, AddAndRemoveClients) {
174d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  media::VideoCaptureParams session_100;
1751e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  session_100.requested_format = media::VideoCaptureFormat(
176f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      gfx::Size(320, 240), 30, media::PIXEL_FORMAT_I420);
177d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  media::VideoCaptureParams session_200 = session_100;
178d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
179d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  media::VideoCaptureParams session_300 = session_100;
180d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
181d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  media::VideoCaptureParams session_400 = session_100;
182d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
183d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Intentionally use the same route ID for two of the clients: the device_ids
184d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // are a per-VideoCaptureHost namespace, and can overlap across hosts.
185d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  const VideoCaptureControllerID client_a_route_1(44);
186d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  const VideoCaptureControllerID client_a_route_2(30);
187d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  const VideoCaptureControllerID client_b_route_1(30);
188d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  const VideoCaptureControllerID client_b_route_2(1);
189d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
190d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Clients in controller: []
191d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  ASSERT_EQ(0, controller_->GetClientCount())
192d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      << "Client count should initially be zero.";
193f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  controller_->AddClient(client_a_route_1,
194f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                         client_a_.get(),
195f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                         base::kNullProcessHandle,
196f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                         100,
197f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                         session_100);
198d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Clients in controller: [A/1]
199d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  ASSERT_EQ(1, controller_->GetClientCount())
200a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      << "Adding client A/1 should bump client count.";
201f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  controller_->AddClient(client_a_route_2,
202f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                         client_a_.get(),
203f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                         base::kNullProcessHandle,
204f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                         200,
205f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                         session_200);
206d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Clients in controller: [A/1, A/2]
207d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  ASSERT_EQ(2, controller_->GetClientCount())
208d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      << "Adding client A/2 should bump client count.";
209f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  controller_->AddClient(client_b_route_1,
210f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                         client_b_.get(),
211f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                         base::kNullProcessHandle,
212f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                         300,
213f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                         session_300);
214d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Clients in controller: [A/1, A/2, B/1]
215d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  ASSERT_EQ(3, controller_->GetClientCount())
216d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      << "Adding client B/1 should bump client count.";
217d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  ASSERT_EQ(200,
218d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      controller_->RemoveClient(client_a_route_2, client_a_.get()))
219d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      << "Removing client A/1 should return its session_id.";
220d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Clients in controller: [A/1, B/1]
221d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  ASSERT_EQ(2, controller_->GetClientCount());
222d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  ASSERT_EQ(static_cast<int>(kInvalidMediaCaptureSessionId),
223d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      controller_->RemoveClient(client_a_route_2, client_a_.get()))
224d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      << "Removing a nonexistant client should fail.";
225d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Clients in controller: [A/1, B/1]
226d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  ASSERT_EQ(2, controller_->GetClientCount());
227d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  ASSERT_EQ(300,
228d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      controller_->RemoveClient(client_b_route_1, client_b_.get()))
229d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      << "Removing client B/1 should return its session_id.";
230d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Clients in controller: [A/1]
231d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  ASSERT_EQ(1, controller_->GetClientCount());
232f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  controller_->AddClient(client_b_route_2,
233f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                         client_b_.get(),
234f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                         base::kNullProcessHandle,
235f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                         400,
236f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                         session_400);
237d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Clients in controller: [A/1, B/2]
238d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
239d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  EXPECT_CALL(*client_a_, DoEnded(client_a_route_1)).Times(1);
240d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  controller_->StopSession(100);  // Session 100 == client A/1
241d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  Mock::VerifyAndClearExpectations(client_a_.get());
242d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  ASSERT_EQ(2, controller_->GetClientCount())
243d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      << "Client should be closed but still exist after StopSession.";
244d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Clients in controller: [A/1 (closed, removal pending), B/2]
245d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  base::RunLoop().RunUntilIdle();
246d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Clients in controller: [B/2]
247d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  ASSERT_EQ(1, controller_->GetClientCount())
248d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      << "Client A/1 should be deleted by now.";
249d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  controller_->StopSession(200);  // Session 200 does not exist anymore
250d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Clients in controller: [B/2]
251d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  ASSERT_EQ(1, controller_->GetClientCount())
252d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      << "Stopping non-existant session 200 should be a no-op.";
253d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  controller_->StopSession(256);  // Session 256 never existed.
254d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Clients in controller: [B/2]
255d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  ASSERT_EQ(1, controller_->GetClientCount())
256d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      << "Stopping non-existant session 256 should be a no-op.";
257d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  ASSERT_EQ(static_cast<int>(kInvalidMediaCaptureSessionId),
258d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      controller_->RemoveClient(client_a_route_1, client_a_.get()))
259d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      << "Removing already-removed client A/1 should fail.";
260d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Clients in controller: [B/2]
261d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  ASSERT_EQ(1, controller_->GetClientCount())
262d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      << "Removing non-existant session 200 should be a no-op.";
263d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  ASSERT_EQ(400,
264d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      controller_->RemoveClient(client_b_route_2, client_b_.get()))
265d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      << "Removing client B/2 should return its session_id.";
266d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Clients in controller: []
267d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  ASSERT_EQ(0, controller_->GetClientCount())
268d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      << "Client count should return to zero after all clients are gone.";
269d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}
270d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
2715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)static void CacheSyncPoint(uint32* called_release_sync_point,
2725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                           uint32 release_sync_point) {
2735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  *called_release_sync_point = release_sync_point;
274a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
275a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
276d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)// This test will connect and disconnect several clients while simulating an
277d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)// active capture device being started and generating frames. It runs on one
278d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)// thread and is intended to behave deterministically.
279d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)TEST_F(VideoCaptureControllerTest, NormalCaptureMultipleClients) {
2805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// VideoCaptureController::ReturnBuffer() uses ImageTransportFactory.
2815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#if defined(OS_ANDROID)
2825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  ImageTransportFactoryAndroid::InitializeForUnitTests(
2835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      scoped_ptr<ImageTransportFactoryAndroid>(
2845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          new NoTransportImageTransportFactoryAndroid));
2855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#else
2865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  ImageTransportFactory::InitializeForUnitTests(
2875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      scoped_ptr<ImageTransportFactory>(new NoTransportImageTransportFactory));
2885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#endif
2895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
290d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  media::VideoCaptureParams session_100;
2911e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  session_100.requested_format = media::VideoCaptureFormat(
292f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      gfx::Size(320, 240), 30, media::PIXEL_FORMAT_I420);
293d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
294d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  media::VideoCaptureParams session_200 = session_100;
295d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
296d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  media::VideoCaptureParams session_300 = session_100;
297d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
298d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  media::VideoCaptureParams session_1 = session_100;
299d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
3001e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  gfx::Size capture_resolution(444, 200);
3011e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
302d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // The device format needn't match the VideoCaptureParams (the camera can do
303f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // what it wants). Pick something random.
304f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  media::VideoCaptureFormat device_format(
305f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      gfx::Size(10, 10), 25, media::PIXEL_FORMAT_RGB24);
306d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
307d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  const VideoCaptureControllerID client_a_route_1(0xa1a1a1a1);
308d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  const VideoCaptureControllerID client_a_route_2(0xa2a2a2a2);
309d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  const VideoCaptureControllerID client_b_route_1(0xb1b1b1b1);
310d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  const VideoCaptureControllerID client_b_route_2(0xb2b2b2b2);
311d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
312d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Start with two clients.
313f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  controller_->AddClient(client_a_route_1,
314f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                         client_a_.get(),
315f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                         base::kNullProcessHandle,
316f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                         100,
317f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                         session_100);
318f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  controller_->AddClient(client_b_route_1,
319f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                         client_b_.get(),
320f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                         base::kNullProcessHandle,
321f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                         300,
322f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                         session_300);
323f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  controller_->AddClient(client_a_route_2,
324f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                         client_a_.get(),
325f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                         base::kNullProcessHandle,
326f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                         200,
327f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                         session_200);
3281e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  ASSERT_EQ(3, controller_->GetClientCount());
329d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
330f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Now, simulate an incoming captured buffer from the capture device. As a
331f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // side effect this will cause the first buffer to be shared with clients.
332f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  uint8 buffer_no = 1;
333f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  scoped_refptr<media::VideoCaptureDevice::Client::Buffer> buffer;
334f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  buffer =
335f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      device_->ReserveOutputBuffer(media::VideoFrame::I420, capture_resolution);
3361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  ASSERT_TRUE(buffer.get());
337f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  memset(buffer->data(), buffer_no++, buffer->size());
338d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  {
339d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    InSequence s;
3401e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    EXPECT_CALL(*client_a_, DoBufferCreated(client_a_route_1)).Times(1);
3411e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    EXPECT_CALL(*client_a_, DoBufferReady(client_a_route_1)).Times(1);
342d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  }
343d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  {
344d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    InSequence s;
3451e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    EXPECT_CALL(*client_b_, DoBufferCreated(client_b_route_1)).Times(1);
3461e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    EXPECT_CALL(*client_b_, DoBufferReady(client_b_route_1)).Times(1);
347d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  }
348d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  {
349d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    InSequence s;
3501e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    EXPECT_CALL(*client_a_, DoBufferCreated(client_a_route_2)).Times(1);
3511e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    EXPECT_CALL(*client_a_, DoBufferReady(client_a_route_2)).Times(1);
352d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  }
353a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  device_->OnIncomingCapturedVideoFrame(
354a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      buffer,
355a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      media::VideoCaptureFormat(capture_resolution,
356a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                device_format.frame_rate,
357a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                media::PIXEL_FORMAT_I420),
358a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      WrapI420Buffer(buffer, capture_resolution),
359a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      base::TimeTicks());
360f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  buffer = NULL;
361d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
362d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  base::RunLoop().RunUntilIdle();
363d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  Mock::VerifyAndClearExpectations(client_a_.get());
364d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  Mock::VerifyAndClearExpectations(client_b_.get());
365d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
366f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Second buffer which ought to use the same shared memory buffer. In this
367f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // case pretend that the Buffer pointer is held by the device for a long
368f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // delay. This shouldn't affect anything.
369f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  buffer =
370f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      device_->ReserveOutputBuffer(media::VideoFrame::I420, capture_resolution);
3711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  ASSERT_TRUE(buffer.get());
372f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  memset(buffer->data(), buffer_no++, buffer->size());
373a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  device_->OnIncomingCapturedVideoFrame(
374a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      buffer,
375a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      media::VideoCaptureFormat(capture_resolution,
376a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                device_format.frame_rate,
377a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                media::PIXEL_FORMAT_I420),
378a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      WrapI420Buffer(buffer, capture_resolution),
379a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      base::TimeTicks());
380f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  buffer = NULL;
381d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
382d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // The buffer should be delivered to the clients in any order.
383d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  EXPECT_CALL(*client_a_, DoBufferReady(client_a_route_1)).Times(1);
384d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  EXPECT_CALL(*client_b_, DoBufferReady(client_b_route_1)).Times(1);
3851e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  EXPECT_CALL(*client_a_, DoBufferReady(client_a_route_2)).Times(1);
386d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  base::RunLoop().RunUntilIdle();
387d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  Mock::VerifyAndClearExpectations(client_a_.get());
388d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  Mock::VerifyAndClearExpectations(client_b_.get());
389d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
390f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Add a fourth client now that some buffers have come through.
391f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  controller_->AddClient(client_b_route_2,
392f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                         client_b_.get(),
393f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                         base::kNullProcessHandle,
394f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                         1,
395f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                         session_1);
396d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  Mock::VerifyAndClearExpectations(client_b_.get());
397d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
398f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Third, fourth, and fifth buffers. Pretend they all arrive at the same time.
399d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  for (int i = 0; i < kPoolSize; i++) {
400f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    buffer = device_->ReserveOutputBuffer(media::VideoFrame::I420,
401f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                          capture_resolution);
4021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    ASSERT_TRUE(buffer.get());
403f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    memset(buffer->data(), buffer_no++, buffer->size());
404a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    device_->OnIncomingCapturedVideoFrame(
405a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        buffer,
406a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        media::VideoCaptureFormat(capture_resolution,
407a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                  device_format.frame_rate,
408a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                  media::PIXEL_FORMAT_I420),
409a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        WrapI420Buffer(buffer, capture_resolution),
410a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        base::TimeTicks());
411f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    buffer = NULL;
412d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  }
413d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // ReserveOutputBuffer ought to fail now, because the pool is depleted.
414f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  ASSERT_FALSE(device_->ReserveOutputBuffer(media::VideoFrame::I420,
4151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                            capture_resolution).get());
4161e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
4171e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // The new client needs to be told of 3 buffers; the old clients only 2.
4181e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  EXPECT_CALL(*client_b_, DoBufferCreated(client_b_route_2)).Times(kPoolSize);
4191e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  EXPECT_CALL(*client_b_, DoBufferReady(client_b_route_2)).Times(kPoolSize);
4201e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  EXPECT_CALL(*client_a_, DoBufferCreated(client_a_route_1))
4211e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      .Times(kPoolSize - 1);
422d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  EXPECT_CALL(*client_a_, DoBufferReady(client_a_route_1)).Times(kPoolSize);
4231e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  EXPECT_CALL(*client_a_, DoBufferCreated(client_a_route_2))
4241e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      .Times(kPoolSize - 1);
425d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  EXPECT_CALL(*client_a_, DoBufferReady(client_a_route_2)).Times(kPoolSize);
4261e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  EXPECT_CALL(*client_b_, DoBufferCreated(client_b_route_1))
4271e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      .Times(kPoolSize - 1);
428d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  EXPECT_CALL(*client_b_, DoBufferReady(client_b_route_1)).Times(kPoolSize);
429d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  base::RunLoop().RunUntilIdle();
430d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  Mock::VerifyAndClearExpectations(client_a_.get());
431d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  Mock::VerifyAndClearExpectations(client_b_.get());
432d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
433f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Now test the interaction of client shutdown and buffer delivery.
434d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Kill A1 via renderer disconnect (synchronous).
435d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  controller_->RemoveClient(client_a_route_1, client_a_.get());
436d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Kill B1 via session close (posts a task to disconnect).
437d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  EXPECT_CALL(*client_b_, DoEnded(client_b_route_1)).Times(1);
438d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  controller_->StopSession(300);
439f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Queue up another buffer.
440f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  buffer =
441f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      device_->ReserveOutputBuffer(media::VideoFrame::I420, capture_resolution);
4421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  ASSERT_TRUE(buffer.get());
443f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  memset(buffer->data(), buffer_no++, buffer->size());
444a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  device_->OnIncomingCapturedVideoFrame(
445a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      buffer,
446a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      media::VideoCaptureFormat(capture_resolution,
447a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                device_format.frame_rate,
448a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                media::PIXEL_FORMAT_I420),
449a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      WrapI420Buffer(buffer, capture_resolution),
450a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      base::TimeTicks());
451f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  buffer = NULL;
452f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  buffer =
453f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      device_->ReserveOutputBuffer(media::VideoFrame::I420, capture_resolution);
454d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  {
455d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    // Kill A2 via session close (posts a task to disconnect, but A2 must not
456f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // be sent either of these two buffers).
457d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    EXPECT_CALL(*client_a_, DoEnded(client_a_route_2)).Times(1);
458d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    controller_->StopSession(200);
459d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  }
4601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  ASSERT_TRUE(buffer.get());
461f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  memset(buffer->data(), buffer_no++, buffer->size());
462a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  device_->OnIncomingCapturedVideoFrame(
463a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      buffer,
464a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      media::VideoCaptureFormat(capture_resolution,
465a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                device_format.frame_rate,
466a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                media::PIXEL_FORMAT_I420),
467a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      WrapI420Buffer(buffer, capture_resolution),
468a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      base::TimeTicks());
469f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  buffer = NULL;
470d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // B2 is the only client left, and is the only one that should
471f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // get the buffer.
472d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  EXPECT_CALL(*client_b_, DoBufferReady(client_b_route_2)).Times(2);
473d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  base::RunLoop().RunUntilIdle();
474d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  Mock::VerifyAndClearExpectations(client_a_.get());
475d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  Mock::VerifyAndClearExpectations(client_b_.get());
476a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
477a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Allocate all buffers from the buffer pool, half as SHM buffer and half as
478a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // mailbox buffers.  Make sure of different counts though.
479a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  int shm_buffers = kPoolSize / 2;
480a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  int mailbox_buffers = kPoolSize - shm_buffers;
481a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (shm_buffers == mailbox_buffers) {
482a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    shm_buffers--;
483a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    mailbox_buffers++;
484a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
485a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
486a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  for (int i = 0; i < shm_buffers; ++i) {
487a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    buffer = device_->ReserveOutputBuffer(media::VideoFrame::I420,
488a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                          capture_resolution);
4891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    ASSERT_TRUE(buffer.get());
490a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    device_->OnIncomingCapturedVideoFrame(
491a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        buffer,
492a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        media::VideoCaptureFormat(capture_resolution,
493a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                  device_format.frame_rate,
494a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                  media::PIXEL_FORMAT_I420),
495a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        WrapI420Buffer(buffer, capture_resolution),
496a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        base::TimeTicks());
497a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    buffer = NULL;
498a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
499a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  std::vector<uint32> mailbox_syncpoints(mailbox_buffers);
5005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  std::vector<uint32> release_syncpoints(mailbox_buffers);
5015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#if defined(OS_ANDROID)
5025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  GLHelper* gl_helper =
5035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      ImageTransportFactoryAndroid::GetInstance()->GetGLHelper();
5045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#else
5055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  GLHelper* gl_helper = ImageTransportFactory::GetInstance()->GetGLHelper();
5065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#endif
507a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  for (int i = 0; i < mailbox_buffers; ++i) {
508a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    buffer = device_->ReserveOutputBuffer(media::VideoFrame::NATIVE_TEXTURE,
509a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                          gfx::Size(0, 0));
5101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    ASSERT_TRUE(buffer.get());
5115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    mailbox_syncpoints[i] = gl_helper->InsertSyncPoint();
512a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    device_->OnIncomingCapturedVideoFrame(
513a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        buffer,
514a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        media::VideoCaptureFormat(capture_resolution,
515a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                  device_format.frame_rate,
516a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                  media::PIXEL_FORMAT_TEXTURE),
5175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        WrapMailboxBuffer(buffer,
5185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                          make_scoped_ptr(new gpu::MailboxHolder(
5195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                              gpu::Mailbox(), 0, mailbox_syncpoints[i])),
5205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                          base::Bind(&CacheSyncPoint, &release_syncpoints[i]),
5215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                          capture_resolution),
522a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        base::TimeTicks());
523a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    buffer = NULL;
524a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
525a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // ReserveOutputBuffers ought to fail now regardless of buffer format, because
526a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // the pool is depleted.
527a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  ASSERT_FALSE(device_->ReserveOutputBuffer(media::VideoFrame::I420,
5281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                            capture_resolution).get());
529a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  ASSERT_FALSE(device_->ReserveOutputBuffer(media::VideoFrame::NATIVE_TEXTURE,
5301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                            gfx::Size(0, 0)).get());
531a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  EXPECT_CALL(*client_b_, DoBufferReady(client_b_route_2)).Times(shm_buffers);
532a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  EXPECT_CALL(*client_b_, DoMailboxBufferReady(client_b_route_2))
533a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      .Times(mailbox_buffers);
534a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  base::RunLoop().RunUntilIdle();
535a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  for (size_t i = 0; i < mailbox_syncpoints.size(); ++i) {
5365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // A new release sync point must be inserted when the video frame is
5375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // returned to the Browser process.
5385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // See: MockVideoCaptureControllerEventHandler::OnMailboxBufferReady() and
5395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // VideoCaptureController::ReturnBuffer()
5405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    ASSERT_NE(mailbox_syncpoints[i], release_syncpoints[i]);
541a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
542a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  Mock::VerifyAndClearExpectations(client_b_.get());
5435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
5445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#if defined(OS_ANDROID)
5455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  ImageTransportFactoryAndroid::TerminateForUnitTests();
5465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#else
5475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  ImageTransportFactory::Terminate();
5485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#endif
549d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}
550d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
551d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)// Exercises the OnError() codepath of VideoCaptureController, and tests the
552d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)// behavior of various operations after the error state has been signalled.
553d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)TEST_F(VideoCaptureControllerTest, ErrorBeforeDeviceCreation) {
554d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  media::VideoCaptureParams session_100;
5551e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  session_100.requested_format = media::VideoCaptureFormat(
556f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      gfx::Size(320, 240), 30, media::PIXEL_FORMAT_I420);
557d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
558d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  media::VideoCaptureParams session_200 = session_100;
559f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
560f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  const gfx::Size capture_resolution(320, 240);
561d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
562d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  const VideoCaptureControllerID route_id(0x99);
563d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
564d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Start with one client.
565f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  controller_->AddClient(
566f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      route_id, client_a_.get(), base::kNullProcessHandle, 100, session_100);
5675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  device_->OnError("Test Error");
568d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  EXPECT_CALL(*client_a_, DoError(route_id)).Times(1);
569d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  base::RunLoop().RunUntilIdle();
570d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  Mock::VerifyAndClearExpectations(client_a_.get());
571d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
572d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Second client connects after the error state. It also should get told of
573d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // the error.
574d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  EXPECT_CALL(*client_b_, DoError(route_id)).Times(1);
575f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  controller_->AddClient(
576f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      route_id, client_b_.get(), base::kNullProcessHandle, 200, session_200);
577d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  base::RunLoop().RunUntilIdle();
578d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  Mock::VerifyAndClearExpectations(client_b_.get());
579d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
580f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  scoped_refptr<media::VideoCaptureDevice::Client::Buffer> buffer =
581f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      device_->ReserveOutputBuffer(media::VideoFrame::I420, capture_resolution);
5821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  ASSERT_TRUE(buffer.get());
583f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
584a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  device_->OnIncomingCapturedVideoFrame(
585a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      buffer,
586a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      media::VideoCaptureFormat(
587a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          capture_resolution, 30, media::PIXEL_FORMAT_I420),
588a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      WrapI420Buffer(buffer, capture_resolution),
589a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      base::TimeTicks());
590f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  buffer = NULL;
591d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
592d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  base::RunLoop().RunUntilIdle();
5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
595d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)// Exercises the OnError() codepath of VideoCaptureController, and tests the
596d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)// behavior of various operations after the error state has been signalled.
597d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)TEST_F(VideoCaptureControllerTest, ErrorAfterDeviceCreation) {
598d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  media::VideoCaptureParams session_100;
5991e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  session_100.requested_format = media::VideoCaptureFormat(
600f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      gfx::Size(320, 240), 30, media::PIXEL_FORMAT_I420);
601d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
602d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  media::VideoCaptureParams session_200 = session_100;
603d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
604d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  const VideoCaptureControllerID route_id(0x99);
605d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
606d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Start with one client.
607f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  controller_->AddClient(
608f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      route_id, client_a_.get(), base::kNullProcessHandle, 100, session_100);
609f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  media::VideoCaptureFormat device_format(
610f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      gfx::Size(10, 10), 25, media::PIXEL_FORMAT_ARGB);
611f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
612f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Start the device. Then, before the first buffer, signal an error and
613f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // deliver the buffer. The error should be propagated to clients; the buffer
614f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // should not be.
615d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  base::RunLoop().RunUntilIdle();
616d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  Mock::VerifyAndClearExpectations(client_a_.get());
617d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
618f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  const gfx::Size dims(320, 240);
619f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  scoped_refptr<media::VideoCaptureDevice::Client::Buffer> buffer =
620f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      device_->ReserveOutputBuffer(media::VideoFrame::I420, dims);
6211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  ASSERT_TRUE(buffer.get());
622d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
6235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  device_->OnError("Test error");
624a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  device_->OnIncomingCapturedVideoFrame(
625a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      buffer,
626a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      media::VideoCaptureFormat(
627a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          dims, device_format.frame_rate, media::PIXEL_FORMAT_I420),
628a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      WrapI420Buffer(buffer, dims),
629a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      base::TimeTicks());
630f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  buffer = NULL;
631d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
632d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  EXPECT_CALL(*client_a_, DoError(route_id)).Times(1);
633d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  base::RunLoop().RunUntilIdle();
634d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  Mock::VerifyAndClearExpectations(client_a_.get());
635d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
636d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Second client connects after the error state. It also should get told of
637d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // the error.
638d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  EXPECT_CALL(*client_b_, DoError(route_id)).Times(1);
639f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  controller_->AddClient(
640f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      route_id, client_b_.get(), base::kNullProcessHandle, 200, session_200);
641d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  Mock::VerifyAndClearExpectations(client_b_.get());
6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace content
645