1// Copyright 2014 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/bind.h"
6#include "base/callback.h"
7#include "base/memory/ref_counted.h"
8#include "base/message_loop/message_loop.h"
9#include "base/run_loop.h"
10#include "content/child/child_process.h"
11#include "content/renderer/media/video_capture_impl.h"
12#include "content/renderer/media/video_capture_impl_manager.h"
13#include "content/renderer/media/video_capture_message_filter.h"
14#include "media/base/bind_to_current_loop.h"
15#include "testing/gmock/include/gmock/gmock.h"
16#include "testing/gtest/include/gtest/gtest.h"
17
18using ::testing::_;
19using ::testing::DoAll;
20using ::testing::SaveArg;
21using media::BindToCurrentLoop;
22
23namespace content {
24
25ACTION_P(RunClosure, closure) {
26  closure.Run();
27}
28
29class MockVideoCaptureImpl : public VideoCaptureImpl {
30 public:
31  MockVideoCaptureImpl(media::VideoCaptureSessionId session_id,
32                       VideoCaptureMessageFilter* filter,
33                       base::Closure destruct_callback)
34      : VideoCaptureImpl(session_id, filter),
35        destruct_callback_(destruct_callback) {
36  }
37
38  virtual ~MockVideoCaptureImpl() {
39    destruct_callback_.Run();
40  }
41
42 private:
43  base::Closure destruct_callback_;
44
45  DISALLOW_COPY_AND_ASSIGN(MockVideoCaptureImpl);
46};
47
48class MockVideoCaptureImplManager : public VideoCaptureImplManager {
49 public:
50  explicit MockVideoCaptureImplManager(
51      base::Closure destruct_video_capture_callback)
52      : destruct_video_capture_callback_(
53          destruct_video_capture_callback) {}
54  virtual ~MockVideoCaptureImplManager() {}
55
56 protected:
57  virtual VideoCaptureImpl* CreateVideoCaptureImplForTesting(
58      media::VideoCaptureSessionId id,
59      VideoCaptureMessageFilter* filter) const OVERRIDE {
60    return new MockVideoCaptureImpl(id,
61                                    filter,
62                                    destruct_video_capture_callback_);
63  }
64
65 private:
66  base::Closure destruct_video_capture_callback_;
67
68  DISALLOW_COPY_AND_ASSIGN(MockVideoCaptureImplManager);
69};
70
71class VideoCaptureImplManagerTest : public ::testing::Test {
72 public:
73  VideoCaptureImplManagerTest()
74      : manager_(new MockVideoCaptureImplManager(
75          BindToCurrentLoop(cleanup_run_loop_.QuitClosure()))) {
76    params_.requested_format = media::VideoCaptureFormat(
77        gfx::Size(176, 144), 30, media::PIXEL_FORMAT_I420);
78    child_process_.reset(new ChildProcess());
79  }
80
81  void FakeChannelSetup() {
82    scoped_refptr<base::MessageLoopProxy> loop =
83        child_process_->io_message_loop_proxy();
84    if (!loop->BelongsToCurrentThread()) {
85      loop->PostTask(
86          FROM_HERE,
87          base::Bind(
88              &VideoCaptureImplManagerTest::FakeChannelSetup,
89              base::Unretained(this)));
90      return;
91    }
92    manager_->video_capture_message_filter()->OnFilterAdded(NULL);
93  }
94
95 protected:
96  MOCK_METHOD3(OnFrameReady,
97              void(const scoped_refptr<media::VideoFrame>&,
98                   const media::VideoCaptureFormat&,
99                   const base::TimeTicks& estimated_capture_time));
100  MOCK_METHOD0(OnStarted, void());
101  MOCK_METHOD0(OnStopped, void());
102
103  void OnStateUpdate(VideoCaptureState state) {
104    switch (state) {
105      case VIDEO_CAPTURE_STATE_STARTED:
106        OnStarted();
107        break;
108      case VIDEO_CAPTURE_STATE_STOPPED:
109        OnStopped();
110        break;
111      default:
112        NOTREACHED();
113    }
114  }
115
116  base::Closure StartCapture(const media::VideoCaptureParams& params) {
117    return manager_->StartCapture(
118        0, params,
119        base::Bind(&VideoCaptureImplManagerTest::OnStateUpdate,
120                   base::Unretained(this)),
121        base::Bind(&VideoCaptureImplManagerTest::OnFrameReady,
122                   base::Unretained(this)));
123  }
124
125  base::MessageLoop message_loop_;
126  scoped_ptr<ChildProcess> child_process_;
127  media::VideoCaptureParams params_;
128  base::RunLoop cleanup_run_loop_;
129  scoped_ptr<MockVideoCaptureImplManager> manager_;
130
131 private:
132  DISALLOW_COPY_AND_ASSIGN(VideoCaptureImplManagerTest);
133};
134
135// Multiple clients with the same session id. There is only one
136// media::VideoCapture object.
137TEST_F(VideoCaptureImplManagerTest, MultipleClients) {
138  base::Closure release_cb1 = manager_->UseDevice(0);
139  base::Closure release_cb2 = manager_->UseDevice(0);
140  base::Closure stop_cb1, stop_cb2;
141  {
142    base::RunLoop run_loop;
143    base::Closure quit_closure = BindToCurrentLoop(
144        run_loop.QuitClosure());
145    EXPECT_CALL(*this, OnStarted()).WillOnce(
146        RunClosure(quit_closure));
147    EXPECT_CALL(*this, OnStarted()).RetiresOnSaturation();
148    stop_cb1 = StartCapture(params_);
149    stop_cb2 = StartCapture(params_);
150    FakeChannelSetup();
151    run_loop.Run();
152  }
153
154  {
155    base::RunLoop run_loop;
156    base::Closure quit_closure = BindToCurrentLoop(
157        run_loop.QuitClosure());
158    EXPECT_CALL(*this, OnStopped()).WillOnce(
159        RunClosure(quit_closure));
160    EXPECT_CALL(*this, OnStopped()).RetiresOnSaturation();
161    stop_cb1.Run();
162    stop_cb2.Run();
163    run_loop.Run();
164  }
165
166  release_cb1.Run();
167  release_cb2.Run();
168  cleanup_run_loop_.Run();
169}
170
171TEST_F(VideoCaptureImplManagerTest, NoLeak) {
172  manager_->UseDevice(0).Reset();
173  manager_.reset();
174  cleanup_run_loop_.Run();
175}
176
177}  // namespace content
178