blob: f8a5bd893d0b31215ece04dae4db9ed55c2ee51d [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 {
Sebastian Jansson836fee12019-02-08 16:08:10 +010023namespace {
Danil Chapovalov0c626af2020-02-10 11:16:00 +010024constexpr TimeDelta kDefaultProcessDelay = TimeDelta::Millis(5);
Sebastian Jansson2b08e312019-02-25 10:24:46 +010025} // namespace
26
27CoDelSimulation::CoDelSimulation() = default;
28CoDelSimulation::~CoDelSimulation() = default;
29
30bool CoDelSimulation::DropDequeuedPacket(Timestamp now,
31 Timestamp enqueing_time,
32 DataSize packet_size,
33 DataSize queue_size) {
Danil Chapovalov0c626af2020-02-10 11:16:00 +010034 constexpr TimeDelta kWindow = TimeDelta::Millis(100);
35 constexpr TimeDelta kDelayThreshold = TimeDelta::Millis(5);
36 constexpr TimeDelta kDropCountMemory = TimeDelta::Millis(1600);
Danil Chapovalovcad3e0e2020-02-17 18:46:07 +010037 constexpr DataSize kMaxPacketSize = DataSize::Bytes(1500);
Sebastian Jansson2b08e312019-02-25 10:24:46 +010038
39 // Compensates for process interval in simulation; not part of standard CoDel.
40 TimeDelta queuing_time = now - enqueing_time - kDefaultProcessDelay;
41
42 if (queue_size < kMaxPacketSize || queuing_time < kDelayThreshold) {
43 enter_drop_state_at_ = Timestamp::PlusInfinity();
44 state_ = kNormal;
45 return false;
46 }
47 switch (state_) {
48 case kNormal:
49 enter_drop_state_at_ = now + kWindow;
50 state_ = kPending;
51 return false;
52
53 case kPending:
54 if (now >= enter_drop_state_at_) {
55 state_ = kDropping;
56 // Starting the drop counter with the drops made during the most recent
57 // drop state period.
58 drop_count_ = drop_count_ - previous_drop_count_;
59 if (now >= last_drop_at_ + kDropCountMemory)
60 drop_count_ = 0;
61 previous_drop_count_ = drop_count_;
62 last_drop_at_ = now;
63 ++drop_count_;
64 return true;
65 }
66 return false;
67
68 case kDropping:
69 TimeDelta drop_delay = kWindow / sqrt(static_cast<double>(drop_count_));
70 Timestamp next_drop_at = last_drop_at_ + drop_delay;
71 if (now >= next_drop_at) {
72 if (queue_size - packet_size < kMaxPacketSize)
73 state_ = kPending;
74 last_drop_at_ = next_drop_at;
75 ++drop_count_;
76 return true;
77 }
78 return false;
79 }
Karl Wibergc95b9392020-11-08 00:49:37 +010080 RTC_CHECK_NOTREACHED();
Sebastian Jansson836fee12019-02-08 16:08:10 +010081}
Sebastian Janssonf96b1ca2018-08-07 18:58:05 +020082
Sebastian Janssoncec24332019-12-04 14:26:50 +010083SimulatedNetwork::SimulatedNetwork(Config config, uint64_t random_seed)
Sebastian Janssonf96b1ca2018-08-07 18:58:05 +020084 : random_(random_seed), bursting_(false) {
85 SetConfig(config);
86}
87
88SimulatedNetwork::~SimulatedNetwork() = default;
89
Sebastian Janssoncec24332019-12-04 14:26:50 +010090void SimulatedNetwork::SetConfig(const Config& config) {
Markus Handell8fe932a2020-07-06 17:41:35 +020091 MutexLock lock(&config_lock_);
Sebastian Janssoneceea312019-01-31 11:50:04 +010092 config_state_.config = config; // Shallow copy of the struct.
Sebastian Janssonf96b1ca2018-08-07 18:58:05 +020093 double prob_loss = config.loss_percent / 100.0;
Sebastian Janssoneceea312019-01-31 11:50:04 +010094 if (config_state_.config.avg_burst_loss_length == -1) {
Sebastian Janssonf96b1ca2018-08-07 18:58:05 +020095 // Uniform loss
Sebastian Janssoneceea312019-01-31 11:50:04 +010096 config_state_.prob_loss_bursting = prob_loss;
97 config_state_.prob_start_bursting = prob_loss;
Sebastian Janssonf96b1ca2018-08-07 18:58:05 +020098 } else {
99 // Lose packets according to a gilbert-elliot model.
100 int avg_burst_loss_length = config.avg_burst_loss_length;
101 int min_avg_burst_loss_length = std::ceil(prob_loss / (1 - prob_loss));
102
103 RTC_CHECK_GT(avg_burst_loss_length, min_avg_burst_loss_length)
Jonas Olssonb2b20312020-01-14 12:11:31 +0100104 << "For a total packet loss of " << config.loss_percent
105 << "%% then"
106 " avg_burst_loss_length must be "
107 << min_avg_burst_loss_length + 1 << " or higher.";
Sebastian Janssonf96b1ca2018-08-07 18:58:05 +0200108
Sebastian Janssoneceea312019-01-31 11:50:04 +0100109 config_state_.prob_loss_bursting = (1.0 - 1.0 / avg_burst_loss_length);
110 config_state_.prob_start_bursting =
111 prob_loss / (1 - prob_loss) / avg_burst_loss_length;
Sebastian Janssonf96b1ca2018-08-07 18:58:05 +0200112 }
113}
114
Sebastian Jansson89eb0bb2020-03-13 17:47:38 +0100115void SimulatedNetwork::UpdateConfig(
116 std::function<void(BuiltInNetworkBehaviorConfig*)> config_modifier) {
Markus Handell8fe932a2020-07-06 17:41:35 +0200117 MutexLock lock(&config_lock_);
Sebastian Jansson89eb0bb2020-03-13 17:47:38 +0100118 config_modifier(&config_state_.config);
119}
120
Sebastian Janssonf96b1ca2018-08-07 18:58:05 +0200121void SimulatedNetwork::PauseTransmissionUntil(int64_t until_us) {
Markus Handell8fe932a2020-07-06 17:41:35 +0200122 MutexLock lock(&config_lock_);
Sebastian Janssoneceea312019-01-31 11:50:04 +0100123 config_state_.pause_transmission_until_us = until_us;
Sebastian Janssonf96b1ca2018-08-07 18:58:05 +0200124}
125
126bool SimulatedNetwork::EnqueuePacket(PacketInFlightInfo packet) {
Sebastian Janssoneceea312019-01-31 11:50:04 +0100127 RTC_DCHECK_RUNS_SERIALIZED(&process_checker_);
128 ConfigState state = GetConfigState();
Christoffer Rodbro813c79b2019-01-31 09:25:12 +0100129
Sebastian Janssoneceea312019-01-31 11:50:04 +0100130 UpdateCapacityQueue(state, packet.send_time_us);
Christoffer Rodbro813c79b2019-01-31 09:25:12 +0100131
Sebastian Janssoneceea312019-01-31 11:50:04 +0100132 packet.size += state.config.packet_overhead;
133
134 if (state.config.queue_length_packets > 0 &&
135 capacity_link_.size() >= state.config.queue_length_packets) {
Sebastian Janssonf96b1ca2018-08-07 18:58:05 +0200136 // Too many packet on the link, drop this one.
137 return false;
138 }
Sebastian Jansson2cd3b4c2018-11-06 19:18:28 +0100139
Christoffer Rodbro813c79b2019-01-31 09:25:12 +0100140 // Set arrival time = send time for now; actual arrival time will be
141 // calculated in UpdateCapacityQueue.
142 queue_size_bytes_ += packet.size;
143 capacity_link_.push({packet, packet.send_time_us});
Sebastian Jansson836fee12019-02-08 16:08:10 +0100144 if (!next_process_time_us_) {
Sebastian Jansson2b08e312019-02-25 10:24:46 +0100145 next_process_time_us_ = packet.send_time_us + kDefaultProcessDelay.us();
Sebastian Jansson836fee12019-02-08 16:08:10 +0100146 }
Sebastian Jansson2cd3b4c2018-11-06 19:18:28 +0100147
Sebastian Janssonf96b1ca2018-08-07 18:58:05 +0200148 return true;
149}
150
151absl::optional<int64_t> SimulatedNetwork::NextDeliveryTimeUs() const {
Sebastian Janssoneceea312019-01-31 11:50:04 +0100152 RTC_DCHECK_RUNS_SERIALIZED(&process_checker_);
Sebastian Jansson836fee12019-02-08 16:08:10 +0100153 return next_process_time_us_;
Sebastian Janssonf96b1ca2018-08-07 18:58:05 +0200154}
Christoffer Rodbro813c79b2019-01-31 09:25:12 +0100155
Sebastian Janssoneceea312019-01-31 11:50:04 +0100156void SimulatedNetwork::UpdateCapacityQueue(ConfigState state,
157 int64_t time_now_us) {
158 bool needs_sort = false;
Christoffer Rodbro813c79b2019-01-31 09:25:12 +0100159
Sebastian Janssoneceea312019-01-31 11:50:04 +0100160 // Catch for thread races.
161 if (time_now_us < last_capacity_link_visit_us_.value_or(time_now_us))
162 return;
Christoffer Rodbro813c79b2019-01-31 09:25:12 +0100163
Sebastian Janssoneceea312019-01-31 11:50:04 +0100164 int64_t time_us = last_capacity_link_visit_us_.value_or(time_now_us);
165 // Check the capacity link first.
166 while (!capacity_link_.empty()) {
167 int64_t time_until_front_exits_us = 0;
168 if (state.config.link_capacity_kbps > 0) {
169 int64_t remaining_bits =
170 capacity_link_.front().packet.size * 8 - pending_drain_bits_;
171 RTC_DCHECK(remaining_bits > 0);
172 // Division rounded up - packet not delivered until its last bit is.
173 time_until_front_exits_us =
174 (1000 * remaining_bits + state.config.link_capacity_kbps - 1) /
175 state.config.link_capacity_kbps;
Sebastian Janssonf96b1ca2018-08-07 18:58:05 +0200176 }
177
Sebastian Janssoneceea312019-01-31 11:50:04 +0100178 if (time_us + time_until_front_exits_us > time_now_us) {
179 // Packet at front will not exit yet. Will not enter here on infinite
180 // capacity(=0) so no special handling needed.
181 pending_drain_bits_ +=
182 ((time_now_us - time_us) * state.config.link_capacity_kbps) / 1000;
183 break;
Sebastian Janssonf96b1ca2018-08-07 18:58:05 +0200184 }
Sebastian Janssoneceea312019-01-31 11:50:04 +0100185 if (state.config.link_capacity_kbps > 0) {
186 pending_drain_bits_ +=
187 (time_until_front_exits_us * state.config.link_capacity_kbps) / 1000;
188 } else {
189 // Enough to drain the whole queue.
190 pending_drain_bits_ = queue_size_bytes_ * 8;
191 }
192
193 // Time to get this packet.
Mirko Bonadei05cf6be2019-01-31 21:38:12 +0100194 PacketInfo packet = capacity_link_.front();
Sebastian Janssoneceea312019-01-31 11:50:04 +0100195 capacity_link_.pop();
196
197 time_us += time_until_front_exits_us;
Sebastian Jansson2b08e312019-02-25 10:24:46 +0100198 if (state.config.codel_active_queue_management) {
199 while (!capacity_link_.empty() &&
200 codel_controller_.DropDequeuedPacket(
Danil Chapovalov0c626af2020-02-10 11:16:00 +0100201 Timestamp::Micros(time_us),
202 Timestamp::Micros(capacity_link_.front().packet.send_time_us),
Danil Chapovalovcad3e0e2020-02-17 18:46:07 +0100203 DataSize::Bytes(capacity_link_.front().packet.size),
204 DataSize::Bytes(queue_size_bytes_))) {
Sebastian Jansson2b08e312019-02-25 10:24:46 +0100205 PacketInfo dropped = capacity_link_.front();
206 capacity_link_.pop();
207 queue_size_bytes_ -= dropped.packet.size;
208 dropped.arrival_time_us = PacketDeliveryInfo::kNotReceived;
209 delay_link_.emplace_back(dropped);
210 }
211 }
Sebastian Janssoneceea312019-01-31 11:50:04 +0100212 RTC_DCHECK(time_us >= packet.packet.send_time_us);
213 packet.arrival_time_us =
214 std::max(state.pause_transmission_until_us, time_us);
215 queue_size_bytes_ -= packet.packet.size;
216 pending_drain_bits_ -= packet.packet.size * 8;
217 RTC_DCHECK(pending_drain_bits_ >= 0);
218
219 // Drop packets at an average rate of |state.config.loss_percent| with
220 // and average loss burst length of |state.config.avg_burst_loss_length|.
221 if ((bursting_ && random_.Rand<double>() < state.prob_loss_bursting) ||
222 (!bursting_ && random_.Rand<double>() < state.prob_start_bursting)) {
223 bursting_ = true;
224 packet.arrival_time_us = PacketDeliveryInfo::kNotReceived;
225 } else {
226 bursting_ = false;
227 int64_t arrival_time_jitter_us = std::max(
228 random_.Gaussian(state.config.queue_delay_ms * 1000,
229 state.config.delay_standard_deviation_ms * 1000),
230 0.0);
231
232 // If reordering is not allowed then adjust arrival_time_jitter
233 // to make sure all packets are sent in order.
234 int64_t last_arrival_time_us =
235 delay_link_.empty() ? -1 : delay_link_.back().arrival_time_us;
236 if (!state.config.allow_reordering && !delay_link_.empty() &&
237 packet.arrival_time_us + arrival_time_jitter_us <
238 last_arrival_time_us) {
239 arrival_time_jitter_us = last_arrival_time_us - packet.arrival_time_us;
240 }
241 packet.arrival_time_us += arrival_time_jitter_us;
242 if (packet.arrival_time_us >= last_arrival_time_us) {
243 last_arrival_time_us = packet.arrival_time_us;
244 } else {
245 needs_sort = true;
246 }
247 }
Mirko Bonadei05cf6be2019-01-31 21:38:12 +0100248 delay_link_.emplace_back(packet);
Sebastian Janssonf96b1ca2018-08-07 18:58:05 +0200249 }
Sebastian Janssoneceea312019-01-31 11:50:04 +0100250 last_capacity_link_visit_us_ = time_now_us;
251 // Cannot save unused capacity for later.
252 pending_drain_bits_ = std::min(pending_drain_bits_, queue_size_bytes_ * 8);
253
254 if (needs_sort) {
255 // Packet(s) arrived out of order, make sure list is sorted.
256 std::sort(delay_link_.begin(), delay_link_.end(),
257 [](const PacketInfo& p1, const PacketInfo& p2) {
258 return p1.arrival_time_us < p2.arrival_time_us;
259 });
260 }
261}
262
263SimulatedNetwork::ConfigState SimulatedNetwork::GetConfigState() const {
Markus Handell8fe932a2020-07-06 17:41:35 +0200264 MutexLock lock(&config_lock_);
Sebastian Janssoneceea312019-01-31 11:50:04 +0100265 return config_state_;
Sebastian Janssonf96b1ca2018-08-07 18:58:05 +0200266}
267
Christoffer Rodbro813c79b2019-01-31 09:25:12 +0100268std::vector<PacketDeliveryInfo> SimulatedNetwork::DequeueDeliverablePackets(
269 int64_t receive_time_us) {
Sebastian Janssoneceea312019-01-31 11:50:04 +0100270 RTC_DCHECK_RUNS_SERIALIZED(&process_checker_);
271 UpdateCapacityQueue(GetConfigState(), receive_time_us);
Christoffer Rodbro813c79b2019-01-31 09:25:12 +0100272 std::vector<PacketDeliveryInfo> packets_to_deliver;
273 // Check the extra delay queue.
274 while (!delay_link_.empty() &&
275 receive_time_us >= delay_link_.front().arrival_time_us) {
276 PacketInfo packet_info = delay_link_.front();
277 packets_to_deliver.emplace_back(
278 PacketDeliveryInfo(packet_info.packet, packet_info.arrival_time_us));
279 delay_link_.pop_front();
280 }
Sebastian Jansson836fee12019-02-08 16:08:10 +0100281
282 if (!delay_link_.empty()) {
283 next_process_time_us_ = delay_link_.front().arrival_time_us;
284 } else if (!capacity_link_.empty()) {
Sebastian Jansson2b08e312019-02-25 10:24:46 +0100285 next_process_time_us_ = receive_time_us + kDefaultProcessDelay.us();
Sebastian Jansson836fee12019-02-08 16:08:10 +0100286 } else {
287 next_process_time_us_.reset();
288 }
Christoffer Rodbro813c79b2019-01-31 09:25:12 +0100289 return packets_to_deliver;
290}
291
Sebastian Janssonf96b1ca2018-08-07 18:58:05 +0200292} // namespace webrtc