summaryrefslogtreecommitdiffstats
path: root/third_party/libwebrtc/call/fake_network_pipe_unittest.cc
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/libwebrtc/call/fake_network_pipe_unittest.cc')
-rw-r--r--third_party/libwebrtc/call/fake_network_pipe_unittest.cc509
1 files changed, 509 insertions, 0 deletions
diff --git a/third_party/libwebrtc/call/fake_network_pipe_unittest.cc b/third_party/libwebrtc/call/fake_network_pipe_unittest.cc
new file mode 100644
index 0000000000..31f97fc85c
--- /dev/null
+++ b/third_party/libwebrtc/call/fake_network_pipe_unittest.cc
@@ -0,0 +1,509 @@
+/*
+ * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "call/fake_network_pipe.h"
+
+#include <memory>
+#include <utility>
+
+#include "api/units/time_delta.h"
+#include "api/units/timestamp.h"
+#include "call/simulated_network.h"
+#include "modules/rtp_rtcp/include/rtp_header_extension_map.h"
+#include "modules/rtp_rtcp/source/rtp_header_extensions.h"
+#include "modules/rtp_rtcp/source/rtp_packet_received.h"
+#include "rtc_base/checks.h"
+#include "system_wrappers/include/clock.h"
+#include "test/gmock.h"
+#include "test/gtest.h"
+
+using ::testing::_;
+using ::testing::Property;
+using ::testing::WithArg;
+
+namespace webrtc {
+class MockReceiver : public PacketReceiver {
+ public:
+ MOCK_METHOD(void,
+ DeliverRtcpPacket,
+ (rtc::CopyOnWriteBuffer packet),
+ (override));
+ MOCK_METHOD(void,
+ DeliverRtpPacket,
+ (MediaType media_type,
+ RtpPacketReceived packet,
+ OnUndemuxablePacketHandler undemuxable_packet_handler),
+ (override));
+ virtual ~MockReceiver() = default;
+};
+
+class ReorderTestReceiver : public MockReceiver {
+ public:
+ void DeliverRtpPacket(
+ MediaType media_type,
+ RtpPacketReceived packet,
+ OnUndemuxablePacketHandler undemuxable_packet_handler) override {
+ RTC_DCHECK_GE(packet.size(), sizeof(int));
+ delivered_sequence_numbers_.push_back(packet.SequenceNumber());
+ }
+ std::vector<int> delivered_sequence_numbers_;
+};
+
+class FakeNetworkPipeTest : public ::testing::Test {
+ public:
+ FakeNetworkPipeTest() : fake_clock_(12345) {}
+
+ protected:
+ void SendPackets(FakeNetworkPipe* pipe, int number_packets, int packet_size) {
+ RTC_DCHECK_GE(packet_size, sizeof(int));
+ for (int i = 0; i < number_packets; ++i) {
+ RtpPacketReceived packet;
+ constexpr size_t kFixedHeaderSize = 12;
+ packet.AllocatePayload(packet_size - kFixedHeaderSize);
+ packet.SetSequenceNumber(i);
+ packet.set_arrival_time(fake_clock_.CurrentTime());
+ RTC_DCHECK_EQ(packet.Buffer().size(), packet_size);
+ pipe->DeliverRtpPacket(MediaType::ANY, std::move(packet),
+ [](const RtpPacketReceived&) { return false; });
+ }
+ }
+
+ int PacketTimeMs(int capacity_kbps, int packet_size) const {
+ return 8 * packet_size / capacity_kbps;
+ }
+
+ SimulatedClock fake_clock_;
+};
+
+// Test the capacity link and verify we get as many packets as we expect.
+TEST_F(FakeNetworkPipeTest, CapacityTest) {
+ BuiltInNetworkBehaviorConfig config;
+ config.queue_length_packets = 20;
+ config.link_capacity_kbps = 80;
+ MockReceiver receiver;
+ auto simulated_network = std::make_unique<SimulatedNetwork>(config);
+ std::unique_ptr<FakeNetworkPipe> pipe(new FakeNetworkPipe(
+ &fake_clock_, std::move(simulated_network), &receiver));
+
+ // Add 10 packets of 1000 bytes, = 80 kb, and verify it takes one second to
+ // get through the pipe.
+ const int kNumPackets = 10;
+ const int kPacketSize = 1000;
+ SendPackets(pipe.get(), kNumPackets, kPacketSize);
+
+ // Time to get one packet through the link.
+ const int kPacketTimeMs =
+ PacketTimeMs(config.link_capacity_kbps, kPacketSize);
+
+ // Time haven't increased yet, so we souldn't get any packets.
+ EXPECT_CALL(receiver, DeliverRtpPacket).Times(0);
+ pipe->Process();
+
+ // Advance enough time to release one packet.
+ fake_clock_.AdvanceTimeMilliseconds(kPacketTimeMs);
+ EXPECT_CALL(receiver, DeliverRtpPacket).Times(1);
+ pipe->Process();
+
+ // Release all but one packet
+ fake_clock_.AdvanceTimeMilliseconds(9 * kPacketTimeMs - 1);
+ EXPECT_CALL(receiver, DeliverRtpPacket).Times(8);
+ pipe->Process();
+
+ // And the last one.
+ fake_clock_.AdvanceTimeMilliseconds(1);
+ EXPECT_CALL(receiver, DeliverRtpPacket).Times(1);
+ pipe->Process();
+}
+
+// Test the extra network delay.
+TEST_F(FakeNetworkPipeTest, ExtraDelayTest) {
+ BuiltInNetworkBehaviorConfig config;
+ config.queue_length_packets = 20;
+ config.queue_delay_ms = 100;
+ config.link_capacity_kbps = 80;
+ MockReceiver receiver;
+ auto simulated_network = std::make_unique<SimulatedNetwork>(config);
+ std::unique_ptr<FakeNetworkPipe> pipe(new FakeNetworkPipe(
+ &fake_clock_, std::move(simulated_network), &receiver));
+
+ const int kNumPackets = 2;
+ const int kPacketSize = 1000;
+ SendPackets(pipe.get(), kNumPackets, kPacketSize);
+
+ // Time to get one packet through the link.
+ const int kPacketTimeMs =
+ PacketTimeMs(config.link_capacity_kbps, kPacketSize);
+
+ // Increase more than kPacketTimeMs, but not more than the extra delay.
+ fake_clock_.AdvanceTimeMilliseconds(kPacketTimeMs);
+ EXPECT_CALL(receiver, DeliverRtpPacket).Times(0);
+ pipe->Process();
+
+ // Advance the network delay to get the first packet.
+ fake_clock_.AdvanceTimeMilliseconds(config.queue_delay_ms);
+ EXPECT_CALL(receiver, DeliverRtpPacket).Times(1);
+ pipe->Process();
+
+ // Advance one more kPacketTimeMs to get the last packet.
+ fake_clock_.AdvanceTimeMilliseconds(kPacketTimeMs);
+ EXPECT_CALL(receiver, DeliverRtpPacket).Times(1);
+ pipe->Process();
+}
+
+// Test the number of buffers and packets are dropped when sending too many
+// packets too quickly.
+TEST_F(FakeNetworkPipeTest, QueueLengthTest) {
+ BuiltInNetworkBehaviorConfig config;
+ config.queue_length_packets = 2;
+ config.link_capacity_kbps = 80;
+ MockReceiver receiver;
+ auto simulated_network = std::make_unique<SimulatedNetwork>(config);
+ std::unique_ptr<FakeNetworkPipe> pipe(new FakeNetworkPipe(
+ &fake_clock_, std::move(simulated_network), &receiver));
+
+ const int kPacketSize = 1000;
+ const int kPacketTimeMs =
+ PacketTimeMs(config.link_capacity_kbps, kPacketSize);
+
+ // Send three packets and verify only 2 are delivered.
+ SendPackets(pipe.get(), 3, kPacketSize);
+
+ // Increase time enough to deliver all three packets, verify only two are
+ // delivered.
+ fake_clock_.AdvanceTimeMilliseconds(3 * kPacketTimeMs);
+ EXPECT_CALL(receiver, DeliverRtpPacket).Times(2);
+ pipe->Process();
+}
+
+// Test we get statistics as expected.
+TEST_F(FakeNetworkPipeTest, StatisticsTest) {
+ BuiltInNetworkBehaviorConfig config;
+ config.queue_length_packets = 2;
+ config.queue_delay_ms = 20;
+ config.link_capacity_kbps = 80;
+ MockReceiver receiver;
+ auto simulated_network = std::make_unique<SimulatedNetwork>(config);
+ std::unique_ptr<FakeNetworkPipe> pipe(new FakeNetworkPipe(
+ &fake_clock_, std::move(simulated_network), &receiver));
+
+ const int kPacketSize = 1000;
+ const int kPacketTimeMs =
+ PacketTimeMs(config.link_capacity_kbps, kPacketSize);
+
+ // Send three packets and verify only 2 are delivered.
+ SendPackets(pipe.get(), 3, kPacketSize);
+ fake_clock_.AdvanceTimeMilliseconds(3 * kPacketTimeMs +
+ config.queue_delay_ms);
+
+ EXPECT_CALL(receiver, DeliverRtpPacket).Times(2);
+ pipe->Process();
+
+ // Packet 1: kPacketTimeMs + config.queue_delay_ms,
+ // packet 2: 2 * kPacketTimeMs + config.queue_delay_ms => 170 ms average.
+ EXPECT_EQ(pipe->AverageDelay(), 170);
+ EXPECT_EQ(pipe->SentPackets(), 2u);
+ EXPECT_EQ(pipe->DroppedPackets(), 1u);
+ EXPECT_EQ(pipe->PercentageLoss(), 1 / 3.f);
+}
+
+// Change the link capacity half-way through the test and verify that the
+// delivery times change accordingly.
+TEST_F(FakeNetworkPipeTest, ChangingCapacityWithEmptyPipeTest) {
+ BuiltInNetworkBehaviorConfig config;
+ config.queue_length_packets = 20;
+ config.link_capacity_kbps = 80;
+ MockReceiver receiver;
+ std::unique_ptr<SimulatedNetwork> network(new SimulatedNetwork(config));
+ SimulatedNetwork* simulated_network = network.get();
+ std::unique_ptr<FakeNetworkPipe> pipe(
+ new FakeNetworkPipe(&fake_clock_, std::move(network), &receiver));
+
+ // Add 10 packets of 1000 bytes, = 80 kb, and verify it takes one second to
+ // get through the pipe.
+ const int kNumPackets = 10;
+ const int kPacketSize = 1000;
+ SendPackets(pipe.get(), kNumPackets, kPacketSize);
+
+ // Time to get one packet through the link.
+ int packet_time_ms = PacketTimeMs(config.link_capacity_kbps, kPacketSize);
+
+ // Time hasn't increased yet, so we souldn't get any packets.
+ EXPECT_CALL(receiver, DeliverRtpPacket).Times(0);
+ pipe->Process();
+
+ // Advance time in steps to release one packet at a time.
+ for (int i = 0; i < kNumPackets; ++i) {
+ fake_clock_.AdvanceTimeMilliseconds(packet_time_ms);
+ EXPECT_CALL(receiver, DeliverRtpPacket).Times(1);
+ pipe->Process();
+ }
+
+ // Change the capacity.
+ config.link_capacity_kbps /= 2; // Reduce to 50%.
+ simulated_network->SetConfig(config);
+
+ // Add another 10 packets of 1000 bytes, = 80 kb, and verify it takes two
+ // seconds to get them through the pipe.
+ SendPackets(pipe.get(), kNumPackets, kPacketSize);
+
+ // Time to get one packet through the link.
+ packet_time_ms = PacketTimeMs(config.link_capacity_kbps, kPacketSize);
+
+ // Time hasn't increased yet, so we souldn't get any packets.
+ EXPECT_CALL(receiver, DeliverRtpPacket).Times(0);
+ pipe->Process();
+
+ // Advance time in steps to release one packet at a time.
+ for (int i = 0; i < kNumPackets; ++i) {
+ fake_clock_.AdvanceTimeMilliseconds(packet_time_ms);
+ EXPECT_CALL(receiver, DeliverRtpPacket).Times(1);
+ pipe->Process();
+ }
+
+ // Check that all the packets were sent.
+ EXPECT_EQ(static_cast<size_t>(2 * kNumPackets), pipe->SentPackets());
+ EXPECT_FALSE(pipe->TimeUntilNextProcess().has_value());
+ fake_clock_.AdvanceTimeMilliseconds(1000);
+ EXPECT_CALL(receiver, DeliverRtpPacket).Times(0);
+ pipe->Process();
+}
+
+// Change the link capacity half-way through the test and verify that the
+// delivery times change accordingly.
+TEST_F(FakeNetworkPipeTest, ChangingCapacityWithPacketsInPipeTest) {
+ BuiltInNetworkBehaviorConfig config;
+ config.queue_length_packets = 20;
+ config.link_capacity_kbps = 80;
+ MockReceiver receiver;
+ std::unique_ptr<SimulatedNetwork> network(new SimulatedNetwork(config));
+ SimulatedNetwork* simulated_network = network.get();
+ std::unique_ptr<FakeNetworkPipe> pipe(
+ new FakeNetworkPipe(&fake_clock_, std::move(network), &receiver));
+
+ // Add 20 packets of 1000 bytes, = 160 kb.
+ const int kNumPackets = 20;
+ const int kPacketSize = 1000;
+ SendPackets(pipe.get(), kNumPackets, kPacketSize);
+
+ // Time hasn't increased yet, so we souldn't get any packets.
+ EXPECT_CALL(receiver, DeliverRtpPacket).Times(0);
+ pipe->Process();
+
+ // Advance time in steps to release half of the packets one at a time.
+ int step_ms = PacketTimeMs(config.link_capacity_kbps, kPacketSize);
+ for (int i = 0; i < kNumPackets / 2; ++i) {
+ fake_clock_.AdvanceTimeMilliseconds(step_ms);
+ EXPECT_CALL(receiver, DeliverRtpPacket).Times(1);
+ pipe->Process();
+ }
+
+ // Change the capacity.
+ config.link_capacity_kbps *= 2; // Double the capacity.
+ simulated_network->SetConfig(config);
+
+ // Advance time in steps to release remaining packets one at a time.
+ step_ms = PacketTimeMs(config.link_capacity_kbps, kPacketSize);
+ for (int i = 0; i < kNumPackets / 2; ++i) {
+ fake_clock_.AdvanceTimeMilliseconds(step_ms);
+ EXPECT_CALL(receiver, DeliverRtpPacket).Times(1);
+ pipe->Process();
+ }
+
+ // Check that all the packets were sent.
+ EXPECT_EQ(static_cast<size_t>(kNumPackets), pipe->SentPackets());
+ EXPECT_FALSE(pipe->TimeUntilNextProcess().has_value());
+ fake_clock_.AdvanceTimeMilliseconds(1000);
+ EXPECT_CALL(receiver, DeliverRtpPacket).Times(0);
+ pipe->Process();
+}
+
+// At first disallow reordering and then allow reordering.
+TEST_F(FakeNetworkPipeTest, DisallowReorderingThenAllowReordering) {
+ BuiltInNetworkBehaviorConfig config;
+ config.queue_length_packets = 1000;
+ config.link_capacity_kbps = 800;
+ config.queue_delay_ms = 100;
+ config.delay_standard_deviation_ms = 10;
+ ReorderTestReceiver receiver;
+ std::unique_ptr<SimulatedNetwork> network(new SimulatedNetwork(config));
+ SimulatedNetwork* simulated_network = network.get();
+ std::unique_ptr<FakeNetworkPipe> pipe(
+ new FakeNetworkPipe(&fake_clock_, std::move(network), &receiver));
+
+ const uint32_t kNumPackets = 100;
+ const int kPacketSize = 10;
+ SendPackets(pipe.get(), kNumPackets, kPacketSize);
+ fake_clock_.AdvanceTimeMilliseconds(1000);
+ pipe->Process();
+
+ // Confirm that all packets have been delivered in order.
+ EXPECT_EQ(kNumPackets, receiver.delivered_sequence_numbers_.size());
+ int last_seq_num = -1;
+ for (int seq_num : receiver.delivered_sequence_numbers_) {
+ EXPECT_GT(seq_num, last_seq_num);
+ last_seq_num = seq_num;
+ }
+
+ config.allow_reordering = true;
+ simulated_network->SetConfig(config);
+ SendPackets(pipe.get(), kNumPackets, kPacketSize);
+ fake_clock_.AdvanceTimeMilliseconds(1000);
+ receiver.delivered_sequence_numbers_.clear();
+ pipe->Process();
+
+ // Confirm that all packets have been delivered
+ // and that reordering has occured.
+ EXPECT_EQ(kNumPackets, receiver.delivered_sequence_numbers_.size());
+ bool reordering_has_occured = false;
+ last_seq_num = -1;
+ for (int seq_num : receiver.delivered_sequence_numbers_) {
+ if (last_seq_num > seq_num) {
+ reordering_has_occured = true;
+ break;
+ }
+ last_seq_num = seq_num;
+ }
+ EXPECT_TRUE(reordering_has_occured);
+}
+
+TEST_F(FakeNetworkPipeTest, BurstLoss) {
+ const int kLossPercent = 5;
+ const int kAvgBurstLength = 3;
+ const int kNumPackets = 10000;
+ const int kPacketSize = 10;
+
+ BuiltInNetworkBehaviorConfig config;
+ config.queue_length_packets = kNumPackets;
+ config.loss_percent = kLossPercent;
+ config.avg_burst_loss_length = kAvgBurstLength;
+ ReorderTestReceiver receiver;
+ auto simulated_network = std::make_unique<SimulatedNetwork>(config);
+ std::unique_ptr<FakeNetworkPipe> pipe(new FakeNetworkPipe(
+ &fake_clock_, std::move(simulated_network), &receiver));
+
+ SendPackets(pipe.get(), kNumPackets, kPacketSize);
+ fake_clock_.AdvanceTimeMilliseconds(1000);
+ pipe->Process();
+
+ // Check that the average loss is `kLossPercent` percent.
+ int lost_packets = kNumPackets - receiver.delivered_sequence_numbers_.size();
+ double loss_fraction = lost_packets / static_cast<double>(kNumPackets);
+
+ EXPECT_NEAR(kLossPercent / 100.0, loss_fraction, 0.05);
+
+ // Find the number of bursts that has occurred.
+ size_t received_packets = receiver.delivered_sequence_numbers_.size();
+ int num_bursts = 0;
+ for (size_t i = 0; i < received_packets - 1; ++i) {
+ int diff = receiver.delivered_sequence_numbers_[i + 1] -
+ receiver.delivered_sequence_numbers_[i];
+ if (diff > 1)
+ ++num_bursts;
+ }
+
+ double average_burst_length = static_cast<double>(lost_packets) / num_bursts;
+
+ EXPECT_NEAR(kAvgBurstLength, average_burst_length, 0.3);
+}
+
+TEST_F(FakeNetworkPipeTest, SetReceiver) {
+ BuiltInNetworkBehaviorConfig config;
+ config.link_capacity_kbps = 800;
+ MockReceiver receiver;
+ auto simulated_network = std::make_unique<SimulatedNetwork>(config);
+ std::unique_ptr<FakeNetworkPipe> pipe(new FakeNetworkPipe(
+ &fake_clock_, std::move(simulated_network), &receiver));
+
+ const int kPacketSize = 1000;
+ const int kPacketTimeMs =
+ PacketTimeMs(config.link_capacity_kbps, kPacketSize);
+ SendPackets(pipe.get(), 1, kPacketSize);
+ fake_clock_.AdvanceTimeMilliseconds(kPacketTimeMs);
+ EXPECT_CALL(receiver, DeliverRtpPacket).Times(1);
+ pipe->Process();
+
+ MockReceiver new_receiver;
+ pipe->SetReceiver(&new_receiver);
+
+ SendPackets(pipe.get(), 1, kPacketSize);
+ fake_clock_.AdvanceTimeMilliseconds(kPacketTimeMs);
+ EXPECT_CALL(receiver, DeliverRtpPacket).Times(0);
+ EXPECT_CALL(new_receiver, DeliverRtpPacket).Times(1);
+ pipe->Process();
+}
+
+TEST_F(FakeNetworkPipeTest, DeliverRtpPacketSetsCorrectArrivalTime) {
+ BuiltInNetworkBehaviorConfig config;
+ config.queue_delay_ms = 100;
+ MockReceiver receiver;
+ auto simulated_network = std::make_unique<SimulatedNetwork>(config);
+ std::unique_ptr<FakeNetworkPipe> pipe(new FakeNetworkPipe(
+ &fake_clock_, std::move(simulated_network), &receiver));
+
+ Timestamp send_time = fake_clock_.CurrentTime();
+ RtpPacketReceived packet(nullptr, send_time);
+ packet.SetExtension<TransportSequenceNumber>(123);
+ pipe->DeliverRtpPacket(MediaType::VIDEO, std::move(packet),
+ [](const RtpPacketReceived&) { return false; });
+
+ // Advance the network delay to get the first packet.
+ fake_clock_.AdvanceTimeMilliseconds(config.queue_delay_ms);
+ EXPECT_CALL(receiver, DeliverRtpPacket(MediaType::VIDEO, _, _))
+ .WillOnce(WithArg<1>([&](RtpPacketReceived packet) {
+ EXPECT_EQ(packet.arrival_time(),
+ send_time + TimeDelta::Millis(config.queue_delay_ms));
+ }));
+ pipe->Process();
+}
+
+TEST_F(FakeNetworkPipeTest, DeliverRtpPacketPropagatesExtensions) {
+ BuiltInNetworkBehaviorConfig config;
+ config.queue_delay_ms = 100;
+ MockReceiver receiver;
+ auto simulated_network = std::make_unique<SimulatedNetwork>(config);
+ std::unique_ptr<FakeNetworkPipe> pipe(new FakeNetworkPipe(
+ &fake_clock_, std::move(simulated_network), &receiver));
+ RtpHeaderExtensionMap extension_map;
+ extension_map.Register<TransportSequenceNumber>(/*id=*/7);
+
+ RtpPacketReceived packet(&extension_map, fake_clock_.CurrentTime());
+ packet.SetExtension<TransportSequenceNumber>(123);
+ pipe->DeliverRtpPacket(MediaType::VIDEO, std::move(packet),
+ [](const RtpPacketReceived&) { return false; });
+
+ // Advance the network delay to get the first packet.
+ fake_clock_.AdvanceTimeMilliseconds(config.queue_delay_ms);
+ EXPECT_CALL(receiver, DeliverRtpPacket(MediaType::VIDEO, _, _))
+ .WillOnce(WithArg<1>([](RtpPacketReceived packet) {
+ EXPECT_EQ(packet.GetExtension<TransportSequenceNumber>(), 123);
+ }));
+ pipe->Process();
+}
+
+TEST_F(FakeNetworkPipeTest, DeliverRtcpPacket) {
+ BuiltInNetworkBehaviorConfig config;
+ config.queue_delay_ms = 100;
+ MockReceiver receiver;
+ auto simulated_network = std::make_unique<SimulatedNetwork>(config);
+ std::unique_ptr<FakeNetworkPipe> pipe(new FakeNetworkPipe(
+ &fake_clock_, std::move(simulated_network), &receiver));
+
+ rtc::CopyOnWriteBuffer buffer(100);
+ memset(buffer.MutableData(), 0, 100);
+ pipe->DeliverRtcpPacket(std::move(buffer));
+
+ // Advance the network delay to get the first packet.
+ fake_clock_.AdvanceTimeMilliseconds(config.queue_delay_ms);
+ EXPECT_CALL(receiver,
+ DeliverRtcpPacket(Property(&rtc::CopyOnWriteBuffer::size, 100)));
+ pipe->Process();
+}
+
+} // namespace webrtc