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#include "base/message_loop/message_loop.h"
6#include "content/child/child_process.h"
7#include "content/common/media/video_capture_messages.h"
8#include "content/renderer/media/video_capture_impl.h"
9#include "media/base/bind_to_current_loop.h"
10#include "testing/gmock/include/gmock/gmock.h"
11#include "testing/gtest/include/gtest/gtest.h"
12
13using ::testing::_;
14using ::testing::AtLeast;
15using ::testing::InvokeWithoutArgs;
16using ::testing::Return;
17using ::testing::SaveArg;
18
19namespace content {
20
21class MockVideoCaptureMessageFilter : public VideoCaptureMessageFilter {
22 public:
23  MockVideoCaptureMessageFilter() : VideoCaptureMessageFilter() {}
24
25  // Filter implementation.
26  MOCK_METHOD1(Send, bool(IPC::Message* message));
27
28 protected:
29  virtual ~MockVideoCaptureMessageFilter() {}
30
31 private:
32  DISALLOW_COPY_AND_ASSIGN(MockVideoCaptureMessageFilter);
33};
34
35class VideoCaptureImplTest : public ::testing::Test {
36 public:
37  class MockVideoCaptureImpl : public VideoCaptureImpl {
38   public:
39    MockVideoCaptureImpl(const media::VideoCaptureSessionId id,
40                         VideoCaptureMessageFilter* filter)
41        : VideoCaptureImpl(id, filter) {
42    }
43    virtual ~MockVideoCaptureImpl() {}
44
45    // Override Send() to mimic device to send events.
46    virtual void Send(IPC::Message* message) OVERRIDE {
47      CHECK(message);
48
49      // In this method, messages are sent to the according handlers as if
50      // we are the device.
51      bool handled = true;
52      IPC_BEGIN_MESSAGE_MAP(MockVideoCaptureImpl, *message)
53        IPC_MESSAGE_HANDLER(VideoCaptureHostMsg_Start, DeviceStartCapture)
54        IPC_MESSAGE_HANDLER(VideoCaptureHostMsg_Pause, DevicePauseCapture)
55        IPC_MESSAGE_HANDLER(VideoCaptureHostMsg_Stop, DeviceStopCapture)
56        IPC_MESSAGE_HANDLER(VideoCaptureHostMsg_BufferReady,
57                            DeviceReceiveEmptyBuffer)
58        IPC_MESSAGE_HANDLER(VideoCaptureHostMsg_GetDeviceSupportedFormats,
59                            DeviceGetSupportedFormats)
60        IPC_MESSAGE_HANDLER(VideoCaptureHostMsg_GetDeviceFormatsInUse,
61                            DeviceGetFormatsInUse)
62        IPC_MESSAGE_UNHANDLED(handled = false)
63      IPC_END_MESSAGE_MAP()
64      EXPECT_TRUE(handled);
65      delete message;
66    }
67
68    void DeviceStartCapture(int device_id,
69                            media::VideoCaptureSessionId session_id,
70                            const media::VideoCaptureParams& params) {
71      OnStateChanged(VIDEO_CAPTURE_STATE_STARTED);
72      capture_params_ = params;
73    }
74
75    void DevicePauseCapture(int device_id) {}
76
77    void DeviceStopCapture(int device_id) {
78      OnStateChanged(VIDEO_CAPTURE_STATE_STOPPED);
79    }
80
81    void DeviceReceiveEmptyBuffer(int device_id,
82                                  int buffer_id,
83                                  const std::vector<uint32>& sync_points) {}
84
85    void DeviceGetSupportedFormats(int device_id,
86                                   media::VideoCaptureSessionId session_id) {
87      // When the mock message filter receives a request for the device
88      // supported formats, replies immediately with an empty format list.
89      OnDeviceSupportedFormatsEnumerated(
90          media::VideoCaptureFormats());
91    }
92
93    void DeviceGetFormatsInUse(int device_id,
94                               media::VideoCaptureSessionId session_id) {
95      OnDeviceFormatsInUseReceived(media::VideoCaptureFormats());
96    }
97
98    void ReceiveStateChangeMessage(VideoCaptureState state) {
99      OnStateChanged(state);
100    }
101
102    const media::VideoCaptureParams& capture_params() const {
103      return capture_params_;
104    }
105
106   private:
107    media::VideoCaptureParams capture_params_;
108  };
109
110  VideoCaptureImplTest() {
111    params_small_.requested_format = media::VideoCaptureFormat(
112        gfx::Size(176, 144), 30, media::PIXEL_FORMAT_I420);
113
114    params_large_.requested_format = media::VideoCaptureFormat(
115        gfx::Size(320, 240), 30, media::PIXEL_FORMAT_I420);
116
117    child_process_.reset(new ChildProcess());
118
119    message_filter_ = new MockVideoCaptureMessageFilter;
120    session_id_ = 1;
121
122    video_capture_impl_.reset(new MockVideoCaptureImpl(
123        session_id_, message_filter_.get()));
124
125    video_capture_impl_->device_id_ = 2;
126  }
127
128  virtual ~VideoCaptureImplTest() {
129  }
130
131 protected:
132  MOCK_METHOD3(OnFrameReady,
133              void(const scoped_refptr<media::VideoFrame>&,
134                   const media::VideoCaptureFormat&,
135                   const base::TimeTicks&));
136  MOCK_METHOD1(OnStateUpdate, void(VideoCaptureState));
137  MOCK_METHOD1(OnDeviceFormatsInUse,
138               void(const media::VideoCaptureFormats&));
139  MOCK_METHOD1(OnDeviceSupportedFormats,
140               void(const media::VideoCaptureFormats&));
141
142  void Init() {
143    video_capture_impl_->Init();
144  }
145
146  void StartCapture(int client_id,
147                    const media::VideoCaptureParams& params) {
148    video_capture_impl_->StartCapture(
149        client_id, params,
150        base::Bind(&VideoCaptureImplTest::OnStateUpdate,
151                   base::Unretained(this)),
152        base::Bind(&VideoCaptureImplTest::OnFrameReady,
153                   base::Unretained(this)));
154  }
155
156  void StopCapture(int client_id) {
157    video_capture_impl_->StopCapture(client_id);
158  }
159
160  void DeInit() {
161    video_capture_impl_->DeInit();
162  }
163
164  void GetDeviceSupportedFormats() {
165    const base::Callback<void(const media::VideoCaptureFormats&)>
166        callback = base::Bind(
167            &VideoCaptureImplTest::OnDeviceSupportedFormats,
168            base::Unretained(this));
169    video_capture_impl_->GetDeviceSupportedFormats(callback);
170  }
171
172  void GetDeviceFormatsInUse() {
173    const base::Callback<void(const media::VideoCaptureFormats&)>
174        callback = base::Bind(
175            &VideoCaptureImplTest::OnDeviceFormatsInUse,
176            base::Unretained(this));
177    video_capture_impl_->GetDeviceFormatsInUse(callback);
178  }
179
180  base::MessageLoop message_loop_;
181  scoped_ptr<ChildProcess> child_process_;
182  scoped_refptr<MockVideoCaptureMessageFilter> message_filter_;
183  media::VideoCaptureSessionId session_id_;
184  scoped_ptr<MockVideoCaptureImpl> video_capture_impl_;
185  media::VideoCaptureParams params_small_;
186  media::VideoCaptureParams params_large_;
187
188 private:
189  DISALLOW_COPY_AND_ASSIGN(VideoCaptureImplTest);
190};
191
192TEST_F(VideoCaptureImplTest, Simple) {
193  // Execute SetCapture() and StopCapture() for one client.
194  EXPECT_CALL(*this, OnStateUpdate(VIDEO_CAPTURE_STATE_STARTED));
195  EXPECT_CALL(*this, OnStateUpdate(VIDEO_CAPTURE_STATE_STOPPED));
196
197  Init();
198  StartCapture(0, params_small_);
199  StopCapture(0);
200  DeInit();
201}
202
203TEST_F(VideoCaptureImplTest, TwoClientsInSequence) {
204  EXPECT_CALL(*this, OnStateUpdate(VIDEO_CAPTURE_STATE_STARTED)).Times(2);
205  EXPECT_CALL(*this, OnStateUpdate(VIDEO_CAPTURE_STATE_STOPPED)).Times(2);
206
207  Init();
208  StartCapture(0, params_small_);
209  StopCapture(0);
210  StartCapture(1, params_small_);
211  StopCapture(1);
212  DeInit();
213}
214
215TEST_F(VideoCaptureImplTest, LargeAndSmall) {
216  EXPECT_CALL(*this, OnStateUpdate(VIDEO_CAPTURE_STATE_STARTED)).Times(2);
217  EXPECT_CALL(*this, OnStateUpdate(VIDEO_CAPTURE_STATE_STOPPED)).Times(2);
218
219  Init();
220  StartCapture(0, params_large_);
221  StopCapture(0);
222  StartCapture(1, params_small_);
223  StopCapture(1);
224  DeInit();
225}
226
227TEST_F(VideoCaptureImplTest, SmallAndLarge) {
228  EXPECT_CALL(*this, OnStateUpdate(VIDEO_CAPTURE_STATE_STARTED)).Times(2);
229  EXPECT_CALL(*this, OnStateUpdate(VIDEO_CAPTURE_STATE_STOPPED)).Times(2);
230
231  Init();
232  StartCapture(0, params_small_);
233  StopCapture(0);
234  StartCapture(1, params_large_);
235  StopCapture(1);
236  DeInit();
237}
238
239// Check that a request to GetDeviceSupportedFormats() ends up eventually in the
240// provided callback.
241TEST_F(VideoCaptureImplTest, GetDeviceFormats) {
242  EXPECT_CALL(*this, OnDeviceSupportedFormats(_));
243
244  Init();
245  GetDeviceSupportedFormats();
246  DeInit();
247}
248
249// Check that two requests to GetDeviceSupportedFormats() end up eventually
250// calling the provided callbacks.
251TEST_F(VideoCaptureImplTest, TwoClientsGetDeviceFormats) {
252  EXPECT_CALL(*this, OnDeviceSupportedFormats(_)).Times(2);
253
254  Init();
255  GetDeviceSupportedFormats();
256  GetDeviceSupportedFormats();
257  DeInit();
258}
259
260// Check that a request to GetDeviceFormatsInUse() ends up eventually in the
261// provided callback.
262TEST_F(VideoCaptureImplTest, GetDeviceFormatsInUse) {
263  EXPECT_CALL(*this, OnDeviceFormatsInUse(_));
264
265  Init();
266  GetDeviceFormatsInUse();
267  DeInit();
268}
269
270TEST_F(VideoCaptureImplTest, AlreadyStarted) {
271  EXPECT_CALL(*this, OnStateUpdate(VIDEO_CAPTURE_STATE_STARTED)).Times(2);
272  EXPECT_CALL(*this, OnStateUpdate(VIDEO_CAPTURE_STATE_STOPPED)).Times(2);
273
274  Init();
275  StartCapture(0, params_small_);
276  StartCapture(1, params_large_);
277  StopCapture(0);
278  StopCapture(1);
279  DeInit();
280  DCHECK(video_capture_impl_->capture_params().requested_format
281            .frame_size ==
282         params_small_.requested_format.frame_size);
283}
284
285TEST_F(VideoCaptureImplTest, EndedBeforeStop) {
286   EXPECT_CALL(*this, OnStateUpdate(VIDEO_CAPTURE_STATE_STARTED));
287   EXPECT_CALL(*this, OnStateUpdate(VIDEO_CAPTURE_STATE_STOPPED));
288
289   Init();
290   StartCapture(0, params_small_);
291
292   // Receive state change message from browser.
293   video_capture_impl_->ReceiveStateChangeMessage(VIDEO_CAPTURE_STATE_ENDED);
294
295   StopCapture(0);
296   DeInit();
297}
298
299TEST_F(VideoCaptureImplTest, ErrorBeforeStop) {
300   EXPECT_CALL(*this, OnStateUpdate(VIDEO_CAPTURE_STATE_STARTED));
301   EXPECT_CALL(*this, OnStateUpdate(VIDEO_CAPTURE_STATE_ERROR));
302
303   Init();
304   StartCapture(0, params_small_);
305
306   // Receive state change message from browser.
307   video_capture_impl_->ReceiveStateChangeMessage(VIDEO_CAPTURE_STATE_ERROR);
308
309   StopCapture(0);
310   DeInit();
311}
312
313}  // namespace content
314