blob: 19f1b5451c82c99bf3bb9b3a2e7c1a9eca00e3d2 [file] [log] [blame]
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +00001/*
2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11#include "webrtc/test/fake_network_pipe.h"
12
13#include <assert.h>
14#include <math.h>
15#include <string.h>
philipel536378b2016-05-31 03:20:23 -070016
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +000017#include <algorithm>
philipel536378b2016-05-31 03:20:23 -070018#include <cmath>
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +000019
20#include "webrtc/call.h"
Peter Boströmd3c94472015-12-09 11:20:58 +010021#include "webrtc/system_wrappers/include/clock.h"
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +000022
23namespace webrtc {
24
Peter Boströmd3c94472015-12-09 11:20:58 +010025FakeNetworkPipe::FakeNetworkPipe(Clock* clock,
26 const FakeNetworkPipe::Config& config)
philipela2c55232016-01-26 08:41:53 -080027 : FakeNetworkPipe(clock, config, 1) {}
28
29FakeNetworkPipe::FakeNetworkPipe(Clock* clock,
30 const FakeNetworkPipe::Config& config,
31 uint64_t seed)
Peter Boströmd3c94472015-12-09 11:20:58 +010032 : clock_(clock),
33 packet_receiver_(NULL),
philipela2c55232016-01-26 08:41:53 -080034 random_(seed),
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +000035 config_(config),
36 dropped_packets_(0),
37 sent_packets_(0),
38 total_packet_delay_(0),
philipel536378b2016-05-31 03:20:23 -070039 bursting_(false),
40 next_process_time_(clock_->TimeInMilliseconds()) {
41 double prob_loss = config.loss_percent / 100.0;
42 if (config_.avg_burst_loss_length == -1) {
43 // Uniform loss
44 prob_loss_bursting_ = prob_loss;
45 prob_start_bursting_ = prob_loss;
46 } else {
47 // Lose packets according to a gilbert-elliot model.
48 int avg_burst_loss_length = config.avg_burst_loss_length;
49 int min_avg_burst_loss_length = std::ceil(prob_loss / (1 - prob_loss));
50
51 RTC_CHECK_GT(avg_burst_loss_length, min_avg_burst_loss_length)
52 << "For a total packet loss of " << config.loss_percent << "%% then"
53 << " avg_burst_loss_length must be " << min_avg_burst_loss_length + 1
54 << " or higher.";
55
56 prob_loss_bursting_ = (1.0 - 1.0 / avg_burst_loss_length);
57 prob_start_bursting_ = prob_loss / (1 - prob_loss) / avg_burst_loss_length;
58 }
59}
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +000060
61FakeNetworkPipe::~FakeNetworkPipe() {
62 while (!capacity_link_.empty()) {
63 delete capacity_link_.front();
64 capacity_link_.pop();
65 }
66 while (!delay_link_.empty()) {
philipela2c55232016-01-26 08:41:53 -080067 delete *delay_link_.begin();
68 delay_link_.erase(delay_link_.begin());
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +000069 }
70}
71
72void FakeNetworkPipe::SetReceiver(PacketReceiver* receiver) {
73 packet_receiver_ = receiver;
74}
75
henrik.lundin@webrtc.orgc0e9aeb2014-02-26 13:34:52 +000076void FakeNetworkPipe::SetConfig(const FakeNetworkPipe::Config& config) {
Peter Boströmf2f82832015-05-01 13:00:41 +020077 rtc::CritScope crit(&lock_);
henrik.lundin@webrtc.orgc0e9aeb2014-02-26 13:34:52 +000078 config_ = config; // Shallow copy of the struct.
79}
80
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +000081void FakeNetworkPipe::SendPacket(const uint8_t* data, size_t data_length) {
82 // A NULL packet_receiver_ means that this pipe will terminate the flow of
83 // packets.
84 if (packet_receiver_ == NULL)
85 return;
Peter Boströmf2f82832015-05-01 13:00:41 +020086 rtc::CritScope crit(&lock_);
stefan@webrtc.orgb8e9e442014-07-09 11:29:06 +000087 if (config_.queue_length_packets > 0 &&
88 capacity_link_.size() >= config_.queue_length_packets) {
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +000089 // Too many packet on the link, drop this one.
90 ++dropped_packets_;
91 return;
92 }
93
Peter Boströmd3c94472015-12-09 11:20:58 +010094 int64_t time_now = clock_->TimeInMilliseconds();
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +000095
96 // Delay introduced by the link capacity.
97 int64_t capacity_delay_ms = 0;
98 if (config_.link_capacity_kbps > 0)
99 capacity_delay_ms = data_length / (config_.link_capacity_kbps / 8);
100 int64_t network_start_time = time_now;
101
102 // Check if there already are packets on the link and change network start
danilchapa6a70072016-06-01 11:20:43 -0700103 // time forward if there is.
104 if (!capacity_link_.empty() &&
105 network_start_time < capacity_link_.back()->arrival_time())
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +0000106 network_start_time = capacity_link_.back()->arrival_time();
107
108 int64_t arrival_time = network_start_time + capacity_delay_ms;
109 NetworkPacket* packet = new NetworkPacket(data, data_length, time_now,
110 arrival_time);
111 capacity_link_.push(packet);
112}
113
114float FakeNetworkPipe::PercentageLoss() {
Peter Boströmf2f82832015-05-01 13:00:41 +0200115 rtc::CritScope crit(&lock_);
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +0000116 if (sent_packets_ == 0)
117 return 0;
118
119 return static_cast<float>(dropped_packets_) /
120 (sent_packets_ + dropped_packets_);
121}
122
123int FakeNetworkPipe::AverageDelay() {
Peter Boströmf2f82832015-05-01 13:00:41 +0200124 rtc::CritScope crit(&lock_);
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +0000125 if (sent_packets_ == 0)
126 return 0;
127
Stefan Holmerff2a6352016-01-14 10:00:21 +0100128 return static_cast<int>(total_packet_delay_ /
129 static_cast<int64_t>(sent_packets_));
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +0000130}
131
132void FakeNetworkPipe::Process() {
Peter Boströmd3c94472015-12-09 11:20:58 +0100133 int64_t time_now = clock_->TimeInMilliseconds();
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +0000134 std::queue<NetworkPacket*> packets_to_deliver;
135 {
Peter Boströmf2f82832015-05-01 13:00:41 +0200136 rtc::CritScope crit(&lock_);
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +0000137 // Check the capacity link first.
philipela2c55232016-01-26 08:41:53 -0800138 while (!capacity_link_.empty() &&
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +0000139 time_now >= capacity_link_.front()->arrival_time()) {
140 // Time to get this packet.
141 NetworkPacket* packet = capacity_link_.front();
142 capacity_link_.pop();
143
philipel536378b2016-05-31 03:20:23 -0700144 // Drop packets at an average rate of |config_.loss_percent| with
145 // and average loss burst length of |config_.avg_burst_loss_length|.
146 if ((bursting_ && random_.Rand<double>() < prob_loss_bursting_) ||
147 (!bursting_ && random_.Rand<double>() < prob_start_bursting_)) {
148 bursting_ = true;
stefan@webrtc.orgbfe6e082014-07-31 12:30:18 +0000149 delete packet;
150 continue;
philipel536378b2016-05-31 03:20:23 -0700151 } else {
152 bursting_ = false;
stefan@webrtc.orgbfe6e082014-07-31 12:30:18 +0000153 }
154
philipela2c55232016-01-26 08:41:53 -0800155 int arrival_time_jitter = random_.Gaussian(
156 config_.queue_delay_ms, config_.delay_standard_deviation_ms);
157
158 // If reordering is not allowed then adjust arrival_time_jitter
159 // to make sure all packets are sent in order.
160 if (!config_.allow_reordering && !delay_link_.empty() &&
161 packet->arrival_time() + arrival_time_jitter <
162 (*delay_link_.rbegin())->arrival_time()) {
163 arrival_time_jitter =
164 (*delay_link_.rbegin())->arrival_time() - packet->arrival_time();
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +0000165 }
philipela2c55232016-01-26 08:41:53 -0800166 packet->IncrementArrivalTime(arrival_time_jitter);
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +0000167 if (packet->arrival_time() < next_process_time_)
168 next_process_time_ = packet->arrival_time();
philipela2c55232016-01-26 08:41:53 -0800169 delay_link_.insert(packet);
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +0000170 }
171
172 // Check the extra delay queue.
philipela2c55232016-01-26 08:41:53 -0800173 while (!delay_link_.empty() &&
174 time_now >= (*delay_link_.begin())->arrival_time()) {
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +0000175 // Deliver this packet.
philipela2c55232016-01-26 08:41:53 -0800176 NetworkPacket* packet = *delay_link_.begin();
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +0000177 packets_to_deliver.push(packet);
philipela2c55232016-01-26 08:41:53 -0800178 delay_link_.erase(delay_link_.begin());
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +0000179 // |time_now| might be later than when the packet should have arrived, due
180 // to NetworkProcess being called too late. For stats, use the time it
181 // should have been on the link.
182 total_packet_delay_ += packet->arrival_time() - packet->send_time();
183 }
184 sent_packets_ += packets_to_deliver.size();
185 }
186 while (!packets_to_deliver.empty()) {
187 NetworkPacket* packet = packets_to_deliver.front();
188 packets_to_deliver.pop();
Fredrik Solenberg23fba1f2015-04-29 15:24:01 +0200189 packet_receiver_->DeliverPacket(MediaType::ANY, packet->data(),
stefan68786d22015-09-08 05:36:15 -0700190 packet->data_length(), PacketTime());
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +0000191 delete packet;
192 }
193}
194
pkasting@chromium.org0b1534c2014-12-15 22:09:40 +0000195int64_t FakeNetworkPipe::TimeUntilNextProcess() const {
Peter Boströmf2f82832015-05-01 13:00:41 +0200196 rtc::CritScope crit(&lock_);
pkasting@chromium.org0b1534c2014-12-15 22:09:40 +0000197 const int64_t kDefaultProcessIntervalMs = 30;
philipela2c55232016-01-26 08:41:53 -0800198 if (capacity_link_.empty() || delay_link_.empty())
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +0000199 return kDefaultProcessIntervalMs;
Peter Boströmd3c94472015-12-09 11:20:58 +0100200 return std::max<int64_t>(next_process_time_ - clock_->TimeInMilliseconds(),
201 0);
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +0000202}
203
204} // namespace webrtc