Upstream version 10.39.233.0
[platform/framework/web/crosswalk.git] / src / remoting / host / video_scheduler_unittest.cc
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 "remoting/host/video_scheduler.h"
6
7 #include "base/bind.h"
8 #include "base/message_loop/message_loop.h"
9 #include "base/run_loop.h"
10 #include "base/single_thread_task_runner.h"
11 #include "remoting/base/auto_thread.h"
12 #include "remoting/base/auto_thread_task_runner.h"
13 #include "remoting/codec/video_encoder.h"
14 #include "remoting/codec/video_encoder_verbatim.h"
15 #include "remoting/host/fake_desktop_capturer.h"
16 #include "remoting/host/fake_mouse_cursor_monitor.h"
17 #include "remoting/host/host_mock_objects.h"
18 #include "remoting/proto/control.pb.h"
19 #include "remoting/proto/video.pb.h"
20 #include "remoting/protocol/protocol_mock_objects.h"
21 #include "testing/gmock/include/gmock/gmock.h"
22 #include "testing/gtest/include/gtest/gtest.h"
23 #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"
24 #include "third_party/webrtc/modules/desktop_capture/mouse_cursor.h"
25 #include "third_party/webrtc/modules/desktop_capture/screen_capturer_mock_objects.h"
26
27 using ::remoting::protocol::MockClientStub;
28 using ::remoting::protocol::MockVideoStub;
29
30 using ::testing::_;
31 using ::testing::AtLeast;
32 using ::testing::AnyNumber;
33 using ::testing::DeleteArg;
34 using ::testing::DoAll;
35 using ::testing::Expectation;
36 using ::testing::InSequence;
37 using ::testing::InvokeWithoutArgs;
38 using ::testing::Return;
39 using ::testing::ReturnRef;
40 using ::testing::SaveArg;
41
42 namespace remoting {
43
44 namespace {
45
46 ACTION(FinishEncode) {
47   scoped_ptr<VideoPacket> packet(new VideoPacket());
48   return packet.release();
49 }
50
51 ACTION(FinishSend) {
52   arg1.Run();
53 }
54
55 }  // namespace
56
57 static const int kWidth = 640;
58 static const int kHeight = 480;
59 static const int kCursorWidth = 64;
60 static const int kCursorHeight = 32;
61 static const int kHotspotX = 11;
62 static const int kHotspotY = 12;
63
64 class MockVideoEncoder : public VideoEncoder {
65  public:
66   MockVideoEncoder() {}
67   virtual ~MockVideoEncoder() {}
68
69   scoped_ptr<VideoPacket> Encode(
70       const webrtc::DesktopFrame& frame) {
71     return scoped_ptr<VideoPacket>(EncodePtr(frame));
72   }
73   MOCK_METHOD1(EncodePtr, VideoPacket*(const webrtc::DesktopFrame& frame));
74
75  private:
76   DISALLOW_COPY_AND_ASSIGN(MockVideoEncoder);
77 };
78
79 class ThreadCheckVideoEncoder : public VideoEncoderVerbatim {
80  public:
81   ThreadCheckVideoEncoder(
82       scoped_refptr<base::SingleThreadTaskRunner> task_runner)
83       : task_runner_(task_runner) {
84   }
85   virtual ~ThreadCheckVideoEncoder() {
86     EXPECT_TRUE(task_runner_->BelongsToCurrentThread());
87   }
88
89  private:
90   scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
91
92   DISALLOW_COPY_AND_ASSIGN(ThreadCheckVideoEncoder);
93 };
94
95 class ThreadCheckDesktopCapturer : public FakeDesktopCapturer {
96  public:
97   ThreadCheckDesktopCapturer(
98       scoped_refptr<base::SingleThreadTaskRunner> task_runner)
99       : task_runner_(task_runner) {
100   }
101   virtual ~ThreadCheckDesktopCapturer() {
102     EXPECT_TRUE(task_runner_->BelongsToCurrentThread());
103   }
104
105  private:
106   scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
107
108   DISALLOW_COPY_AND_ASSIGN(ThreadCheckDesktopCapturer);
109 };
110
111 class ThreadCheckMouseCursorMonitor : public FakeMouseCursorMonitor {
112  public:
113   ThreadCheckMouseCursorMonitor(
114       scoped_refptr<base::SingleThreadTaskRunner> task_runner)
115       : task_runner_(task_runner) {
116   }
117   virtual ~ThreadCheckMouseCursorMonitor() {
118     EXPECT_TRUE(task_runner_->BelongsToCurrentThread());
119   }
120
121  private:
122   scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
123
124   DISALLOW_COPY_AND_ASSIGN(ThreadCheckMouseCursorMonitor);
125 };
126
127 class VideoSchedulerTest : public testing::Test {
128  public:
129   VideoSchedulerTest();
130
131   virtual void SetUp() OVERRIDE;
132   virtual void TearDown() OVERRIDE;
133
134   void StartVideoScheduler(
135       scoped_ptr<webrtc::DesktopCapturer> capturer,
136       scoped_ptr<VideoEncoder> encoder,
137       scoped_ptr<webrtc::MouseCursorMonitor> mouse_monitor);
138   void StopVideoScheduler();
139
140   // webrtc::DesktopCapturer mocks.
141   void OnCapturerStart(webrtc::DesktopCapturer::Callback* callback);
142   void OnCaptureFrame(const webrtc::DesktopRegion& region);
143
144   // webrtc::MouseCursorMonitor mocks.
145   void OnMouseCursorMonitorInit(
146       webrtc::MouseCursorMonitor::Callback* callback,
147       webrtc::MouseCursorMonitor::Mode mode);
148   void OnCaptureMouse();
149   void SetCursorShape(const protocol::CursorShapeInfo& cursor_shape);
150
151  protected:
152   base::MessageLoop message_loop_;
153   base::RunLoop run_loop_;
154   scoped_refptr<AutoThreadTaskRunner> capture_task_runner_;
155   scoped_refptr<AutoThreadTaskRunner> encode_task_runner_;
156   scoped_refptr<AutoThreadTaskRunner> main_task_runner_;
157   scoped_refptr<VideoScheduler> scheduler_;
158
159   MockClientStub client_stub_;
160   MockVideoStub video_stub_;
161
162   // Points to the callback passed to webrtc::DesktopCapturer::Start().
163   webrtc::DesktopCapturer::Callback* capturer_callback_;
164
165   // Points to the callback passed to webrtc::MouseCursor::Init().
166   webrtc::MouseCursorMonitor::Callback* mouse_monitor_callback_;
167
168  private:
169   DISALLOW_COPY_AND_ASSIGN(VideoSchedulerTest);
170 };
171
172 VideoSchedulerTest::VideoSchedulerTest()
173     : capturer_callback_(NULL),
174       mouse_monitor_callback_(NULL) {
175 }
176
177 void VideoSchedulerTest::SetUp() {
178   main_task_runner_ = new AutoThreadTaskRunner(
179       message_loop_.message_loop_proxy(), run_loop_.QuitClosure());
180   capture_task_runner_ = main_task_runner_;
181   encode_task_runner_ = main_task_runner_;
182 }
183
184 void VideoSchedulerTest::TearDown() {
185   // Release the task runners, so that the test can quit.
186   capture_task_runner_ = NULL;
187   encode_task_runner_ = NULL;
188   main_task_runner_ = NULL;
189
190   // Run the MessageLoop until everything has torn down.
191   run_loop_.Run();
192 }
193
194 void VideoSchedulerTest::StartVideoScheduler(
195     scoped_ptr<webrtc::DesktopCapturer> capturer,
196     scoped_ptr<VideoEncoder> encoder,
197     scoped_ptr<webrtc::MouseCursorMonitor> mouse_monitor) {
198   scheduler_ = new VideoScheduler(
199       capture_task_runner_,
200       encode_task_runner_,
201       main_task_runner_,
202       capturer.Pass(),
203       mouse_monitor.Pass(),
204       encoder.Pass(),
205       &client_stub_,
206       &video_stub_);
207   scheduler_->Start();
208 }
209
210 void VideoSchedulerTest::StopVideoScheduler() {
211   scheduler_->Stop();
212   scheduler_ = NULL;
213 }
214
215 void VideoSchedulerTest::OnCapturerStart(
216     webrtc::DesktopCapturer::Callback* callback) {
217   EXPECT_FALSE(capturer_callback_);
218   EXPECT_TRUE(callback);
219
220   capturer_callback_ = callback;
221 }
222
223 void VideoSchedulerTest::OnCaptureFrame(const webrtc::DesktopRegion& region) {
224   scoped_ptr<webrtc::DesktopFrame> frame(
225       new webrtc::BasicDesktopFrame(webrtc::DesktopSize(kWidth, kHeight)));
226   frame->mutable_updated_region()->SetRect(
227       webrtc::DesktopRect::MakeXYWH(0, 0, 10, 10));
228   capturer_callback_->OnCaptureCompleted(frame.release());
229 }
230
231 void VideoSchedulerTest::OnCaptureMouse() {
232   EXPECT_TRUE(mouse_monitor_callback_);
233
234   scoped_ptr<webrtc::MouseCursor> mouse_cursor(
235       new webrtc::MouseCursor(
236           new webrtc::BasicDesktopFrame(
237               webrtc::DesktopSize(kCursorWidth, kCursorHeight)),
238           webrtc::DesktopVector(kHotspotX, kHotspotY)));
239
240   mouse_monitor_callback_->OnMouseCursor(mouse_cursor.release());
241 }
242
243 void VideoSchedulerTest::OnMouseCursorMonitorInit(
244     webrtc::MouseCursorMonitor::Callback* callback,
245     webrtc::MouseCursorMonitor::Mode mode) {
246   EXPECT_FALSE(mouse_monitor_callback_);
247   EXPECT_TRUE(callback);
248
249   mouse_monitor_callback_ = callback;
250 }
251
252 void VideoSchedulerTest::SetCursorShape(
253     const protocol::CursorShapeInfo& cursor_shape) {
254   EXPECT_TRUE(cursor_shape.has_width());
255   EXPECT_EQ(kCursorWidth, cursor_shape.width());
256   EXPECT_TRUE(cursor_shape.has_height());
257   EXPECT_EQ(kCursorHeight, cursor_shape.height());
258   EXPECT_TRUE(cursor_shape.has_hotspot_x());
259   EXPECT_EQ(kHotspotX, cursor_shape.hotspot_x());
260   EXPECT_TRUE(cursor_shape.has_hotspot_y());
261   EXPECT_EQ(kHotspotY, cursor_shape.hotspot_y());
262   EXPECT_TRUE(cursor_shape.has_data());
263   EXPECT_EQ(kCursorWidth * kCursorHeight * webrtc::DesktopFrame::kBytesPerPixel,
264             static_cast<int>(cursor_shape.data().size()));
265 }
266
267 // This test mocks capturer, encoder and network layer to simulate one capture
268 // cycle. When the first encoded packet is submitted to the network
269 // VideoScheduler is instructed to come to a complete stop. We expect the stop
270 // sequence to be executed successfully.
271 TEST_F(VideoSchedulerTest, StartAndStop) {
272   scoped_ptr<webrtc::MockScreenCapturer> capturer(
273       new webrtc::MockScreenCapturer());
274   scoped_ptr<MockMouseCursorMonitor> cursor_monitor(
275       new MockMouseCursorMonitor());
276
277   {
278     InSequence s;
279
280     EXPECT_CALL(*cursor_monitor, Init(_, _))
281         .WillOnce(
282             Invoke(this, &VideoSchedulerTest::OnMouseCursorMonitorInit));
283
284     EXPECT_CALL(*cursor_monitor, Capture())
285         .WillRepeatedly(Invoke(this, &VideoSchedulerTest::OnCaptureMouse));
286   }
287
288   Expectation capturer_start =
289       EXPECT_CALL(*capturer, Start(_))
290           .WillOnce(Invoke(this, &VideoSchedulerTest::OnCapturerStart));
291
292   // First the capturer is called.
293   Expectation capturer_capture = EXPECT_CALL(*capturer, Capture(_))
294       .After(capturer_start)
295       .WillRepeatedly(Invoke(this, &VideoSchedulerTest::OnCaptureFrame));
296
297   scoped_ptr<MockVideoEncoder> encoder(new MockVideoEncoder());
298
299   // Expect the encoder be called.
300   EXPECT_CALL(*encoder, EncodePtr(_))
301       .WillRepeatedly(FinishEncode());
302
303   // By default delete the arguments when ProcessVideoPacket is received.
304   EXPECT_CALL(video_stub_, ProcessVideoPacketPtr(_, _))
305       .WillRepeatedly(FinishSend());
306
307   // When the first ProcessVideoPacket is received we stop the VideoScheduler.
308   EXPECT_CALL(video_stub_, ProcessVideoPacketPtr(_, _))
309       .WillOnce(DoAll(
310           FinishSend(),
311           InvokeWithoutArgs(this, &VideoSchedulerTest::StopVideoScheduler)))
312       .RetiresOnSaturation();
313
314   EXPECT_CALL(client_stub_, SetCursorShape(_))
315       .WillOnce(Invoke(this, &VideoSchedulerTest::SetCursorShape));
316
317   // Start video frame capture.
318   scoped_ptr<webrtc::MouseCursorMonitor> mouse_cursor_monitor(
319       new FakeMouseCursorMonitor());
320   StartVideoScheduler(capturer.PassAs<webrtc::DesktopCapturer>(),
321                       encoder.PassAs<VideoEncoder>(),
322                       cursor_monitor.PassAs<webrtc::MouseCursorMonitor>());
323
324   // Run until there are no more pending tasks from the VideoScheduler.
325   // Otherwise, a lingering frame capture might attempt to trigger a capturer
326   // expectation action and crash.
327   base::RunLoop().RunUntilIdle();
328 }
329
330 // Verify that the capturer, encoder and mouse monitor are torn down on the
331 // correct threads.
332 TEST_F(VideoSchedulerTest, DeleteOnThreads) {
333   capture_task_runner_ = AutoThread::Create("capture", main_task_runner_);
334   encode_task_runner_ = AutoThread::Create("encode", main_task_runner_);
335
336   scoped_ptr<webrtc::DesktopCapturer> capturer(
337       new ThreadCheckDesktopCapturer(capture_task_runner_));
338   scoped_ptr<VideoEncoder> encoder(
339       new ThreadCheckVideoEncoder(encode_task_runner_));
340   scoped_ptr<webrtc::MouseCursorMonitor> mouse_cursor_monitor(
341       new ThreadCheckMouseCursorMonitor(capture_task_runner_));
342
343   // Start and stop the scheduler, so it will tear down the screen capturer,
344   // video encoder and mouse monitor.
345   StartVideoScheduler(capturer.Pass(), encoder.Pass(),
346                       mouse_cursor_monitor.Pass());
347   StopVideoScheduler();
348 }
349
350 }  // namespace remoting