blob: 31f97fc85c736b82f0afaedf7531ea13b83abbef [file] [log] [blame]
/*
* 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