基于延迟的带宽估计

概述

img

通过Transport feedback包统计发送时间和到达时间,并通过这些信息统计计算包组延迟差,通过延迟差估计延迟变化趋势,通过这个趋势和给定阈值的比较来判断链路状态,在检测状态的同时阈值也在自适应的变化。然后通过检测的链路状态,通过状态机进行状态的变化以及在对应状态进行对应的码率控制逻辑。

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
//xrtcsdk_gcc\xrtc\rtc\modules\congestion_controller\goog_cc\goog_cc_network_controller.h
#include "xrtc/rtc/pc/network_controller.h"
#include "xrtc/rtc/modules/congestion_controller/goog_cc/delay_based_bwe.h"

namespace xrtc {

class GoogCcNetworkController : public NetworkControllerInterface {
public:
GoogCcNetworkController();
~GoogCcNetworkController() override;

webrtc::NetworkControlUpdate OnTransportPacketsFeedback(
const webrtc::TransportPacketsFeedback& report) override;

private:
std::unique_ptr<DelayBasedBwe> delay_base_bwe_;
};

} // namespace xrtc
//xrtcsdk_gcc\xrtc\rtc\modules\congestion_controller\goog_cc\goog_cc_network_controller.cpp
#include "xrtc/rtc/modules/congestion_controller/goog_cc/goog_cc_network_controller.h"

namespace xrtc {

GoogCcNetworkController::GoogCcNetworkController() :
delay_base_bwe_(std::make_unique<DelayBasedBwe>())
{
}

GoogCcNetworkController::~GoogCcNetworkController() {
}

webrtc::NetworkControlUpdate GoogCcNetworkController::OnTransportPacketsFeedback(
const webrtc::TransportPacketsFeedback& report)
{
if (report.packet_feedbacks.empty()) {
return webrtc::NetworkControlUpdate();
}

DelayBasedBwe::Result result;
result = delay_base_bwe_->IncomingPacketFeedbackVector(report);
}

} // namespace xrtc
//xrtcsdk_gcc\xrtc\rtc\modules\congestion_controller\goog_cc\delay_based_bwe.h
#include "api/transport/network_types.h"
#include "api/units/data_rate.h"

namespace xrtc {

class DelayBasedBwe {
public:
struct Result {
bool updated = false;
webrtc::DataRate target_bitrate = webrtc::DataRate::Zero();
};

DelayBasedBwe();
virtual ~DelayBasedBwe();

Result IncomingPacketFeedbackVector(
const webrtc::TransportPacketsFeedback& msg);
};

} // namespace xrtc

#endif // XRTCSDK_XRTC_RTC_MODULES_CONGESTION_CONTROLLER_GOOG_CC_DELAY_BASED_BWE_H_
//xrtcsdk_gcc\xrtc\rtc\modules\congestion_controller\goog_cc\delay_based_bwe.cpp
#include "xrtc/rtc/modules/congestion_controller/goog_cc/delay_based_bwe.h"

namespace xrtc {

DelayBasedBwe::DelayBasedBwe() {
}
DelayBasedBwe::~DelayBasedBwe() {
}

DelayBasedBwe::Result DelayBasedBwe::IncomingPacketFeedbackVector(
const webrtc::TransportPacketsFeedback& msg)
{
return DelayBasedBwe::Result();
}

} // namespace xrtc

包组延迟差的计算

由于单个数据包的延迟差抖动较大,所以取一段时间的包作为一组,取分组的平均时间来计算延迟差。

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
//xrtcsdk_gcc\xrtc\rtc\modules\congestion_controller\goog_cc\inter_arrival_delta.h
#include <api/units/time_delta.h>
#include <api/units/timestamp.h>

