| 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
|
|
|