-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrobust_throughput_estimator.cc
executable file
·135 lines (120 loc) · 5.42 KB
/
robust_throughput_estimator.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
/*
* Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "modules/congestion_controller/goog_cc/robust_throughput_estimator.h"
#include <stddef.h>
#include <algorithm>
#include <utility>
#include "rtc_base/checks.h"
namespace webrtc {
RobustThroughputEstimator::RobustThroughputEstimator(
const RobustThroughputEstimatorSettings& settings)
: settings_(settings) {
RTC_DCHECK(settings.enabled);
}
RobustThroughputEstimator::~RobustThroughputEstimator() {}
void RobustThroughputEstimator::IncomingPacketFeedbackVector(
const std::vector<PacketResult>& packet_feedback_vector) {
RTC_DCHECK(std::is_sorted(packet_feedback_vector.begin(),
packet_feedback_vector.end(),
PacketResult::ReceiveTimeOrder()));
for (const auto& packet : packet_feedback_vector) {
// Insert the new packet.
window_.push_back(packet);
window_.back().sent_packet.prior_unacked_data =
window_.back().sent_packet.prior_unacked_data *
settings_.unacked_weight;
// In most cases, receive timestamps should already be in order, but in the
// rare case where feedback packets have been reordered, we do some swaps to
// ensure that the window is sorted.
for (size_t i = window_.size() - 1;
i > 0 && window_[i].receive_time < window_[i - 1].receive_time; i--) {
std::swap(window_[i], window_[i - 1]);
}
// Remove old packets.
while (window_.size() > settings_.kMaxPackets ||
(window_.size() > settings_.min_packets &&
packet.receive_time - window_.front().receive_time >
settings_.window_duration)) {
window_.pop_front();
}
}
}
absl::optional<DataRate> RobustThroughputEstimator::bitrate() const {
if (window_.size() < settings_.initial_packets)
return absl::nullopt;
TimeDelta largest_recv_gap(TimeDelta::Millis(0));
TimeDelta second_largest_recv_gap(TimeDelta::Millis(0));
for (size_t i = 1; i < window_.size(); i++) {
// Find receive time gaps
TimeDelta gap = window_[i].receive_time - window_[i - 1].receive_time;
if (gap > largest_recv_gap) {
second_largest_recv_gap = largest_recv_gap;
largest_recv_gap = gap;
} else if (gap > second_largest_recv_gap) {
second_largest_recv_gap = gap;
}
}
Timestamp min_send_time = window_[0].sent_packet.send_time;
Timestamp max_send_time = window_[0].sent_packet.send_time;
Timestamp min_recv_time = window_[0].receive_time;
Timestamp max_recv_time = window_[0].receive_time;
DataSize data_size = DataSize::Bytes(0);
for (const auto& packet : window_) {
min_send_time = std::min(min_send_time, packet.sent_packet.send_time);
max_send_time = std::max(max_send_time, packet.sent_packet.send_time);
min_recv_time = std::min(min_recv_time, packet.receive_time);
max_recv_time = std::max(max_recv_time, packet.receive_time);
data_size += packet.sent_packet.size;
data_size += packet.sent_packet.prior_unacked_data;
}
// Suppose a packet of size S is sent every T milliseconds.
// A window of N packets would contain N*S bytes, but the time difference
// between the first and the last packet would only be (N-1)*T. Thus, we
// need to remove one packet.
DataSize recv_size = data_size;
DataSize send_size = data_size;
if (settings_.assume_shared_link) {
// Depending on how the bottleneck queue is implemented, a large packet
// may delay sending of sebsequent packets, so the delay between packets
// i and i+1 depends on the size of both packets. In this case we minimize
// the maximum error by removing half of both the first and last packet
// size.
DataSize first_last_average_size =
(window_.front().sent_packet.size +
window_.front().sent_packet.prior_unacked_data +
window_.back().sent_packet.size +
window_.back().sent_packet.prior_unacked_data) /
2;
recv_size -= first_last_average_size;
send_size -= first_last_average_size;
} else {
// In the simpler case where the delay between packets i and i+1 only
// depends on the size of packet i+1, the first packet doesn't give us
// any information. Analogously, we assume that the start send time
// for the last packet doesn't depend on the size of the packet.
recv_size -= (window_.front().sent_packet.size +
window_.front().sent_packet.prior_unacked_data);
send_size -= (window_.back().sent_packet.size +
window_.back().sent_packet.prior_unacked_data);
}
// Remove the largest gap by replacing it by the second largest gap
// or the average gap.
TimeDelta send_duration = max_send_time - min_send_time;
TimeDelta recv_duration = (max_recv_time - min_recv_time) - largest_recv_gap;
if (settings_.reduce_bias) {
recv_duration += second_largest_recv_gap;
} else {
recv_duration += recv_duration / (window_.size() - 2);
}
send_duration = std::max(send_duration, TimeDelta::Millis(1));
recv_duration = std::max(recv_duration, TimeDelta::Millis(1));
return std::min(send_size / send_duration, recv_size / recv_duration);
}
} // namespace webrtc