-
Notifications
You must be signed in to change notification settings - Fork 840
/
congctl.cpp
663 lines (562 loc) · 24.2 KB
/
congctl.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
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
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
/*
* SRT - Secure, Reliable, Transport
* Copyright (c) 2018 Haivision Systems Inc.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
*/
// This is a controversial thing, so temporarily blocking
//#define SRT_ENABLE_SYSTEMBUFFER_TRACE
#include "platform_sys.h"
#ifdef SRT_ENABLE_SYSTEMBUFFER_TRACE
#if defined(unix)
// XXX will be nonportable
#include <sys/ioctl.h>
#endif
#endif
#include <string>
#include <cmath>
#include "common.h"
#include "core.h"
#include "queue.h"
#include "packet.h"
#include "congctl.h"
#include "logging.h"
using namespace std;
using namespace srt::sync;
using namespace srt_logging;
namespace srt {
SrtCongestionControlBase::SrtCongestionControlBase(CUDT* parent)
{
m_parent = parent;
m_dMaxCWndSize = m_parent->flowWindowSize();
// RcvRate (deliveryRate()), RTT and Bandwidth can be read directly from CUDT when needed.
m_dCWndSize = 1000;
m_dPktSndPeriod = 1;
}
void SrtCongestion::Check()
{
if (!congctl)
throw CUDTException(MJ_CONNECTION, MN_NOCONN, 0);
}
// Useful macro to shorthand passing a method as argument
// Requires "Me" name by which a class refers to itself
#define SSLOT(method) EventSlot(this, &Me:: method)
class LiveCC: public SrtCongestionControlBase
{
int64_t m_llSndMaxBW; //Max bandwidth (bytes/sec)
srt::sync::atomic<size_t> m_zSndAvgPayloadSize; //Average Payload Size of packets to xmit
size_t m_zMaxPayloadSize;
size_t m_zHeaderSize;
// NAKREPORT stuff.
int m_iMinNakInterval_us; // Minimum NAK Report Period (usec)
int m_iNakReportAccel; // NAK Report Period (RTT) accelerator
typedef LiveCC Me; // required for SSLOT macro
public:
LiveCC(CUDT* parent)
: SrtCongestionControlBase(parent)
{
m_llSndMaxBW = BW_INFINITE; // 1 Gbbps in Bytes/sec BW_INFINITE
m_zMaxPayloadSize = parent->OPT_PayloadSize();
if (m_zMaxPayloadSize == 0)
m_zMaxPayloadSize = parent->maxPayloadSize();
m_zSndAvgPayloadSize = m_zMaxPayloadSize;
m_zHeaderSize = parent->m_config.iMSS - parent->maxPayloadSize();
m_iMinNakInterval_us = 20000; //Minimum NAK Report Period (usec)
m_iNakReportAccel = 2; //Default NAK Report Period (RTT) accelerator (send periodic NAK every RTT/2)
HLOGC(cclog.Debug, log << "Creating LiveCC: bw=" << m_llSndMaxBW << " avgplsize=" << m_zSndAvgPayloadSize);
updatePktSndPeriod();
// NOTE: TEV_SEND gets dispatched from Sending thread, all others
// from receiving thread.
parent->ConnectSignal(TEV_SEND, SSLOT(updatePayloadSize));
//
// Adjust the max SndPeriod onACK and onTimeout.
//
parent->ConnectSignal(TEV_CHECKTIMER, SSLOT(onRTO));
parent->ConnectSignal(TEV_ACK, SSLOT(onAck));
}
bool checkTransArgs(SrtCongestion::TransAPI api, SrtCongestion::TransDir dir, const char* , size_t size, int , bool ) ATR_OVERRIDE
{
if (api != SrtCongestion::STA_MESSAGE)
{
LOGC(cclog.Error, log << "LiveCC: invalid API use. Only sendmsg/recvmsg allowed.");
return false;
}
if (dir == SrtCongestion::STAD_SEND)
{
// For sending, check if the size of data doesn't exceed the maximum live packet size.
if (size > m_zMaxPayloadSize)
{
LOGC(cclog.Error, log << "LiveCC: payload size: " << size << " exceeds maximum allowed " << m_zMaxPayloadSize);
return false;
}
}
else
{
// For receiving, check if the buffer has enough space to keep the payload.
if (size < m_zMaxPayloadSize)
{
LOGC(cclog.Error, log << "LiveCC: buffer size: " << size << " is too small for the maximum possible " << m_zMaxPayloadSize);
return false;
}
}
return true;
}
// XXX You can decide here if the not-fully-packed packet should require immediate ACK or not.
// bool needsQuickACK(const CPacket& pkt) ATR_OVERRIDE
virtual int64_t sndBandwidth() ATR_OVERRIDE { return m_llSndMaxBW; }
private:
// SLOTS:
// TEV_SEND -> CPacket*.
void updatePayloadSize(ETransmissionEvent, EventVariant var)
{
const CPacket& packet = *var.get<EventVariant::PACKET>();
// XXX NOTE: TEV_SEND is sent from CSndQueue::worker thread, which is
// different to threads running any other events (TEV_CHECKTIMER and TEV_ACK).
// The m_zSndAvgPayloadSize field is however left unguarded because
// there's no other modifier of this field.
// Worst case scenario, the procedure running in CRcvQueue::worker
// thread will pick up a "slightly outdated" average value from this
// field - this is insignificant.
m_zSndAvgPayloadSize = avg_iir<128, size_t>(m_zSndAvgPayloadSize, packet.getLength());
HLOGC(cclog.Debug, log << "LiveCC: avg payload size updated: " << m_zSndAvgPayloadSize);
}
/// @brief On RTO event update an inter-packet send interval.
/// @param arg EventVariant::STAGE to distinguish between INIT and actual RTO.
void onRTO(ETransmissionEvent , EventVariant var)
{
if (var.get<EventVariant::STAGE>() != TEV_CHT_INIT )
updatePktSndPeriod();
}
/// @brief Handle an incoming ACK event.
/// Mainly updates a send interval between packets relying on the maximum BW limit.
void onAck(ETransmissionEvent, EventVariant )
{
updatePktSndPeriod();
}
/// @brief Updates a send interval between packets relying on the maximum BW limit.
void updatePktSndPeriod()
{
// packet = payload + header
const double pktsize = (double) m_zSndAvgPayloadSize.load() + m_zHeaderSize;
m_dPktSndPeriod = 1000 * 1000.0 * (pktsize / m_llSndMaxBW);
HLOGC(cclog.Debug, log << "LiveCC: sending period updated: " << m_dPktSndPeriod
<< " by avg pktsize=" << m_zSndAvgPayloadSize
<< ", bw=" << m_llSndMaxBW);
}
void setMaxBW(int64_t maxbw)
{
m_llSndMaxBW = maxbw > 0 ? maxbw : BW_INFINITE;
updatePktSndPeriod();
/*
* UDT default flow control should not trigger under normal SRT operation
* UDT stops sending if the number of packets in transit (not acknowledged)
* is larger than the congestion window.
* Up to SRT 1.0.6, this value was set at 1000 pkts, which may be insufficient
* for satellite links with ~1000 msec RTT and high bit rate.
*/
// XXX Consider making this a socket option.
m_dCWndSize = m_dMaxCWndSize;
}
void updateBandwidth(int64_t maxbw, int64_t bw) ATR_OVERRIDE
{
// bw is the bandwidth calculated with regard to the
// SRTO_INPUTBW and SRTO_OHEADBW parameters. The maxbw
// value simply represents the SRTO_MAXBW setting.
if (maxbw)
{
setMaxBW(maxbw);
return;
}
if (bw == 0)
{
return;
}
setMaxBW(bw);
}
SrtCongestion::RexmitMethod rexmitMethod() ATR_OVERRIDE
{
return SrtCongestion::SRM_FASTREXMIT;
}
int64_t updateNAKInterval(int64_t nakint_us, int /*rcv_speed*/, size_t /*loss_length*/) ATR_OVERRIDE
{
/*
* duB:
* The RTT accounts for the time for the last NAK to reach sender and start resending lost pkts.
* The rcv_speed add the time to resend all the pkts in the loss list.
*
* For realtime Transport Stream content, pkts/sec is not a good indication of time to transmit
* since packets are not filled to m_iMSS and packet size average is lower than (7*188)
* for low bit rates.
* If NAK report is lost, another cycle (RTT) is required which is bad for low latency so we
* accelerate the NAK Reports frequency, at the cost of possible duplicate resend.
* Finally, the UDT4 native minimum NAK interval (m_ullMinNakInt_tk) is 300 ms which is too high
* (~10 i30 video frames) to maintain low latency.
*/
// Note: this value will still be reshaped to defined minimum,
// as per minNAKInterval.
return nakint_us / m_iNakReportAccel;
}
int64_t minNAKInterval() ATR_OVERRIDE
{
return m_iMinNakInterval_us;
}
};
class FileCC : public SrtCongestionControlBase
{
typedef FileCC Me; // Required by SSLOT macro
// Fields from CUDTCC
int m_iRCInterval; // UDT Rate control interval
steady_clock::time_point m_LastRCTime; // last rate increase time
bool m_bSlowStart; // if in slow start phase
int32_t m_iLastAck; // last ACKed seq no
bool m_bLoss; // if loss happened since last rate increase
int32_t m_iLastDecSeq; // max pkt seq no sent out when last decrease happened
double m_dLastDecPeriod; // value of pktsndperiod when last decrease happened
int m_iNAKCount; // NAK counter
int m_iDecRandom; // random threshold on decrease by number of loss events
int m_iAvgNAKNum; // average number of NAKs per congestion
int m_iDecCount; // number of decreases in a congestion epoch
int64_t m_maxSR;
public:
FileCC(CUDT* parent)
: SrtCongestionControlBase(parent)
, m_iRCInterval(CUDT::COMM_SYN_INTERVAL_US)
, m_LastRCTime(steady_clock::now())
, m_bSlowStart(true)
, m_iLastAck(parent->sndSeqNo())
, m_bLoss(false)
, m_iLastDecSeq(CSeqNo::decseq(m_iLastAck))
, m_dLastDecPeriod(1)
, m_iNAKCount(0)
, m_iDecRandom(1)
, m_iAvgNAKNum(0)
, m_iDecCount(0)
, m_maxSR(0)
{
// Note that this function is called at the moment of
// calling m_Smoother.configure(this). It is placed more less
// at the same position as the series-of-parameter-setting-then-init
// in the original UDT code. So, old CUDTCC::init() can be moved
// to constructor.
// SmotherBase
m_dCWndSize = 16;
m_dPktSndPeriod = 1;
parent->ConnectSignal(TEV_ACK, SSLOT(onACK));
parent->ConnectSignal(TEV_LOSSREPORT, SSLOT(onLossReport));
parent->ConnectSignal(TEV_CHECKTIMER, SSLOT(onRTO));
HLOGC(cclog.Debug, log << "Creating FileCC");
}
bool checkTransArgs(SrtCongestion::TransAPI, SrtCongestion::TransDir, const char*, size_t, int, bool) ATR_OVERRIDE
{
// XXX
// The FileCC has currently no restrictions, although it should be
// rather required that the "message" mode or "buffer" mode be used on both sides the same.
// This must be somehow checked separately.
return true;
}
/// Tells if an early ACK is needed (before the next Full ACK happening every 10ms).
/// In FileCC, treat non-full-payload as an end-of-message (stream)
/// and request ACK to be sent immediately.
bool needsQuickACK(const CPacket& pkt) ATR_OVERRIDE
{
if (pkt.getLength() < m_parent->maxPayloadSize())
{
// This is not a regular fixed size packet...
// an irregular sized packet usually indicates the end of a message, so send an ACK immediately
return true;
}
return false;
}
void updateBandwidth(int64_t maxbw, int64_t) ATR_OVERRIDE
{
if (maxbw != 0)
{
m_maxSR = maxbw;
HLOGC(cclog.Debug, log << "FileCC: updated BW: " << m_maxSR);
}
}
private:
/// Handle icoming ACK event.
/// In slow start stage increase CWND. Leave slow start once maximum CWND is reached.
/// In congestion avoidance stage adjust inter packet send interval value to achieve maximum rate.
void onACK(ETransmissionEvent, EventVariant arg)
{
const int ack = arg.get<EventVariant::ACK>();
const steady_clock::time_point currtime = steady_clock::now();
if (count_microseconds(currtime - m_LastRCTime) < m_iRCInterval)
return;
m_LastRCTime = currtime;
if (m_bSlowStart)
{
m_dCWndSize += CSeqNo::seqlen(m_iLastAck, ack);
m_iLastAck = ack;
if (m_dCWndSize > m_dMaxCWndSize)
{
m_bSlowStart = false;
if (m_parent->deliveryRate() > 0)
{
m_dPktSndPeriod = 1000000.0 / m_parent->deliveryRate();
HLOGC(cclog.Debug, log << "FileCC: UPD (slowstart:ENDED) wndsize="
<< m_dCWndSize << "/" << m_dMaxCWndSize
<< " sndperiod=" << m_dPktSndPeriod << "us = 1M/("
<< m_parent->deliveryRate() << " pkts/s)");
}
else
{
m_dPktSndPeriod = m_dCWndSize / (m_parent->SRTT() + m_iRCInterval);
HLOGC(cclog.Debug, log << "FileCC: UPD (slowstart:ENDED) wndsize="
<< m_dCWndSize << "/" << m_dMaxCWndSize
<< " sndperiod=" << m_dPktSndPeriod << "us = wndsize/(RTT+RCIV) RTT="
<< m_parent->SRTT() << " RCIV=" << m_iRCInterval);
}
}
else
{
HLOGC(cclog.Debug, log << "FileCC: UPD (slowstart:KEPT) wndsize="
<< m_dCWndSize << "/" << m_dMaxCWndSize
<< " sndperiod=" << m_dPktSndPeriod << "us");
}
}
else
{
m_dCWndSize = m_parent->deliveryRate() / 1000000.0 * (m_parent->SRTT() + m_iRCInterval) + 16;
HLOGC(cclog.Debug, log << "FileCC: UPD (speed mode) wndsize="
<< m_dCWndSize << "/" << m_dMaxCWndSize << " RTT = " << m_parent->SRTT()
<< " sndperiod=" << m_dPktSndPeriod << "us. deliverRate = "
<< m_parent->deliveryRate() << " pkts/s)");
}
if (!m_bSlowStart)
{
if (m_bLoss)
{
m_bLoss = false;
}
// During Slow Start, no rate increase
else
{
double inc = 0;
const int loss_bw = static_cast<int>(2 * (1000000 / m_dLastDecPeriod)); // 2 times last loss point
const int bw_pktps = min(loss_bw, m_parent->bandwidth());
int64_t B = (int64_t)(bw_pktps - 1000000.0 / m_dPktSndPeriod);
if ((m_dPktSndPeriod > m_dLastDecPeriod) && ((bw_pktps / 9) < B))
B = bw_pktps / 9;
if (B <= 0)
inc = 1.0 / m_parent->MSS();
else
{
// inc = max(10 ^ ceil(log10( B * MSS * 8 ) * Beta / MSS, 1/MSS)
// Beta = 1.5 * 10^(-6)
inc = pow(10.0, ceil(log10(B * m_parent->MSS() * 8.0))) * 0.0000015 / m_parent->MSS();
inc = max(inc, 1.0 / m_parent->MSS());
}
HLOGC(cclog.Debug, log << "FileCC: UPD (slowstart:OFF) loss_bw=" << loss_bw
<< " bandwidth=" << m_parent->bandwidth() << " inc=" << inc
<< " m_dPktSndPeriod=" << m_dPktSndPeriod
<< "->" << (m_dPktSndPeriod * m_iRCInterval) / (m_dPktSndPeriod * inc + m_iRCInterval));
m_dPktSndPeriod = (m_dPktSndPeriod * m_iRCInterval) / (m_dPktSndPeriod * inc + m_iRCInterval);
}
}
#if ENABLE_HEAVY_LOGGING
// Try to do reverse-calculation for m_dPktSndPeriod, as per minSP below
// sndperiod = mega / (maxbw / MSS)
// 1/sndperiod = (maxbw/MSS) / mega
// mega/sndperiod = maxbw/MSS
// maxbw = (MSS*mega)/sndperiod
uint64_t usedbw = (m_parent->MSS() * 1000000.0) / m_dPktSndPeriod;
#if defined(unix) && defined (SRT_ENABLE_SYSTEMBUFFER_TRACE)
// Check the outgoing system queue level
int udp_buffer_size = m_parent->sndQueue()->sockoptQuery(SOL_SOCKET, SO_SNDBUF);
int udp_buffer_level = m_parent->sndQueue()->ioctlQuery(TIOCOUTQ);
int udp_buffer_free = udp_buffer_size - udp_buffer_level;
#else
int udp_buffer_free = -1;
#endif
HLOGC(cclog.Debug, log << "FileCC: UPD (slowstart:"
<< (m_bSlowStart ? "ON" : "OFF") << ") wndsize=" << m_dCWndSize
<< " sndperiod=" << m_dPktSndPeriod << "us BANDWIDTH USED:" << usedbw << " (limit: " << m_maxSR << ")"
" SYSTEM BUFFER LEFT: " << udp_buffer_free);
#endif
//set maximum transfer rate
if (m_maxSR)
{
double minSP = 1000000.0 / (double(m_maxSR) / m_parent->MSS());
if (m_dPktSndPeriod < minSP)
{
m_dPktSndPeriod = minSP;
HLOGC(cclog.Debug, log << "FileCC: BW limited to " << m_maxSR
<< " - SLOWDOWN sndperiod=" << m_dPktSndPeriod << "us");
}
}
}
/// When a lossreport has been received, it might be due to having
/// reached the available bandwidth limit. Slowdown to avoid further losses.
/// Leave the slow start stage if it was active.
void onLossReport(ETransmissionEvent, EventVariant arg)
{
const int32_t* losslist = arg.get_ptr();
size_t losslist_size = arg.get_len();
// Sanity check. Should be impossible that TEV_LOSSREPORT event
// is called with a nonempty loss list.
if (losslist_size == 0)
{
LOGC(cclog.Error, log << "IPE: FileCC: empty loss list!");
return;
}
//Slow Start stopped, if it hasn't yet
if (m_bSlowStart)
{
m_bSlowStart = false;
if (m_parent->deliveryRate() > 0)
{
m_dPktSndPeriod = 1000000.0 / m_parent->deliveryRate();
HLOGC(cclog.Debug, log << "FileCC: LOSS, SLOWSTART:OFF, sndperiod=" << m_dPktSndPeriod << "us AS mega/rate (rate="
<< m_parent->deliveryRate() << ")");
}
else
{
m_dPktSndPeriod = m_dCWndSize / (m_parent->SRTT() + m_iRCInterval);
HLOGC(cclog.Debug, log << "FileCC: LOSS, SLOWSTART:OFF, sndperiod=" << m_dPktSndPeriod << "us AS wndsize/(RTT+RCIV) (RTT="
<< m_parent->SRTT() << " RCIV=" << m_iRCInterval << ")");
}
}
m_bLoss = true;
// TODO: const int pktsInFlight = CSeqNo::seqoff(m_iLastAck, m_parent->sndSeqNo());
const int pktsInFlight = static_cast<int>(m_parent->SRTT() / m_dPktSndPeriod);
const int numPktsLost = m_parent->sndLossLength();
const int lost_pcent_x10 = pktsInFlight > 0 ? (numPktsLost * 1000) / pktsInFlight : 0;
HLOGC(cclog.Debug, log << "FileCC: LOSS: "
<< "sent=" << CSeqNo::seqlen(m_iLastAck, m_parent->sndSeqNo()) << ", inFlight=" << pktsInFlight
<< ", lost=" << numPktsLost << " ("
<< lost_pcent_x10 / 10 << "." << lost_pcent_x10 % 10 << "%)");
if (lost_pcent_x10 < 20) // 2.0%
{
HLOGC(cclog.Debug, log << "FileCC: LOSS: m_dLastDecPeriod=" << m_dLastDecPeriod << "->" << m_dPktSndPeriod);
m_dLastDecPeriod = m_dPktSndPeriod;
return;
}
// In contradiction to UDT, TEV_LOSSREPORT will be reported also when
// the lossreport is being sent again, periodically, as a result of
// NAKREPORT feature. You should make sure that NAKREPORT is off when
// using FileCC, so relying on SRTO_TRANSTYPE rather than
// just SRTO_CONGESTION is recommended.
int32_t lossbegin = SEQNO_VALUE::unwrap(losslist[0]);
if (CSeqNo::seqcmp(lossbegin, m_iLastDecSeq) > 0)
{
m_dLastDecPeriod = m_dPktSndPeriod;
m_dPktSndPeriod = ceil(m_dPktSndPeriod * 1.03);
const double loss_share_factor = 0.03;
m_iAvgNAKNum = (int)ceil(m_iAvgNAKNum * (1 - loss_share_factor) + m_iNAKCount * loss_share_factor);
m_iNAKCount = 1;
m_iDecCount = 1;
m_iLastDecSeq = m_parent->sndSeqNo();
m_iDecRandom = m_iAvgNAKNum > 1 ? genRandomInt(1, m_iAvgNAKNum) : 1;
SRT_ASSERT(m_iDecRandom >= 1);
HLOGC(cclog.Debug, log << "FileCC: LOSS:NEW lseqno=" << lossbegin
<< ", lastsentseqno=" << m_iLastDecSeq
<< ", seqdiff=" << CSeqNo::seqoff(m_iLastDecSeq, lossbegin)
<< ", rand=" << m_iDecRandom
<< " avg NAK:" << m_iAvgNAKNum
<< ", sndperiod=" << m_dPktSndPeriod << "us");
}
else if ((m_iDecCount++ < 5) && (0 == (++m_iNAKCount % m_iDecRandom)))
{
// 0.875^5 = 0.51, rate should not be decreased by more than half within a congestion period
m_dPktSndPeriod = ceil(m_dPktSndPeriod * 1.03);
m_iLastDecSeq = m_parent->sndSeqNo();
HLOGC(cclog.Debug, log << "FileCC: LOSS:PERIOD lseqno=" << lossbegin
<< ", lastsentseqno=" << m_iLastDecSeq
<< ", seqdiff=" << CSeqNo::seqoff(m_iLastDecSeq, lossbegin)
<< ", deccnt=" << m_iDecCount
<< ", decrnd=" << m_iDecRandom
<< ", sndperiod=" << m_dPktSndPeriod << "us");
}
else
{
HLOGC(cclog.Debug, log << "FileCC: LOSS:STILL lseqno=" << lossbegin
<< ", lastsentseqno=" << m_iLastDecSeq
<< ", seqdiff=" << CSeqNo::seqoff(m_iLastDecSeq, lossbegin)
<< ", deccnt=" << m_iDecCount
<< ", decrnd=" << m_iDecRandom
<< ", sndperiod=" << m_dPktSndPeriod << "us");
}
}
/// @brief On retransmission timeout leave slow start stage if it was active.
/// @param arg EventVariant::STAGE to distinguish between INIT and actual RTO.
void onRTO(ETransmissionEvent, EventVariant arg)
{
ECheckTimerStage stg = arg.get<EventVariant::STAGE>();
// TEV_INIT is in the beginning of checkTimers(), used
// only to synchronize back the values (which is done in updateCC
// after emitting the signal).
if (stg == TEV_CHT_INIT)
return;
if (m_bSlowStart)
{
m_bSlowStart = false;
if (m_parent->deliveryRate() > 0)
{
m_dPktSndPeriod = 1000000.0 / m_parent->deliveryRate();
HLOGC(cclog.Debug, log << "FileCC: CHKTIMER, SLOWSTART:OFF, sndperiod=" << m_dPktSndPeriod << "us AS mega/rate (rate="
<< m_parent->deliveryRate() << ")");
}
else
{
m_dPktSndPeriod = m_dCWndSize / (m_parent->SRTT() + m_iRCInterval);
HLOGC(cclog.Debug, log << "FileCC: CHKTIMER, SLOWSTART:OFF, sndperiod=" << m_dPktSndPeriod << "us AS wndsize/(RTT+RCIV) (wndsize="
<< m_dCWndSize << " RTT=" << m_parent->SRTT() << " RCIV=" << m_iRCInterval << ")");
}
}
else
{
// XXX This code is a copy of legacy CUDTCC::onTimeout() body.
// This part was commented out there already.
/*
m_dLastDecPeriod = m_dPktSndPeriod;
m_dPktSndPeriod = ceil(m_dPktSndPeriod * 2);
m_iLastDecSeq = m_iLastAck;
*/
}
}
SrtCongestion::RexmitMethod rexmitMethod() ATR_OVERRIDE
{
return SrtCongestion::SRM_LATEREXMIT;
}
};
#undef SSLOT
template <class Target>
struct Creator
{
static SrtCongestionControlBase* Create(CUDT* parent) { return new Target(parent); }
};
SrtCongestion::NamePtr SrtCongestion::congctls[N_CONTROLLERS] =
{
{"live", Creator<LiveCC>::Create },
{"file", Creator<FileCC>::Create }
};
bool SrtCongestion::configure(CUDT* parent)
{
if (selector == N_CONTROLLERS)
return false;
// Found a congctl, so call the creation function
congctl = (*congctls[selector].second)(parent);
// The congctl should have pinned in all events
// that are of its interest. It's stated that
// it's ready after creation.
return !!congctl;
}
void SrtCongestion::dispose()
{
if (congctl)
{
delete congctl;
congctl = 0;
}
}
SrtCongestion::~SrtCongestion()
{
dispose();
}
} // namespace srt