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"
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
;
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
;
46 ACTION(FinishEncode
) {
47 scoped_ptr
<VideoPacket
> packet(new VideoPacket());
48 return packet
.release();
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
{
67 virtual ~MockVideoEncoder() {}
69 scoped_ptr
<VideoPacket
> Encode(const webrtc::DesktopFrame
& frame
) {
70 return make_scoped_ptr(EncodePtr(frame
));
72 MOCK_METHOD1(EncodePtr
, VideoPacket
*(const webrtc::DesktopFrame
& frame
));
75 DISALLOW_COPY_AND_ASSIGN(MockVideoEncoder
);
78 class ThreadCheckVideoEncoder
: public VideoEncoderVerbatim
{
80 ThreadCheckVideoEncoder(
81 scoped_refptr
<base::SingleThreadTaskRunner
> task_runner
)
82 : task_runner_(task_runner
) {
84 ~ThreadCheckVideoEncoder() override
{
85 EXPECT_TRUE(task_runner_
->BelongsToCurrentThread());
89 scoped_refptr
<base::SingleThreadTaskRunner
> task_runner_
;
91 DISALLOW_COPY_AND_ASSIGN(ThreadCheckVideoEncoder
);
94 class ThreadCheckDesktopCapturer
: public FakeDesktopCapturer
{
96 ThreadCheckDesktopCapturer(
97 scoped_refptr
<base::SingleThreadTaskRunner
> task_runner
)
98 : task_runner_(task_runner
) {
100 ~ThreadCheckDesktopCapturer() override
{
101 EXPECT_TRUE(task_runner_
->BelongsToCurrentThread());
105 scoped_refptr
<base::SingleThreadTaskRunner
> task_runner_
;
107 DISALLOW_COPY_AND_ASSIGN(ThreadCheckDesktopCapturer
);
110 class ThreadCheckMouseCursorMonitor
: public FakeMouseCursorMonitor
{
112 ThreadCheckMouseCursorMonitor(
113 scoped_refptr
<base::SingleThreadTaskRunner
> task_runner
)
114 : task_runner_(task_runner
) {
116 ~ThreadCheckMouseCursorMonitor() override
{
117 EXPECT_TRUE(task_runner_
->BelongsToCurrentThread());
121 scoped_refptr
<base::SingleThreadTaskRunner
> task_runner_
;
123 DISALLOW_COPY_AND_ASSIGN(ThreadCheckMouseCursorMonitor
);
126 class VideoSchedulerTest
: public testing::Test
{
128 VideoSchedulerTest();
130 void SetUp() override
;
131 void TearDown() override
;
133 void StartVideoScheduler(
134 scoped_ptr
<webrtc::DesktopCapturer
> capturer
,
135 scoped_ptr
<VideoEncoder
> encoder
,
136 scoped_ptr
<webrtc::MouseCursorMonitor
> mouse_monitor
);
137 void StopVideoScheduler();
139 // webrtc::DesktopCapturer mocks.
140 void OnCapturerStart(webrtc::DesktopCapturer::Callback
* callback
);
141 void OnCaptureFrame(const webrtc::DesktopRegion
& region
);
143 // webrtc::MouseCursorMonitor mocks.
144 void OnMouseCursorMonitorInit(
145 webrtc::MouseCursorMonitor::Callback
* callback
,
146 webrtc::MouseCursorMonitor::Mode mode
);
147 void OnCaptureMouse();
148 void SetCursorShape(const protocol::CursorShapeInfo
& cursor_shape
);
151 base::MessageLoop message_loop_
;
152 base::RunLoop run_loop_
;
153 scoped_refptr
<AutoThreadTaskRunner
> capture_task_runner_
;
154 scoped_refptr
<AutoThreadTaskRunner
> encode_task_runner_
;
155 scoped_refptr
<AutoThreadTaskRunner
> main_task_runner_
;
156 scoped_refptr
<VideoScheduler
> scheduler_
;
158 MockClientStub client_stub_
;
159 MockVideoStub video_stub_
;
161 // Points to the callback passed to webrtc::DesktopCapturer::Start().
162 webrtc::DesktopCapturer::Callback
* capturer_callback_
;
164 // Points to the callback passed to webrtc::MouseCursor::Init().
165 webrtc::MouseCursorMonitor::Callback
* mouse_monitor_callback_
;
168 DISALLOW_COPY_AND_ASSIGN(VideoSchedulerTest
);
171 VideoSchedulerTest::VideoSchedulerTest()
172 : capturer_callback_(NULL
),
173 mouse_monitor_callback_(NULL
) {
176 void VideoSchedulerTest::SetUp() {
177 main_task_runner_
= new AutoThreadTaskRunner(
178 message_loop_
.message_loop_proxy(), run_loop_
.QuitClosure());
179 capture_task_runner_
= main_task_runner_
;
180 encode_task_runner_
= main_task_runner_
;
183 void VideoSchedulerTest::TearDown() {
184 // Release the task runners, so that the test can quit.
185 capture_task_runner_
= NULL
;
186 encode_task_runner_
= NULL
;
187 main_task_runner_
= NULL
;
189 // Run the MessageLoop until everything has torn down.
193 void VideoSchedulerTest::StartVideoScheduler(
194 scoped_ptr
<webrtc::DesktopCapturer
> capturer
,
195 scoped_ptr
<VideoEncoder
> encoder
,
196 scoped_ptr
<webrtc::MouseCursorMonitor
> mouse_monitor
) {
197 scheduler_
= new VideoScheduler(
198 capture_task_runner_
,
202 mouse_monitor
.Pass(),
209 void VideoSchedulerTest::StopVideoScheduler() {
214 void VideoSchedulerTest::OnCapturerStart(
215 webrtc::DesktopCapturer::Callback
* callback
) {
216 EXPECT_FALSE(capturer_callback_
);
217 EXPECT_TRUE(callback
);
219 capturer_callback_
= callback
;
222 void VideoSchedulerTest::OnCaptureFrame(const webrtc::DesktopRegion
& region
) {
223 scoped_ptr
<webrtc::DesktopFrame
> frame(
224 new webrtc::BasicDesktopFrame(webrtc::DesktopSize(kWidth
, kHeight
)));
225 frame
->mutable_updated_region()->SetRect(
226 webrtc::DesktopRect::MakeXYWH(0, 0, 10, 10));
227 capturer_callback_
->OnCaptureCompleted(frame
.release());
230 void VideoSchedulerTest::OnCaptureMouse() {
231 EXPECT_TRUE(mouse_monitor_callback_
);
233 scoped_ptr
<webrtc::MouseCursor
> mouse_cursor(
234 new webrtc::MouseCursor(
235 new webrtc::BasicDesktopFrame(
236 webrtc::DesktopSize(kCursorWidth
, kCursorHeight
)),
237 webrtc::DesktopVector(kHotspotX
, kHotspotY
)));
239 mouse_monitor_callback_
->OnMouseCursor(mouse_cursor
.release());
242 void VideoSchedulerTest::OnMouseCursorMonitorInit(
243 webrtc::MouseCursorMonitor::Callback
* callback
,
244 webrtc::MouseCursorMonitor::Mode mode
) {
245 EXPECT_FALSE(mouse_monitor_callback_
);
246 EXPECT_TRUE(callback
);
248 mouse_monitor_callback_
= callback
;
251 void VideoSchedulerTest::SetCursorShape(
252 const protocol::CursorShapeInfo
& cursor_shape
) {
253 EXPECT_TRUE(cursor_shape
.has_width());
254 EXPECT_EQ(kCursorWidth
, cursor_shape
.width());
255 EXPECT_TRUE(cursor_shape
.has_height());
256 EXPECT_EQ(kCursorHeight
, cursor_shape
.height());
257 EXPECT_TRUE(cursor_shape
.has_hotspot_x());
258 EXPECT_EQ(kHotspotX
, cursor_shape
.hotspot_x());
259 EXPECT_TRUE(cursor_shape
.has_hotspot_y());
260 EXPECT_EQ(kHotspotY
, cursor_shape
.hotspot_y());
261 EXPECT_TRUE(cursor_shape
.has_data());
262 EXPECT_EQ(kCursorWidth
* kCursorHeight
* webrtc::DesktopFrame::kBytesPerPixel
,
263 static_cast<int>(cursor_shape
.data().size()));
266 // This test mocks capturer, encoder and network layer to simulate one capture
267 // cycle. When the first encoded packet is submitted to the network
268 // VideoScheduler is instructed to come to a complete stop. We expect the stop
269 // sequence to be executed successfully.
270 TEST_F(VideoSchedulerTest
, StartAndStop
) {
271 scoped_ptr
<webrtc::MockScreenCapturer
> capturer(
272 new webrtc::MockScreenCapturer());
273 scoped_ptr
<MockMouseCursorMonitor
> cursor_monitor(
274 new MockMouseCursorMonitor());
279 EXPECT_CALL(*cursor_monitor
, Init(_
, _
))
281 Invoke(this, &VideoSchedulerTest::OnMouseCursorMonitorInit
));
283 EXPECT_CALL(*cursor_monitor
, Capture())
284 .WillRepeatedly(Invoke(this, &VideoSchedulerTest::OnCaptureMouse
));
287 Expectation capturer_start
=
288 EXPECT_CALL(*capturer
, Start(_
))
289 .WillOnce(Invoke(this, &VideoSchedulerTest::OnCapturerStart
));
291 // First the capturer is called.
292 Expectation capturer_capture
= EXPECT_CALL(*capturer
, Capture(_
))
293 .After(capturer_start
)
294 .WillRepeatedly(Invoke(this, &VideoSchedulerTest::OnCaptureFrame
));
296 scoped_ptr
<MockVideoEncoder
> encoder(new MockVideoEncoder());
298 // Expect the encoder be called.
299 EXPECT_CALL(*encoder
, EncodePtr(_
))
300 .WillRepeatedly(FinishEncode());
302 // By default delete the arguments when ProcessVideoPacket is received.
303 EXPECT_CALL(video_stub_
, ProcessVideoPacketPtr(_
, _
))
304 .WillRepeatedly(FinishSend());
306 // When the first ProcessVideoPacket is received we stop the VideoScheduler.
307 EXPECT_CALL(video_stub_
, ProcessVideoPacketPtr(_
, _
))
310 InvokeWithoutArgs(this, &VideoSchedulerTest::StopVideoScheduler
)))
311 .RetiresOnSaturation();
313 EXPECT_CALL(client_stub_
, SetCursorShape(_
))
314 .WillOnce(Invoke(this, &VideoSchedulerTest::SetCursorShape
));
316 // Start video frame capture.
317 scoped_ptr
<webrtc::MouseCursorMonitor
> mouse_cursor_monitor(
318 new FakeMouseCursorMonitor());
319 StartVideoScheduler(capturer
.Pass(), encoder
.Pass(), cursor_monitor
.Pass());
321 // Run until there are no more pending tasks from the VideoScheduler.
322 // Otherwise, a lingering frame capture might attempt to trigger a capturer
323 // expectation action and crash.
324 base::RunLoop().RunUntilIdle();
327 // Verify that the capturer, encoder and mouse monitor are torn down on the
329 TEST_F(VideoSchedulerTest
, DeleteOnThreads
) {
330 capture_task_runner_
= AutoThread::Create("capture", main_task_runner_
);
331 encode_task_runner_
= AutoThread::Create("encode", main_task_runner_
);
333 scoped_ptr
<webrtc::DesktopCapturer
> capturer(
334 new ThreadCheckDesktopCapturer(capture_task_runner_
));
335 scoped_ptr
<VideoEncoder
> encoder(
336 new ThreadCheckVideoEncoder(encode_task_runner_
));
337 scoped_ptr
<webrtc::MouseCursorMonitor
> mouse_cursor_monitor(
338 new ThreadCheckMouseCursorMonitor(capture_task_runner_
));
340 // Start and stop the scheduler, so it will tear down the screen capturer,
341 // video encoder and mouse monitor.
342 StartVideoScheduler(capturer
.Pass(), encoder
.Pass(),
343 mouse_cursor_monitor
.Pass());
344 StopVideoScheduler();
347 } // namespace remoting