namespace xrtc {

class InterArrivalDelta {
public:
InterArrivalDelta(webrtc::TimeDelta send_time_group_length);
~InterArrivalDelta();

bool ComputeDeltas(webrtc::Timestamp send_time,
webrtc::Timestamp arrival_time,
webrtc::Timestamp system_time,
size_t packet_size,
webrtc::TimeDelta* send_time_delta,
webrtc::TimeDelta* arrival_time_delta,
int* packet_size_delta);

private:
// 包组结构体
struct SendTimeGroup {
SendTimeGroup() :
size(0),
first_send_time(webrtc::Timestamp::MinusInfinity()),
send_time(webrtc::Timestamp::MinusInfinity()),
first_arrival(webrtc::Timestamp::MinusInfinity()),
complete_time(webrtc::Timestamp::MinusInfinity()),
last_system_time(webrtc::Timestamp::MinusInfinity())
{
}

bool IsFirstPacket() const {// 通过完成时间是否有值判断是否是第一个包
return complete_time.IsInfinite();
}

// 分组中所有包的累计字节数
size_t size;
// 分组第一个包的发送时间
webrtc::Timestamp first_send_time;
// 分组最后一个包的发送时间
webrtc::Timestamp send_time;
// 分组中第一个达到接收端的包的时间
webrtc::Timestamp first_arrival;
// 分组中最后一个达到接收端的包的时间
webrtc::Timestamp complete_time;
// 最新的系统时间
webrtc::Timestamp last_system_time;
};
// 创建新的时间分组
bool NewTimestampGroup(webrtc::Timestamp arrival_time,
webrtc::Timestamp send_time) const;
// 突发流判断,用来判断是否放在同一个分组内
bool BelongsToBurst(webrtc::Timestamp arrival_time,
webrtc::Timestamp send_time) const;
// 重置包组
void Reset();

private:
webrtc::TimeDelta send_time_group_length_;// 包组长度
SendTimeGroup current_timestamp_group_; // 当前包组
SendTimeGroup prev_timestamp_group_; // 前一个包组
};

} // namespace xrtc

#endif // XRTCSDK_XRTC_RTC_MODULES_CONGESTION_CONTROLLER_GOOG_CC_INTER_ARRIVAL_DELTA_H_

计算包组延迟差

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
//xrtcsdk_gcc\xrtc\rtc\modules\congestion_controller\goog_cc\inter_arrival_delta.cpp

/*
// return:bool
// 后三个参数用于返回计算的发送延迟差、到达延迟差、包大小差(什么作用?),利用这些参数计算单项延迟差。
*/
bool InterArrivalDelta::ComputeDeltas(webrtc::Timestamp send_time,
webrtc::Timestamp arrival_time,
webrtc::Timestamp system_time,
size_t packet_size,
webrtc::TimeDelta* send_time_delta,
webrtc::TimeDelta* arrival_time_delta,
int* packet_size_delta)
{
bool calculated_delta = false;
// 如果是第一个包
if (current_timestamp_group_.IsFirstPacket()) {
current_timestamp_group_.send_time = send_time;
current_timestamp_group_.first_send_time = send_time;
current_timestamp_group_.first_arrival = arrival_time;
}
else if (send_time < current_timestamp_group_.send_time) {//发送时间早于分组的第一个包则舍弃
return false;
}
// 如果需要创建新的分组
else if (NewTimestampGroup(arrival_time, send_time)) {
// 判断是否需要计算两个包组之间的时间差
if (prev_timestamp_group_.complete_time.IsFinite()) {
// 前一个分组的完成时间有值(前一个包组有效),则接下来完成该分组的时间计算
*send_time_delta = current_timestamp_group_.send_time -
prev_timestamp_group_.send_time;
*arrival_time_delta = current_timestamp_group_.complete_time -
prev_timestamp_group_.complete_time;
webrtc::TimeDelta system_time_delta = current_timestamp_group_.last_system_time -
prev_timestamp_group_.last_system_time;
if (*arrival_time_delta - system_time_delta >=
kArrivalTimeOffsetThreshold) //??? 分组无效,重置分组
{
RTC_LOG(LS_WARNING) << "Arrival time clock offset has changed, "
<< "diff: " << arrival_time_delta->ms() - system_time_delta.ms()
<< ", resetting";
Reset();
return false;
}
}

// 当前分组已结束且已完成时间差计算
*packet_size_delta = static_cast<int>(current_timestamp_group_.size -
prev_timestamp_group_.size);
calculated_delta = true;

// 初始化下一个分组
prev_timestamp_group_ = current_timestamp_group_;
current_timestamp_group_.first_send_time = send_time;
current_timestamp_group_.send_time = send_time;
current_timestamp_group_.first_arrival = arrival_time;
current_timestamp_group_.size = 0;
}
else { // 更新当前分组的包的发送时间
current_timestamp_group_.send_time =
std::max(current_timestamp_group_.send_time, send_time);
}

// 累计分组的包大小,更新最新的到达时间和系统时间
current_timestamp_group_.size += packet_size;
current_timestamp_group_.complete_time = arrival_time;
current_timestamp_group_.last_system_time = system_time;

return calculated_delta;
}

