Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(121)

Unified Diff: remoting/protocol/client_video_dispatcher_unittest.cc

Issue 850983002: Implement video frame acknowledgements in the chromoting protocol. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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

Powered by Google App Engine
This is Rietveld 408576698