|  | // Copyright 2015 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/protocol/client_video_dispatcher.h" | 
|  |  | 
|  | #include <memory> | 
|  | #include <vector> | 
|  |  | 
|  | #include "base/bind.h" | 
|  | #include "base/message_loop/message_loop.h" | 
|  | #include "base/run_loop.h" | 
|  | #include "remoting/base/buffered_socket_writer.h" | 
|  | #include "remoting/base/constants.h" | 
|  | #include "remoting/proto/video.pb.h" | 
|  | #include "remoting/protocol/fake_stream_socket.h" | 
|  | #include "remoting/protocol/message_reader.h" | 
|  | #include "remoting/protocol/message_serialization.h" | 
|  | #include "remoting/protocol/protocol_mock_objects.h" | 
|  | #include "remoting/protocol/stream_message_pipe_adapter.h" | 
|  | #include "remoting/protocol/video_stub.h" | 
|  | #include "testing/gtest/include/gtest/gtest.h" | 
|  |  | 
|  | namespace remoting { | 
|  | namespace protocol { | 
|  |  | 
|  | class ClientVideoDispatcherTest : public testing::Test, | 
|  | public VideoStub, | 
|  | public ChannelDispatcherBase::EventHandler { | 
|  | public: | 
|  | ClientVideoDispatcherTest(); | 
|  |  | 
|  | // VideoStub interface. | 
|  | void ProcessVideoPacket(std::unique_ptr<VideoPacket> video_packet, | 
|  | const base::Closure& done) override; | 
|  |  | 
|  | // ChannelDispatcherBase::EventHandler interface. | 
|  | void OnChannelInitialized(ChannelDispatcherBase* channel_dispatcher) override; | 
|  | void OnChannelClosed(ChannelDispatcherBase* channel_dispatcher) override; | 
|  |  | 
|  | protected: | 
|  | void OnChannelError(int error); | 
|  |  | 
|  | void OnMessageReceived(std::unique_ptr<CompoundBuffer> buffer); | 
|  | void OnReadError(int error); | 
|  |  | 
|  | base::MessageLoop message_loop_; | 
|  |  | 
|  | // Set to true in OnChannelInitialized(). | 
|  | bool initialized_ = false; | 
|  |  | 
|  | // Client side. | 
|  | FakeStreamChannelFactory client_channel_factory_; | 
|  | StreamMessageChannelFactoryAdapter channel_factory_adapter_; | 
|  | MockClientStub client_stub_; | 
|  | ClientVideoDispatcher dispatcher_; | 
|  |  | 
|  | // Host side. | 
|  | FakeStreamSocket host_socket_; | 
|  | MessageReader reader_; | 
|  | BufferedSocketWriter writer_; | 
|  |  | 
|  | std::vector<std::unique_ptr<VideoPacket>> video_packets_; | 
|  | std::vector<base::Closure> packet_done_callbacks_; | 
|  |  | 
|  | std::vector<std::unique_ptr<VideoAck>> ack_messages_; | 
|  | }; | 
|  |  | 
|  | ClientVideoDispatcherTest::ClientVideoDispatcherTest() | 
|  | : channel_factory_adapter_( | 
|  | &client_channel_factory_, | 
|  | base::Bind(&ClientVideoDispatcherTest::OnChannelError, | 
|  | base::Unretained(this))), | 
|  | dispatcher_(this, &client_stub_) { | 
|  | dispatcher_.Init(&channel_factory_adapter_, this); | 
|  | base::RunLoop().RunUntilIdle(); | 
|  | DCHECK(initialized_); | 
|  | host_socket_.PairWith( | 
|  | client_channel_factory_.GetFakeChannel(kVideoChannelName)); | 
|  | reader_.StartReading(&host_socket_, | 
|  | base::Bind(&ClientVideoDispatcherTest::OnMessageReceived, | 
|  | base::Unretained(this)), | 
|  | base::Bind(&ClientVideoDispatcherTest::OnReadError, | 
|  | base::Unretained(this))); | 
|  | writer_.Start( | 
|  | base::Bind(&P2PStreamSocket::Write, base::Unretained(&host_socket_)), | 
|  | BufferedSocketWriter::WriteFailedCallback()); | 
|  | } | 
|  |  | 
|  | void ClientVideoDispatcherTest::ProcessVideoPacket( | 
|  | std::unique_ptr<VideoPacket> video_packet, | 
|  | const base::Closure& done) { | 
|  | video_packets_.push_back(std::move(video_packet)); | 
|  | packet_done_callbacks_.push_back(done); | 
|  | } | 
|  |  | 
|  | void ClientVideoDispatcherTest::OnChannelInitialized( | 
|  | ChannelDispatcherBase* channel_dispatcher) { | 
|  | initialized_ = true; | 
|  | } | 
|  |  | 
|  | void ClientVideoDispatcherTest::OnChannelClosed( | 
|  | ChannelDispatcherBase* channel_dispatcher) { | 
|  | // Don't expect channels to be closed. | 
|  | FAIL(); | 
|  | } | 
|  |  | 
|  | void ClientVideoDispatcherTest::OnChannelError(int error) { | 
|  | // Don't expect channel creation to fail. | 
|  | FAIL(); | 
|  | } | 
|  |  | 
|  | void ClientVideoDispatcherTest::OnMessageReceived( | 
|  | std::unique_ptr<CompoundBuffer> buffer) { | 
|  | std::unique_ptr<VideoAck> ack = ParseMessage<VideoAck>(buffer.get()); | 
|  | EXPECT_TRUE(ack); | 
|  | ack_messages_.push_back(std::move(ack)); | 
|  | } | 
|  |  | 
|  | void ClientVideoDispatcherTest::OnReadError(int error) { | 
|  | LOG(FATAL) << "Unexpected read error: " << error; | 
|  | } | 
|  |  | 
|  | // Verify that the client can receive video packets and acks are not sent for | 
|  | // VideoPackets that don't have frame_id field set. | 
|  | TEST_F(ClientVideoDispatcherTest, WithoutAcks) { | 
|  | VideoPacket packet; | 
|  | packet.set_data(std::string()); | 
|  |  | 
|  | // Send a VideoPacket and verify that the client receives it. | 
|  | writer_.Write(SerializeAndFrameMessage(packet), base::Closure()); | 
|  | base::RunLoop().RunUntilIdle(); | 
|  | EXPECT_EQ(1U, video_packets_.size()); | 
|  |  | 
|  | packet_done_callbacks_.front().Run(); | 
|  | base::RunLoop().RunUntilIdle(); | 
|  |  | 
|  | // Ack should never be sent for the packet without frame_id. | 
|  | EXPECT_TRUE(ack_messages_.empty()); | 
|  | } | 
|  |  | 
|  | // Verifies that the dispatcher sends Ack message with correct rendering delay. | 
|  | TEST_F(ClientVideoDispatcherTest, WithAcks) { | 
|  | int kTestFrameId = 3; | 
|  |  | 
|  | VideoPacket packet; | 
|  | packet.set_data(std::string()); | 
|  | packet.set_frame_id(kTestFrameId); | 
|  |  | 
|  | // Send a VideoPacket and verify that the client receives it. | 
|  | writer_.Write(SerializeAndFrameMessage(packet), base::Closure()); | 
|  | base::RunLoop().RunUntilIdle(); | 
|  | EXPECT_EQ(1U, video_packets_.size()); | 
|  |  | 
|  | // Ack should only be sent after the packet is processed. | 
|  | EXPECT_TRUE(ack_messages_.empty()); | 
|  | base::RunLoop().RunUntilIdle(); | 
|  |  | 
|  | // Fake completion of video packet decoding, to trigger the Ack. | 
|  | packet_done_callbacks_.front().Run(); | 
|  | base::RunLoop().RunUntilIdle(); | 
|  |  | 
|  | // Verify that the Ack message has been received. | 
|  | ASSERT_EQ(1U, ack_messages_.size()); | 
|  | EXPECT_EQ(kTestFrameId, ack_messages_[0]->frame_id()); | 
|  | } | 
|  |  | 
|  | // Verifies that the dispatcher properly synthesizes VideoLayout message when | 
|  | // screen size changes. | 
|  | TEST_F(ClientVideoDispatcherTest, VideoLayout) { | 
|  | const int kScreenSize = 100; | 
|  | const float kScaleFactor = 2.0; | 
|  |  | 
|  | VideoPacket packet; | 
|  | packet.set_data(std::string()); | 
|  | packet.set_frame_id(42); | 
|  | packet.mutable_format()->set_screen_width(kScreenSize); | 
|  | packet.mutable_format()->set_screen_height(kScreenSize); | 
|  | packet.mutable_format()->set_x_dpi(kDefaultDpi * kScaleFactor); | 
|  | packet.mutable_format()->set_y_dpi(kDefaultDpi * kScaleFactor); | 
|  |  | 
|  | VideoLayout layout; | 
|  | EXPECT_CALL(client_stub_, SetVideoLayout(testing::_)) | 
|  | .WillOnce(testing::SaveArg<0>(&layout)); | 
|  |  | 
|  | // Send a VideoPacket and verify that the client receives it. | 
|  | writer_.Write(SerializeAndFrameMessage(packet), base::Closure()); | 
|  | base::RunLoop().RunUntilIdle(); | 
|  |  | 
|  | ASSERT_EQ(1, layout.video_track_size()); | 
|  | EXPECT_EQ(0, layout.video_track(0).position_x()); | 
|  | EXPECT_EQ(0, layout.video_track(0).position_y()); | 
|  | EXPECT_EQ(kScreenSize / kScaleFactor, layout.video_track(0).width()); | 
|  | EXPECT_EQ(kScreenSize / kScaleFactor, layout.video_track(0).height()); | 
|  | EXPECT_EQ(kDefaultDpi * kScaleFactor, layout.video_track(0).x_dpi()); | 
|  | EXPECT_EQ(kDefaultDpi * kScaleFactor, layout.video_track(0).y_dpi()); | 
|  | } | 
|  |  | 
|  | // Verify that Ack messages are sent in correct order. | 
|  | TEST_F(ClientVideoDispatcherTest, AcksOrder) { | 
|  | int kTestFrameId = 3; | 
|  |  | 
|  | VideoPacket packet; | 
|  | packet.set_data(std::string()); | 
|  | packet.set_frame_id(kTestFrameId); | 
|  |  | 
|  | // Send two VideoPackets. | 
|  | writer_.Write(SerializeAndFrameMessage(packet), base::Closure()); | 
|  | base::RunLoop().RunUntilIdle(); | 
|  |  | 
|  | packet.set_frame_id(kTestFrameId + 1); | 
|  | writer_.Write(SerializeAndFrameMessage(packet), base::Closure()); | 
|  | base::RunLoop().RunUntilIdle(); | 
|  |  | 
|  | EXPECT_EQ(2U, video_packets_.size()); | 
|  | EXPECT_TRUE(ack_messages_.empty()); | 
|  |  | 
|  | // Call completion callbacks in revers order. | 
|  | packet_done_callbacks_[1].Run(); | 
|  | packet_done_callbacks_[0].Run(); | 
|  |  | 
|  | base::RunLoop().RunUntilIdle(); | 
|  |  | 
|  | // Verify order of Ack messages. | 
|  | ASSERT_EQ(2U, ack_messages_.size()); | 
|  | EXPECT_EQ(kTestFrameId, ack_messages_[0]->frame_id()); | 
|  | EXPECT_EQ(kTestFrameId + 1, ack_messages_[1]->frame_id()); | 
|  | } | 
|  |  | 
|  | }  // namespace protocol | 
|  | }  // namespace remoting |