Index: remoting/protocol/client_video_dispatcher_unittest.cc |
diff --git a/remoting/protocol/client_video_dispatcher_unittest.cc b/remoting/protocol/client_video_dispatcher_unittest.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..b31ff7e5fa25baaf80113ecc12c06c2a6a50dbb4 |
--- /dev/null |
+++ b/remoting/protocol/client_video_dispatcher_unittest.cc |
@@ -0,0 +1,241 @@ |
+// 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 "base/bind.h" |
+#include "base/memory/scoped_vector.h" |
+#include "base/message_loop/message_loop.h" |
+#include "base/run_loop.h" |
+#include "remoting/base/constants.h" |
+#include "remoting/proto/video.pb.h" |
+#include "remoting/protocol/fake_session.h" |
+#include "remoting/protocol/fake_stream_socket.h" |
+#include "remoting/protocol/message_serialization.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() |
+ : initialized_(false), |
+ dispatcher_(this), |
+ parser_(base::Bind(&ClientVideoDispatcherTest::OnVideoAck, |
+ base::Unretained(this)), |
+ &reader_) { |
+ } |
+ |
+ void InitializeWithProtocolVersion(int version) { |
+ dispatcher_.Init(&session_, |
+ ChannelConfig(ChannelConfig::TRANSPORT_MUX_STREAM, version, |
+ ChannelConfig::CODEC_UNDEFINED), |
+ this); |
+ base::RunLoop().RunUntilIdle(); |
+ DCHECK(initialized_); |
+ host_socket_.PairWith( |
+ session_.fake_channel_factory().GetFakeChannel(kVideoChannelName)); |
+ reader_.StartReading(&host_socket_); |
+ writer_.Init(&host_socket_, BufferedSocketWriter::WriteFailedCallback()); |
+ } |
+ |
+ // VideoStub interface. |
+ void ProcessVideoPacket(scoped_ptr<VideoPacket> video_packet, |
+ const ProgressCallback& progress_callback) { |
+ video_packets_.push_back(video_packet.release()); |
+ packet_progress_callbacks_.push_back(progress_callback); |
+ } |
+ |
+ // ChannelDispatcherBase::EventHandler interface. |
+ void OnChannelInitialized(ChannelDispatcherBase* channel_dispatcher) { |
+ initialized_ = true; |
+ } |
+ void OnChannelError(ChannelDispatcherBase* channel_dispatcher, |
+ ErrorCode error) { |
+ // Don't expect channel creation to fail. |
+ FAIL(); |
+ } |
+ |
+ protected: |
+ void OnVideoAck(scoped_ptr<VideoAck> ack, const base::Closure& done) { |
+ ack_messages_.push_back(ack.release()); |
+ done.Run(); |
+ } |
+ |
+ base::MessageLoop message_loop_; |
+ |
+ // Set to true in OnChannelInitialized(). |
+ bool initialized_; |
+ |
+ // Client side. |
+ ClientVideoDispatcher dispatcher_; |
+ FakeSession session_; |
+ |
+ // Host side. |
+ FakeStreamSocket host_socket_; |
+ MessageReader reader_; |
+ ProtobufMessageParser<VideoAck> parser_; |
+ BufferedSocketWriter writer_; |
+ |
+ ScopedVector<VideoPacket> video_packets_; |
+ std::vector<ProgressCallback> packet_progress_callbacks_; |
+ |
+ ScopedVector<VideoAck> ack_messages_; |
+}; |
+ |
+// Verify that the client can receive video packets and acks are not sent for |
+// older versions of the protocol. |
+TEST_F(ClientVideoDispatcherTest, WithoutAcks) { |
+ int kTestFrameId = 3; |
+ |
+ InitializeWithProtocolVersion(kVideoStreamVersionNoAck); |
+ |
+ 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()); |
+ |
+ packet_progress_callbacks_.front().Run(VideoStub::PacketProgress::DONE); |
+ base::RunLoop().RunUntilIdle(); |
+ |
+ // Ack should never be sent for this version of the protocol. |
+ EXPECT_TRUE(ack_messages_.empty()); |
+} |
+ |
+// Verifies that the dispatcher sends Ack message with correct rendering delay. |
+TEST_F(ClientVideoDispatcherTest, WithAcks) { |
+ int kTestFrameId = 3; |
+ |
+ InitializeWithProtocolVersion(kVideoStreamVersion); |
+ |
+ VideoPacket packet; |
+ packet.set_data(std::string()); |
+ packet.set_frame_id(kTestFrameId); |
+ |
+ // Send a VideoPacket and verify that the client receives it. |
+ base::TimeTicks write_started_time = base::TimeTicks::Now(); |
+ 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()); |
+ |
+ // Simulate frame render delay. |
+ base::TimeTicks render_started_time = base::TimeTicks::Now(); |
+ base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(1)); |
+ base::TimeDelta render_delay_min = |
+ base::TimeTicks::Now() - render_started_time; |
+ |
+ //Fake completion of video packet decoding, to trigger the Ack. |
+ packet_progress_callbacks_.front().Run(VideoStub::PacketProgress::DONE); |
+ base::TimeDelta render_delay_max = |
+ base::TimeTicks::Now() - write_started_time; |
+ |
+ base::RunLoop().RunUntilIdle(); |
+ ASSERT_EQ(1U, ack_messages_.size()); |
+ EXPECT_EQ(kTestFrameId, ack_messages_[0]->frame_id()); |
+ |
+ // Verify that rendering latency is reported correctly. |
+ base::TimeDelta render_delay = |
+ base::TimeDelta::FromMicroseconds(ack_messages_[0]->rendering_delay_us()); |
+ EXPECT_TRUE(render_delay >= render_delay_min); |
+ EXPECT_TRUE(render_delay <= render_delay_max); |
+} |
+ |
+// Verifies that the dispatcher reports correct read delay in the messages it |
+// receives. |
+TEST_F(ClientVideoDispatcherTest, ReadDelay) { |
+ int kTestFrameId = 3; |
+ |
+ InitializeWithProtocolVersion(kVideoStreamVersion); |
+ |
+ VideoPacket packet; |
+ packet.set_data(std::string()); |
+ packet.set_frame_id(kTestFrameId); |
+ |
+ // Generate buffers for two video frames. |
+ scoped_refptr<net::IOBufferWithSize> packet_buffer_1 = |
+ SerializeAndFrameMessage(packet); |
+ packet.set_frame_id(kTestFrameId + 1); |
+ scoped_refptr<net::IOBufferWithSize> packet_buffer_2 = |
+ SerializeAndFrameMessage(packet); |
+ packet.set_frame_id(kTestFrameId + 2); |
+ scoped_refptr<net::IOBufferWithSize> packet_buffer_3 = |
+ SerializeAndFrameMessage(packet); |
+ |
+ base::TimeTicks send_started_time = base::TimeTicks::Now(); |
+ |
+ // First send all data for the first frame and the first byte for the second |
+ // frame in a single network packet. |
+ scoped_refptr<net::IOBufferWithSize> buffer = |
+ new net::IOBufferWithSize(packet_buffer_1->size() + 1); |
+ memcpy(buffer->data(), packet_buffer_1->data(), packet_buffer_1->size()); |
+ memcpy(buffer->data() + packet_buffer_1->size(), packet_buffer_2->data(), 1); |
+ writer_.Write(buffer, base::Closure()); |
+ base::RunLoop().RunUntilIdle(); |
+ |
+ // Verify that the packet was received. |
+ EXPECT_EQ(1U, video_packets_.size()); |
+ video_packets_.clear(); |
+ packet_progress_callbacks_.front().Run(VideoStub::PacketProgress::DONE); |
+ packet_progress_callbacks_.clear(); |
+ base::RunLoop().RunUntilIdle(); |
+ |
+ // Verify that the Ack message for the first video frame has time_to_receive |
+ // field set to 0, because the whole frame was received in one message. |
+ ASSERT_EQ(1U, ack_messages_.size()); |
+ EXPECT_EQ(kTestFrameId, ack_messages_[0]->frame_id()); |
+ EXPECT_EQ(0, ack_messages_[0]->time_to_receive_us()); |
+ ack_messages_.clear(); |
+ |
+ // Simulate networking latency while receiving the second frame. |
+ base::TimeTicks network_delay_started_time = base::TimeTicks::Now(); |
+ base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(1)); |
+ base::TimeDelta time_to_receive_min = |
+ base::TimeTicks::Now() - network_delay_started_time; |
+ |
+ // Send the remainder of the second frame. |
+ buffer = new net::IOBufferWithSize(packet_buffer_2->size() - 1 + |
+ packet_buffer_3->size()); |
+ memcpy(buffer->data(), packet_buffer_2->data() + 1, |
+ packet_buffer_2->size() - 1); |
+ memcpy(buffer->data() + packet_buffer_2->size() - 1, packet_buffer_3->data(), |
+ packet_buffer_3->size()); |
+ writer_.Write(buffer, base::Closure()); |
+ base::RunLoop().RunUntilIdle(); |
+ |
+ base::TimeDelta time_to_receive_max = |
+ base::TimeTicks::Now() - send_started_time; |
+ |
+ // Verify that the last 2 packets were received. |
+ EXPECT_EQ(2U, video_packets_.size()); |
+ packet_progress_callbacks_[0].Run(VideoStub::PacketProgress::DONE); |
+ packet_progress_callbacks_[1].Run(VideoStub::PacketProgress::DONE); |
+ base::RunLoop().RunUntilIdle(); |
+ |
+ // Verify that we've received 2 Ack for the last 2 frames. |
+ ASSERT_EQ(2U, ack_messages_.size()); |
+ EXPECT_EQ(kTestFrameId + 1, ack_messages_[0]->frame_id()); |
+ |
+ // Verify that the dispatcher set correct time_to_receive value. |
+ base::TimeDelta time_to_receive = |
+ base::TimeDelta::FromMicroseconds(ack_messages_[0]->time_to_receive_us()); |
+ EXPECT_TRUE(time_to_receive >= time_to_receive_min); |
+ EXPECT_TRUE(time_to_receive <= time_to_receive_max); |
+ |
+ EXPECT_EQ(kTestFrameId + 2, ack_messages_[1]->frame_id()); |
+ EXPECT_EQ(0, ack_messages_[1]->time_to_receive_us()); |
+} |
+ |
+} // namespace protocol |
+} // namespace remoting |