blob: 92e945b4c41c69c4611c4543b54e9b4b8b8924cb [file] [log] [blame]
Sebastian Janssonf96b1ca2018-08-07 18:58:05 +02001/*
2 * Copyright 2018 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 "call/simulated_network.h"
12
13#include <algorithm>
14#include <cmath>
15#include <utility>
Yves Gerey3e707812018-11-28 16:47:49 +010016
Sebastian Jansson2cd3b4c2018-11-06 19:18:28 +010017#include "api/units/data_rate.h"
Yves Gerey3e707812018-11-28 16:47:49 +010018#include "api/units/data_size.h"
19#include "api/units/time_delta.h"
20#include "rtc_base/checks.h"
Sebastian Janssonf96b1ca2018-08-07 18:58:05 +020021
22namespace webrtc {
23
24SimulatedNetwork::SimulatedNetwork(SimulatedNetwork::Config config,
25 uint64_t random_seed)
26 : random_(random_seed), bursting_(false) {
27 SetConfig(config);
28}
29
30SimulatedNetwork::~SimulatedNetwork() = default;
31
32void SimulatedNetwork::SetConfig(const SimulatedNetwork::Config& config) {
33 rtc::CritScope crit(&config_lock_);
34 config_ = config; // Shallow copy of the struct.
35 double prob_loss = config.loss_percent / 100.0;
36 if (config_.avg_burst_loss_length == -1) {
37 // Uniform loss
38 prob_loss_bursting_ = prob_loss;
39 prob_start_bursting_ = prob_loss;
40 } else {
41 // Lose packets according to a gilbert-elliot model.
42 int avg_burst_loss_length = config.avg_burst_loss_length;
43 int min_avg_burst_loss_length = std::ceil(prob_loss / (1 - prob_loss));
44
45 RTC_CHECK_GT(avg_burst_loss_length, min_avg_burst_loss_length)
46 << "For a total packet loss of " << config.loss_percent << "%% then"
47 << " avg_burst_loss_length must be " << min_avg_burst_loss_length + 1
48 << " or higher.";
49
50 prob_loss_bursting_ = (1.0 - 1.0 / avg_burst_loss_length);
51 prob_start_bursting_ = prob_loss / (1 - prob_loss) / avg_burst_loss_length;
52 }
53}
54
55void SimulatedNetwork::PauseTransmissionUntil(int64_t until_us) {
56 rtc::CritScope crit(&config_lock_);
57 pause_transmission_until_us_ = until_us;
58}
59
60bool SimulatedNetwork::EnqueuePacket(PacketInFlightInfo packet) {
61 Config config;
62 {
63 rtc::CritScope crit(&config_lock_);
64 config = config_;
65 }
Christoffer Rodbro813c79b2019-01-31 09:25:12 +010066
67 UpdateCapacityQueue(packet.send_time_us);
68
Sebastian Jansson8c8feb92019-01-29 15:59:17 +010069 packet.size += config.packet_overhead;
Sebastian Janssonf96b1ca2018-08-07 18:58:05 +020070 rtc::CritScope crit(&process_lock_);
71 if (config.queue_length_packets > 0 &&
72 capacity_link_.size() >= config.queue_length_packets) {
73 // Too many packet on the link, drop this one.
74 return false;
75 }
Sebastian Jansson2cd3b4c2018-11-06 19:18:28 +010076
Christoffer Rodbro813c79b2019-01-31 09:25:12 +010077 // Set arrival time = send time for now; actual arrival time will be
78 // calculated in UpdateCapacityQueue.
79 queue_size_bytes_ += packet.size;
80 capacity_link_.push({packet, packet.send_time_us});
Sebastian Jansson2cd3b4c2018-11-06 19:18:28 +010081
Sebastian Janssonf96b1ca2018-08-07 18:58:05 +020082 return true;
83}
84
85absl::optional<int64_t> SimulatedNetwork::NextDeliveryTimeUs() const {
Sebastian Jansson2cd3b4c2018-11-06 19:18:28 +010086 rtc::CritScope crit(&process_lock_);
Sebastian Janssonf96b1ca2018-08-07 18:58:05 +020087 if (!delay_link_.empty())
88 return delay_link_.begin()->arrival_time_us;
89 return absl::nullopt;
90}
Christoffer Rodbro813c79b2019-01-31 09:25:12 +010091
92void SimulatedNetwork::UpdateCapacityQueue(int64_t time_now_us) {
Sebastian Janssonf96b1ca2018-08-07 18:58:05 +020093 Config config;
94 double prob_loss_bursting;
95 double prob_start_bursting;
Christoffer Rodbro813c79b2019-01-31 09:25:12 +010096 int64_t pause_transmission_until_us;
Sebastian Janssonf96b1ca2018-08-07 18:58:05 +020097 {
98 rtc::CritScope crit(&config_lock_);
99 config = config_;
100 prob_loss_bursting = prob_loss_bursting_;
101 prob_start_bursting = prob_start_bursting_;
Christoffer Rodbro813c79b2019-01-31 09:25:12 +0100102 pause_transmission_until_us = pause_transmission_until_us_.value_or(0);
Sebastian Janssonf96b1ca2018-08-07 18:58:05 +0200103 }
104 {
105 rtc::CritScope crit(&process_lock_);
Christoffer Rodbro813c79b2019-01-31 09:25:12 +0100106 bool needs_sort = false;
107
108 // Catch for thread races.
109 if (time_now_us < last_capacity_link_visit_us_.value_or(time_now_us))
110 return;
111
112 int64_t time_us = last_capacity_link_visit_us_.value_or(time_now_us);
Sebastian Janssonf96b1ca2018-08-07 18:58:05 +0200113 // Check the capacity link first.
Christoffer Rodbro813c79b2019-01-31 09:25:12 +0100114 while (!capacity_link_.empty()) {
115 int64_t time_until_front_exits_us = 0;
116 if (config.link_capacity_kbps > 0) {
117 int64_t remaining_bits =
118 capacity_link_.front().packet.size * 8 - pending_drain_bits_;
119 RTC_DCHECK(remaining_bits > 0);
120 // Division rounded up - packet not delivered until its last bit is.
121 time_until_front_exits_us =
122 (1000 * remaining_bits + config.link_capacity_kbps - 1) /
123 config.link_capacity_kbps;
124 }
Sebastian Janssonf96b1ca2018-08-07 18:58:05 +0200125
Christoffer Rodbro813c79b2019-01-31 09:25:12 +0100126 if (time_us + time_until_front_exits_us > time_now_us) {
127 // Packet at front will not exit yet. Will not enter here on infinite
128 // capacity(=0) so no special handling needed.
129 pending_drain_bits_ +=
130 ((time_now_us - time_us) * config.link_capacity_kbps) / 1000;
131 break;
132 }
133 if (config.link_capacity_kbps > 0) {
134 pending_drain_bits_ +=
135 (time_until_front_exits_us * config.link_capacity_kbps) / 1000;
136 } else {
137 // Enough to drain the whole queue.
138 pending_drain_bits_ = queue_size_bytes_ * 8;
139 }
Sebastian Janssonf96b1ca2018-08-07 18:58:05 +0200140
Christoffer Rodbro813c79b2019-01-31 09:25:12 +0100141 // Time to get this packet.
142 PacketInfo packet = std::move(capacity_link_.front());
143 capacity_link_.pop();
144
145 time_us += time_until_front_exits_us;
146 RTC_DCHECK(time_us >= packet.packet.send_time_us);
147 packet.arrival_time_us = std::max(pause_transmission_until_us, time_us);
148 queue_size_bytes_ -= packet.packet.size;
149 pending_drain_bits_ -= packet.packet.size * 8;
150 RTC_DCHECK(pending_drain_bits_ >= 0);
151
152 // Drop packets at an average rate of |config_.loss_percent| with
153 // and average loss burst length of |config_.avg_burst_loss_length|.
154 if ((bursting_ && random_.Rand<double>() < prob_loss_bursting) ||
155 (!bursting_ && random_.Rand<double>() < prob_start_bursting)) {
156 bursting_ = true;
157 packet.arrival_time_us = PacketDeliveryInfo::kNotReceived;
158 } else {
159 bursting_ = false;
160 int64_t arrival_time_jitter_us = std::max(
161 random_.Gaussian(config.queue_delay_ms * 1000,
162 config.delay_standard_deviation_ms * 1000),
163 0.0);
164
165 // If reordering is not allowed then adjust arrival_time_jitter
166 // to make sure all packets are sent in order.
167 int64_t last_arrival_time_us =
168 delay_link_.empty() ? -1 : delay_link_.back().arrival_time_us;
169 if (!config.allow_reordering && !delay_link_.empty() &&
170 packet.arrival_time_us + arrival_time_jitter_us <
171 last_arrival_time_us) {
172 arrival_time_jitter_us =
173 last_arrival_time_us - packet.arrival_time_us;
Sebastian Janssonf96b1ca2018-08-07 18:58:05 +0200174 }
Christoffer Rodbro813c79b2019-01-31 09:25:12 +0100175 packet.arrival_time_us += arrival_time_jitter_us;
176 if (packet.arrival_time_us >= last_arrival_time_us) {
177 last_arrival_time_us = packet.arrival_time_us;
178 } else {
179 needs_sort = true;
180 }
Sebastian Janssonf96b1ca2018-08-07 18:58:05 +0200181 }
Christoffer Rodbro813c79b2019-01-31 09:25:12 +0100182 delay_link_.emplace_back(std::move(packet));
Sebastian Janssonf96b1ca2018-08-07 18:58:05 +0200183 }
Christoffer Rodbro813c79b2019-01-31 09:25:12 +0100184 last_capacity_link_visit_us_ = time_now_us;
185 // Cannot save unused capacity for later.
186 pending_drain_bits_ = std::min(pending_drain_bits_, queue_size_bytes_ * 8);
Sebastian Janssonf96b1ca2018-08-07 18:58:05 +0200187
Christoffer Rodbro813c79b2019-01-31 09:25:12 +0100188 if (needs_sort) {
189 // Packet(s) arrived out of order, make sure list is sorted.
190 std::sort(delay_link_.begin(), delay_link_.end(),
191 [](const PacketInfo& p1, const PacketInfo& p2) {
192 return p1.arrival_time_us < p2.arrival_time_us;
193 });
Sebastian Janssonf96b1ca2018-08-07 18:58:05 +0200194 }
Sebastian Janssonf96b1ca2018-08-07 18:58:05 +0200195 }
196}
197
Christoffer Rodbro813c79b2019-01-31 09:25:12 +0100198std::vector<PacketDeliveryInfo> SimulatedNetwork::DequeueDeliverablePackets(
199 int64_t receive_time_us) {
200 UpdateCapacityQueue(receive_time_us);
201
202 rtc::CritScope crit(&process_lock_);
203 std::vector<PacketDeliveryInfo> packets_to_deliver;
204 // Check the extra delay queue.
205 while (!delay_link_.empty() &&
206 receive_time_us >= delay_link_.front().arrival_time_us) {
207 PacketInfo packet_info = delay_link_.front();
208 packets_to_deliver.emplace_back(
209 PacketDeliveryInfo(packet_info.packet, packet_info.arrival_time_us));
210 delay_link_.pop_front();
211 }
212 return packets_to_deliver;
213}
214
Sebastian Janssonf96b1ca2018-08-07 18:58:05 +0200215} // namespace webrtc