/* * 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 #include #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 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(config); std::unique_ptr 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(config); std::unique_ptr 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(config); std::unique_ptr 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(config); std::unique_ptr 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 network(new SimulatedNetwork(config)); SimulatedNetwork* simulated_network = network.get(); std::unique_ptr 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(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 network(new SimulatedNetwork(config)); SimulatedNetwork* simulated_network = network.get(); std::unique_ptr 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(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 network(new SimulatedNetwork(config)); SimulatedNetwork* simulated_network = network.get(); std::unique_ptr 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(config); std::unique_ptr 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(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(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(config); std::unique_ptr 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(config); std::unique_ptr pipe(new FakeNetworkPipe( &fake_clock_, std::move(simulated_network), &receiver)); Timestamp send_time = fake_clock_.CurrentTime(); RtpPacketReceived packet(nullptr, send_time); packet.SetExtension(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(config); std::unique_ptr pipe(new FakeNetworkPipe( &fake_clock_, std::move(simulated_network), &receiver)); RtpHeaderExtensionMap extension_map; extension_map.Register(/*id=*/7); RtpPacketReceived packet(&extension_map, fake_clock_.CurrentTime()); packet.SetExtension(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(), 123); })); pipe->Process(); } TEST_F(FakeNetworkPipeTest, DeliverRtcpPacket) { BuiltInNetworkBehaviorConfig config; config.queue_delay_ms = 100; MockReceiver receiver; auto simulated_network = std::make_unique(config); std::unique_ptr 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