blob: 1e209c7fb49b0035c1f5a19dcaea1a7dc9f55f41 [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 }
Danil Chapovalov292a73e2017-12-07 17:00:40 +010056 packet_receiver_->DeliverPacket(
57 media_type, rtc::CopyOnWriteBuffer(packet_data, packet_length),
58 packet_time);
minyue20c84cc2017-04-10 16:57:57 -070059}
philipela2c55232016-01-26 08:41:53 -080060
61FakeNetworkPipe::FakeNetworkPipe(Clock* clock,
62 const FakeNetworkPipe::Config& config,
minyue20c84cc2017-04-10 16:57:57 -070063 std::unique_ptr<Demuxer> demuxer)
64 : FakeNetworkPipe(clock, config, std::move(demuxer), 1) {}
65
66FakeNetworkPipe::FakeNetworkPipe(Clock* clock,
67 const FakeNetworkPipe::Config& config,
68 std::unique_ptr<Demuxer> demuxer,
philipela2c55232016-01-26 08:41:53 -080069 uint64_t seed)
Peter Boströmd3c94472015-12-09 11:20:58 +010070 : clock_(clock),
minyue20c84cc2017-04-10 16:57:57 -070071 demuxer_(std::move(demuxer)),
philipela2c55232016-01-26 08:41:53 -080072 random_(seed),
philipel5ef2bc12017-02-21 07:28:31 -080073 config_(),
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +000074 dropped_packets_(0),
75 sent_packets_(0),
76 total_packet_delay_(0),
philipel536378b2016-05-31 03:20:23 -070077 bursting_(false),
stefane9ad2712017-02-10 06:09:28 -080078 next_process_time_(clock_->TimeInMilliseconds()),
79 last_log_time_(clock_->TimeInMilliseconds()) {
philipel5ef2bc12017-02-21 07:28:31 -080080 SetConfig(config);
philipel536378b2016-05-31 03:20:23 -070081}
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +000082
83FakeNetworkPipe::~FakeNetworkPipe() {
84 while (!capacity_link_.empty()) {
85 delete capacity_link_.front();
86 capacity_link_.pop();
87 }
88 while (!delay_link_.empty()) {
philipela2c55232016-01-26 08:41:53 -080089 delete *delay_link_.begin();
90 delay_link_.erase(delay_link_.begin());
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +000091 }
92}
93
94void FakeNetworkPipe::SetReceiver(PacketReceiver* receiver) {
minyue20c84cc2017-04-10 16:57:57 -070095 RTC_CHECK(demuxer_);
96 demuxer_->SetReceiver(receiver);
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +000097}
98
henrik.lundin@webrtc.orgc0e9aeb2014-02-26 13:34:52 +000099void FakeNetworkPipe::SetConfig(const FakeNetworkPipe::Config& config) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200100 rtc::CritScope crit(&lock_);
henrik.lundin@webrtc.orgc0e9aeb2014-02-26 13:34:52 +0000101 config_ = config; // Shallow copy of the struct.
philipel5ef2bc12017-02-21 07:28:31 -0800102 double prob_loss = config.loss_percent / 100.0;
103 if (config_.avg_burst_loss_length == -1) {
104 // Uniform loss
105 prob_loss_bursting_ = prob_loss;
106 prob_start_bursting_ = prob_loss;
107 } else {
108 // Lose packets according to a gilbert-elliot model.
109 int avg_burst_loss_length = config.avg_burst_loss_length;
110 int min_avg_burst_loss_length = std::ceil(prob_loss / (1 - prob_loss));
111
112 RTC_CHECK_GT(avg_burst_loss_length, min_avg_burst_loss_length)
113 << "For a total packet loss of " << config.loss_percent << "%% then"
114 << " avg_burst_loss_length must be " << min_avg_burst_loss_length + 1
115 << " or higher.";
116
117 prob_loss_bursting_ = (1.0 - 1.0 / avg_burst_loss_length);
118 prob_start_bursting_ = prob_loss / (1 - prob_loss) / avg_burst_loss_length;
119 }
henrik.lundin@webrtc.orgc0e9aeb2014-02-26 13:34:52 +0000120}
121
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +0000122void FakeNetworkPipe::SendPacket(const uint8_t* data, size_t data_length) {
minyue20c84cc2017-04-10 16:57:57 -0700123 RTC_CHECK(demuxer_);
Peter Boströmf2f82832015-05-01 13:00:41 +0200124 rtc::CritScope crit(&lock_);
stefan@webrtc.orgb8e9e442014-07-09 11:29:06 +0000125 if (config_.queue_length_packets > 0 &&
126 capacity_link_.size() >= config_.queue_length_packets) {
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +0000127 // Too many packet on the link, drop this one.
128 ++dropped_packets_;
129 return;
130 }
131
Peter Boströmd3c94472015-12-09 11:20:58 +0100132 int64_t time_now = clock_->TimeInMilliseconds();
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +0000133
134 // Delay introduced by the link capacity.
135 int64_t capacity_delay_ms = 0;
philipel19f51432017-09-07 09:08:50 -0700136 if (config_.link_capacity_kbps > 0) {
137 const int bytes_per_millisecond = config_.link_capacity_kbps / 8;
138 // To round to the closest millisecond we add half a milliseconds worth of
139 // bytes to the delay calculation.
140 capacity_delay_ms = (data_length + capacity_delay_error_bytes_ +
141 bytes_per_millisecond / 2) /
142 bytes_per_millisecond;
143 capacity_delay_error_bytes_ +=
144 data_length - capacity_delay_ms * bytes_per_millisecond;
145 }
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +0000146 int64_t network_start_time = time_now;
147
148 // Check if there already are packets on the link and change network start
danilchapa6a70072016-06-01 11:20:43 -0700149 // time forward if there is.
150 if (!capacity_link_.empty() &&
151 network_start_time < capacity_link_.back()->arrival_time())
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +0000152 network_start_time = capacity_link_.back()->arrival_time();
153
154 int64_t arrival_time = network_start_time + capacity_delay_ms;
155 NetworkPacket* packet = new NetworkPacket(data, data_length, time_now,
156 arrival_time);
157 capacity_link_.push(packet);
158}
159
160float FakeNetworkPipe::PercentageLoss() {
Peter Boströmf2f82832015-05-01 13:00:41 +0200161 rtc::CritScope crit(&lock_);
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +0000162 if (sent_packets_ == 0)
163 return 0;
164
165 return static_cast<float>(dropped_packets_) /
166 (sent_packets_ + dropped_packets_);
167}
168
169int FakeNetworkPipe::AverageDelay() {
Peter Boströmf2f82832015-05-01 13:00:41 +0200170 rtc::CritScope crit(&lock_);
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +0000171 if (sent_packets_ == 0)
172 return 0;
173
Stefan Holmerff2a6352016-01-14 10:00:21 +0100174 return static_cast<int>(total_packet_delay_ /
175 static_cast<int64_t>(sent_packets_));
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +0000176}
177
178void FakeNetworkPipe::Process() {
Peter Boströmd3c94472015-12-09 11:20:58 +0100179 int64_t time_now = clock_->TimeInMilliseconds();
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +0000180 std::queue<NetworkPacket*> packets_to_deliver;
181 {
Peter Boströmf2f82832015-05-01 13:00:41 +0200182 rtc::CritScope crit(&lock_);
stefane9ad2712017-02-10 06:09:28 -0800183 if (time_now - last_log_time_ > 5000) {
184 int64_t queueing_delay_ms = 0;
185 if (!capacity_link_.empty()) {
186 queueing_delay_ms = time_now - capacity_link_.front()->send_time();
187 }
Mirko Bonadei675513b2017-11-09 11:09:25 +0100188 RTC_LOG(LS_INFO) << "Network queue: " << queueing_delay_ms << " ms.";
stefane9ad2712017-02-10 06:09:28 -0800189 last_log_time_ = time_now;
190 }
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +0000191 // Check the capacity link first.
philipela2c55232016-01-26 08:41:53 -0800192 while (!capacity_link_.empty() &&
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +0000193 time_now >= capacity_link_.front()->arrival_time()) {
194 // Time to get this packet.
195 NetworkPacket* packet = capacity_link_.front();
196 capacity_link_.pop();
197
philipel536378b2016-05-31 03:20:23 -0700198 // Drop packets at an average rate of |config_.loss_percent| with
199 // and average loss burst length of |config_.avg_burst_loss_length|.
200 if ((bursting_ && random_.Rand<double>() < prob_loss_bursting_) ||
201 (!bursting_ && random_.Rand<double>() < prob_start_bursting_)) {
202 bursting_ = true;
stefan@webrtc.orgbfe6e082014-07-31 12:30:18 +0000203 delete packet;
204 continue;
philipel536378b2016-05-31 03:20:23 -0700205 } else {
206 bursting_ = false;
stefan@webrtc.orgbfe6e082014-07-31 12:30:18 +0000207 }
208
philipela2c55232016-01-26 08:41:53 -0800209 int arrival_time_jitter = random_.Gaussian(
210 config_.queue_delay_ms, config_.delay_standard_deviation_ms);
211
212 // If reordering is not allowed then adjust arrival_time_jitter
213 // to make sure all packets are sent in order.
214 if (!config_.allow_reordering && !delay_link_.empty() &&
215 packet->arrival_time() + arrival_time_jitter <
216 (*delay_link_.rbegin())->arrival_time()) {
217 arrival_time_jitter =
218 (*delay_link_.rbegin())->arrival_time() - packet->arrival_time();
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +0000219 }
philipela2c55232016-01-26 08:41:53 -0800220 packet->IncrementArrivalTime(arrival_time_jitter);
philipela2c55232016-01-26 08:41:53 -0800221 delay_link_.insert(packet);
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +0000222 }
223
224 // Check the extra delay queue.
philipela2c55232016-01-26 08:41:53 -0800225 while (!delay_link_.empty() &&
226 time_now >= (*delay_link_.begin())->arrival_time()) {
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +0000227 // Deliver this packet.
philipela2c55232016-01-26 08:41:53 -0800228 NetworkPacket* packet = *delay_link_.begin();
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +0000229 packets_to_deliver.push(packet);
philipela2c55232016-01-26 08:41:53 -0800230 delay_link_.erase(delay_link_.begin());
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +0000231 // |time_now| might be later than when the packet should have arrived, due
232 // to NetworkProcess being called too late. For stats, use the time it
233 // should have been on the link.
234 total_packet_delay_ += packet->arrival_time() - packet->send_time();
235 }
236 sent_packets_ += packets_to_deliver.size();
237 }
238 while (!packets_to_deliver.empty()) {
239 NetworkPacket* packet = packets_to_deliver.front();
240 packets_to_deliver.pop();
minyue20c84cc2017-04-10 16:57:57 -0700241 demuxer_->DeliverPacket(packet, PacketTime());
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +0000242 delete packet;
243 }
philipel50235b72017-02-28 02:19:33 -0800244
245 next_process_time_ = !delay_link_.empty()
246 ? (*delay_link_.begin())->arrival_time()
247 : time_now + kDefaultProcessIntervalMs;
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +0000248}
249
pkasting@chromium.org0b1534c2014-12-15 22:09:40 +0000250int64_t FakeNetworkPipe::TimeUntilNextProcess() const {
Peter Boströmf2f82832015-05-01 13:00:41 +0200251 rtc::CritScope crit(&lock_);
Peter Boströmd3c94472015-12-09 11:20:58 +0100252 return std::max<int64_t>(next_process_time_ - clock_->TimeInMilliseconds(),
253 0);
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +0000254}
255
256} // namespace webrtc