| // 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<VideoPacket> 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<VideoPacket> Encode( |
| const webrtc::DesktopFrame& frame) { |
| return scoped_ptr<VideoPacket>(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<webrtc::ScreenCapturer> 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<AutoThreadTaskRunner> task_runner_; |
| scoped_refptr<VideoScheduler> scheduler_; |
| |
| MockClientStub client_stub_; |
| MockVideoStub video_stub_; |
| |
| // The following mock objects are owned by VideoScheduler. |
| MockVideoEncoder* encoder_; |
| |
| scoped_ptr<webrtc::DesktopFrame> 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<webrtc::ScreenCapturer> capturer) { |
| scheduler_ = new VideoScheduler( |
| task_runner_, // Capture |
| task_runner_, // Encode |
| task_runner_, // Network |
| capturer.Pass(), |
| scoped_ptr<VideoEncoder>(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<webrtc::MockScreenCapturer> 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<webrtc::ScreenCapturer>()); |
| |
| task_runner_ = NULL; |
| run_loop_.Run(); |
| } |
| |
| } // namespace remoting |