/*
// 判断是否需要建立新的分组
*/
bool InterArrivalDelta::NewTimestampGroup(webrtc::Timestamp arrival_time,
webrtc::Timestamp send_time) const
{
if (current_timestamp_group_.complete_time.IsInfinite()) {// 当前分组未完成
return false;
}
// 突发的包要分为一组,而不去创建新组
else if (BelongsToBurst(arrival_time, send_time)) {
return false;
}
else {// 分组时间跨度不能超过阈值
return send_time - current_timestamp_group_.first_send_time >
send_time_group_length_;
}
}

/*
// 判断当前包是否属于当前分组的突发流的一员
*/
bool InterArrivalDelta::BelongsToBurst(webrtc::Timestamp arrival_time,
webrtc::Timestamp send_time) const
{
webrtc::TimeDelta arrival_time_delta =
arrival_time - current_timestamp_group_.complete_time;
webrtc::TimeDelta send_time_delta =
send_time - current_timestamp_group_.send_time;
// 计算传播延迟差
webrtc::TimeDelta propgation_delta = arrival_time_delta -
send_time_delta;

if (send_time_delta.IsZero()) { // 发送时间相同的包
return true;
}
// 延迟差小于0,说明包提前到达了,说明该包跟前一个包一起到达,说明属于同一个burst
// 到达时间与最后一个包的到达时间差小于阈值 或者 与分组中第一个包的到达时间差小于一个阈值
else if (propgation_delta < webrtc::TimeDelta::Zero() &&
arrival_time_delta < kBurstDeltaThreshold &&
arrival_time - current_timestamp_group_.first_arrival
< kMaxBurstDuration)
{
return true;
}

return false;
}

void InterArrivalDelta::Reset() {
current_timestamp_group_ = SendTimeGroup();
prev_timestamp_group_ = SendTimeGroup();
}

在delay_based_bwe.cpp文件中调用

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
//xrtcsdk_gcc\xrtc\rtc\modules\congestion_controller\goog_cc\delay_based_bwe.cpp
DelayBasedBwe::Result DelayBasedBwe::IncomingPacketFeedbackVector(
const webrtc::TransportPacketsFeedback& msg)
{
// 数据包按照到达时间进行排序
auto packet_feedback_vector = msg.SortedByReceiveTime();
if (packet_feedback_vector.empty()) {
return DelayBasedBwe::Result();
}

for (const auto& packet_feedback : packet_feedback_vector) {
IncomingPacketFeedback(packet_feedback, msg.feedback_time);
}

return DelayBasedBwe::Result();
}

void DelayBasedBwe::IncomingPacketFeedback(const webrtc::PacketResult& packet_feedback,
webrtc::Timestamp at_time)
{
// 如果是第一次收到packet,需要创建计算包组时间差的对象
// 如果长时间没有收到packet超过一定的阈值,需要重新创建对象
if (last_seen_timestamp_.IsInfinite() ||
at_time - last_seen_timestamp_ > kStreamTimeout)
{
video_inter_arrival_delta_ = std::make_unique<InterArrivalDelta>(
kSendTimeGroupLength);
}

last_seen_timestamp_ = at_time;

size_t packet_size = packet_feedback.sent_packet.size.bytes();

webrtc::TimeDelta send_time_delta = webrtc::TimeDelta::Zero();
webrtc::TimeDelta recv_time_delta = webrtc::TimeDelta::Zero();
int packet_size_delta = 0;

// 计算延迟差
bool calculated_delta = video_inter_arrival_delta_->ComputeDeltas(
packet_feedback.sent_packet.send_time,
packet_feedback.receive_time,
at_time,
packet_size,
&send_time_delta, &recv_time_delta, &packet_size_delta);
}

trendline估计器

通过之前统计到的一系列延迟差数据,利用最小二乘法,估计出单项延迟变化趋势。

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
// xrtcsdk_gcc\xrtc\rtc\modules\congestion_controller\goog_cc\delay_based_bwe.cpp
void DelayBasedBwe::IncomingPacketFeedback(const webrtc::PacketResult& packet_feedback,
webrtc::Timestamp at_time)
{
// 如果是第一次收到packet,需要创建计算包组时间差的对象
// 如果长时间没有收到packet超过一定的阈值,需要重新创建对象
if (last_seen_timestamp_.IsInfinite() ||
at_time - last_seen_timestamp_ > kStreamTimeout)
{
video_inter_arrival_delta_ = std::make_unique<InterArrivalDelta>(
kSendTimeGroupLength);
//video_delay_detector_.reset(new TrendlineEstimator());
}

last_seen_timestamp_ = at_time;

size_t packet_size = packet_feedback.sent_packet.size.bytes();

webrtc::TimeDelta send_time_delta = webrtc::TimeDelta::Zero();
webrtc::TimeDelta recv_time_delta = webrtc::TimeDelta::Zero();
int packet_size_delta = 0;

bool calculated_delta = video_inter_arrival_delta_->ComputeDeltas(
packet_feedback.sent_packet.send_time,
packet_feedback.receive_time,
at_time,
packet_size,
&send_time_delta, &recv_time_delta, &packet_size_delta);

/*
if (calculated_delta) {
RTC_LOG(LS_WARNING) << "**************send_delta: " << send_time_delta.ms()
<< ", recv_delta: " << recv_time_delta.ms()
<< ", packet_size_delta: " << packet_size_delta;
}
*/
// 更新延迟trendline
video_delay_detector_->Update(recv_time_delta, send_time_delta,
packet_feedback.sent_packet.send_time,
packet_feedback.receive_time,
packet_size,
calculated_delta);
}

