blob: 01a74e51f18f6cd96a0ba1b4f0c5db89c443d627 [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_);
Sebastian Jansson2cd3b4c2018-11-06 19:18:28 +010034 if (config_.link_capacity_kbps != config.link_capacity_kbps) {
35 reset_capacity_delay_error_ = true;
36 }
Sebastian Janssonf96b1ca2018-08-07 18:58:05 +020037 config_ = config; // Shallow copy of the struct.
38 double prob_loss = config.loss_percent / 100.0;
39 if (config_.avg_burst_loss_length == -1) {
40 // Uniform loss
41 prob_loss_bursting_ = prob_loss;
42 prob_start_bursting_ = prob_loss;
43 } else {
44 // Lose packets according to a gilbert-elliot model.
45 int avg_burst_loss_length = config.avg_burst_loss_length;
46 int min_avg_burst_loss_length = std::ceil(prob_loss / (1 - prob_loss));
47
48 RTC_CHECK_GT(avg_burst_loss_length, min_avg_burst_loss_length)
49 << "For a total packet loss of " << config.loss_percent << "%% then"
50 << " avg_burst_loss_length must be " << min_avg_burst_loss_length + 1
51 << " or higher.";
52
53 prob_loss_bursting_ = (1.0 - 1.0 / avg_burst_loss_length);
54 prob_start_bursting_ = prob_loss / (1 - prob_loss) / avg_burst_loss_length;
55 }
56}
57
58void SimulatedNetwork::PauseTransmissionUntil(int64_t until_us) {
59 rtc::CritScope crit(&config_lock_);
60 pause_transmission_until_us_ = until_us;
61}
62
63bool SimulatedNetwork::EnqueuePacket(PacketInFlightInfo packet) {
64 Config config;
65 {
66 rtc::CritScope crit(&config_lock_);
67 config = config_;
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 Janssonf96b1ca2018-08-07 18:58:05 +020076 int64_t network_start_time_us = packet.send_time_us;
Sebastian Janssonf96b1ca2018-08-07 18:58:05 +020077 {
78 rtc::CritScope crit(&config_lock_);
Sebastian Jansson2cd3b4c2018-11-06 19:18:28 +010079 if (reset_capacity_delay_error_) {
80 capacity_delay_error_bytes_ = 0;
81 reset_capacity_delay_error_ = false;
82 }
Sebastian Janssonf96b1ca2018-08-07 18:58:05 +020083 if (pause_transmission_until_us_) {
84 network_start_time_us =
85 std::max(network_start_time_us, *pause_transmission_until_us_);
86 pause_transmission_until_us_.reset();
87 }
88 }
Sebastian Jansson2cd3b4c2018-11-06 19:18:28 +010089
90 // Delay introduced by the link capacity.
91 TimeDelta capacity_delay = TimeDelta::Zero();
92 if (config.link_capacity_kbps > 0) {
93 const DataRate link_capacity = DataRate::kbps(config.link_capacity_kbps);
94 int64_t compensated_size =
95 static_cast<int64_t>(packet.size) + capacity_delay_error_bytes_;
96 capacity_delay = DataSize::bytes(compensated_size) / link_capacity;
97
98 capacity_delay_error_bytes_ +=
99 packet.size - (capacity_delay * link_capacity).bytes();
100 }
101
Sebastian Janssonf96b1ca2018-08-07 18:58:05 +0200102 // Check if there already are packets on the link and change network start
103 // time forward if there is.
104 if (!capacity_link_.empty() &&
105 network_start_time_us < capacity_link_.back().arrival_time_us)
106 network_start_time_us = capacity_link_.back().arrival_time_us;
107
Sebastian Jansson2cd3b4c2018-11-06 19:18:28 +0100108 int64_t arrival_time_us = network_start_time_us + capacity_delay.us();
Sebastian Janssonf96b1ca2018-08-07 18:58:05 +0200109 capacity_link_.push({packet, arrival_time_us});
110 return true;
111}
112
113absl::optional<int64_t> SimulatedNetwork::NextDeliveryTimeUs() const {
Sebastian Jansson2cd3b4c2018-11-06 19:18:28 +0100114 rtc::CritScope crit(&process_lock_);
Sebastian Janssonf96b1ca2018-08-07 18:58:05 +0200115 if (!delay_link_.empty())
116 return delay_link_.begin()->arrival_time_us;
117 return absl::nullopt;
118}
119std::vector<PacketDeliveryInfo> SimulatedNetwork::DequeueDeliverablePackets(
120 int64_t receive_time_us) {
121 int64_t time_now_us = receive_time_us;
122 Config config;
123 double prob_loss_bursting;
124 double prob_start_bursting;
125 {
126 rtc::CritScope crit(&config_lock_);
127 config = config_;
128 prob_loss_bursting = prob_loss_bursting_;
129 prob_start_bursting = prob_start_bursting_;
130 }
131 {
132 rtc::CritScope crit(&process_lock_);
133 // Check the capacity link first.
134 if (!capacity_link_.empty()) {
135 int64_t last_arrival_time_us =
136 delay_link_.empty() ? -1 : delay_link_.back().arrival_time_us;
137 bool needs_sort = false;
138 while (!capacity_link_.empty() &&
139 time_now_us >= capacity_link_.front().arrival_time_us) {
140 // Time to get this packet.
141 PacketInfo packet = std::move(capacity_link_.front());
142 capacity_link_.pop();
143
144 // 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;
Johannes Krona8f9e252019-01-24 15:38:23 +0100149 packet.arrival_time_us = PacketDeliveryInfo::kNotReceived;
Sebastian Janssonf96b1ca2018-08-07 18:58:05 +0200150 } else {
151 bursting_ = false;
Johannes Krona8f9e252019-01-24 15:38:23 +0100152 int64_t arrival_time_jitter_us = std::max(
153 random_.Gaussian(config.queue_delay_ms * 1000,
154 config.delay_standard_deviation_ms * 1000),
155 0.0);
Sebastian Janssonf96b1ca2018-08-07 18:58:05 +0200156
Johannes Krona8f9e252019-01-24 15:38:23 +0100157 // If reordering is not allowed then adjust arrival_time_jitter
158 // to make sure all packets are sent in order.
159 if (!config.allow_reordering && !delay_link_.empty() &&
160 packet.arrival_time_us + arrival_time_jitter_us <
161 last_arrival_time_us) {
162 arrival_time_jitter_us =
163 last_arrival_time_us - packet.arrival_time_us;
164 }
165 packet.arrival_time_us += arrival_time_jitter_us;
166 if (packet.arrival_time_us >= last_arrival_time_us) {
167 last_arrival_time_us = packet.arrival_time_us;
168 } else {
169 needs_sort = true;
170 }
Sebastian Janssonf96b1ca2018-08-07 18:58:05 +0200171 }
172 delay_link_.emplace_back(std::move(packet));
173 }
174
175 if (needs_sort) {
176 // Packet(s) arrived out of order, make sure list is sorted.
177 std::sort(delay_link_.begin(), delay_link_.end(),
178 [](const PacketInfo& p1, const PacketInfo& p2) {
179 return p1.arrival_time_us < p2.arrival_time_us;
180 });
181 }
182 }
183
184 std::vector<PacketDeliveryInfo> packets_to_deliver;
185 // Check the extra delay queue.
186 while (!delay_link_.empty() &&
187 time_now_us >= delay_link_.front().arrival_time_us) {
188 PacketInfo packet_info = delay_link_.front();
189 packets_to_deliver.emplace_back(
190 PacketDeliveryInfo(packet_info.packet, packet_info.arrival_time_us));
191 delay_link_.pop_front();
192 }
193 return packets_to_deliver;
194 }
195}
196
197} // namespace webrtc