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 "remoting/base/auto_thread_task_runner.h" 11 #include "remoting/codec/video_encoder.h" 12 #include "remoting/proto/video.pb.h" 13 #include "remoting/protocol/protocol_mock_objects.h" 14 #include "testing/gmock/include/gmock/gmock.h" 15 #include "testing/gtest/include/gtest/gtest.h" 16 #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h" 17 #include "third_party/webrtc/modules/desktop_capture/screen_capturer_mock_objects.h" 18 19 using ::remoting::protocol::MockClientStub; 20 using ::remoting::protocol::MockVideoStub; 21 22 using ::testing::_; 23 using ::testing::AtLeast; 24 using ::testing::AnyNumber; 25 using ::testing::DeleteArg; 26 using ::testing::DoAll; 27 using ::testing::Expectation; 28 using ::testing::InSequence; 29 using ::testing::InvokeWithoutArgs; 30 using ::testing::Return; 31 using ::testing::ReturnRef; 32 using ::testing::SaveArg; 33 34 namespace remoting { 35 36 namespace { 37 38 ACTION(FinishEncode) { 39 scoped_ptr<VideoPacket> packet(new VideoPacket()); 40 return packet.release(); 41 } 42 43 ACTION(FinishSend) { 44 arg1.Run(); 45 } 46 47 } // namespace 48 49 static const int kWidth = 640; 50 static const int kHeight = 480; 51 52 class MockVideoEncoder : public VideoEncoder { 53 public: 54 MockVideoEncoder(); 55 virtual ~MockVideoEncoder(); 56 57 scoped_ptr<VideoPacket> Encode( 58 const webrtc::DesktopFrame& frame) { 59 return scoped_ptr<VideoPacket>(EncodePtr(frame)); 60 } 61 MOCK_METHOD1(EncodePtr, VideoPacket*(const webrtc::DesktopFrame& frame)); 62 63 private: 64 DISALLOW_COPY_AND_ASSIGN(MockVideoEncoder); 65 }; 66 67 MockVideoEncoder::MockVideoEncoder() {} 68 69 MockVideoEncoder::~MockVideoEncoder() {} 70 71 class VideoSchedulerTest : public testing::Test { 72 public: 73 VideoSchedulerTest(); 74 75 virtual void SetUp() OVERRIDE; 76 77 void StartVideoScheduler(scoped_ptr<webrtc::ScreenCapturer> capturer); 78 void StopVideoScheduler(); 79 80 // webrtc::ScreenCapturer mocks. 81 void OnCapturerStart(webrtc::ScreenCapturer::Callback* callback); 82 void OnCaptureFrame(const webrtc::DesktopRegion& region); 83 84 protected: 85 base::MessageLoop message_loop_; 86 base::RunLoop run_loop_; 87 scoped_refptr<AutoThreadTaskRunner> task_runner_; 88 scoped_refptr<VideoScheduler> scheduler_; 89 90 MockClientStub client_stub_; 91 MockVideoStub video_stub_; 92 93 // The following mock objects are owned by VideoScheduler. 94 MockVideoEncoder* encoder_; 95 96 scoped_ptr<webrtc::DesktopFrame> frame_; 97 98 // Points to the callback passed to webrtc::ScreenCapturer::Start(). 99 webrtc::ScreenCapturer::Callback* capturer_callback_; 100 101 private: 102 DISALLOW_COPY_AND_ASSIGN(VideoSchedulerTest); 103 }; 104 105 VideoSchedulerTest::VideoSchedulerTest() 106 : encoder_(NULL), 107 capturer_callback_(NULL) { 108 } 109 110 void VideoSchedulerTest::SetUp() { 111 task_runner_ = new AutoThreadTaskRunner( 112 message_loop_.message_loop_proxy(), run_loop_.QuitClosure()); 113 114 encoder_ = new MockVideoEncoder(); 115 } 116 117 void VideoSchedulerTest::StartVideoScheduler( 118 scoped_ptr<webrtc::ScreenCapturer> capturer) { 119 scheduler_ = new VideoScheduler( 120 task_runner_, // Capture 121 task_runner_, // Encode 122 task_runner_, // Network 123 capturer.Pass(), 124 scoped_ptr<VideoEncoder>(encoder_), 125 &client_stub_, 126 &video_stub_); 127 scheduler_->Start(); 128 } 129 130 void VideoSchedulerTest::StopVideoScheduler() { 131 scheduler_->Stop(); 132 scheduler_ = NULL; 133 } 134 135 void VideoSchedulerTest::OnCapturerStart( 136 webrtc::ScreenCapturer::Callback* callback) { 137 EXPECT_FALSE(capturer_callback_); 138 EXPECT_TRUE(callback); 139 140 capturer_callback_ = callback; 141 } 142 143 void VideoSchedulerTest::OnCaptureFrame(const webrtc::DesktopRegion& region) { 144 frame_->mutable_updated_region()->SetRect( 145 webrtc::DesktopRect::MakeXYWH(0, 0, 10, 10)); 146 capturer_callback_->OnCaptureCompleted(frame_.release()); 147 } 148 149 // This test mocks capturer, encoder and network layer to simulate one capture 150 // cycle. When the first encoded packet is submitted to the network 151 // VideoScheduler is instructed to come to a complete stop. We expect the stop 152 // sequence to be executed successfully. 153 TEST_F(VideoSchedulerTest, StartAndStop) { 154 scoped_ptr<webrtc::MockScreenCapturer> capturer( 155 new webrtc::MockScreenCapturer()); 156 Expectation capturer_start = 157 EXPECT_CALL(*capturer, Start(_)) 158 .WillOnce(Invoke(this, &VideoSchedulerTest::OnCapturerStart)); 159 160 frame_.reset(new webrtc::BasicDesktopFrame( 161 webrtc::DesktopSize(kWidth, kHeight))); 162 163 // First the capturer is called. 164 Expectation capturer_capture = EXPECT_CALL(*capturer, Capture(_)) 165 .After(capturer_start) 166 .WillRepeatedly(Invoke(this, &VideoSchedulerTest::OnCaptureFrame)); 167 168 // Expect the encoder be called. 169 EXPECT_CALL(*encoder_, EncodePtr(_)) 170 .WillRepeatedly(FinishEncode()); 171 172 // By default delete the arguments when ProcessVideoPacket is received. 173 EXPECT_CALL(video_stub_, ProcessVideoPacketPtr(_, _)) 174 .WillRepeatedly(FinishSend()); 175 176 // For the first time when ProcessVideoPacket is received we stop the 177 // VideoScheduler. 178 EXPECT_CALL(video_stub_, ProcessVideoPacketPtr(_, _)) 179 .WillOnce(DoAll( 180 FinishSend(), 181 InvokeWithoutArgs(this, &VideoSchedulerTest::StopVideoScheduler))) 182 .RetiresOnSaturation(); 183 184 // Start video frame capture. 185 StartVideoScheduler(capturer.PassAs<webrtc::ScreenCapturer>()); 186 187 task_runner_ = NULL; 188 run_loop_.Run(); 189 } 190 191 } // namespace remoting 192