diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
commit | 36d22d82aa202bb199967e9512281e9a53db42c9 (patch) | |
tree | 105e8c98ddea1c1e4784a60a5a6410fa416be2de /third_party/libwebrtc/call/fake_network_pipe_unittest.cc | |
parent | Initial commit. (diff) | |
download | firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip |
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/libwebrtc/call/fake_network_pipe_unittest.cc')
-rw-r--r-- | third_party/libwebrtc/call/fake_network_pipe_unittest.cc | 509 |
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 |