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/memory/ref_counted.h"
11#include "base/memory/scoped_ptr.h"
12#include "base/message_loop/message_loop.h"
13#include "content/browser/browser_thread_impl.h"
14#include "content/browser/renderer_host/media/media_stream_provider.h"
15#include "content/browser/renderer_host/media/video_capture_controller.h"
16#include "content/browser/renderer_host/media/video_capture_manager.h"
17#include "content/common/media/media_stream_options.h"
18#include "media/video/capture/fake_video_capture_device.h"
19#include "media/video/capture/video_capture_device.h"
20#include "testing/gmock/include/gmock/gmock.h"
21#include "testing/gtest/include/gtest/gtest.h"
22
23using ::testing::_;
24using ::testing::AnyNumber;
25using ::testing::AtLeast;
26using ::testing::InSequence;
27using ::testing::Return;
28
29namespace content {
30
31enum { kDeviceId = 1 };
32
33ACTION_P4(StopCapture, controller, controller_id, controller_handler,
34          message_loop) {
35  message_loop->PostTask(FROM_HERE,
36      base::Bind(&VideoCaptureController::StopCapture,
37                 controller, controller_id, controller_handler));
38  message_loop->PostTask(FROM_HERE, base::MessageLoop::QuitClosure());
39}
40
41ACTION_P3(StopSession, controller, session_id, message_loop) {
42  message_loop->PostTask(FROM_HERE,
43      base::Bind(&VideoCaptureController::StopSession,
44                 controller, session_id));
45  message_loop->PostTask(FROM_HERE, base::MessageLoop::QuitClosure());
46}
47
48class MockVideoCaptureControllerEventHandler
49    : public VideoCaptureControllerEventHandler {
50 public:
51  MockVideoCaptureControllerEventHandler(VideoCaptureController* controller,
52                                         base::MessageLoop* message_loop)
53      : controller_(controller),
54        message_loop_(message_loop),
55        controller_id_(kDeviceId),
56        process_handle_(base::kNullProcessHandle) {
57  }
58  virtual ~MockVideoCaptureControllerEventHandler() {}
59
60  MOCK_METHOD1(DoBufferCreated, void(const VideoCaptureControllerID&));
61  MOCK_METHOD1(DoBufferReady, void(const VideoCaptureControllerID&));
62  MOCK_METHOD1(DoFrameInfo, void(const VideoCaptureControllerID&));
63  MOCK_METHOD1(DoEnded, void(const VideoCaptureControllerID&));
64
65  virtual void OnError(const VideoCaptureControllerID& id) OVERRIDE {}
66  virtual void OnBufferCreated(const VideoCaptureControllerID& id,
67                               base::SharedMemoryHandle handle,
68                               int length, int buffer_id) OVERRIDE {
69    EXPECT_EQ(id, controller_id_);
70    DoBufferCreated(id);
71  }
72  virtual void OnBufferReady(const VideoCaptureControllerID& id,
73                             int buffer_id,
74                             base::Time timestamp) OVERRIDE {
75    EXPECT_EQ(id, controller_id_);
76    DoBufferReady(id);
77    message_loop_->PostTask(FROM_HERE,
78        base::Bind(&VideoCaptureController::ReturnBuffer,
79                   controller_, controller_id_, this, buffer_id));
80  }
81  virtual void OnFrameInfo(
82      const VideoCaptureControllerID& id,
83      const media::VideoCaptureCapability& format) OVERRIDE {
84    EXPECT_EQ(id, controller_id_);
85    DoFrameInfo(id);
86  }
87  virtual void OnEnded(const VideoCaptureControllerID& id) OVERRIDE {
88    EXPECT_EQ(id, controller_id_);
89    DoEnded(id);
90  }
91
92  scoped_refptr<VideoCaptureController> controller_;
93  base::MessageLoop* message_loop_;
94  VideoCaptureControllerID controller_id_;
95  base::ProcessHandle process_handle_;
96};
97
98class MockVideoCaptureManager : public VideoCaptureManager {
99 public:
100  MockVideoCaptureManager()
101      : video_session_id_(kStartOpenSessionId),
102        device_name_("fake_device_0", "/dev/video0") {}
103
104  void Init() {
105    video_capture_device_.reset(
106        media::FakeVideoCaptureDevice::Create(device_name_));
107    ASSERT_TRUE(video_capture_device_.get() != NULL);
108  }
109
110  MOCK_METHOD3(StartCapture, void(int, int,
111      media::VideoCaptureDevice::EventHandler*));
112  MOCK_METHOD1(StopCapture, void(const media::VideoCaptureSessionId&));
113
114  void Start(const media::VideoCaptureParams& capture_params,
115             media::VideoCaptureDevice::EventHandler* vc_receiver) OVERRIDE {
116    StartCapture(capture_params.width, capture_params.height, vc_receiver);
117    // TODO(mcasas): Add testing for variable resolution video capture devices,
118    // supported by FakeVideoCaptureDevice. See crbug.com/261410, second part.
119    media::VideoCaptureCapability capture_format(
120        capture_params.width,
121        capture_params.height,
122        capture_params.frame_per_second,
123        media::VideoCaptureCapability::kI420,
124        0,
125        false,
126        media::ConstantResolutionVideoCaptureDevice);
127    video_capture_device_->Allocate(capture_format, vc_receiver);
128    video_capture_device_->Start();
129  }
130
131  void Stop(const media::VideoCaptureSessionId& capture_session_id,
132            base::Closure stopped_cb) OVERRIDE {
133    StopCapture(capture_session_id);
134    video_capture_device_->Stop();
135    video_capture_device_->DeAllocate();
136  }
137
138  int video_session_id_;
139  media::VideoCaptureDevice::Name device_name_;
140  scoped_ptr<media::VideoCaptureDevice> video_capture_device_;
141
142 private:
143  virtual ~MockVideoCaptureManager() {}
144  DISALLOW_COPY_AND_ASSIGN(MockVideoCaptureManager);
145};
146
147// Test class.
148class VideoCaptureControllerTest : public testing::Test {
149 public:
150  VideoCaptureControllerTest() {}
151  virtual ~VideoCaptureControllerTest() {}
152
153 protected:
154  virtual void SetUp() OVERRIDE {
155    message_loop_.reset(new base::MessageLoop(base::MessageLoop::TYPE_IO));
156    file_thread_.reset(new BrowserThreadImpl(BrowserThread::FILE,
157                                             message_loop_.get()));
158    io_thread_.reset(new BrowserThreadImpl(BrowserThread::IO,
159                                           message_loop_.get()));
160
161    vcm_ = new MockVideoCaptureManager();
162    vcm_->Init();
163    controller_ = new VideoCaptureController(vcm_.get());
164    controller_handler_.reset(new MockVideoCaptureControllerEventHandler(
165        controller_.get(), message_loop_.get()));
166  }
167
168  virtual void TearDown() OVERRIDE {}
169
170  scoped_ptr<base::MessageLoop> message_loop_;
171  scoped_ptr<BrowserThreadImpl> file_thread_;
172  scoped_ptr<BrowserThreadImpl> io_thread_;
173  scoped_refptr<MockVideoCaptureManager> vcm_;
174  scoped_ptr<MockVideoCaptureControllerEventHandler> controller_handler_;
175  scoped_refptr<VideoCaptureController> controller_;
176
177 private:
178  DISALLOW_COPY_AND_ASSIGN(VideoCaptureControllerTest);
179};
180
181// Try to start and stop capture.
182TEST_F(VideoCaptureControllerTest, StartAndStop) {
183  media::VideoCaptureParams capture_params;
184  capture_params.session_id = vcm_->video_session_id_;
185  capture_params.width = 320;
186  capture_params.height = 240;
187  capture_params.frame_per_second = 30;
188
189  InSequence s;
190  EXPECT_CALL(*vcm_.get(),
191              StartCapture(capture_params.width,
192                           capture_params.height,
193                           controller_.get())).Times(1);
194  EXPECT_CALL(*controller_handler_,
195              DoFrameInfo(controller_handler_->controller_id_))
196      .Times(AtLeast(1));
197  EXPECT_CALL(*controller_handler_,
198              DoBufferCreated(controller_handler_->controller_id_))
199      .Times(AtLeast(1));
200  EXPECT_CALL(*controller_handler_,
201              DoBufferReady(controller_handler_->controller_id_))
202      .Times(AtLeast(1))
203      .WillOnce(StopCapture(controller_.get(),
204                            controller_handler_->controller_id_,
205                            controller_handler_.get(),
206                            message_loop_.get()));
207  EXPECT_CALL(*vcm_.get(), StopCapture(vcm_->video_session_id_)).Times(1);
208
209  controller_->StartCapture(controller_handler_->controller_id_,
210                            controller_handler_.get(),
211                            controller_handler_->process_handle_,
212                            capture_params);
213  message_loop_->Run();
214}
215
216// Try to stop session before stopping capture.
217TEST_F(VideoCaptureControllerTest, StopSession) {
218  media::VideoCaptureParams capture_params;
219  capture_params.session_id = vcm_->video_session_id_;
220  capture_params.width = 320;
221  capture_params.height = 240;
222  capture_params.frame_per_second = 30;
223
224  InSequence s;
225  EXPECT_CALL(*vcm_.get(),
226              StartCapture(capture_params.width,
227                           capture_params.height,
228                           controller_.get())).Times(1);
229  EXPECT_CALL(*controller_handler_,
230              DoFrameInfo(controller_handler_->controller_id_))
231      .Times(AtLeast(1));
232  EXPECT_CALL(*controller_handler_,
233              DoBufferCreated(controller_handler_->controller_id_))
234      .Times(AtLeast(1));
235  EXPECT_CALL(*controller_handler_,
236              DoBufferReady(controller_handler_->controller_id_))
237      .Times(AtLeast(1))
238      .WillOnce(StopSession(controller_.get(),
239                            vcm_->video_session_id_,
240                            message_loop_.get()));
241  EXPECT_CALL(*controller_handler_,
242              DoEnded(controller_handler_->controller_id_))
243      .Times(1);
244
245  controller_->StartCapture(controller_handler_->controller_id_,
246                            controller_handler_.get(),
247                            controller_handler_->process_handle_,
248                            capture_params);
249  message_loop_->Run();
250
251  // The session is stopped now. There should be no buffer coming from
252  // controller.
253  EXPECT_CALL(*controller_handler_,
254              DoBufferReady(controller_handler_->controller_id_))
255      .Times(0);
256  message_loop_->PostDelayedTask(FROM_HERE,
257      base::MessageLoop::QuitClosure(), base::TimeDelta::FromSeconds(1));
258  message_loop_->Run();
259
260  EXPECT_CALL(*vcm_.get(), StopCapture(vcm_->video_session_id_)).Times(1);
261  controller_->StopCapture(controller_handler_->controller_id_,
262                           controller_handler_.get());
263}
264
265}  // namespace content
266