Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / remoting / host / video_scheduler_unittest.cc
blob1d76d589c7b64d3dc6355dc7b6c08bf1726d4841
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.
5 #include "remoting/host/video_scheduler.h"
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"
27 using ::remoting::protocol::MockClientStub;
28 using ::remoting::protocol::MockVideoStub;
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;
42 namespace remoting {
44 namespace {
46 ACTION(FinishEncode) {
47 scoped_ptr<VideoPacket> packet(new VideoPacket());
48 return packet.release();
51 ACTION(FinishSend) {
52 arg1.Run();
55 } // namespace
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;
64 class MockVideoEncoder : public VideoEncoder {
65 public:
66 MockVideoEncoder() {}
67 virtual ~MockVideoEncoder() {}
69 scoped_ptr<VideoPacket> Encode(
70 const webrtc::DesktopFrame& frame) {
71 return scoped_ptr<VideoPacket>(EncodePtr(frame));
73 MOCK_METHOD1(EncodePtr, VideoPacket*(const webrtc::DesktopFrame& frame));
75 private:
76 DISALLOW_COPY_AND_ASSIGN(MockVideoEncoder);
79 class ThreadCheckVideoEncoder : public VideoEncoderVerbatim {
80 public:
81 ThreadCheckVideoEncoder(
82 scoped_refptr<base::SingleThreadTaskRunner> task_runner)
83 : task_runner_(task_runner) {
85 virtual ~ThreadCheckVideoEncoder() {
86 EXPECT_TRUE(task_runner_->BelongsToCurrentThread());
89 private:
90 scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
92 DISALLOW_COPY_AND_ASSIGN(ThreadCheckVideoEncoder);
95 class ThreadCheckDesktopCapturer : public FakeDesktopCapturer {
96 public:
97 ThreadCheckDesktopCapturer(
98 scoped_refptr<base::SingleThreadTaskRunner> task_runner)
99 : task_runner_(task_runner) {
101 virtual ~ThreadCheckDesktopCapturer() {
102 EXPECT_TRUE(task_runner_->BelongsToCurrentThread());
105 private:
106 scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
108 DISALLOW_COPY_AND_ASSIGN(ThreadCheckDesktopCapturer);
111 class ThreadCheckMouseCursorMonitor : public FakeMouseCursorMonitor {
112 public:
113 ThreadCheckMouseCursorMonitor(
114 scoped_refptr<base::SingleThreadTaskRunner> task_runner)
115 : task_runner_(task_runner) {
117 virtual ~ThreadCheckMouseCursorMonitor() {
118 EXPECT_TRUE(task_runner_->BelongsToCurrentThread());
121 private:
122 scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
124 DISALLOW_COPY_AND_ASSIGN(ThreadCheckMouseCursorMonitor);
127 class VideoSchedulerTest : public testing::Test {
128 public:
129 VideoSchedulerTest();
131 virtual void SetUp() OVERRIDE;
132 virtual void TearDown() OVERRIDE;
134 void StartVideoScheduler(
135 scoped_ptr<webrtc::DesktopCapturer> capturer,
136 scoped_ptr<VideoEncoder> encoder,
137 scoped_ptr<webrtc::MouseCursorMonitor> mouse_monitor);
138 void StopVideoScheduler();
140 // webrtc::DesktopCapturer mocks.
141 void OnCapturerStart(webrtc::DesktopCapturer::Callback* callback);
142 void OnCaptureFrame(const webrtc::DesktopRegion& region);
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);
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_;
159 MockClientStub client_stub_;
160 MockVideoStub video_stub_;
162 // Points to the callback passed to webrtc::DesktopCapturer::Start().
163 webrtc::DesktopCapturer::Callback* capturer_callback_;
165 // Points to the callback passed to webrtc::MouseCursor::Init().
166 webrtc::MouseCursorMonitor::Callback* mouse_monitor_callback_;
168 private:
169 DISALLOW_COPY_AND_ASSIGN(VideoSchedulerTest);
172 VideoSchedulerTest::VideoSchedulerTest()
173 : capturer_callback_(NULL),
174 mouse_monitor_callback_(NULL) {
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_;
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;
190 // Run the MessageLoop until everything has torn down.
191 run_loop_.Run();
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();
210 void VideoSchedulerTest::StopVideoScheduler() {
211 scheduler_->Stop();
212 scheduler_ = NULL;
215 void VideoSchedulerTest::OnCapturerStart(
216 webrtc::DesktopCapturer::Callback* callback) {
217 EXPECT_FALSE(capturer_callback_);
218 EXPECT_TRUE(callback);
220 capturer_callback_ = callback;
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());
231 void VideoSchedulerTest::OnCaptureMouse() {
232 EXPECT_TRUE(mouse_monitor_callback_);
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)));
240 mouse_monitor_callback_->OnMouseCursor(mouse_cursor.release());
243 void VideoSchedulerTest::OnMouseCursorMonitorInit(
244 webrtc::MouseCursorMonitor::Callback* callback,
245 webrtc::MouseCursorMonitor::Mode mode) {
246 EXPECT_FALSE(mouse_monitor_callback_);
247 EXPECT_TRUE(callback);
249 mouse_monitor_callback_ = callback;
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()));
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());
278 InSequence s;
280 EXPECT_CALL(*cursor_monitor, Init(_, _))
281 .WillOnce(
282 Invoke(this, &VideoSchedulerTest::OnMouseCursorMonitorInit));
284 EXPECT_CALL(*cursor_monitor, Capture())
285 .WillRepeatedly(Invoke(this, &VideoSchedulerTest::OnCaptureMouse));
288 Expectation capturer_start =
289 EXPECT_CALL(*capturer, Start(_))
290 .WillOnce(Invoke(this, &VideoSchedulerTest::OnCapturerStart));
292 // First the capturer is called.
293 Expectation capturer_capture = EXPECT_CALL(*capturer, Capture(_))
294 .After(capturer_start)
295 .WillRepeatedly(Invoke(this, &VideoSchedulerTest::OnCaptureFrame));
297 scoped_ptr<MockVideoEncoder> encoder(new MockVideoEncoder());
299 // Expect the encoder be called.
300 EXPECT_CALL(*encoder, EncodePtr(_))
301 .WillRepeatedly(FinishEncode());
303 // By default delete the arguments when ProcessVideoPacket is received.
304 EXPECT_CALL(video_stub_, ProcessVideoPacketPtr(_, _))
305 .WillRepeatedly(FinishSend());
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();
314 EXPECT_CALL(client_stub_, SetCursorShape(_))
315 .WillOnce(Invoke(this, &VideoSchedulerTest::SetCursorShape));
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>());
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();
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_);
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_));
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();
350 } // namespace remoting