blob: 6678f1c37448938409603a16442765343a8597bb [file] [log] [blame]
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +00001/*
2 * Copyright (c) 2012 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
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "test/fake_network_pipe.h"
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +000012
13#include <assert.h>
14#include <math.h>
15#include <string.h>
philipel536378b2016-05-31 03:20:23 -070016
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +000017#include <algorithm>
philipel536378b2016-05-31 03:20:23 -070018#include <cmath>
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +000019
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020020#include "call/call.h"
21#include "modules/rtp_rtcp/include/rtp_header_parser.h"
22#include "rtc_base/logging.h"
23#include "system_wrappers/include/clock.h"
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +000024
25namespace webrtc {
26
philipel50235b72017-02-28 02:19:33 -080027namespace {
28constexpr int64_t kDefaultProcessIntervalMs = 5;
29}
30
minyue20c84cc2017-04-10 16:57:57 -070031DemuxerImpl::DemuxerImpl(const std::map<uint8_t, MediaType>& payload_type_map)
32 : packet_receiver_(nullptr), payload_type_map_(payload_type_map) {}
33
34void DemuxerImpl::SetReceiver(PacketReceiver* receiver) {
35 packet_receiver_ = receiver;
36}
37
38void DemuxerImpl::DeliverPacket(const NetworkPacket* packet,
39 const PacketTime& packet_time) {
40 // No packet receiver means that this demuxer will terminate the flow of
41 // packets.
42 if (!packet_receiver_)
43 return;
44 const uint8_t* const packet_data = packet->data();
45 const size_t packet_length = packet->data_length();
46 MediaType media_type = MediaType::ANY;
47 if (!RtpHeaderParser::IsRtcp(packet_data, packet_length)) {
48 RTC_CHECK_GE(packet_length, 2);
49 const uint8_t payload_type = packet_data[1] & 0x7f;
50 std::map<uint8_t, MediaType>::const_iterator it =
51 payload_type_map_.find(payload_type);
52 RTC_CHECK(it != payload_type_map_.end())
53 << "payload type " << static_cast<int>(payload_type) << " unknown.";
54 media_type = it->second;
55 }
56 packet_receiver_->DeliverPacket(media_type, packet_data, packet_length,
57 packet_time);
58}
philipela2c55232016-01-26 08:41:53 -080059
60FakeNetworkPipe::FakeNetworkPipe(Clock* clock,
61 const FakeNetworkPipe::Config& config,
minyue20c84cc2017-04-10 16:57:57 -070062 std::unique_ptr<Demuxer> demuxer)
63 : FakeNetworkPipe(clock, config, std::move(demuxer), 1) {}
64
65FakeNetworkPipe::FakeNetworkPipe(Clock* clock,
66 const FakeNetworkPipe::Config& config,
67 std::unique_ptr<Demuxer> demuxer,
philipela2c55232016-01-26 08:41:53 -080068 uint64_t seed)
Peter Boströmd3c94472015-12-09 11:20:58 +010069 : clock_(clock),
minyue20c84cc2017-04-10 16:57:57 -070070 demuxer_(std::move(demuxer)),
philipela2c55232016-01-26 08:41:53 -080071 random_(seed),
philipel5ef2bc12017-02-21 07:28:31 -080072 config_(),
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +000073 dropped_packets_(0),
74 sent_packets_(0),
75 total_packet_delay_(0),
philipel536378b2016-05-31 03:20:23 -070076 bursting_(false),
stefane9ad2712017-02-10 06:09:28 -080077 next_process_time_(clock_->TimeInMilliseconds()),
78 last_log_time_(clock_->TimeInMilliseconds()) {
philipel5ef2bc12017-02-21 07:28:31 -080079 SetConfig(config);
philipel536378b2016-05-31 03:20:23 -070080}
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +000081
82FakeNetworkPipe::~FakeNetworkPipe() {
83 while (!capacity_link_.empty()) {
84 delete capacity_link_.front();
85 capacity_link_.pop();
86 }
87 while (!delay_link_.empty()) {
philipela2c55232016-01-26 08:41:53 -080088 delete *delay_link_.begin();
89 delay_link_.erase(delay_link_.begin());
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +000090 }
91}
92
93void FakeNetworkPipe::SetReceiver(PacketReceiver* receiver) {
minyue20c84cc2017-04-10 16:57:57 -070094 RTC_CHECK(demuxer_);
95 demuxer_->SetReceiver(receiver);
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +000096}
97
henrik.lundin@webrtc.orgc0e9aeb2014-02-26 13:34:52 +000098void FakeNetworkPipe::SetConfig(const FakeNetworkPipe::Config& config) {
Peter Boströmf2f82832015-05-01 13:00:41 +020099 rtc::CritScope crit(&lock_);
henrik.lundin@webrtc.orgc0e9aeb2014-02-26 13:34:52 +0000100 config_ = config; // Shallow copy of the struct.
philipel5ef2bc12017-02-21 07:28:31 -0800101 double prob_loss = config.loss_percent / 100.0;
102 if (config_.avg_burst_loss_length == -1) {
103 // Uniform loss
104 prob_loss_bursting_ = prob_loss;
105 prob_start_bursting_ = prob_loss;
106 } else {
107 // Lose packets according to a gilbert-elliot model.
108 int avg_burst_loss_length = config.avg_burst_loss_length;
109 int min_avg_burst_loss_length = std::ceil(prob_loss / (1 - prob_loss));
110
111 RTC_CHECK_GT(avg_burst_loss_length, min_avg_burst_loss_length)
112 << "For a total packet loss of " << config.loss_percent << "%% then"
113 << " avg_burst_loss_length must be " << min_avg_burst_loss_length + 1
114 << " or higher.";
115
116 prob_loss_bursting_ = (1.0 - 1.0 / avg_burst_loss_length);
117 prob_start_bursting_ = prob_loss / (1 - prob_loss) / avg_burst_loss_length;
118 }
henrik.lundin@webrtc.orgc0e9aeb2014-02-26 13:34:52 +0000119}
120
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +0000121void FakeNetworkPipe::SendPacket(const uint8_t* data, size_t data_length) {
minyue20c84cc2017-04-10 16:57:57 -0700122 RTC_CHECK(demuxer_);
Peter Boströmf2f82832015-05-01 13:00:41 +0200123 rtc::CritScope crit(&lock_);
stefan@webrtc.orgb8e9e442014-07-09 11:29:06 +0000124 if (config_.queue_length_packets > 0 &&
125 capacity_link_.size() >= config_.queue_length_packets) {
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +0000126 // Too many packet on the link, drop this one.
127 ++dropped_packets_;
128 return;
129 }
130
Peter Boströmd3c94472015-12-09 11:20:58 +0100131 int64_t time_now = clock_->TimeInMilliseconds();
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +0000132
133 // Delay introduced by the link capacity.
134 int64_t capacity_delay_ms = 0;
philipel19f51432017-09-07 09:08:50 -0700135 if (config_.link_capacity_kbps > 0) {
136 const int bytes_per_millisecond = config_.link_capacity_kbps / 8;
137 // To round to the closest millisecond we add half a milliseconds worth of
138 // bytes to the delay calculation.
139 capacity_delay_ms = (data_length + capacity_delay_error_bytes_ +
140 bytes_per_millisecond / 2) /
141 bytes_per_millisecond;
142 capacity_delay_error_bytes_ +=
143 data_length - capacity_delay_ms * bytes_per_millisecond;
144 }
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +0000145 int64_t network_start_time = time_now;
146
147 // Check if there already are packets on the link and change network start
danilchapa6a70072016-06-01 11:20:43 -0700148 // time forward if there is.
149 if (!capacity_link_.empty() &&
150 network_start_time < capacity_link_.back()->arrival_time())
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +0000151 network_start_time = capacity_link_.back()->arrival_time();
152
153 int64_t arrival_time = network_start_time + capacity_delay_ms;
154 NetworkPacket* packet = new NetworkPacket(data, data_length, time_now,
155 arrival_time);
156 capacity_link_.push(packet);
157}
158
159float FakeNetworkPipe::PercentageLoss() {
Peter Boströmf2f82832015-05-01 13:00:41 +0200160 rtc::CritScope crit(&lock_);
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +0000161 if (sent_packets_ == 0)
162 return 0;
163
164 return static_cast<float>(dropped_packets_) /
165 (sent_packets_ + dropped_packets_);
166}
167
168int FakeNetworkPipe::AverageDelay() {
Peter Boströmf2f82832015-05-01 13:00:41 +0200169 rtc::CritScope crit(&lock_);
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +0000170 if (sent_packets_ == 0)
171 return 0;
172
Stefan Holmerff2a6352016-01-14 10:00:21 +0100173 return static_cast<int>(total_packet_delay_ /
174 static_cast<int64_t>(sent_packets_));
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +0000175}
176
177void FakeNetworkPipe::Process() {
Peter Boströmd3c94472015-12-09 11:20:58 +0100178 int64_t time_now = clock_->TimeInMilliseconds();
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +0000179 std::queue<NetworkPacket*> packets_to_deliver;
180 {
Peter Boströmf2f82832015-05-01 13:00:41 +0200181 rtc::CritScope crit(&lock_);
stefane9ad2712017-02-10 06:09:28 -0800182 if (time_now - last_log_time_ > 5000) {
183 int64_t queueing_delay_ms = 0;
184 if (!capacity_link_.empty()) {
185 queueing_delay_ms = time_now - capacity_link_.front()->send_time();
186 }
Mirko Bonadei675513b2017-11-09 11:09:25 +0100187 RTC_LOG(LS_INFO) << "Network queue: " << queueing_delay_ms << " ms.";
stefane9ad2712017-02-10 06:09:28 -0800188 last_log_time_ = time_now;
189 }
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +0000190 // Check the capacity link first.
philipela2c55232016-01-26 08:41:53 -0800191 while (!capacity_link_.empty() &&
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +0000192 time_now >= capacity_link_.front()->arrival_time()) {
193 // Time to get this packet.
194 NetworkPacket* packet = capacity_link_.front();
195 capacity_link_.pop();
196
philipel536378b2016-05-31 03:20:23 -0700197 // Drop packets at an average rate of |config_.loss_percent| with
198 // and average loss burst length of |config_.avg_burst_loss_length|.
199 if ((bursting_ && random_.Rand<double>() < prob_loss_bursting_) ||
200 (!bursting_ && random_.Rand<double>() < prob_start_bursting_)) {
201 bursting_ = true;
stefan@webrtc.orgbfe6e082014-07-31 12:30:18 +0000202 delete packet;
203 continue;
philipel536378b2016-05-31 03:20:23 -0700204 } else {
205 bursting_ = false;
stefan@webrtc.orgbfe6e082014-07-31 12:30:18 +0000206 }
207
philipela2c55232016-01-26 08:41:53 -0800208 int arrival_time_jitter = random_.Gaussian(
209 config_.queue_delay_ms, config_.delay_standard_deviation_ms);
210
211 // If reordering is not allowed then adjust arrival_time_jitter
212 // to make sure all packets are sent in order.
213 if (!config_.allow_reordering && !delay_link_.empty() &&
214 packet->arrival_time() + arrival_time_jitter <
215 (*delay_link_.rbegin())->arrival_time()) {
216 arrival_time_jitter =
217 (*delay_link_.rbegin())->arrival_time() - packet->arrival_time();
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +0000218 }
philipela2c55232016-01-26 08:41:53 -0800219 packet->IncrementArrivalTime(arrival_time_jitter);
philipela2c55232016-01-26 08:41:53 -0800220 delay_link_.insert(packet);
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +0000221 }
222
223 // Check the extra delay queue.
philipela2c55232016-01-26 08:41:53 -0800224 while (!delay_link_.empty() &&
225 time_now >= (*delay_link_.begin())->arrival_time()) {
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +0000226 // Deliver this packet.
philipela2c55232016-01-26 08:41:53 -0800227 NetworkPacket* packet = *delay_link_.begin();
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +0000228 packets_to_deliver.push(packet);
philipela2c55232016-01-26 08:41:53 -0800229 delay_link_.erase(delay_link_.begin());
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +0000230 // |time_now| might be later than when the packet should have arrived, due
231 // to NetworkProcess being called too late. For stats, use the time it
232 // should have been on the link.
233 total_packet_delay_ += packet->arrival_time() - packet->send_time();
234 }
235 sent_packets_ += packets_to_deliver.size();
236 }
237 while (!packets_to_deliver.empty()) {
238 NetworkPacket* packet = packets_to_deliver.front();
239 packets_to_deliver.pop();
minyue20c84cc2017-04-10 16:57:57 -0700240 demuxer_->DeliverPacket(packet, PacketTime());
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +0000241 delete packet;
242 }
philipel50235b72017-02-28 02:19:33 -0800243
244 next_process_time_ = !delay_link_.empty()
245 ? (*delay_link_.begin())->arrival_time()
246 : time_now + kDefaultProcessIntervalMs;
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +0000247}
248
pkasting@chromium.org0b1534c2014-12-15 22:09:40 +0000249int64_t FakeNetworkPipe::TimeUntilNextProcess() const {
Peter Boströmf2f82832015-05-01 13:00:41 +0200250 rtc::CritScope crit(&lock_);
Peter Boströmd3c94472015-12-09 11:20:58 +0100251 return std::max<int64_t>(next_process_time_ - clock_->TimeInMilliseconds(),
252 0);
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +0000253}
254
255} // namespace webrtc