congctl.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660
  1. /*
  2. * SRT - Secure, Reliable, Transport
  3. * Copyright (c) 2018 Haivision Systems Inc.
  4. *
  5. * This Source Code Form is subject to the terms of the Mozilla Public
  6. * License, v. 2.0. If a copy of the MPL was not distributed with this
  7. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  8. *
  9. */
  10. // This is a controversial thing, so temporarily blocking
  11. //#define SRT_ENABLE_SYSTEMBUFFER_TRACE
  12. #include "platform_sys.h"
  13. #ifdef SRT_ENABLE_SYSTEMBUFFER_TRACE
  14. #if defined(unix)
  15. // XXX will be nonportable
  16. #include <sys/ioctl.h>
  17. #endif
  18. #endif
  19. #include <string>
  20. #include <cmath>
  21. #include "common.h"
  22. #include "core.h"
  23. #include "queue.h"
  24. #include "packet.h"
  25. #include "congctl.h"
  26. #include "logging.h"
  27. using namespace std;
  28. using namespace srt::sync;
  29. using namespace srt_logging;
  30. namespace srt {
  31. SrtCongestionControlBase::SrtCongestionControlBase(CUDT* parent)
  32. {
  33. m_parent = parent;
  34. m_dMaxCWndSize = m_parent->flowWindowSize();
  35. // RcvRate (deliveryRate()), RTT and Bandwidth can be read directly from CUDT when needed.
  36. m_dCWndSize = 1000;
  37. m_dPktSndPeriod = 1;
  38. }
  39. void SrtCongestion::Check()
  40. {
  41. if (!congctl)
  42. throw CUDTException(MJ_CONNECTION, MN_NOCONN, 0);
  43. }
  44. // Useful macro to shorthand passing a method as argument
  45. // Requires "Me" name by which a class refers to itself
  46. #define SSLOT(method) EventSlot(this, &Me:: method)
  47. class LiveCC: public SrtCongestionControlBase
  48. {
  49. int64_t m_llSndMaxBW; //Max bandwidth (bytes/sec)
  50. srt::sync::atomic<size_t> m_zSndAvgPayloadSize; //Average Payload Size of packets to xmit
  51. size_t m_zMaxPayloadSize;
  52. // NAKREPORT stuff.
  53. int m_iMinNakInterval_us; // Minimum NAK Report Period (usec)
  54. int m_iNakReportAccel; // NAK Report Period (RTT) accelerator
  55. typedef LiveCC Me; // required for SSLOT macro
  56. public:
  57. LiveCC(CUDT* parent)
  58. : SrtCongestionControlBase(parent)
  59. {
  60. m_llSndMaxBW = BW_INFINITE; // 1 Gbbps in Bytes/sec BW_INFINITE
  61. m_zMaxPayloadSize = parent->OPT_PayloadSize();
  62. if (m_zMaxPayloadSize == 0)
  63. m_zMaxPayloadSize = parent->maxPayloadSize();
  64. m_zSndAvgPayloadSize = m_zMaxPayloadSize;
  65. m_iMinNakInterval_us = 20000; //Minimum NAK Report Period (usec)
  66. m_iNakReportAccel = 2; //Default NAK Report Period (RTT) accelerator (send periodic NAK every RTT/2)
  67. HLOGC(cclog.Debug, log << "Creating LiveCC: bw=" << m_llSndMaxBW << " avgplsize=" << m_zSndAvgPayloadSize);
  68. updatePktSndPeriod();
  69. // NOTE: TEV_SEND gets dispatched from Sending thread, all others
  70. // from receiving thread.
  71. parent->ConnectSignal(TEV_SEND, SSLOT(updatePayloadSize));
  72. //
  73. // Adjust the max SndPeriod onACK and onTimeout.
  74. //
  75. parent->ConnectSignal(TEV_CHECKTIMER, SSLOT(onRTO));
  76. parent->ConnectSignal(TEV_ACK, SSLOT(onAck));
  77. }
  78. bool checkTransArgs(SrtCongestion::TransAPI api, SrtCongestion::TransDir dir, const char* , size_t size, int , bool ) ATR_OVERRIDE
  79. {
  80. if (api != SrtCongestion::STA_MESSAGE)
  81. {
  82. LOGC(cclog.Error, log << "LiveCC: invalid API use. Only sendmsg/recvmsg allowed.");
  83. return false;
  84. }
  85. if (dir == SrtCongestion::STAD_SEND)
  86. {
  87. // For sending, check if the size of data doesn't exceed the maximum live packet size.
  88. if (size > m_zMaxPayloadSize)
  89. {
  90. LOGC(cclog.Error, log << "LiveCC: payload size: " << size << " exceeds maximum allowed " << m_zMaxPayloadSize);
  91. return false;
  92. }
  93. }
  94. else
  95. {
  96. // For receiving, check if the buffer has enough space to keep the payload.
  97. if (size < m_zMaxPayloadSize)
  98. {
  99. LOGC(cclog.Error, log << "LiveCC: buffer size: " << size << " is too small for the maximum possible " << m_zMaxPayloadSize);
  100. return false;
  101. }
  102. }
  103. return true;
  104. }
  105. // XXX You can decide here if the not-fully-packed packet should require immediate ACK or not.
  106. // bool needsQuickACK(const CPacket& pkt) ATR_OVERRIDE
  107. virtual int64_t sndBandwidth() ATR_OVERRIDE { return m_llSndMaxBW; }
  108. private:
  109. // SLOTS:
  110. // TEV_SEND -> CPacket*.
  111. void updatePayloadSize(ETransmissionEvent, EventVariant var)
  112. {
  113. const CPacket& packet = *var.get<EventVariant::PACKET>();
  114. // XXX NOTE: TEV_SEND is sent from CSndQueue::worker thread, which is
  115. // different to threads running any other events (TEV_CHECKTIMER and TEV_ACK).
  116. // The m_zSndAvgPayloadSize field is however left unguarded because
  117. // there's no other modifier of this field.
  118. // Worst case scenario, the procedure running in CRcvQueue::worker
  119. // thread will pick up a "slightly outdated" average value from this
  120. // field - this is insignificant.
  121. m_zSndAvgPayloadSize = avg_iir<128, size_t>(m_zSndAvgPayloadSize, packet.getLength());
  122. HLOGC(cclog.Debug, log << "LiveCC: avg payload size updated: " << m_zSndAvgPayloadSize);
  123. }
  124. /// @brief On RTO event update an inter-packet send interval.
  125. /// @param arg EventVariant::STAGE to distinguish between INIT and actual RTO.
  126. void onRTO(ETransmissionEvent , EventVariant var)
  127. {
  128. if (var.get<EventVariant::STAGE>() != TEV_CHT_INIT )
  129. updatePktSndPeriod();
  130. }
  131. /// @brief Handle an incoming ACK event.
  132. /// Mainly updates a send interval between packets relying on the maximum BW limit.
  133. void onAck(ETransmissionEvent, EventVariant )
  134. {
  135. updatePktSndPeriod();
  136. }
  137. /// @brief Updates a send interval between packets relying on the maximum BW limit.
  138. void updatePktSndPeriod()
  139. {
  140. // packet = payload + header
  141. const double pktsize = (double) m_zSndAvgPayloadSize.load() + CPacket::SRT_DATA_HDR_SIZE;
  142. m_dPktSndPeriod = 1000 * 1000.0 * (pktsize / m_llSndMaxBW);
  143. HLOGC(cclog.Debug, log << "LiveCC: sending period updated: " << m_dPktSndPeriod
  144. << " by avg pktsize=" << m_zSndAvgPayloadSize
  145. << ", bw=" << m_llSndMaxBW);
  146. }
  147. void setMaxBW(int64_t maxbw)
  148. {
  149. m_llSndMaxBW = maxbw > 0 ? maxbw : BW_INFINITE;
  150. updatePktSndPeriod();
  151. /*
  152. * UDT default flow control should not trigger under normal SRT operation
  153. * UDT stops sending if the number of packets in transit (not acknowledged)
  154. * is larger than the congestion window.
  155. * Up to SRT 1.0.6, this value was set at 1000 pkts, which may be insufficient
  156. * for satellite links with ~1000 msec RTT and high bit rate.
  157. */
  158. // XXX Consider making this a socket option.
  159. m_dCWndSize = m_dMaxCWndSize;
  160. }
  161. void updateBandwidth(int64_t maxbw, int64_t bw) ATR_OVERRIDE
  162. {
  163. // bw is the bandwidth calculated with regard to the
  164. // SRTO_INPUTBW and SRTO_OHEADBW parameters. The maxbw
  165. // value simply represents the SRTO_MAXBW setting.
  166. if (maxbw)
  167. {
  168. setMaxBW(maxbw);
  169. return;
  170. }
  171. if (bw == 0)
  172. {
  173. return;
  174. }
  175. setMaxBW(bw);
  176. }
  177. SrtCongestion::RexmitMethod rexmitMethod() ATR_OVERRIDE
  178. {
  179. return SrtCongestion::SRM_FASTREXMIT;
  180. }
  181. int64_t updateNAKInterval(int64_t nakint_us, int /*rcv_speed*/, size_t /*loss_length*/) ATR_OVERRIDE
  182. {
  183. /*
  184. * duB:
  185. * The RTT accounts for the time for the last NAK to reach sender and start resending lost pkts.
  186. * The rcv_speed add the time to resend all the pkts in the loss list.
  187. *
  188. * For realtime Transport Stream content, pkts/sec is not a good indication of time to transmit
  189. * since packets are not filled to m_iMSS and packet size average is lower than (7*188)
  190. * for low bit rates.
  191. * If NAK report is lost, another cycle (RTT) is required which is bad for low latency so we
  192. * accelerate the NAK Reports frequency, at the cost of possible duplicate resend.
  193. * Finally, the UDT4 native minimum NAK interval (m_ullMinNakInt_tk) is 300 ms which is too high
  194. * (~10 i30 video frames) to maintain low latency.
  195. */
  196. // Note: this value will still be reshaped to defined minimum,
  197. // as per minNAKInterval.
  198. return nakint_us / m_iNakReportAccel;
  199. }
  200. int64_t minNAKInterval() ATR_OVERRIDE
  201. {
  202. return m_iMinNakInterval_us;
  203. }
  204. };
  205. class FileCC : public SrtCongestionControlBase
  206. {
  207. typedef FileCC Me; // Required by SSLOT macro
  208. // Fields from CUDTCC
  209. int m_iRCInterval; // UDT Rate control interval
  210. steady_clock::time_point m_LastRCTime; // last rate increase time
  211. bool m_bSlowStart; // if in slow start phase
  212. int32_t m_iLastAck; // last ACKed seq no
  213. bool m_bLoss; // if loss happened since last rate increase
  214. int32_t m_iLastDecSeq; // max pkt seq no sent out when last decrease happened
  215. double m_dLastDecPeriod; // value of pktsndperiod when last decrease happened
  216. int m_iNAKCount; // NAK counter
  217. int m_iDecRandom; // random threshold on decrease by number of loss events
  218. int m_iAvgNAKNum; // average number of NAKs per congestion
  219. int m_iDecCount; // number of decreases in a congestion epoch
  220. int64_t m_maxSR;
  221. public:
  222. FileCC(CUDT* parent)
  223. : SrtCongestionControlBase(parent)
  224. , m_iRCInterval(CUDT::COMM_SYN_INTERVAL_US)
  225. , m_LastRCTime(steady_clock::now())
  226. , m_bSlowStart(true)
  227. , m_iLastAck(parent->sndSeqNo())
  228. , m_bLoss(false)
  229. , m_iLastDecSeq(CSeqNo::decseq(m_iLastAck))
  230. , m_dLastDecPeriod(1)
  231. , m_iNAKCount(0)
  232. , m_iDecRandom(1)
  233. , m_iAvgNAKNum(0)
  234. , m_iDecCount(0)
  235. , m_maxSR(0)
  236. {
  237. // Note that this function is called at the moment of
  238. // calling m_Smoother.configure(this). It is placed more less
  239. // at the same position as the series-of-parameter-setting-then-init
  240. // in the original UDT code. So, old CUDTCC::init() can be moved
  241. // to constructor.
  242. // SmotherBase
  243. m_dCWndSize = 16;
  244. m_dPktSndPeriod = 1;
  245. parent->ConnectSignal(TEV_ACK, SSLOT(onACK));
  246. parent->ConnectSignal(TEV_LOSSREPORT, SSLOT(onLossReport));
  247. parent->ConnectSignal(TEV_CHECKTIMER, SSLOT(onRTO));
  248. HLOGC(cclog.Debug, log << "Creating FileCC");
  249. }
  250. bool checkTransArgs(SrtCongestion::TransAPI, SrtCongestion::TransDir, const char*, size_t, int, bool) ATR_OVERRIDE
  251. {
  252. // XXX
  253. // The FileCC has currently no restrictions, although it should be
  254. // rather required that the "message" mode or "buffer" mode be used on both sides the same.
  255. // This must be somehow checked separately.
  256. return true;
  257. }
  258. /// Tells if an early ACK is needed (before the next Full ACK happening every 10ms).
  259. /// In FileCC, treat non-full-payload as an end-of-message (stream)
  260. /// and request ACK to be sent immediately.
  261. bool needsQuickACK(const CPacket& pkt) ATR_OVERRIDE
  262. {
  263. if (pkt.getLength() < m_parent->maxPayloadSize())
  264. {
  265. // This is not a regular fixed size packet...
  266. // an irregular sized packet usually indicates the end of a message, so send an ACK immediately
  267. return true;
  268. }
  269. return false;
  270. }
  271. void updateBandwidth(int64_t maxbw, int64_t) ATR_OVERRIDE
  272. {
  273. if (maxbw != 0)
  274. {
  275. m_maxSR = maxbw;
  276. HLOGC(cclog.Debug, log << "FileCC: updated BW: " << m_maxSR);
  277. }
  278. }
  279. private:
  280. /// Handle icoming ACK event.
  281. /// In slow start stage increase CWND. Leave slow start once maximum CWND is reached.
  282. /// In congestion avoidance stage adjust inter packet send interval value to achieve maximum rate.
  283. void onACK(ETransmissionEvent, EventVariant arg)
  284. {
  285. const int ack = arg.get<EventVariant::ACK>();
  286. const steady_clock::time_point currtime = steady_clock::now();
  287. if (count_microseconds(currtime - m_LastRCTime) < m_iRCInterval)
  288. return;
  289. m_LastRCTime = currtime;
  290. if (m_bSlowStart)
  291. {
  292. m_dCWndSize += CSeqNo::seqlen(m_iLastAck, ack);
  293. m_iLastAck = ack;
  294. if (m_dCWndSize > m_dMaxCWndSize)
  295. {
  296. m_bSlowStart = false;
  297. if (m_parent->deliveryRate() > 0)
  298. {
  299. m_dPktSndPeriod = 1000000.0 / m_parent->deliveryRate();
  300. HLOGC(cclog.Debug, log << "FileCC: UPD (slowstart:ENDED) wndsize="
  301. << m_dCWndSize << "/" << m_dMaxCWndSize
  302. << " sndperiod=" << m_dPktSndPeriod << "us = 1M/("
  303. << m_parent->deliveryRate() << " pkts/s)");
  304. }
  305. else
  306. {
  307. m_dPktSndPeriod = m_dCWndSize / (m_parent->SRTT() + m_iRCInterval);
  308. HLOGC(cclog.Debug, log << "FileCC: UPD (slowstart:ENDED) wndsize="
  309. << m_dCWndSize << "/" << m_dMaxCWndSize
  310. << " sndperiod=" << m_dPktSndPeriod << "us = wndsize/(RTT+RCIV) RTT="
  311. << m_parent->SRTT() << " RCIV=" << m_iRCInterval);
  312. }
  313. }
  314. else
  315. {
  316. HLOGC(cclog.Debug, log << "FileCC: UPD (slowstart:KEPT) wndsize="
  317. << m_dCWndSize << "/" << m_dMaxCWndSize
  318. << " sndperiod=" << m_dPktSndPeriod << "us");
  319. }
  320. }
  321. else
  322. {
  323. m_dCWndSize = m_parent->deliveryRate() / 1000000.0 * (m_parent->SRTT() + m_iRCInterval) + 16;
  324. HLOGC(cclog.Debug, log << "FileCC: UPD (speed mode) wndsize="
  325. << m_dCWndSize << "/" << m_dMaxCWndSize << " RTT = " << m_parent->SRTT()
  326. << " sndperiod=" << m_dPktSndPeriod << "us. deliverRate = "
  327. << m_parent->deliveryRate() << " pkts/s)");
  328. }
  329. if (!m_bSlowStart)
  330. {
  331. if (m_bLoss)
  332. {
  333. m_bLoss = false;
  334. }
  335. // During Slow Start, no rate increase
  336. else
  337. {
  338. double inc = 0;
  339. const int loss_bw = static_cast<int>(2 * (1000000 / m_dLastDecPeriod)); // 2 times last loss point
  340. const int bw_pktps = min(loss_bw, m_parent->bandwidth());
  341. int64_t B = (int64_t)(bw_pktps - 1000000.0 / m_dPktSndPeriod);
  342. if ((m_dPktSndPeriod > m_dLastDecPeriod) && ((bw_pktps / 9) < B))
  343. B = bw_pktps / 9;
  344. if (B <= 0)
  345. inc = 1.0 / m_parent->MSS();
  346. else
  347. {
  348. // inc = max(10 ^ ceil(log10( B * MSS * 8 ) * Beta / MSS, 1/MSS)
  349. // Beta = 1.5 * 10^(-6)
  350. inc = pow(10.0, ceil(log10(B * m_parent->MSS() * 8.0))) * 0.0000015 / m_parent->MSS();
  351. inc = max(inc, 1.0 / m_parent->MSS());
  352. }
  353. HLOGC(cclog.Debug, log << "FileCC: UPD (slowstart:OFF) loss_bw=" << loss_bw
  354. << " bandwidth=" << m_parent->bandwidth() << " inc=" << inc
  355. << " m_dPktSndPeriod=" << m_dPktSndPeriod
  356. << "->" << (m_dPktSndPeriod * m_iRCInterval) / (m_dPktSndPeriod * inc + m_iRCInterval));
  357. m_dPktSndPeriod = (m_dPktSndPeriod * m_iRCInterval) / (m_dPktSndPeriod * inc + m_iRCInterval);
  358. }
  359. }
  360. #if ENABLE_HEAVY_LOGGING
  361. // Try to do reverse-calculation for m_dPktSndPeriod, as per minSP below
  362. // sndperiod = mega / (maxbw / MSS)
  363. // 1/sndperiod = (maxbw/MSS) / mega
  364. // mega/sndperiod = maxbw/MSS
  365. // maxbw = (MSS*mega)/sndperiod
  366. uint64_t usedbw = (m_parent->MSS() * 1000000.0) / m_dPktSndPeriod;
  367. #if defined(unix) && defined (SRT_ENABLE_SYSTEMBUFFER_TRACE)
  368. // Check the outgoing system queue level
  369. int udp_buffer_size = m_parent->sndQueue()->sockoptQuery(SOL_SOCKET, SO_SNDBUF);
  370. int udp_buffer_level = m_parent->sndQueue()->ioctlQuery(TIOCOUTQ);
  371. int udp_buffer_free = udp_buffer_size - udp_buffer_level;
  372. #else
  373. int udp_buffer_free = -1;
  374. #endif
  375. HLOGC(cclog.Debug, log << "FileCC: UPD (slowstart:"
  376. << (m_bSlowStart ? "ON" : "OFF") << ") wndsize=" << m_dCWndSize
  377. << " sndperiod=" << m_dPktSndPeriod << "us BANDWIDTH USED:" << usedbw << " (limit: " << m_maxSR << ")"
  378. " SYSTEM BUFFER LEFT: " << udp_buffer_free);
  379. #endif
  380. //set maximum transfer rate
  381. if (m_maxSR)
  382. {
  383. double minSP = 1000000.0 / (double(m_maxSR) / m_parent->MSS());
  384. if (m_dPktSndPeriod < minSP)
  385. {
  386. m_dPktSndPeriod = minSP;
  387. HLOGC(cclog.Debug, log << "FileCC: BW limited to " << m_maxSR
  388. << " - SLOWDOWN sndperiod=" << m_dPktSndPeriod << "us");
  389. }
  390. }
  391. }
  392. /// When a lossreport has been received, it might be due to having
  393. /// reached the available bandwidth limit. Slowdown to avoid further losses.
  394. /// Leave the slow start stage if it was active.
  395. void onLossReport(ETransmissionEvent, EventVariant arg)
  396. {
  397. const int32_t* losslist = arg.get_ptr();
  398. size_t losslist_size = arg.get_len();
  399. // Sanity check. Should be impossible that TEV_LOSSREPORT event
  400. // is called with a nonempty loss list.
  401. if (losslist_size == 0)
  402. {
  403. LOGC(cclog.Error, log << "IPE: FileCC: empty loss list!");
  404. return;
  405. }
  406. //Slow Start stopped, if it hasn't yet
  407. if (m_bSlowStart)
  408. {
  409. m_bSlowStart = false;
  410. if (m_parent->deliveryRate() > 0)
  411. {
  412. m_dPktSndPeriod = 1000000.0 / m_parent->deliveryRate();
  413. HLOGC(cclog.Debug, log << "FileCC: LOSS, SLOWSTART:OFF, sndperiod=" << m_dPktSndPeriod << "us AS mega/rate (rate="
  414. << m_parent->deliveryRate() << ")");
  415. }
  416. else
  417. {
  418. m_dPktSndPeriod = m_dCWndSize / (m_parent->SRTT() + m_iRCInterval);
  419. HLOGC(cclog.Debug, log << "FileCC: LOSS, SLOWSTART:OFF, sndperiod=" << m_dPktSndPeriod << "us AS wndsize/(RTT+RCIV) (RTT="
  420. << m_parent->SRTT() << " RCIV=" << m_iRCInterval << ")");
  421. }
  422. }
  423. m_bLoss = true;
  424. // TODO: const int pktsInFlight = CSeqNo::seqoff(m_iLastAck, m_parent->sndSeqNo());
  425. const int pktsInFlight = static_cast<int>(m_parent->SRTT() / m_dPktSndPeriod);
  426. const int numPktsLost = m_parent->sndLossLength();
  427. const int lost_pcent_x10 = pktsInFlight > 0 ? (numPktsLost * 1000) / pktsInFlight : 0;
  428. HLOGC(cclog.Debug, log << "FileCC: LOSS: "
  429. << "sent=" << CSeqNo::seqlen(m_iLastAck, m_parent->sndSeqNo()) << ", inFlight=" << pktsInFlight
  430. << ", lost=" << numPktsLost << " ("
  431. << lost_pcent_x10 / 10 << "." << lost_pcent_x10 % 10 << "%)");
  432. if (lost_pcent_x10 < 20) // 2.0%
  433. {
  434. HLOGC(cclog.Debug, log << "FileCC: LOSS: m_dLastDecPeriod=" << m_dLastDecPeriod << "->" << m_dPktSndPeriod);
  435. m_dLastDecPeriod = m_dPktSndPeriod;
  436. return;
  437. }
  438. // In contradiction to UDT, TEV_LOSSREPORT will be reported also when
  439. // the lossreport is being sent again, periodically, as a result of
  440. // NAKREPORT feature. You should make sure that NAKREPORT is off when
  441. // using FileCC, so relying on SRTO_TRANSTYPE rather than
  442. // just SRTO_CONGESTION is recommended.
  443. int32_t lossbegin = SEQNO_VALUE::unwrap(losslist[0]);
  444. if (CSeqNo::seqcmp(lossbegin, m_iLastDecSeq) > 0)
  445. {
  446. m_dLastDecPeriod = m_dPktSndPeriod;
  447. m_dPktSndPeriod = ceil(m_dPktSndPeriod * 1.03);
  448. const double loss_share_factor = 0.03;
  449. m_iAvgNAKNum = (int)ceil(m_iAvgNAKNum * (1 - loss_share_factor) + m_iNAKCount * loss_share_factor);
  450. m_iNAKCount = 1;
  451. m_iDecCount = 1;
  452. m_iLastDecSeq = m_parent->sndSeqNo();
  453. m_iDecRandom = m_iAvgNAKNum > 1 ? genRandomInt(1, m_iAvgNAKNum) : 1;
  454. SRT_ASSERT(m_iDecRandom >= 1);
  455. HLOGC(cclog.Debug, log << "FileCC: LOSS:NEW lseqno=" << lossbegin
  456. << ", lastsentseqno=" << m_iLastDecSeq
  457. << ", seqdiff=" << CSeqNo::seqoff(m_iLastDecSeq, lossbegin)
  458. << ", rand=" << m_iDecRandom
  459. << " avg NAK:" << m_iAvgNAKNum
  460. << ", sndperiod=" << m_dPktSndPeriod << "us");
  461. }
  462. else if ((m_iDecCount++ < 5) && (0 == (++m_iNAKCount % m_iDecRandom)))
  463. {
  464. // 0.875^5 = 0.51, rate should not be decreased by more than half within a congestion period
  465. m_dPktSndPeriod = ceil(m_dPktSndPeriod * 1.03);
  466. m_iLastDecSeq = m_parent->sndSeqNo();
  467. HLOGC(cclog.Debug, log << "FileCC: LOSS:PERIOD lseqno=" << lossbegin
  468. << ", lastsentseqno=" << m_iLastDecSeq
  469. << ", seqdiff=" << CSeqNo::seqoff(m_iLastDecSeq, lossbegin)
  470. << ", deccnt=" << m_iDecCount
  471. << ", decrnd=" << m_iDecRandom
  472. << ", sndperiod=" << m_dPktSndPeriod << "us");
  473. }
  474. else
  475. {
  476. HLOGC(cclog.Debug, log << "FileCC: LOSS:STILL lseqno=" << lossbegin
  477. << ", lastsentseqno=" << m_iLastDecSeq
  478. << ", seqdiff=" << CSeqNo::seqoff(m_iLastDecSeq, lossbegin)
  479. << ", deccnt=" << m_iDecCount
  480. << ", decrnd=" << m_iDecRandom
  481. << ", sndperiod=" << m_dPktSndPeriod << "us");
  482. }
  483. }
  484. /// @brief On retransmission timeout leave slow start stage if it was active.
  485. /// @param arg EventVariant::STAGE to distinguish between INIT and actual RTO.
  486. void onRTO(ETransmissionEvent, EventVariant arg)
  487. {
  488. ECheckTimerStage stg = arg.get<EventVariant::STAGE>();
  489. // TEV_INIT is in the beginning of checkTimers(), used
  490. // only to synchronize back the values (which is done in updateCC
  491. // after emitting the signal).
  492. if (stg == TEV_CHT_INIT)
  493. return;
  494. if (m_bSlowStart)
  495. {
  496. m_bSlowStart = false;
  497. if (m_parent->deliveryRate() > 0)
  498. {
  499. m_dPktSndPeriod = 1000000.0 / m_parent->deliveryRate();
  500. HLOGC(cclog.Debug, log << "FileCC: CHKTIMER, SLOWSTART:OFF, sndperiod=" << m_dPktSndPeriod << "us AS mega/rate (rate="
  501. << m_parent->deliveryRate() << ")");
  502. }
  503. else
  504. {
  505. m_dPktSndPeriod = m_dCWndSize / (m_parent->SRTT() + m_iRCInterval);
  506. HLOGC(cclog.Debug, log << "FileCC: CHKTIMER, SLOWSTART:OFF, sndperiod=" << m_dPktSndPeriod << "us AS wndsize/(RTT+RCIV) (wndsize="
  507. << setprecision(6) << m_dCWndSize << " RTT=" << m_parent->SRTT() << " RCIV=" << m_iRCInterval << ")");
  508. }
  509. }
  510. else
  511. {
  512. // XXX This code is a copy of legacy CUDTCC::onTimeout() body.
  513. // This part was commented out there already.
  514. /*
  515. m_dLastDecPeriod = m_dPktSndPeriod;
  516. m_dPktSndPeriod = ceil(m_dPktSndPeriod * 2);
  517. m_iLastDecSeq = m_iLastAck;
  518. */
  519. }
  520. }
  521. SrtCongestion::RexmitMethod rexmitMethod() ATR_OVERRIDE
  522. {
  523. return SrtCongestion::SRM_LATEREXMIT;
  524. }
  525. };
  526. #undef SSLOT
  527. template <class Target>
  528. struct Creator
  529. {
  530. static SrtCongestionControlBase* Create(CUDT* parent) { return new Target(parent); }
  531. };
  532. SrtCongestion::NamePtr SrtCongestion::congctls[N_CONTROLLERS] =
  533. {
  534. {"live", Creator<LiveCC>::Create },
  535. {"file", Creator<FileCC>::Create }
  536. };
  537. bool SrtCongestion::configure(CUDT* parent)
  538. {
  539. if (selector == N_CONTROLLERS)
  540. return false;
  541. // Found a congctl, so call the creation function
  542. congctl = (*congctls[selector].second)(parent);
  543. // The congctl should have pinned in all events
  544. // that are of its interest. It's stated that
  545. // it's ready after creation.
  546. return !!congctl;
  547. }
  548. void SrtCongestion::dispose()
  549. {
  550. if (congctl)
  551. {
  552. delete congctl;
  553. congctl = 0;
  554. }
  555. }
  556. SrtCongestion::~SrtCongestion()
  557. {
  558. dispose();
  559. }
  560. } // namespace srt