blob: 77be14821c2aef1eb77f5ffa66f17fbe4640b2cd [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>
Sebastian Jansson2cd3b4c2018-11-06 19:18:28 +010016#include "api/units/data_rate.h"
Sebastian Janssonf96b1ca2018-08-07 18:58:05 +020017
18namespace webrtc {
19
20SimulatedNetwork::SimulatedNetwork(SimulatedNetwork::Config config,
21 uint64_t random_seed)
22 : random_(random_seed), bursting_(false) {
23 SetConfig(config);
24}
25
26SimulatedNetwork::~SimulatedNetwork() = default;
27
28void SimulatedNetwork::SetConfig(const SimulatedNetwork::Config& config) {
29 rtc::CritScope crit(&config_lock_);
Sebastian Jansson2cd3b4c2018-11-06 19:18:28 +010030 if (config_.link_capacity_kbps != config.link_capacity_kbps) {
31 reset_capacity_delay_error_ = true;
32 }
Sebastian Janssonf96b1ca2018-08-07 18:58:05 +020033 config_ = config; // Shallow copy of the struct.
34 double prob_loss = config.loss_percent / 100.0;
35 if (config_.avg_burst_loss_length == -1) {
36 // Uniform loss
37 prob_loss_bursting_ = prob_loss;
38 prob_start_bursting_ = prob_loss;
39 } else {
40 // Lose packets according to a gilbert-elliot model.
41 int avg_burst_loss_length = config.avg_burst_loss_length;
42 int min_avg_burst_loss_length = std::ceil(prob_loss / (1 - prob_loss));
43
44 RTC_CHECK_GT(avg_burst_loss_length, min_avg_burst_loss_length)
45 << "For a total packet loss of " << config.loss_percent << "%% then"
46 << " avg_burst_loss_length must be " << min_avg_burst_loss_length + 1
47 << " or higher.";
48
49 prob_loss_bursting_ = (1.0 - 1.0 / avg_burst_loss_length);
50 prob_start_bursting_ = prob_loss / (1 - prob_loss) / avg_burst_loss_length;
51 }
52}
53
54void SimulatedNetwork::PauseTransmissionUntil(int64_t until_us) {
55 rtc::CritScope crit(&config_lock_);
56 pause_transmission_until_us_ = until_us;
57}
58
59bool SimulatedNetwork::EnqueuePacket(PacketInFlightInfo packet) {
60 Config config;
61 {
62 rtc::CritScope crit(&config_lock_);
63 config = config_;
64 }
65 rtc::CritScope crit(&process_lock_);
66 if (config.queue_length_packets > 0 &&
67 capacity_link_.size() >= config.queue_length_packets) {
68 // Too many packet on the link, drop this one.
69 return false;
70 }
Sebastian Janssonf96b1ca2018-08-07 18:58:05 +020071 int64_t network_start_time_us = packet.send_time_us;
Sebastian Janssonf96b1ca2018-08-07 18:58:05 +020072 {
73 rtc::CritScope crit(&config_lock_);
Sebastian Jansson2cd3b4c2018-11-06 19:18:28 +010074 if (reset_capacity_delay_error_) {
75 capacity_delay_error_bytes_ = 0;
76 reset_capacity_delay_error_ = false;
77 }
Sebastian Janssonf96b1ca2018-08-07 18:58:05 +020078 if (pause_transmission_until_us_) {
79 network_start_time_us =
80 std::max(network_start_time_us, *pause_transmission_until_us_);
81 pause_transmission_until_us_.reset();
82 }
83 }
Sebastian Jansson2cd3b4c2018-11-06 19:18:28 +010084
85 // Delay introduced by the link capacity.
86 TimeDelta capacity_delay = TimeDelta::Zero();
87 if (config.link_capacity_kbps > 0) {
88 const DataRate link_capacity = DataRate::kbps(config.link_capacity_kbps);
89 int64_t compensated_size =
90 static_cast<int64_t>(packet.size) + capacity_delay_error_bytes_;
91 capacity_delay = DataSize::bytes(compensated_size) / link_capacity;
92
93 capacity_delay_error_bytes_ +=
94 packet.size - (capacity_delay * link_capacity).bytes();
95 }
96
Sebastian Janssonf96b1ca2018-08-07 18:58:05 +020097 // Check if there already are packets on the link and change network start
98 // time forward if there is.
99 if (!capacity_link_.empty() &&
100 network_start_time_us < capacity_link_.back().arrival_time_us)
101 network_start_time_us = capacity_link_.back().arrival_time_us;
102
Sebastian Jansson2cd3b4c2018-11-06 19:18:28 +0100103 int64_t arrival_time_us = network_start_time_us + capacity_delay.us();
Sebastian Janssonf96b1ca2018-08-07 18:58:05 +0200104 capacity_link_.push({packet, arrival_time_us});
105 return true;
106}
107
108absl::optional<int64_t> SimulatedNetwork::NextDeliveryTimeUs() const {
Sebastian Jansson2cd3b4c2018-11-06 19:18:28 +0100109 rtc::CritScope crit(&process_lock_);
Sebastian Janssonf96b1ca2018-08-07 18:58:05 +0200110 if (!delay_link_.empty())
111 return delay_link_.begin()->arrival_time_us;
112 return absl::nullopt;
113}
114std::vector<PacketDeliveryInfo> SimulatedNetwork::DequeueDeliverablePackets(
115 int64_t receive_time_us) {
116 int64_t time_now_us = receive_time_us;
117 Config config;
118 double prob_loss_bursting;
119 double prob_start_bursting;
120 {
121 rtc::CritScope crit(&config_lock_);
122 config = config_;
123 prob_loss_bursting = prob_loss_bursting_;
124 prob_start_bursting = prob_start_bursting_;
125 }
126 {
127 rtc::CritScope crit(&process_lock_);
128 // Check the capacity link first.
129 if (!capacity_link_.empty()) {
130 int64_t last_arrival_time_us =
131 delay_link_.empty() ? -1 : delay_link_.back().arrival_time_us;
132 bool needs_sort = false;
133 while (!capacity_link_.empty() &&
134 time_now_us >= capacity_link_.front().arrival_time_us) {
135 // Time to get this packet.
136 PacketInfo packet = std::move(capacity_link_.front());
137 capacity_link_.pop();
138
139 // Drop packets at an average rate of |config_.loss_percent| with
140 // and average loss burst length of |config_.avg_burst_loss_length|.
141 if ((bursting_ && random_.Rand<double>() < prob_loss_bursting) ||
142 (!bursting_ && random_.Rand<double>() < prob_start_bursting)) {
143 bursting_ = true;
144 continue;
145 } else {
146 bursting_ = false;
147 }
148
149 int64_t arrival_time_jitter_us = std::max(
150 random_.Gaussian(config.queue_delay_ms * 1000,
151 config.delay_standard_deviation_ms * 1000),
152 0.0);
153
154 // If reordering is not allowed then adjust arrival_time_jitter
155 // to make sure all packets are sent in order.
156 if (!config.allow_reordering && !delay_link_.empty() &&
157 packet.arrival_time_us + arrival_time_jitter_us <
158 last_arrival_time_us) {
159 arrival_time_jitter_us =
160 last_arrival_time_us - packet.arrival_time_us;
161 }
162 packet.arrival_time_us += arrival_time_jitter_us;
163 if (packet.arrival_time_us >= last_arrival_time_us) {
164 last_arrival_time_us = packet.arrival_time_us;
165 } else {
166 needs_sort = true;
167 }
168 delay_link_.emplace_back(std::move(packet));
169 }
170
171 if (needs_sort) {
172 // Packet(s) arrived out of order, make sure list is sorted.
173 std::sort(delay_link_.begin(), delay_link_.end(),
174 [](const PacketInfo& p1, const PacketInfo& p2) {
175 return p1.arrival_time_us < p2.arrival_time_us;
176 });
177 }
178 }
179
180 std::vector<PacketDeliveryInfo> packets_to_deliver;
181 // Check the extra delay queue.
182 while (!delay_link_.empty() &&
183 time_now_us >= delay_link_.front().arrival_time_us) {
184 PacketInfo packet_info = delay_link_.front();
185 packets_to_deliver.emplace_back(
186 PacketDeliveryInfo(packet_info.packet, packet_info.arrival_time_us));
187 delay_link_.pop_front();
188 }
189 return packets_to_deliver;
190 }
191}
192
193} // namespace webrtc