在计算完成单项延迟差后,通过以下函数更新trendline

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
void TrendlineEstimator::Update(webrtc::TimeDelta recv_time_delta, 
webrtc::TimeDelta send_time_delta,
webrtc::Timestamp send_time,
webrtc::Timestamp arrival_time,
size_t packet_size,
bool calculated_delta)
{
if (calculated_delta) {
UpdateTrendline(recv_time_delta.ms<double>(),
send_time_delta.ms<double>(),
send_time.ms(), arrival_time.ms(),
packet_size);
}
}

void TrendlineEstimator::UpdateTrendline(double recv_delta_ms,
double send_delta_ms,
int64_t send_time_ms,
int64_t arrival_time_ms,
size_t packet_size)
{
if (-1 == first_arrival_time_ms_) {
first_arrival_time_ms_ = arrival_time_ms;
}

// 统计样本的个数
++num_of_deltas_;

// 计算传输的延迟差
double delta_ms = recv_delta_ms - send_delta_ms;
accumulated_delay_ms_ += delta_ms;
// 计算指数平滑后的累计延迟差
smoothed_delay_ms_ = smoothing_coef_ * smoothed_delay_ms_ +
(1 - smoothing_coef_) * accumulated_delay_ms_;
// 将样本数据添加到队列
delay_hist_.emplace_back(
static_cast<double>(arrival_time_ms - first_arrival_time_ms_),
smoothed_delay_ms_, accumulated_delay_ms_);

if (delay_hist_.size() > 20) {
delay_hist_.pop_front();
}

// 当样本数据满足要求,计算trend值
double trend = prev_trend_;
if (delay_hist_.size() == kDefaultTrendlineWindowSize) {
trend = LinearFitSlope(delay_hist_).value_or(trend);//(LinearFitSlope(delay_hist_) | trend)
}

// 根据trend值进行过载检测
Detect(trend, send_delta_ms, arrival_time_ms);
}

// 线性回归最小二乘法
absl::optional<double> TrendlineEstimator::LinearFitSlope(
const std::deque<PacketTiming>& packets)
{
double sum_x = 0.0f;
double sum_y = 0.0f;
for (const auto& packet : packets) {
sum_x += packet.arrival_time_ms;
sum_y += packet.smoothed_delay_ms;
}

// 计算x,y的平均值
double avg_x = sum_x / packets.size();
double avg_y = sum_y / packets.size();

// 分别计算分子和分母
double num = 0.0f;
double den = 0.0f;
for (const auto& packet : packets) {
double x = packet.arrival_time_ms;
double y = packet.smoothed_delay_ms;

num += (x - avg_x) * (y - avg_y);
den += (x - avg_x) * (x - avg_x);
}

if (0.0f == den) {
return absl::nullopt;
}

return num / den;
}

void TrendlineEstimator::Detect(double trend, double ts_delta,
int64_t now_ms)
{
if (num_of_deltas_ < 2) {
hypothesis_ = webrtc::BandwidthUsage::kBwNormal;
return;
}

// 1. 对原始的trend值进行增益处理,增加区分度
double modified_trend =
std::min(num_of_deltas_, kMinNumDeltas) * trend * threshold_gain_;

// 2. 进行过载检测
if (modified_trend > threshold_) { // 有可能过载了
if (-1 == time_over_using_) { // 第一次超过阈值
time_over_using_ = ts_delta / 2;
}
else {
time_over_using_ += ts_delta;
}

++overuse_counter_;

if (time_over_using_ > kOverUsingTimeThreshold && overuse_counter_ > 1) {
if (trend > prev_trend_) {
// 判定过载
time_over_using_ = 0;
overuse_counter_ = 0;
hypothesis_ = webrtc::BandwidthUsage::kBwOverusing;
}
}
}
else if (modified_trend < -threshold_) {
// 判定负载过低了
time_over_using_ = -1;
overuse_counter_ = 0;
hypothesis_ = webrtc::BandwidthUsage::kBwUnderusing;
}
else {
// 判定正常网络状态
time_over_using_ = -1;
overuse_counter_ = 0;
hypothesis_ = webrtc::BandwidthUsage::kBwNormal;
}

prev_trend_ = trend;

// 阈值的动态自适应调整
UpdateThreshold(modified_trend, now_ms);

// for test
x_time_ << now_ms - first_arrival_time_ms_ << std::endl;
y_trend_ << modified_trend << std::endl;
y_threshold_ << threshold_ << std::endl;
}


