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_verbatim.h"
14 #include "remoting/host/fake_screen_capturer.h"
15 #include "remoting/proto/video.pb.h"
16 #include "remoting/protocol/protocol_mock_objects.h"
17 #include "testing/gmock/include/gmock/gmock.h"
18 #include "testing/gtest/include/gtest/gtest.h"
19 #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"
20 #include "third_party/webrtc/modules/desktop_capture/screen_capturer_mock_objects.h"
22 using ::remoting::protocol::MockClientStub
;
23 using ::remoting::protocol::MockVideoStub
;
26 using ::testing::AtLeast
;
27 using ::testing::AnyNumber
;
28 using ::testing::DeleteArg
;
29 using ::testing::DoAll
;
30 using ::testing::Expectation
;
31 using ::testing::InSequence
;
32 using ::testing::InvokeWithoutArgs
;
33 using ::testing::Return
;
34 using ::testing::ReturnRef
;
35 using ::testing::SaveArg
;
41 ACTION(FinishEncode
) {
42 scoped_ptr
<VideoPacket
> packet(new VideoPacket());
43 return packet
.release();
52 static const int kWidth
= 640;
53 static const int kHeight
= 480;
55 class MockVideoEncoder
: public VideoEncoder
{
58 virtual ~MockVideoEncoder() {}
60 scoped_ptr
<VideoPacket
> Encode(
61 const webrtc::DesktopFrame
& frame
) {
62 return scoped_ptr
<VideoPacket
>(EncodePtr(frame
));
64 MOCK_METHOD1(EncodePtr
, VideoPacket
*(const webrtc::DesktopFrame
& frame
));
67 DISALLOW_COPY_AND_ASSIGN(MockVideoEncoder
);
70 class ThreadCheckVideoEncoder
: public VideoEncoderVerbatim
{
72 ThreadCheckVideoEncoder(
73 scoped_refptr
<base::SingleThreadTaskRunner
> task_runner
)
74 : task_runner_(task_runner
) {
76 virtual ~ThreadCheckVideoEncoder() {
77 EXPECT_TRUE(task_runner_
->BelongsToCurrentThread());
81 scoped_refptr
<base::SingleThreadTaskRunner
> task_runner_
;
83 DISALLOW_COPY_AND_ASSIGN(ThreadCheckVideoEncoder
);
86 class ThreadCheckScreenCapturer
: public FakeScreenCapturer
{
88 ThreadCheckScreenCapturer(
89 scoped_refptr
<base::SingleThreadTaskRunner
> task_runner
)
90 : task_runner_(task_runner
) {
92 virtual ~ThreadCheckScreenCapturer() {
93 EXPECT_TRUE(task_runner_
->BelongsToCurrentThread());
97 scoped_refptr
<base::SingleThreadTaskRunner
> task_runner_
;
99 DISALLOW_COPY_AND_ASSIGN(ThreadCheckScreenCapturer
);
102 class VideoSchedulerTest
: public testing::Test
{
104 VideoSchedulerTest();
106 virtual void SetUp() OVERRIDE
;
107 virtual void TearDown() OVERRIDE
;
109 void StartVideoScheduler(
110 scoped_ptr
<webrtc::ScreenCapturer
> capturer
,
111 scoped_ptr
<VideoEncoder
> encoder
);
112 void StopVideoScheduler();
114 // webrtc::ScreenCapturer mocks.
115 void OnCapturerStart(webrtc::ScreenCapturer::Callback
* callback
);
116 void OnCaptureFrame(const webrtc::DesktopRegion
& region
);
119 base::MessageLoop message_loop_
;
120 base::RunLoop run_loop_
;
121 scoped_refptr
<AutoThreadTaskRunner
> capture_task_runner_
;
122 scoped_refptr
<AutoThreadTaskRunner
> encode_task_runner_
;
123 scoped_refptr
<AutoThreadTaskRunner
> main_task_runner_
;
124 scoped_refptr
<VideoScheduler
> scheduler_
;
126 MockClientStub client_stub_
;
127 MockVideoStub video_stub_
;
129 scoped_ptr
<webrtc::DesktopFrame
> frame_
;
131 // Points to the callback passed to webrtc::ScreenCapturer::Start().
132 webrtc::ScreenCapturer::Callback
* capturer_callback_
;
135 DISALLOW_COPY_AND_ASSIGN(VideoSchedulerTest
);
138 VideoSchedulerTest::VideoSchedulerTest()
139 : capturer_callback_(NULL
) {
142 void VideoSchedulerTest::SetUp() {
143 main_task_runner_
= new AutoThreadTaskRunner(
144 message_loop_
.message_loop_proxy(), run_loop_
.QuitClosure());
145 capture_task_runner_
= main_task_runner_
;
146 encode_task_runner_
= main_task_runner_
;
149 void VideoSchedulerTest::TearDown() {
150 // Release the task runners, so that the test can quit.
151 capture_task_runner_
= NULL
;
152 encode_task_runner_
= NULL
;
153 main_task_runner_
= NULL
;
155 // Run the MessageLoop until everything has torn down.
159 void VideoSchedulerTest::StartVideoScheduler(
160 scoped_ptr
<webrtc::ScreenCapturer
> capturer
,
161 scoped_ptr
<VideoEncoder
> encoder
) {
162 scheduler_
= new VideoScheduler(
163 capture_task_runner_
,
173 void VideoSchedulerTest::StopVideoScheduler() {
178 void VideoSchedulerTest::OnCapturerStart(
179 webrtc::ScreenCapturer::Callback
* callback
) {
180 EXPECT_FALSE(capturer_callback_
);
181 EXPECT_TRUE(callback
);
183 capturer_callback_
= callback
;
186 void VideoSchedulerTest::OnCaptureFrame(const webrtc::DesktopRegion
& region
) {
187 frame_
->mutable_updated_region()->SetRect(
188 webrtc::DesktopRect::MakeXYWH(0, 0, 10, 10));
189 capturer_callback_
->OnCaptureCompleted(frame_
.release());
192 // This test mocks capturer, encoder and network layer to simulate one capture
193 // cycle. When the first encoded packet is submitted to the network
194 // VideoScheduler is instructed to come to a complete stop. We expect the stop
195 // sequence to be executed successfully.
196 TEST_F(VideoSchedulerTest
, StartAndStop
) {
197 scoped_ptr
<webrtc::MockScreenCapturer
> capturer(
198 new webrtc::MockScreenCapturer());
199 Expectation capturer_start
=
200 EXPECT_CALL(*capturer
, Start(_
))
201 .WillOnce(Invoke(this, &VideoSchedulerTest::OnCapturerStart
));
203 frame_
.reset(new webrtc::BasicDesktopFrame(
204 webrtc::DesktopSize(kWidth
, kHeight
)));
206 // First the capturer is called.
207 Expectation capturer_capture
= EXPECT_CALL(*capturer
, Capture(_
))
208 .After(capturer_start
)
209 .WillRepeatedly(Invoke(this, &VideoSchedulerTest::OnCaptureFrame
));
211 scoped_ptr
<MockVideoEncoder
> encoder(new MockVideoEncoder());
213 // Expect the encoder be called.
214 EXPECT_CALL(*encoder
, EncodePtr(_
))
215 .WillRepeatedly(FinishEncode());
217 // By default delete the arguments when ProcessVideoPacket is received.
218 EXPECT_CALL(video_stub_
, ProcessVideoPacketPtr(_
, _
))
219 .WillRepeatedly(FinishSend());
221 // When the first ProcessVideoPacket is received we stop the VideoScheduler.
222 EXPECT_CALL(video_stub_
, ProcessVideoPacketPtr(_
, _
))
225 InvokeWithoutArgs(this, &VideoSchedulerTest::StopVideoScheduler
)))
226 .RetiresOnSaturation();
228 // Start video frame capture.
229 StartVideoScheduler(capturer
.PassAs
<webrtc::ScreenCapturer
>(),
230 encoder
.PassAs
<VideoEncoder
>());
233 // Verify that the capturer and encoder are torn down on the correct threads.
234 TEST_F(VideoSchedulerTest
, DeleteOnThreads
) {
235 capture_task_runner_
= AutoThread::Create("capture", main_task_runner_
);
236 encode_task_runner_
= AutoThread::Create("encode", main_task_runner_
);
238 scoped_ptr
<webrtc::ScreenCapturer
> capturer(
239 new ThreadCheckScreenCapturer(capture_task_runner_
));
240 scoped_ptr
<VideoEncoder
> encoder(
241 new ThreadCheckVideoEncoder(encode_task_runner_
));
243 // Start and stop the scheduler, so it will tear down the screen capturer and
245 StartVideoScheduler(capturer
.Pass(), encoder
.Pass());
246 StopVideoScheduler();
249 } // namespace remoting