Allow FakeNetworkPipe to drop packets in bursts.
The fake network pipe will still only drop packets at an average rate of
|loss_percent| but in bursts at an average length specified by
|avg_burst_loss_length|.
Also added the flag -avg_burst_loss_length to video loopback.
BUG=
Review-Url: https://codereview.webrtc.org/1995683003
Cr-Commit-Position: refs/heads/master@{#12969}
diff --git a/webrtc/test/fake_network_pipe.cc b/webrtc/test/fake_network_pipe.cc
index ea4e551..360b32c 100644
--- a/webrtc/test/fake_network_pipe.cc
+++ b/webrtc/test/fake_network_pipe.cc
@@ -13,7 +13,9 @@
#include <assert.h>
#include <math.h>
#include <string.h>
+
#include <algorithm>
+#include <cmath>
#include "webrtc/call.h"
#include "webrtc/system_wrappers/include/clock.h"
@@ -34,7 +36,27 @@
dropped_packets_(0),
sent_packets_(0),
total_packet_delay_(0),
- next_process_time_(clock_->TimeInMilliseconds()) {}
+ bursting_(false),
+ next_process_time_(clock_->TimeInMilliseconds()) {
+ double prob_loss = config.loss_percent / 100.0;
+ if (config_.avg_burst_loss_length == -1) {
+ // Uniform loss
+ prob_loss_bursting_ = prob_loss;
+ prob_start_bursting_ = prob_loss;
+ } else {
+ // Lose packets according to a gilbert-elliot model.
+ int avg_burst_loss_length = config.avg_burst_loss_length;
+ int min_avg_burst_loss_length = std::ceil(prob_loss / (1 - prob_loss));
+
+ RTC_CHECK_GT(avg_burst_loss_length, min_avg_burst_loss_length)
+ << "For a total packet loss of " << config.loss_percent << "%% then"
+ << " avg_burst_loss_length must be " << min_avg_burst_loss_length + 1
+ << " or higher.";
+
+ prob_loss_bursting_ = (1.0 - 1.0 / avg_burst_loss_length);
+ prob_start_bursting_ = prob_loss / (1 - prob_loss) / avg_burst_loss_length;
+ }
+}
FakeNetworkPipe::~FakeNetworkPipe() {
while (!capacity_link_.empty()) {
@@ -118,10 +140,15 @@
NetworkPacket* packet = capacity_link_.front();
capacity_link_.pop();
- // Packets are randomly dropped after being affected by the bottleneck.
- if (random_.Rand(100) < static_cast<uint32_t>(config_.loss_percent)) {
+ // Drop packets at an average rate of |config_.loss_percent| with
+ // and average loss burst length of |config_.avg_burst_loss_length|.
+ if ((bursting_ && random_.Rand<double>() < prob_loss_bursting_) ||
+ (!bursting_ && random_.Rand<double>() < prob_start_bursting_)) {
+ bursting_ = true;
delete packet;
continue;
+ } else {
+ bursting_ = false;
}
int arrival_time_jitter = random_.Gaussian(
diff --git a/webrtc/test/fake_network_pipe.h b/webrtc/test/fake_network_pipe.h
index 608ff00..2dcbcf5 100644
--- a/webrtc/test/fake_network_pipe.h
+++ b/webrtc/test/fake_network_pipe.h
@@ -80,6 +80,8 @@
int loss_percent = 0;
// If packets are allowed to be reordered.
bool allow_reordering = false;
+ // The average length of a burst of lost packets.
+ int avg_burst_loss_length = -1;
};
FakeNetworkPipe(Clock* clock, const FakeNetworkPipe::Config& config);
@@ -133,6 +135,16 @@
size_t sent_packets_;
int64_t total_packet_delay_;
+ // Are we currently dropping a burst of packets?
+ bool bursting_;
+
+ // The probability to drop the packet if we are currently dropping a
+ // burst of packet
+ double prob_loss_bursting_;
+
+ // The probability to drop a burst of packets.
+ double prob_start_bursting_;
+
int64_t next_process_time_;
RTC_DISALLOW_COPY_AND_ASSIGN(FakeNetworkPipe);
diff --git a/webrtc/test/fake_network_pipe_unittest.cc b/webrtc/test/fake_network_pipe_unittest.cc
index 0bd46df..fcc0c93 100644
--- a/webrtc/test/fake_network_pipe_unittest.cc
+++ b/webrtc/test/fake_network_pipe_unittest.cc
@@ -379,4 +379,45 @@
}
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;
+
+ FakeNetworkPipe::Config config;
+ config.queue_length_packets = kNumPackets;
+ config.loss_percent = kLossPercent;
+ config.avg_burst_loss_length = kAvgBurstLength;
+ std::unique_ptr<FakeNetworkPipe> pipe(
+ new FakeNetworkPipe(&fake_clock_, config));
+ ReorderTestReceiver* receiver = new ReorderTestReceiver();
+ receiver_.reset(receiver);
+ pipe->SetReceiver(receiver_.get());
+
+ 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);
+}
} // namespace webrtc
diff --git a/webrtc/video/video_loopback.cc b/webrtc/video/video_loopback.cc
index 0974d58..70a940d 100644
--- a/webrtc/video/video_loopback.cc
+++ b/webrtc/video/video_loopback.cc
@@ -101,6 +101,11 @@
return static_cast<int>(FLAGS_loss_percent);
}
+DEFINE_int32(avg_burst_loss_length, 1, "Average burst length of lost packets.");
+int AvgBurstLossLength() {
+ return static_cast<int>(FLAGS_avg_burst_loss_length);
+}
+
DEFINE_int32(link_capacity,
0,
"Capacity (kbps) of the fake link. 0 means infinite.");
@@ -201,6 +206,7 @@
void Loopback() {
FakeNetworkPipe::Config pipe_config;
pipe_config.loss_percent = flags::LossPercent();
+ pipe_config.avg_burst_loss_length = flags::AvgBurstLossLength();
pipe_config.link_capacity_kbps = flags::LinkCapacityKbps();
pipe_config.queue_length_packets = flags::QueueSize();
pipe_config.queue_delay_ms = flags::AvgPropagationDelayMs();