void TrendlineEstimator::UpdateThreshold(double modified_trend,
int64_t now_ms)
{
if (-1 == last_update_ms_) {
last_update_ms_ = now_ms;
}

// 如果modified_trend异常大的时候,忽略本次更新
if (modified_trend > threshold_ + kMaxAdaptOffset) {
last_update_ms_ = now_ms;
return;
}

// 调整阈值,当阈值调小的时候,使用的系数0.039
// 当阈值调大的时候,使用的系数是0.0087
double k = fabs(modified_trend) < threshold_ ? k_down_ : k_up_;
const int64_t kMaxTimeDelta = 100;
int64_t time_delta_ms = std::min(now_ms - last_update_ms_, kMaxTimeDelta);
threshold_ += k * (fabs(modified_trend) - threshold_) * time_delta_ms;
threshold_ = rtc::SafeClamp(threshold_, 6.0f, 600.0f);
last_update_ms_ = now_ms;
}

AIMD码率控制

AIMD(Additive Increase Multiplicative Decrease)码率控制,指的是加性增加乘性减少。当网络过载时,以乘性的方式减少码率;当网络没有过载时,以加性的方式增加码率。另外,当我们认为可用带宽发生了变化或者未知时,会切换到慢启动模式,此种模式会以倍速的方式增加码率。

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
// xrtcsdk_gcc\xrtc\rtc\modules\congestion_controller\goog_cc\delay_based_bwe.cpp
DelayBasedBwe::Result DelayBasedBwe::IncomingPacketFeedbackVector(
const webrtc::TransportPacketsFeedback& msg,
absl::optional<webrtc::DataRate> acked_bitrate)
{
// 数据包按照到达时间进行排序
auto packet_feedback_vector = msg.SortedByReceiveTime();
if (packet_feedback_vector.empty()) {
return DelayBasedBwe::Result();
}

bool recover_from_overusing = false;
webrtc::BandwidthUsage prev_detector_state = video_delay_detector_->State();
for (const auto& packet_feedback : packet_feedback_vector) {
IncomingPacketFeedback(packet_feedback, msg.feedback_time);
if (prev_detector_state == webrtc::BandwidthUsage::kBwUnderusing &&
video_delay_detector_->State() == webrtc::BandwidthUsage::kBwNormal)
{
recover_from_overusing = true;//表示从拥塞状态恢复到了正常
}
prev_detector_state = video_delay_detector_->State();
}

return MaybeUpdateEstimate(acked_bitrate, recover_from_overusing, msg.feedback_time);
}

DelayBasedBwe::Result DelayBasedBwe::MaybeUpdateEstimate(
absl::optional<webrtc::DataRate> acked_bitrate,
bool recover_from_overusing,
webrtc::Timestamp at_time)
{
// 根据网络检测状态来动态的调整发送码率
Result result;
// 当网络出现过载的时候
if (video_delay_detector_->State() == webrtc::BandwidthUsage::kBwOverusing) {
// 已知吞吐量时
if (acked_bitrate && rate_control_.TimeToReduceFurther(at_time, *acked_bitrate)) {
result.updated = UpdateEstimate(acked_bitrate, at_time, &result.target_bitrate);
}
// 当我们不知道吞吐量的时候
else if (!acked_bitrate && rate_control_.ValidEstimate() &&
rate_control_.InitialTimeToReduceFurther(at_time))
{
// 当我们不知道吞吐量的时候,将当前的码率下降一半
rate_control_.SetEstimate(rate_control_.LatestEstimate() / 2,
at_time);
result.updated = true;
result.target_bitrate = rate_control_.LatestEstimate();
}
}
// 网络没有出现过载
else {
result.updated = UpdateEstimate(acked_bitrate, at_time, &result.target_bitrate);
}

return result;
}

