blob: 2dee92d8cd0cfd3292d494bfb731841633707a48 [file] [log] [blame]
Sebastian Janssonf96b1ca2018-08-07 16:58:051/*
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 15:47:4916
Sebastian Jansson2cd3b4c2018-11-06 18:18:2817#include "api/units/data_rate.h"
Yves Gerey3e707812018-11-28 15:47:4918#include "api/units/data_size.h"
19#include "api/units/time_delta.h"
20#include "rtc_base/checks.h"
Sebastian Janssonf96b1ca2018-08-07 16:58:0521
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 18:18:2834 if (config_.link_capacity_kbps != config.link_capacity_kbps) {
35 reset_capacity_delay_error_ = true;
36 }
Sebastian Janssonf96b1ca2018-08-07 16:58:0537 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 }
69 rtc::CritScope crit(&process_lock_);
70 if (config.queue_length_packets > 0 &&
71 capacity_link_.size() >= config.queue_length_packets) {
72 // Too many packet on the link, drop this one.
73 return false;
74 }
Sebastian Janssonf96b1ca2018-08-07 16:58:0575 int64_t network_start_time_us = packet.send_time_us;
Sebastian Janssonf96b1ca2018-08-07 16:58:0576 {
77 rtc::CritScope crit(&config_lock_);
Sebastian Jansson2cd3b4c2018-11-06 18:18:2878 if (reset_capacity_delay_error_) {
79 capacity_delay_error_bytes_ = 0;
80 reset_capacity_delay_error_ = false;
81 }
Sebastian Janssonf96b1ca2018-08-07 16:58:0582 if (pause_transmission_until_us_) {
83 network_start_time_us =
84 std::max(network_start_time_us, *pause_transmission_until_us_);
85 pause_transmission_until_us_.reset();
86 }
87 }
Sebastian Jansson2cd3b4c2018-11-06 18:18:2888
89 // Delay introduced by the link capacity.
90 TimeDelta capacity_delay = TimeDelta::Zero();
91 if (config.link_capacity_kbps > 0) {
92 const DataRate link_capacity = DataRate::kbps(config.link_capacity_kbps);
93 int64_t compensated_size =
94 static_cast<int64_t>(packet.size) + capacity_delay_error_bytes_;
95 capacity_delay = DataSize::bytes(compensated_size) / link_capacity;
96
97 capacity_delay_error_bytes_ +=
98 packet.size - (capacity_delay * link_capacity).bytes();
99 }
100
Sebastian Janssonf96b1ca2018-08-07 16:58:05101 // Check if there already are packets on the link and change network start
102 // time forward if there is.
103 if (!capacity_link_.empty() &&
104 network_start_time_us < capacity_link_.back().arrival_time_us)
105 network_start_time_us = capacity_link_.back().arrival_time_us;
106
Sebastian Jansson2cd3b4c2018-11-06 18:18:28107 int64_t arrival_time_us = network_start_time_us + capacity_delay.us();
Sebastian Janssonf96b1ca2018-08-07 16:58:05108 capacity_link_.push({packet, arrival_time_us});
109 return true;
110}
111
112absl::optional<int64_t> SimulatedNetwork::NextDeliveryTimeUs() const {
Sebastian Jansson2cd3b4c2018-11-06 18:18:28113 rtc::CritScope crit(&process_lock_);
Sebastian Janssonf96b1ca2018-08-07 16:58:05114 if (!delay_link_.empty())
115 return delay_link_.begin()->arrival_time_us;
116 return absl::nullopt;
117}
118std::vector<PacketDeliveryInfo> SimulatedNetwork::DequeueDeliverablePackets(
119 int64_t receive_time_us) {
120 int64_t time_now_us = receive_time_us;
121 Config config;
122 double prob_loss_bursting;
123 double prob_start_bursting;
124 {
125 rtc::CritScope crit(&config_lock_);
126 config = config_;
127 prob_loss_bursting = prob_loss_bursting_;
128 prob_start_bursting = prob_start_bursting_;
129 }
130 {
131 rtc::CritScope crit(&process_lock_);
132 // Check the capacity link first.
133 if (!capacity_link_.empty()) {
134 int64_t last_arrival_time_us =
135 delay_link_.empty() ? -1 : delay_link_.back().arrival_time_us;
136 bool needs_sort = false;
137 while (!capacity_link_.empty() &&
138 time_now_us >= capacity_link_.front().arrival_time_us) {
139 // Time to get this packet.
140 PacketInfo packet = std::move(capacity_link_.front());
141 capacity_link_.pop();
142
143 // Drop packets at an average rate of |config_.loss_percent| with
144 // and average loss burst length of |config_.avg_burst_loss_length|.
145 if ((bursting_ && random_.Rand<double>() < prob_loss_bursting) ||
146 (!bursting_ && random_.Rand<double>() < prob_start_bursting)) {
147 bursting_ = true;
148 continue;
149 } else {
150 bursting_ = false;
151 }
152
153 int64_t arrival_time_jitter_us = std::max(
154 random_.Gaussian(config.queue_delay_ms * 1000,
155 config.delay_standard_deviation_ms * 1000),
156 0.0);
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_us + arrival_time_jitter_us <
162 last_arrival_time_us) {
163 arrival_time_jitter_us =
164 last_arrival_time_us - packet.arrival_time_us;
165 }
166 packet.arrival_time_us += arrival_time_jitter_us;
167 if (packet.arrival_time_us >= last_arrival_time_us) {
168 last_arrival_time_us = packet.arrival_time_us;
169 } else {
170 needs_sort = true;
171 }
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