// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "remoting/host/video_scheduler.h" #include "base/bind.h" #include "base/message_loop/message_loop.h" #include "base/run_loop.h" #include "remoting/base/auto_thread_task_runner.h" #include "remoting/codec/video_encoder.h" #include "remoting/proto/video.pb.h" #include "remoting/protocol/protocol_mock_objects.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h" #include "third_party/webrtc/modules/desktop_capture/screen_capturer_mock_objects.h" using ::remoting::protocol::MockClientStub; using ::remoting::protocol::MockVideoStub; using ::testing::_; using ::testing::AtLeast; using ::testing::AnyNumber; using ::testing::DeleteArg; using ::testing::DoAll; using ::testing::Expectation; using ::testing::InSequence; using ::testing::InvokeWithoutArgs; using ::testing::Return; using ::testing::ReturnRef; using ::testing::SaveArg; namespace remoting { namespace { ACTION(FinishEncode) { scoped_ptr packet(new VideoPacket()); return packet.release(); } ACTION(FinishSend) { arg1.Run(); } } // namespace static const int kWidth = 640; static const int kHeight = 480; class MockVideoEncoder : public VideoEncoder { public: MockVideoEncoder(); virtual ~MockVideoEncoder(); scoped_ptr Encode( const webrtc::DesktopFrame& frame) { return scoped_ptr(EncodePtr(frame)); } MOCK_METHOD1(EncodePtr, VideoPacket*(const webrtc::DesktopFrame& frame)); private: DISALLOW_COPY_AND_ASSIGN(MockVideoEncoder); }; MockVideoEncoder::MockVideoEncoder() {} MockVideoEncoder::~MockVideoEncoder() {} class VideoSchedulerTest : public testing::Test { public: VideoSchedulerTest(); virtual void SetUp() OVERRIDE; void StartVideoScheduler(scoped_ptr capturer); void StopVideoScheduler(); // webrtc::ScreenCapturer mocks. void OnCapturerStart(webrtc::ScreenCapturer::Callback* callback); void OnCaptureFrame(const webrtc::DesktopRegion& region); protected: base::MessageLoop message_loop_; base::RunLoop run_loop_; scoped_refptr task_runner_; scoped_refptr scheduler_; MockClientStub client_stub_; MockVideoStub video_stub_; // The following mock objects are owned by VideoScheduler. MockVideoEncoder* encoder_; scoped_ptr frame_; // Points to the callback passed to webrtc::ScreenCapturer::Start(). webrtc::ScreenCapturer::Callback* capturer_callback_; private: DISALLOW_COPY_AND_ASSIGN(VideoSchedulerTest); }; VideoSchedulerTest::VideoSchedulerTest() : encoder_(NULL), capturer_callback_(NULL) { } void VideoSchedulerTest::SetUp() { task_runner_ = new AutoThreadTaskRunner( message_loop_.message_loop_proxy(), run_loop_.QuitClosure()); encoder_ = new MockVideoEncoder(); } void VideoSchedulerTest::StartVideoScheduler( scoped_ptr capturer) { scheduler_ = new VideoScheduler( task_runner_, // Capture task_runner_, // Encode task_runner_, // Network capturer.Pass(), scoped_ptr(encoder_), &client_stub_, &video_stub_); scheduler_->Start(); } void VideoSchedulerTest::StopVideoScheduler() { scheduler_->Stop(); scheduler_ = NULL; } void VideoSchedulerTest::OnCapturerStart( webrtc::ScreenCapturer::Callback* callback) { EXPECT_FALSE(capturer_callback_); EXPECT_TRUE(callback); capturer_callback_ = callback; } void VideoSchedulerTest::OnCaptureFrame(const webrtc::DesktopRegion& region) { frame_->mutable_updated_region()->SetRect( webrtc::DesktopRect::MakeXYWH(0, 0, 10, 10)); capturer_callback_->OnCaptureCompleted(frame_.release()); } // This test mocks capturer, encoder and network layer to simulate one capture // cycle. When the first encoded packet is submitted to the network // VideoScheduler is instructed to come to a complete stop. We expect the stop // sequence to be executed successfully. TEST_F(VideoSchedulerTest, StartAndStop) { scoped_ptr capturer( new webrtc::MockScreenCapturer()); Expectation capturer_start = EXPECT_CALL(*capturer, Start(_)) .WillOnce(Invoke(this, &VideoSchedulerTest::OnCapturerStart)); frame_.reset(new webrtc::BasicDesktopFrame( webrtc::DesktopSize(kWidth, kHeight))); // First the capturer is called. Expectation capturer_capture = EXPECT_CALL(*capturer, Capture(_)) .After(capturer_start) .WillRepeatedly(Invoke(this, &VideoSchedulerTest::OnCaptureFrame)); // Expect the encoder be called. EXPECT_CALL(*encoder_, EncodePtr(_)) .WillRepeatedly(FinishEncode()); // By default delete the arguments when ProcessVideoPacket is received. EXPECT_CALL(video_stub_, ProcessVideoPacketPtr(_, _)) .WillRepeatedly(FinishSend()); // For the first time when ProcessVideoPacket is received we stop the // VideoScheduler. EXPECT_CALL(video_stub_, ProcessVideoPacketPtr(_, _)) .WillOnce(DoAll( FinishSend(), InvokeWithoutArgs(this, &VideoSchedulerTest::StopVideoScheduler))) .RetiresOnSaturation(); // Start video frame capture. StartVideoScheduler(capturer.PassAs()); task_runner_ = NULL; run_loop_.Run(); } } // namespace remoting