bool DelayBasedBwe::UpdateEstimate(absl::optional<webrtc::DataRate> acked_bitrate,
webrtc::Timestamp at_time,
webrtc::DataRate* target_bitrate)
{
*target_bitrate = rate_control_.Update(acked_bitrate,
video_delay_detector_->State(), at_time);
return rate_control_.ValidEstimate();
}
// xrtcsdk_gcc\xrtc\rtc\modules\congestion_controller\goog_cc\aimd_rate_control.h
#include <api/units/data_rate.h>
#include <api/units/timestamp.h>
#include <api/network_state_predictor.h>
#include <absl/types/optional.h>

#include "xrtc/rtc/modules/congestion_controller/goog_cc/link_capacity_estimator.h"

namespace xrtc {

class AimdRateControl {
public:
AimdRateControl();
~AimdRateControl();

void SetStartBitrate(webrtc::DataRate start_bitrate);
bool ValidEstimate() const;

bool TimeToReduceFurther(webrtc::Timestamp at_time,
webrtc::DataRate estimated_throughput) const;
bool InitialTimeToReduceFurther(webrtc::Timestamp at_time) const;
webrtc::DataRate LatestEstimate() const;
void SetRtt(webrtc::TimeDelta rtt);
void SetEstimate(webrtc::DataRate new_bitrate, webrtc::Timestamp at_time);
webrtc::DataRate Update(absl::optional<webrtc::DataRate> throughput_estimate,
webrtc::BandwidthUsage state,
webrtc::Timestamp at_time);

private:
enum class RateControlState {
kRcHold, // 保持码率不变
kRcIncrease, // 增加码率
kRcDecrease, // 降低码率
};

webrtc::DataRate ClampBitrate(webrtc::DataRate new_bitrate);
webrtc::DataRate AdditiveRateIncrease(webrtc::Timestamp at_time,
webrtc::Timestamp last_time);
webrtc::DataRate MultiplicativeRateIncrease(webrtc::Timestamp at_time,
webrtc::Timestamp last_time);
double GetNearMaxIncreaseRateBpsPerSecond() const;
void ChangeBitrate(absl::optional<webrtc::DataRate> throughput_estimate,
webrtc::BandwidthUsage state,
webrtc::Timestamp at_time);
void ChangeState(webrtc::BandwidthUsage state,
webrtc::Timestamp at_time);

private:
webrtc::DataRate min_config_bitrate_;
webrtc::DataRate max_config_bitrate_;
webrtc::DataRate current_bitrate_;
webrtc::DataRate latest_estimated_throughput_;
bool bitrate_is_init_ = false;
webrtc::TimeDelta rtt_;
double beta_;
webrtc::Timestamp time_last_bitrate_change_ = webrtc::Timestamp::MinusInfinity();
webrtc::Timestamp time_last_bitrate_decrease_ = webrtc::Timestamp::MinusInfinity();
webrtc::Timestamp time_first_throughput_estimate_ = webrtc::Timestamp::MinusInfinity();
RateControlState rate_control_state_ = RateControlState::kRcHold;
LinkCapacityEstimator link_capacity_;
};

} // namespace xrtc
// xrtcsdk_gcc\xrtc\rtc\modules\congestion_controller\goog_cc\aimd_rate_control.cpp
#include "xrtc/rtc/modules/congestion_controller/goog_cc/aimd_rate_control.h"
#include <rtc_base/logging.h>

