blob: d594ab8104e3b6d7b0499b85415732544ae3b40d [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
stefane9ad2712017-02-10 06:09:28 -080020#include "webrtc/base/logging.h"
ossuf515ab82016-12-07 04:52:58 -080021#include "webrtc/call/call.h"
Peter Boströmd3c94472015-12-09 11:20:58 +010022#include "webrtc/system_wrappers/include/clock.h"
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +000023
24namespace webrtc {
25
Peter Boströmd3c94472015-12-09 11:20:58 +010026FakeNetworkPipe::FakeNetworkPipe(Clock* clock,
27 const FakeNetworkPipe::Config& config)
philipela2c55232016-01-26 08:41:53 -080028 : FakeNetworkPipe(clock, config, 1) {}
29
30FakeNetworkPipe::FakeNetworkPipe(Clock* clock,
31 const FakeNetworkPipe::Config& config,
32 uint64_t seed)
Peter Boströmd3c94472015-12-09 11:20:58 +010033 : clock_(clock),
34 packet_receiver_(NULL),
philipela2c55232016-01-26 08:41:53 -080035 random_(seed),
philipel5ef2bc12017-02-21 07:28:31 -080036 config_(),
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +000037 dropped_packets_(0),
38 sent_packets_(0),
39 total_packet_delay_(0),
philipel536378b2016-05-31 03:20:23 -070040 bursting_(false),
stefane9ad2712017-02-10 06:09:28 -080041 next_process_time_(clock_->TimeInMilliseconds()),
42 last_log_time_(clock_->TimeInMilliseconds()) {
philipel5ef2bc12017-02-21 07:28:31 -080043 SetConfig(config);
philipel536378b2016-05-31 03:20:23 -070044}
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +000045
46FakeNetworkPipe::~FakeNetworkPipe() {
47 while (!capacity_link_.empty()) {
48 delete capacity_link_.front();
49 capacity_link_.pop();
50 }
51 while (!delay_link_.empty()) {
philipela2c55232016-01-26 08:41:53 -080052 delete *delay_link_.begin();
53 delay_link_.erase(delay_link_.begin());
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +000054 }
55}
56
57void FakeNetworkPipe::SetReceiver(PacketReceiver* receiver) {
58 packet_receiver_ = receiver;
59}
60
henrik.lundin@webrtc.orgc0e9aeb2014-02-26 13:34:52 +000061void FakeNetworkPipe::SetConfig(const FakeNetworkPipe::Config& config) {
Peter Boströmf2f82832015-05-01 13:00:41 +020062 rtc::CritScope crit(&lock_);
henrik.lundin@webrtc.orgc0e9aeb2014-02-26 13:34:52 +000063 config_ = config; // Shallow copy of the struct.
philipel5ef2bc12017-02-21 07:28:31 -080064 double prob_loss = config.loss_percent / 100.0;
65 if (config_.avg_burst_loss_length == -1) {
66 // Uniform loss
67 prob_loss_bursting_ = prob_loss;
68 prob_start_bursting_ = prob_loss;
69 } else {
70 // Lose packets according to a gilbert-elliot model.
71 int avg_burst_loss_length = config.avg_burst_loss_length;
72 int min_avg_burst_loss_length = std::ceil(prob_loss / (1 - prob_loss));
73
74 RTC_CHECK_GT(avg_burst_loss_length, min_avg_burst_loss_length)
75 << "For a total packet loss of " << config.loss_percent << "%% then"
76 << " avg_burst_loss_length must be " << min_avg_burst_loss_length + 1
77 << " or higher.";
78
79 prob_loss_bursting_ = (1.0 - 1.0 / avg_burst_loss_length);
80 prob_start_bursting_ = prob_loss / (1 - prob_loss) / avg_burst_loss_length;
81 }
henrik.lundin@webrtc.orgc0e9aeb2014-02-26 13:34:52 +000082}
83
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +000084void FakeNetworkPipe::SendPacket(const uint8_t* data, size_t data_length) {
85 // A NULL packet_receiver_ means that this pipe will terminate the flow of
86 // packets.
87 if (packet_receiver_ == NULL)
88 return;
Peter Boströmf2f82832015-05-01 13:00:41 +020089 rtc::CritScope crit(&lock_);
stefan@webrtc.orgb8e9e442014-07-09 11:29:06 +000090 if (config_.queue_length_packets > 0 &&
91 capacity_link_.size() >= config_.queue_length_packets) {
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +000092 // Too many packet on the link, drop this one.
93 ++dropped_packets_;
94 return;
95 }
96
Peter Boströmd3c94472015-12-09 11:20:58 +010097 int64_t time_now = clock_->TimeInMilliseconds();
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +000098
99 // Delay introduced by the link capacity.
100 int64_t capacity_delay_ms = 0;
101 if (config_.link_capacity_kbps > 0)
102 capacity_delay_ms = data_length / (config_.link_capacity_kbps / 8);
103 int64_t network_start_time = time_now;
104
105 // Check if there already are packets on the link and change network start
danilchapa6a70072016-06-01 11:20:43 -0700106 // time forward if there is.
107 if (!capacity_link_.empty() &&
108 network_start_time < capacity_link_.back()->arrival_time())
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +0000109 network_start_time = capacity_link_.back()->arrival_time();
110
111 int64_t arrival_time = network_start_time + capacity_delay_ms;
112 NetworkPacket* packet = new NetworkPacket(data, data_length, time_now,
113 arrival_time);
114 capacity_link_.push(packet);
115}
116
117float FakeNetworkPipe::PercentageLoss() {
Peter Boströmf2f82832015-05-01 13:00:41 +0200118 rtc::CritScope crit(&lock_);
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +0000119 if (sent_packets_ == 0)
120 return 0;
121
122 return static_cast<float>(dropped_packets_) /
123 (sent_packets_ + dropped_packets_);
124}
125
126int FakeNetworkPipe::AverageDelay() {
Peter Boströmf2f82832015-05-01 13:00:41 +0200127 rtc::CritScope crit(&lock_);
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +0000128 if (sent_packets_ == 0)
129 return 0;
130
Stefan Holmerff2a6352016-01-14 10:00:21 +0100131 return static_cast<int>(total_packet_delay_ /
132 static_cast<int64_t>(sent_packets_));
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +0000133}
134
135void FakeNetworkPipe::Process() {
Peter Boströmd3c94472015-12-09 11:20:58 +0100136 int64_t time_now = clock_->TimeInMilliseconds();
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +0000137 std::queue<NetworkPacket*> packets_to_deliver;
138 {
Peter Boströmf2f82832015-05-01 13:00:41 +0200139 rtc::CritScope crit(&lock_);
stefane9ad2712017-02-10 06:09:28 -0800140 if (time_now - last_log_time_ > 5000) {
141 int64_t queueing_delay_ms = 0;
142 if (!capacity_link_.empty()) {
143 queueing_delay_ms = time_now - capacity_link_.front()->send_time();
144 }
145 LOG(LS_INFO) << "Network queue: " << queueing_delay_ms << " ms.";
146 last_log_time_ = time_now;
147 }
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +0000148 // Check the capacity link first.
philipela2c55232016-01-26 08:41:53 -0800149 while (!capacity_link_.empty() &&
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +0000150 time_now >= capacity_link_.front()->arrival_time()) {
151 // Time to get this packet.
152 NetworkPacket* packet = capacity_link_.front();
153 capacity_link_.pop();
154
philipel536378b2016-05-31 03:20:23 -0700155 // Drop packets at an average rate of |config_.loss_percent| with
156 // and average loss burst length of |config_.avg_burst_loss_length|.
157 if ((bursting_ && random_.Rand<double>() < prob_loss_bursting_) ||
158 (!bursting_ && random_.Rand<double>() < prob_start_bursting_)) {
159 bursting_ = true;
stefan@webrtc.orgbfe6e082014-07-31 12:30:18 +0000160 delete packet;
161 continue;
philipel536378b2016-05-31 03:20:23 -0700162 } else {
163 bursting_ = false;
stefan@webrtc.orgbfe6e082014-07-31 12:30:18 +0000164 }
165
philipela2c55232016-01-26 08:41:53 -0800166 int arrival_time_jitter = random_.Gaussian(
167 config_.queue_delay_ms, config_.delay_standard_deviation_ms);
168
169 // If reordering is not allowed then adjust arrival_time_jitter
170 // to make sure all packets are sent in order.
171 if (!config_.allow_reordering && !delay_link_.empty() &&
172 packet->arrival_time() + arrival_time_jitter <
173 (*delay_link_.rbegin())->arrival_time()) {
174 arrival_time_jitter =
175 (*delay_link_.rbegin())->arrival_time() - packet->arrival_time();
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +0000176 }
philipela2c55232016-01-26 08:41:53 -0800177 packet->IncrementArrivalTime(arrival_time_jitter);
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +0000178 if (packet->arrival_time() < next_process_time_)
179 next_process_time_ = packet->arrival_time();
philipela2c55232016-01-26 08:41:53 -0800180 delay_link_.insert(packet);
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +0000181 }
182
183 // Check the extra delay queue.
philipela2c55232016-01-26 08:41:53 -0800184 while (!delay_link_.empty() &&
185 time_now >= (*delay_link_.begin())->arrival_time()) {
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +0000186 // Deliver this packet.
philipela2c55232016-01-26 08:41:53 -0800187 NetworkPacket* packet = *delay_link_.begin();
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +0000188 packets_to_deliver.push(packet);
philipela2c55232016-01-26 08:41:53 -0800189 delay_link_.erase(delay_link_.begin());
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +0000190 // |time_now| might be later than when the packet should have arrived, due
191 // to NetworkProcess being called too late. For stats, use the time it
192 // should have been on the link.
193 total_packet_delay_ += packet->arrival_time() - packet->send_time();
194 }
195 sent_packets_ += packets_to_deliver.size();
196 }
197 while (!packets_to_deliver.empty()) {
198 NetworkPacket* packet = packets_to_deliver.front();
199 packets_to_deliver.pop();
Fredrik Solenberg23fba1f2015-04-29 15:24:01 +0200200 packet_receiver_->DeliverPacket(MediaType::ANY, packet->data(),
stefan68786d22015-09-08 05:36:15 -0700201 packet->data_length(), PacketTime());
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +0000202 delete packet;
203 }
204}
205
pkasting@chromium.org0b1534c2014-12-15 22:09:40 +0000206int64_t FakeNetworkPipe::TimeUntilNextProcess() const {
Peter Boströmf2f82832015-05-01 13:00:41 +0200207 rtc::CritScope crit(&lock_);
isheriff90ce01d2016-09-29 02:02:11 -0700208 const int64_t kDefaultProcessIntervalMs = 5;
philipela2c55232016-01-26 08:41:53 -0800209 if (capacity_link_.empty() || delay_link_.empty())
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +0000210 return kDefaultProcessIntervalMs;
Peter Boströmd3c94472015-12-09 11:20:58 +0100211 return std::max<int64_t>(next_process_time_ - clock_->TimeInMilliseconds(),
212 0);
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +0000213}
214
215} // namespace webrtc