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 VideoCaptureManager.
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 "base/run_loop.h"
14#include "content/browser/browser_thread_impl.h"
15#include "content/browser/renderer_host/media/media_stream_provider.h"
16#include "content/browser/renderer_host/media/video_capture_controller_event_handler.h"
17#include "content/browser/renderer_host/media/video_capture_manager.h"
18#include "content/common/media/media_stream_options.h"
19#include "media/video/capture/fake_video_capture_device_factory.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::InSequence;
26using ::testing::Return;
27using ::testing::SaveArg;
28
29namespace content {
30
31// Listener class used to track progress of VideoCaptureManager test.
32class MockMediaStreamProviderListener : public MediaStreamProviderListener {
33 public:
34  MockMediaStreamProviderListener() {}
35  ~MockMediaStreamProviderListener() {}
36
37  MOCK_METHOD2(Opened, void(MediaStreamType, int));
38  MOCK_METHOD2(Closed, void(MediaStreamType, int));
39  MOCK_METHOD2(DevicesEnumerated, void(MediaStreamType,
40                                       const StreamDeviceInfoArray&));
41  MOCK_METHOD2(Aborted, void(MediaStreamType, int));
42};  // class MockMediaStreamProviderListener
43
44// Needed as an input argument to StartCaptureForClient().
45class MockFrameObserver : public VideoCaptureControllerEventHandler {
46 public:
47  MOCK_METHOD1(OnError, void(const VideoCaptureControllerID& id));
48
49  virtual void OnBufferCreated(const VideoCaptureControllerID& id,
50                               base::SharedMemoryHandle handle,
51                               int length, int buffer_id) OVERRIDE {}
52  virtual void OnBufferDestroyed(const VideoCaptureControllerID& id,
53                               int buffer_id) OVERRIDE {}
54  virtual void OnBufferReady(const VideoCaptureControllerID& id,
55                             int buffer_id,
56                             const media::VideoCaptureFormat& format,
57                             const gfx::Rect& visible_rect,
58                             base::TimeTicks timestamp) OVERRIDE {}
59  virtual void OnMailboxBufferReady(const VideoCaptureControllerID& id,
60                                    int buffer_id,
61                                    const gpu::MailboxHolder& mailbox_holder,
62                                    const media::VideoCaptureFormat& format,
63                                    base::TimeTicks timestamp) OVERRIDE {}
64  virtual void OnEnded(const VideoCaptureControllerID& id) OVERRIDE {}
65
66  void OnGotControllerCallback(VideoCaptureControllerID) {}
67};
68
69// Test class
70class VideoCaptureManagerTest : public testing::Test {
71 public:
72  VideoCaptureManagerTest() : next_client_id_(1) {}
73  virtual ~VideoCaptureManagerTest() {}
74
75 protected:
76  virtual void SetUp() OVERRIDE {
77    listener_.reset(new MockMediaStreamProviderListener());
78    message_loop_.reset(new base::MessageLoopForIO);
79    io_thread_.reset(new BrowserThreadImpl(BrowserThread::IO,
80                                           message_loop_.get()));
81    vcm_ = new VideoCaptureManager(scoped_ptr<media::VideoCaptureDeviceFactory>(
82        new media::FakeVideoCaptureDeviceFactory()));
83    video_capture_device_factory_ =
84        static_cast<media::FakeVideoCaptureDeviceFactory*>(
85            vcm_->video_capture_device_factory());
86    const int32 kNumberOfFakeDevices = 2;
87    video_capture_device_factory_->set_number_of_devices(kNumberOfFakeDevices);
88    vcm_->Register(listener_.get(), message_loop_->message_loop_proxy().get());
89    frame_observer_.reset(new MockFrameObserver());
90  }
91
92  virtual void TearDown() OVERRIDE {}
93
94  void OnGotControllerCallback(
95      VideoCaptureControllerID id,
96      base::Closure quit_closure,
97      bool expect_success,
98      const base::WeakPtr<VideoCaptureController>& controller) {
99    if (expect_success) {
100      ASSERT_TRUE(controller);
101      ASSERT_TRUE(0 == controllers_.count(id));
102      controllers_[id] = controller.get();
103    } else {
104      ASSERT_TRUE(NULL == controller);
105    }
106    quit_closure.Run();
107  }
108
109  VideoCaptureControllerID StartClient(int session_id, bool expect_success) {
110    media::VideoCaptureParams params;
111    params.requested_format = media::VideoCaptureFormat(
112        gfx::Size(320, 240), 30, media::PIXEL_FORMAT_I420);
113
114    VideoCaptureControllerID client_id(next_client_id_++);
115    base::RunLoop run_loop;
116    vcm_->StartCaptureForClient(
117        session_id,
118        params,
119        base::kNullProcessHandle,
120        client_id,
121        frame_observer_.get(),
122        base::Bind(&VideoCaptureManagerTest::OnGotControllerCallback,
123                   base::Unretained(this),
124                   client_id,
125                   run_loop.QuitClosure(),
126                   expect_success));
127    run_loop.Run();
128    return client_id;
129  }
130
131  void StopClient(VideoCaptureControllerID client_id) {
132    ASSERT_TRUE(1 == controllers_.count(client_id));
133    vcm_->StopCaptureForClient(controllers_[client_id], client_id,
134                               frame_observer_.get(), false);
135    controllers_.erase(client_id);
136  }
137
138  int next_client_id_;
139  std::map<VideoCaptureControllerID, VideoCaptureController*> controllers_;
140  scoped_refptr<VideoCaptureManager> vcm_;
141  scoped_ptr<MockMediaStreamProviderListener> listener_;
142  scoped_ptr<base::MessageLoop> message_loop_;
143  scoped_ptr<BrowserThreadImpl> io_thread_;
144  scoped_ptr<MockFrameObserver> frame_observer_;
145  media::FakeVideoCaptureDeviceFactory* video_capture_device_factory_;
146
147 private:
148  DISALLOW_COPY_AND_ASSIGN(VideoCaptureManagerTest);
149};
150
151// Test cases
152
153// Try to open, start, stop and close a device.
154TEST_F(VideoCaptureManagerTest, CreateAndClose) {
155  StreamDeviceInfoArray devices;
156
157  InSequence s;
158  EXPECT_CALL(*listener_, DevicesEnumerated(MEDIA_DEVICE_VIDEO_CAPTURE, _))
159      .WillOnce(SaveArg<1>(&devices));
160  EXPECT_CALL(*listener_, Opened(MEDIA_DEVICE_VIDEO_CAPTURE, _));
161  EXPECT_CALL(*listener_, Closed(MEDIA_DEVICE_VIDEO_CAPTURE, _));
162
163  vcm_->EnumerateDevices(MEDIA_DEVICE_VIDEO_CAPTURE);
164
165  // Wait to get device callback.
166  message_loop_->RunUntilIdle();
167
168  int video_session_id = vcm_->Open(devices.front());
169  VideoCaptureControllerID client_id = StartClient(video_session_id, true);
170
171  StopClient(client_id);
172  vcm_->Close(video_session_id);
173
174  // Wait to check callbacks before removing the listener.
175  message_loop_->RunUntilIdle();
176  vcm_->Unregister();
177}
178
179// Try to open, start, and abort a device.
180TEST_F(VideoCaptureManagerTest, CreateAndAbort) {
181  StreamDeviceInfoArray devices;
182
183  InSequence s;
184  EXPECT_CALL(*listener_, DevicesEnumerated(MEDIA_DEVICE_VIDEO_CAPTURE, _))
185      .WillOnce(SaveArg<1>(&devices));
186  EXPECT_CALL(*listener_, Opened(MEDIA_DEVICE_VIDEO_CAPTURE, _));
187  EXPECT_CALL(*listener_, Aborted(MEDIA_DEVICE_VIDEO_CAPTURE, _));
188
189  vcm_->EnumerateDevices(MEDIA_DEVICE_VIDEO_CAPTURE);
190
191  // Wait to get device callback.
192  message_loop_->RunUntilIdle();
193
194  int video_session_id = vcm_->Open(devices.front());
195  VideoCaptureControllerID client_id = StartClient(video_session_id, true);
196
197  // Wait for device opened.
198  message_loop_->RunUntilIdle();
199
200  vcm_->StopCaptureForClient(controllers_[client_id], client_id,
201                             frame_observer_.get(), true);
202
203  // Wait to check callbacks before removing the listener.
204  message_loop_->RunUntilIdle();
205  vcm_->Unregister();
206}
207
208// Open the same device twice.
209TEST_F(VideoCaptureManagerTest, OpenTwice) {
210  StreamDeviceInfoArray devices;
211
212  InSequence s;
213  EXPECT_CALL(*listener_, DevicesEnumerated(MEDIA_DEVICE_VIDEO_CAPTURE, _))
214      .WillOnce(SaveArg<1>(&devices));
215  EXPECT_CALL(*listener_, Opened(MEDIA_DEVICE_VIDEO_CAPTURE, _)).Times(2);
216  EXPECT_CALL(*listener_, Closed(MEDIA_DEVICE_VIDEO_CAPTURE, _)).Times(2);
217
218  vcm_->EnumerateDevices(MEDIA_DEVICE_VIDEO_CAPTURE);
219
220  // Wait to get device callback.
221  message_loop_->RunUntilIdle();
222
223  int video_session_id_first = vcm_->Open(devices.front());
224
225  // This should trigger an error callback with error code
226  // 'kDeviceAlreadyInUse'.
227  int video_session_id_second = vcm_->Open(devices.front());
228  EXPECT_NE(video_session_id_first, video_session_id_second);
229
230  vcm_->Close(video_session_id_first);
231  vcm_->Close(video_session_id_second);
232
233  // Wait to check callbacks before removing the listener.
234  message_loop_->RunUntilIdle();
235  vcm_->Unregister();
236}
237
238// Connect and disconnect devices.
239TEST_F(VideoCaptureManagerTest, ConnectAndDisconnectDevices) {
240  StreamDeviceInfoArray devices;
241  int number_of_devices_keep =
242    video_capture_device_factory_->number_of_devices();
243
244  InSequence s;
245  EXPECT_CALL(*listener_, DevicesEnumerated(MEDIA_DEVICE_VIDEO_CAPTURE, _))
246      .WillOnce(SaveArg<1>(&devices));
247  vcm_->EnumerateDevices(MEDIA_DEVICE_VIDEO_CAPTURE);
248  message_loop_->RunUntilIdle();
249  ASSERT_EQ(devices.size(), 2u);
250
251  // Simulate we remove 1 fake device.
252  video_capture_device_factory_->set_number_of_devices(1);
253  EXPECT_CALL(*listener_, DevicesEnumerated(MEDIA_DEVICE_VIDEO_CAPTURE, _))
254      .WillOnce(SaveArg<1>(&devices));
255  vcm_->EnumerateDevices(MEDIA_DEVICE_VIDEO_CAPTURE);
256  message_loop_->RunUntilIdle();
257  ASSERT_EQ(devices.size(), 1u);
258
259  // Simulate we add 2 fake devices.
260  video_capture_device_factory_->set_number_of_devices(3);
261  EXPECT_CALL(*listener_, DevicesEnumerated(MEDIA_DEVICE_VIDEO_CAPTURE, _))
262      .WillOnce(SaveArg<1>(&devices));
263  vcm_->EnumerateDevices(MEDIA_DEVICE_VIDEO_CAPTURE);
264  message_loop_->RunUntilIdle();
265  ASSERT_EQ(devices.size(), 3u);
266
267  vcm_->Unregister();
268  video_capture_device_factory_->set_number_of_devices(number_of_devices_keep);
269}
270
271// Enumerate devices and open the first, then check the list of supported
272// formats. Then start the opened device. The capability list should stay the
273// same. Finally stop the device and check that the capabilities stay unchanged.
274TEST_F(VideoCaptureManagerTest, ManipulateDeviceAndCheckCapabilities) {
275  StreamDeviceInfoArray devices;
276
277  // Before enumerating the devices, requesting formats should return false.
278  int video_session_id = 0;
279  media::VideoCaptureFormats supported_formats;
280  supported_formats.clear();
281  EXPECT_FALSE(
282      vcm_->GetDeviceSupportedFormats(video_session_id, &supported_formats));
283
284  InSequence s;
285  EXPECT_CALL(*listener_, DevicesEnumerated(MEDIA_DEVICE_VIDEO_CAPTURE, _))
286      .WillOnce(SaveArg<1>(&devices));
287  vcm_->EnumerateDevices(MEDIA_DEVICE_VIDEO_CAPTURE);
288  message_loop_->RunUntilIdle();
289  ASSERT_GE(devices.size(), 2u);
290
291  EXPECT_CALL(*listener_, Opened(MEDIA_DEVICE_VIDEO_CAPTURE, _));
292  video_session_id = vcm_->Open(devices.front());
293  message_loop_->RunUntilIdle();
294
295  // Right after opening the device, we should see all its formats.
296  supported_formats.clear();
297  EXPECT_TRUE(
298      vcm_->GetDeviceSupportedFormats(video_session_id, &supported_formats));
299  ASSERT_GT(supported_formats.size(), 1u);
300  EXPECT_GT(supported_formats[0].frame_size.width(), 1);
301  EXPECT_GT(supported_formats[0].frame_size.height(), 1);
302  EXPECT_GT(supported_formats[0].frame_rate, 1);
303  EXPECT_GT(supported_formats[1].frame_size.width(), 1);
304  EXPECT_GT(supported_formats[1].frame_size.height(), 1);
305  EXPECT_GT(supported_formats[1].frame_rate, 1);
306
307  VideoCaptureControllerID client_id = StartClient(video_session_id, true);
308  message_loop_->RunUntilIdle();
309  // After StartClient(), device's supported formats should stay the same.
310  supported_formats.clear();
311  EXPECT_TRUE(
312      vcm_->GetDeviceSupportedFormats(video_session_id, &supported_formats));
313  ASSERT_GE(supported_formats.size(), 2u);
314  EXPECT_GT(supported_formats[0].frame_size.width(), 1);
315  EXPECT_GT(supported_formats[0].frame_size.height(), 1);
316  EXPECT_GT(supported_formats[0].frame_rate, 1);
317  EXPECT_GT(supported_formats[1].frame_size.width(), 1);
318  EXPECT_GT(supported_formats[1].frame_size.height(), 1);
319  EXPECT_GT(supported_formats[1].frame_rate, 1);
320
321  EXPECT_CALL(*listener_, Closed(MEDIA_DEVICE_VIDEO_CAPTURE, _));
322  StopClient(client_id);
323  supported_formats.clear();
324  EXPECT_TRUE(
325      vcm_->GetDeviceSupportedFormats(video_session_id, &supported_formats));
326  ASSERT_GE(supported_formats.size(), 2u);
327  EXPECT_GT(supported_formats[0].frame_size.width(), 1);
328  EXPECT_GT(supported_formats[0].frame_size.height(), 1);
329  EXPECT_GT(supported_formats[0].frame_rate, 1);
330  EXPECT_GT(supported_formats[1].frame_size.width(), 1);
331  EXPECT_GT(supported_formats[1].frame_size.height(), 1);
332  EXPECT_GT(supported_formats[1].frame_rate, 1);
333
334  vcm_->Close(video_session_id);
335  message_loop_->RunUntilIdle();
336  vcm_->Unregister();
337}
338
339// Enumerate devices and open the first, then check the formats currently in
340// use, which should be an empty vector. Then start the opened device. The
341// format(s) in use should be just one format (the one used when configuring-
342// starting the device). Finally stop the device and check that the formats in
343// use is an empty vector.
344TEST_F(VideoCaptureManagerTest, StartDeviceAndGetDeviceFormatInUse) {
345  StreamDeviceInfoArray devices;
346
347  InSequence s;
348  EXPECT_CALL(*listener_, DevicesEnumerated(MEDIA_DEVICE_VIDEO_CAPTURE, _))
349      .WillOnce(SaveArg<1>(&devices));
350  vcm_->EnumerateDevices(MEDIA_DEVICE_VIDEO_CAPTURE);
351  message_loop_->RunUntilIdle();
352  ASSERT_GE(devices.size(), 2u);
353
354  EXPECT_CALL(*listener_, Opened(MEDIA_DEVICE_VIDEO_CAPTURE, _));
355  int video_session_id = vcm_->Open(devices.front());
356  message_loop_->RunUntilIdle();
357
358  // Right after opening the device, we should see no format in use.
359  media::VideoCaptureFormats formats_in_use;
360  EXPECT_TRUE(vcm_->GetDeviceFormatsInUse(video_session_id, &formats_in_use));
361  EXPECT_TRUE(formats_in_use.empty());
362
363  VideoCaptureControllerID client_id = StartClient(video_session_id, true);
364  message_loop_->RunUntilIdle();
365  // After StartClient(), |formats_in_use| should contain one valid format.
366  EXPECT_TRUE(vcm_->GetDeviceFormatsInUse(video_session_id, &formats_in_use));
367  EXPECT_EQ(formats_in_use.size(), 1u);
368  if (formats_in_use.size()) {
369    media::VideoCaptureFormat& format_in_use = formats_in_use.front();
370    EXPECT_TRUE(format_in_use.IsValid());
371    EXPECT_GT(format_in_use.frame_size.width(), 1);
372    EXPECT_GT(format_in_use.frame_size.height(), 1);
373    EXPECT_GT(format_in_use.frame_rate, 1);
374  }
375  formats_in_use.clear();
376
377  EXPECT_CALL(*listener_, Closed(MEDIA_DEVICE_VIDEO_CAPTURE, _));
378  StopClient(client_id);
379  message_loop_->RunUntilIdle();
380  // After StopClient(), the device's formats in use should be empty again.
381  EXPECT_TRUE(vcm_->GetDeviceFormatsInUse(video_session_id, &formats_in_use));
382  EXPECT_TRUE(formats_in_use.empty());
383
384  vcm_->Close(video_session_id);
385  message_loop_->RunUntilIdle();
386  vcm_->Unregister();
387}
388
389// Open two different devices.
390TEST_F(VideoCaptureManagerTest, OpenTwo) {
391  StreamDeviceInfoArray devices;
392
393  InSequence s;
394  EXPECT_CALL(*listener_, DevicesEnumerated(MEDIA_DEVICE_VIDEO_CAPTURE, _))
395      .WillOnce(SaveArg<1>(&devices));
396  EXPECT_CALL(*listener_, Opened(MEDIA_DEVICE_VIDEO_CAPTURE, _)).Times(2);
397  EXPECT_CALL(*listener_, Closed(MEDIA_DEVICE_VIDEO_CAPTURE, _)).Times(2);
398
399  vcm_->EnumerateDevices(MEDIA_DEVICE_VIDEO_CAPTURE);
400
401  // Wait to get device callback.
402  message_loop_->RunUntilIdle();
403
404  StreamDeviceInfoArray::iterator it = devices.begin();
405
406  int video_session_id_first = vcm_->Open(*it);
407  ++it;
408  int video_session_id_second = vcm_->Open(*it);
409
410  vcm_->Close(video_session_id_first);
411  vcm_->Close(video_session_id_second);
412
413  // Wait to check callbacks before removing the listener.
414  message_loop_->RunUntilIdle();
415  vcm_->Unregister();
416}
417
418// Try open a non-existing device.
419TEST_F(VideoCaptureManagerTest, OpenNotExisting) {
420  StreamDeviceInfoArray devices;
421
422  InSequence s;
423  EXPECT_CALL(*listener_, DevicesEnumerated(MEDIA_DEVICE_VIDEO_CAPTURE, _))
424      .WillOnce(SaveArg<1>(&devices));
425  EXPECT_CALL(*listener_, Opened(MEDIA_DEVICE_VIDEO_CAPTURE, _));
426  EXPECT_CALL(*frame_observer_, OnError(_));
427  EXPECT_CALL(*listener_, Closed(MEDIA_DEVICE_VIDEO_CAPTURE, _));
428
429  vcm_->EnumerateDevices(MEDIA_DEVICE_VIDEO_CAPTURE);
430
431  // Wait to get device callback.
432  message_loop_->RunUntilIdle();
433
434  MediaStreamType stream_type = MEDIA_DEVICE_VIDEO_CAPTURE;
435  std::string device_name("device_doesnt_exist");
436  std::string device_id("id_doesnt_exist");
437  StreamDeviceInfo dummy_device(stream_type, device_name, device_id);
438
439  // This should fail with an error to the controller.
440  int session_id = vcm_->Open(dummy_device);
441  VideoCaptureControllerID client_id = StartClient(session_id, true);
442  message_loop_->RunUntilIdle();
443
444  StopClient(client_id);
445  vcm_->Close(session_id);
446  message_loop_->RunUntilIdle();
447
448  vcm_->Unregister();
449}
450
451// Start a device without calling Open, using a non-magic ID.
452TEST_F(VideoCaptureManagerTest, StartInvalidSession) {
453  StartClient(22, false);
454
455  // Wait to check callbacks before removing the listener.
456  message_loop_->RunUntilIdle();
457  vcm_->Unregister();
458}
459
460// Open and start a device, close it before calling Stop.
461TEST_F(VideoCaptureManagerTest, CloseWithoutStop) {
462  StreamDeviceInfoArray devices;
463
464  InSequence s;
465  EXPECT_CALL(*listener_, DevicesEnumerated(MEDIA_DEVICE_VIDEO_CAPTURE, _))
466      .WillOnce(SaveArg<1>(&devices));
467  EXPECT_CALL(*listener_, Opened(MEDIA_DEVICE_VIDEO_CAPTURE, _));
468  EXPECT_CALL(*listener_, Closed(MEDIA_DEVICE_VIDEO_CAPTURE, _));
469
470  vcm_->EnumerateDevices(MEDIA_DEVICE_VIDEO_CAPTURE);
471
472  // Wait to get device callback.
473  message_loop_->RunUntilIdle();
474
475  int video_session_id = vcm_->Open(devices.front());
476
477  VideoCaptureControllerID client_id = StartClient(video_session_id, true);
478
479  // Close will stop the running device, an assert will be triggered in
480  // VideoCaptureManager destructor otherwise.
481  vcm_->Close(video_session_id);
482  StopClient(client_id);
483
484  // Wait to check callbacks before removing the listener
485  message_loop_->RunUntilIdle();
486  vcm_->Unregister();
487}
488
489// TODO(mcasas): Add a test to check consolidation of the supported formats
490// provided by the device when http://crbug.com/323913 is closed.
491
492}  // namespace content
493