namespace xrtc {
namespace {

constexpr webrtc::TimeDelta kDefaultRtt = webrtc::TimeDelta::Millis(200);
const double kDefaultBackOffFractor = 0.85;

} // namespace

AimdRateControl::AimdRateControl() :
min_config_bitrate_(webrtc::DataRate::KilobitsPerSec(5)),
max_config_bitrate_(webrtc::DataRate::KilobitsPerSec(30000)),
current_bitrate_(max_config_bitrate_),
latest_estimated_throughput_(current_bitrate_),
rtt_(kDefaultRtt),
beta_(kDefaultBackOffFractor)
{
}

AimdRateControl::~AimdRateControl() {
}

void AimdRateControl::SetStartBitrate(webrtc::DataRate start_bitrate) {
current_bitrate_ = start_bitrate;
bitrate_is_init_ = true;
}

bool AimdRateControl::ValidEstimate() const {
return bitrate_is_init_;
}

bool AimdRateControl::TimeToReduceFurther(webrtc::Timestamp at_time,
webrtc::DataRate estimated_throughput) const
{
// 为了防止码率降低的过于频繁,需要控制码率降低的频率
// 两次码率降低的间隔,要大于1个RTT
webrtc::TimeDelta bitrate_reduction_interval =
rtt_.Clamped(webrtc::TimeDelta::Millis(10),
webrtc::TimeDelta::Millis(200));
if (at_time - time_last_bitrate_change_ >= rtt_) {
return true;
}

// 当前码率的一半必须要大于吞吐量,避免码率降得过低
if (ValidEstimate()) {
webrtc::DataRate threshold = LatestEstimate() * 0.5;
return estimated_throughput < threshold;
}

return false;
}

bool AimdRateControl::InitialTimeToReduceFurther(
webrtc::Timestamp at_time) const
{
return ValidEstimate() && TimeToReduceFurther(at_time,
LatestEstimate() / 2 - webrtc::DataRate::BitsPerSec(1));
}

webrtc::DataRate AimdRateControl::LatestEstimate() const {
return current_bitrate_;
}

void AimdRateControl::SetRtt(webrtc::TimeDelta rtt) {
rtt_ = rtt;
RTC_LOG(LS_WARNING) << "==========rtt: " << rtt.ms();
}

void AimdRateControl::SetEstimate(webrtc::DataRate new_bitrate,
webrtc::Timestamp at_time)
{
bitrate_is_init_ = true;
webrtc::DataRate prev_bitrate = current_bitrate_;
current_bitrate_ = ClampBitrate(new_bitrate);
time_last_bitrate_change_ = at_time;
if (current_bitrate_ < prev_bitrate) {
time_last_bitrate_decrease_ = at_time;
}
}

webrtc::DataRate AimdRateControl::Update(
absl::optional<webrtc::DataRate> throughput_estimate,
webrtc::BandwidthUsage state,
webrtc::Timestamp at_time)
{
if (!bitrate_is_init_) {
const webrtc::TimeDelta kInitTime = webrtc::TimeDelta::Seconds(5);
if (time_first_throughput_estimate_.IsInfinite()) {
time_first_throughput_estimate_ = at_time;
}
else if (at_time - time_first_throughput_estimate_ > kInitTime
&& throughput_estimate)
{
current_bitrate_ = *throughput_estimate;
bitrate_is_init_ = true;
}
}

ChangeBitrate(throughput_estimate, state, at_time);

return current_bitrate_;
}

webrtc::DataRate AimdRateControl::ClampBitrate(webrtc::DataRate new_bitrate) {
new_bitrate = std::max(new_bitrate, min_config_bitrate_);
return new_bitrate;
}

webrtc::DataRate AimdRateControl::AdditiveRateIncrease(
webrtc::Timestamp at_time,
webrtc::Timestamp last_time)
{
double time_delta_seconds =
(at_time - last_time).seconds<double>();
double increase_rate_bps =
GetNearMaxIncreaseRateBpsPerSecond() * time_delta_seconds;
return webrtc::DataRate::BitsPerSec(increase_rate_bps);
}

webrtc::DataRate AimdRateControl::MultiplicativeRateIncrease(
webrtc::Timestamp at_time,
webrtc::Timestamp last_time)
{
double alpha = 1.08;
if (last_time.IsFinite()) {
double time_since_last_update =
(at_time - last_time).seconds<double>();
alpha = pow(alpha, std::min(time_since_last_update, 1.0));
}

webrtc::DataRate multiplicative_increase =
std::max(current_bitrate_ * (alpha - 1.0),
webrtc::DataRate::BitsPerSec(1000));

return multiplicative_increase;
}

double AimdRateControl::GetNearMaxIncreaseRateBpsPerSecond() const {
const webrtc::TimeDelta kFrameInterval = webrtc::TimeDelta::Seconds(1) / 30;
webrtc::DataSize frame_size = current_bitrate_ * kFrameInterval;
const webrtc::DataSize packet_size = webrtc::DataSize::Bytes(1200);
double packets_per_frame = std::ceil(frame_size / packet_size);
webrtc::DataSize avg_packet_size = frame_size / packets_per_frame;

// 100ms表示网络过载时增加的延迟
webrtc::TimeDelta response_time = rtt_ + webrtc::TimeDelta::Millis(100);
double increase_rate_bps_per_second =
(avg_packet_size / response_time).bps<double>();
const double kMinIncreaseRateBps = 4000;

return std::max(kMinIncreaseRateBps, increase_rate_bps_per_second);
}

void AimdRateControl::ChangeBitrate(
absl::optional<webrtc::DataRate> acked_bitrate,
webrtc::BandwidthUsage state,
webrtc::Timestamp at_time)
{
absl::optional<webrtc::DataRate> new_bitrate;
webrtc::DataRate estimated_throughput =
acked_bitrate.value_or(latest_estimated_throughput_);
// 更新最新的吞吐量
if (acked_bitrate) {
latest_estimated_throughput_ = *acked_bitrate;
}

// 当前网络状态是过载状态,即使没有初始化起始码率,仍然需要降低码率
if (!bitrate_is_init_ && state != webrtc::BandwidthUsage::kBwOverusing) {
return;
}

ChangeState(state, at_time);

// 为了防止码率无限制的增加,码率增加的上限设置为吞吐量的1.5倍 + 10k
webrtc::DataRate throughput_base_limit =
estimated_throughput * 1.5 + webrtc::DataRate::KilobitsPerSec(10);

switch (rate_control_state_) {
case RateControlState::kRcHold:
break;
case RateControlState::kRcIncrease:
// 吞吐量已经超出了估计值的上限,估计值已经不可靠了,重置
if (estimated_throughput > link_capacity_.UpperBound()) {
link_capacity_.Reset();
}

if (current_bitrate_ < throughput_base_limit) {
webrtc::DataRate increased_bitrate = webrtc::DataRate::MinusInfinity();
// 如果当前的链路容量的估计值有效,表示我们的目标码率快接近最大容量
// 此时,码率的增加应该谨慎,采取加性增加的方式
if (link_capacity_.HasEstimate()) {
webrtc::DataRate additive_increase =
AdditiveRateIncrease(at_time, time_last_bitrate_change_);
increased_bitrate = current_bitrate_ + additive_increase;
RTC_LOG(LS_WARNING) << "**************add_increase: " << additive_increase.kbps()
<< ", increased_bitrate: " << increased_bitrate.kbps();
}
else {
// 当链路容量未知时,采用乘性增加码率的方式
// 以快速发现容量
webrtc::DataRate multiplicative_increase =
MultiplicativeRateIncrease(at_time, time_last_bitrate_change_);
increased_bitrate = current_bitrate_ + multiplicative_increase;
RTC_LOG(LS_WARNING) << "**************muliti_increase: " << multiplicative_increase.kbps()
<< ", increased_bitrate: " << increased_bitrate.kbps();
}

new_bitrate = std::min(increased_bitrate, throughput_base_limit);
}

time_last_bitrate_change_ = at_time;
break;
case RateControlState::kRcDecrease:
{
webrtc::DataRate decreased_bitrate = webrtc::DataRate::PlusInfinity();
decreased_bitrate = estimated_throughput * beta_;
if (decreased_bitrate > current_bitrate_) {
if (link_capacity_.HasEstimate()) {
decreased_bitrate = link_capacity_.estimate() * beta_;
}
}

// 避免码率下降逻辑,当前码率反而升高了
if (decreased_bitrate < current_bitrate_) {
new_bitrate = decreased_bitrate;
RTC_LOG(LS_WARNING) << "**************decreased_bitrate: " << decreased_bitrate.kbps();
}

// 吞吐量已经超出了估计值的下限,估计值已经不可靠了,重置
if (estimated_throughput < link_capacity_.LowerBound()) {
link_capacity_.Reset();
}

link_capacity_.OnOveruseDetected(estimated_throughput);
bitrate_is_init_ = true;
rate_control_state_ = RateControlState::kRcHold;
time_last_bitrate_change_ = at_time;
time_last_bitrate_decrease_ = at_time;
}
break;
default:
break;
}

current_bitrate_ = ClampBitrate(new_bitrate.value_or(current_bitrate_));
}

void AimdRateControl::ChangeState(webrtc::BandwidthUsage state,
webrtc::Timestamp at_time)
{
switch (state) {
case webrtc::BandwidthUsage::kBwNormal:
if (rate_control_state_ == RateControlState::kRcHold) {
rate_control_state_ = RateControlState::kRcIncrease;
time_last_bitrate_change_ = at_time;
}
break;
case webrtc::BandwidthUsage::kBwOverusing:
if (rate_control_state_ != RateControlState::kRcDecrease) {
rate_control_state_ = RateControlState::kRcDecrease;
}
break;
case webrtc::BandwidthUsage::kBwUnderusing:
rate_control_state_ = RateControlState::kRcHold;
break;
default:
break;
}
}

} // namespace xrtc

基于延迟的带宽估计
http://example.com/2024/03/07/基于延迟的带宽估计/
作者
Nuts
发布于
2024年3月7日
许可协议