ScreamCongestionController.cpp 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. //
  2. // Created by Grishka on 25/02/2019.
  3. //
  4. #include <algorithm>
  5. #include <math.h>
  6. #include "ScreamCongestionController.h"
  7. #include "../logging.h"
  8. #include "../VoIPController.h"
  9. using namespace tgvoip;
  10. using namespace tgvoip::video;
  11. namespace{
  12. /*static*/ constexpr float QDELAY_TARGET_LO=0.1f; // seconds
  13. /*static*/ constexpr float QDELAY_TARGET_HI=0.4f; // seconds
  14. /*static*/ constexpr float QDELAY_WEIGHT=0.1f;
  15. /*static*/ constexpr float QDELAY_TREND_TH=0.2f;
  16. /*static*/ constexpr uint32_t MIN_CWND=3000; // bytes
  17. /*static*/ constexpr float MAX_BYTES_IN_FLIGHT_HEAD_ROOM=1.1f;
  18. /*static*/ constexpr float GAIN=1.0f;
  19. /*static*/ constexpr float BETA_LOSS=0.8f;
  20. /*static*/ constexpr float BETA_ECN=0.9f;
  21. /*static*/ constexpr float BETA_R=0.9f;
  22. /*static*/ constexpr uint32_t MSS=1024;
  23. /*static*/ constexpr float RATE_ADJUST_INTERVAL=0.2f;
  24. /*static*/ constexpr uint32_t TARGET_BITRATE_MIN=50*1024; // bps
  25. /*static*/ constexpr uint32_t TARGET_BITRATE_MAX=500*1024; // bps
  26. /*static*/ constexpr uint32_t RAMP_UP_SPEED=200000; // bps/s
  27. /*static*/ constexpr float PRE_CONGESTION_GUARD=0.1f;
  28. /*static*/ constexpr float TX_QUEUE_SIZE_FACTOR=1.0f;
  29. /*static*/ constexpr float RTP_QDELAY_TH=0.02f; // seconds
  30. /*static*/ constexpr float TARGET_RATE_SCALE_RTP_QDELAY=0.95f;
  31. /*static*/ constexpr float QDELAY_TREND_LO=0.2f;
  32. /*static*/ constexpr float T_RESUME_FAST_INCREASE=5.0f; // seconds
  33. /*static*/ constexpr uint32_t RATE_PACE_MIN=50000; // bps
  34. }
  35. ScreamCongestionController::ScreamCongestionController() : qdelayTarget(QDELAY_TARGET_LO), cwnd(MIN_CWND) {
  36. }
  37. void ScreamCongestionController::UpdateVariables(float qdelay){
  38. float qdelayFraction=qdelay/qdelayTarget;
  39. qdelayFractionAvg=(1.0f-QDELAY_WEIGHT)*qdelayFractionAvg+qdelayFraction*QDELAY_WEIGHT;
  40. qdelayFractionHist.Add(qdelayFraction);
  41. float avg=qdelayFractionHist.Average();
  42. float r1=0.0, r0=0.0;
  43. for(int i=(int)qdelayFractionHist.Size()-1;i>=0;i--){
  44. float v=qdelayFractionHist[i]-avg;
  45. r0+=v*v;
  46. }
  47. for(int i=(int)qdelayFractionHist.Size()-1;i>=1;i--){
  48. float v1=qdelayFractionHist[i]-avg;
  49. float v2=qdelayFractionHist[i-1]-avg;
  50. r1+=v1*v2;
  51. }
  52. float a=r1/r0;
  53. qdelayTrend=std::min(1.0f, std::max(0.0f, a*qdelayFractionAvg));
  54. qdelayTrendMem=std::max(0.99f*qdelayTrendMem, qdelayTrend);
  55. if(qdelayTrend>QDELAY_TREND_LO){
  56. lastTimeQDelayTrendWasGreaterThanLo=VoIPController::GetCurrentTime();
  57. }
  58. }
  59. void ScreamCongestionController::UpdateCWnd(float qdelay){
  60. if(inFastIncrease){
  61. if(qdelayTrend>=QDELAY_TREND_TH){
  62. inFastIncrease=false;
  63. }else{
  64. if((float)bytesInFlight*1.5f+bytesNewlyAcked>cwnd){
  65. LOGD("HERE");
  66. cwnd+=bytesNewlyAcked;
  67. }
  68. return;
  69. }
  70. }
  71. float offTarget=(qdelayTarget-qdelay)/qdelayTarget;
  72. float gain=GAIN;
  73. float cwndDelta=gain*offTarget*bytesNewlyAcked*MSS/(float)cwnd;
  74. if(offTarget>0 && (float)bytesInFlight*1.25f+bytesNewlyAcked<=cwnd){
  75. cwndDelta=0.0;
  76. }
  77. cwnd+=cwndDelta;
  78. cwnd=std::min(cwnd, (uint32_t)(maxBytesInFlight*MAX_BYTES_IN_FLIGHT_HEAD_ROOM));
  79. cwnd=std::max(cwnd, MIN_CWND);
  80. }
  81. void ScreamCongestionController::AdjustQDelayTarget(float qdelay){
  82. float qdelayNorm=qdelay/QDELAY_TARGET_LO;
  83. qdelayNormHist.Add(qdelayNorm);
  84. float qdelayNormAvg=qdelayNormHist.Average();
  85. float qdelayNormVar=0.0;
  86. for(uint32_t i=0;i<qdelayNormHist.Size();i++){
  87. float tmp=qdelayNormHist[i]-qdelayNormAvg;
  88. qdelayNormVar+=tmp*tmp;
  89. }
  90. qdelayNormVar/=qdelayNormHist.Size();
  91. float newTarget=qdelayNormAvg+sqrt(qdelayNormVar);
  92. newTarget*=QDELAY_TARGET_LO;
  93. if(lossEventRate>0.002f){
  94. qdelayTarget=1.5f*newTarget;
  95. }else{
  96. if(qdelayNormVar<0.2f){
  97. qdelayTarget=newTarget;
  98. }else{
  99. if(newTarget<QDELAY_TARGET_LO){
  100. qdelayTarget=std::max(qdelayTarget*0.5f, newTarget);
  101. }else{
  102. qdelayTarget*=0.9;
  103. }
  104. }
  105. }
  106. qdelayTarget=std::min(QDELAY_TARGET_HI, qdelayTarget);
  107. qdelayTarget=std::max(QDELAY_TARGET_LO, qdelayTarget);
  108. }
  109. void ScreamCongestionController::AdjustBitrate(){
  110. if(lossPending){
  111. lossPending=false;
  112. targetBitrate=std::max((uint32_t)(BETA_R*(float)targetBitrate), TARGET_BITRATE_MIN);
  113. return;
  114. }
  115. float rampUpSpeed=std::min(RAMP_UP_SPEED, targetBitrate/2);
  116. float scale=(float)(targetBitrate-targetBitrateLastMax)/(float)targetBitrateLastMax;
  117. scale=std::max(0.2f, std::min(1.0f, (scale*4)*(scale*4)));
  118. float currentRate=std::max(rateTransmit, rateAck);
  119. if(inFastIncrease){
  120. float increment=(rampUpSpeed*RATE_ADJUST_INTERVAL)*scale;
  121. targetBitrate+=increment;
  122. }else{
  123. float deltaRate=currentRate*(1.0f-PRE_CONGESTION_GUARD*qdelayTrend)-TX_QUEUE_SIZE_FACTOR*(float)rtpQueueSize;
  124. if(deltaRate>0.0f){
  125. deltaRate*=scale;
  126. deltaRate=std::min(deltaRate, rampUpSpeed*RATE_ADJUST_INTERVAL);
  127. }
  128. targetBitrate+=deltaRate;
  129. float rtpQueueDelay=(float)rtpQueueSize/currentRate;
  130. if(rtpQueueDelay>RTP_QDELAY_TH){
  131. targetBitrate=(uint32_t)((float)targetBitrate*TARGET_RATE_SCALE_RTP_QDELAY);
  132. }
  133. }
  134. float rateMediaLimit=std::max(currentRate, std::max(rateMedia, rateMediaMedian));
  135. rateMediaLimit*=(2.0-qdelayTrendMem);
  136. targetBitrate=std::min(targetBitrate, (uint32_t)rateMediaLimit);
  137. targetBitrate=std::min(TARGET_BITRATE_MAX, std::max(TARGET_BITRATE_MIN, targetBitrate));
  138. }
  139. void ScreamCongestionController::CalculateSendWindow(float qdelay){
  140. if(qdelay<=qdelayTarget)
  141. sendWnd=cwnd+MSS-bytesInFlight;
  142. else
  143. sendWnd=cwnd-bytesInFlight;
  144. }
  145. void ScreamCongestionController::ProcessAcks(float oneWayDelay, uint32_t bytesNewlyAcked, uint32_t lossCount, double rtt){
  146. if(prevOneWayDelay!=0.0f){
  147. double currentTime=VoIPController::GetCurrentTime();
  148. float qdelay=oneWayDelay-prevOneWayDelay;
  149. sRTT=(float)rtt;
  150. bytesInFlight-=bytesNewlyAcked;
  151. rtpQueueSize-=(bytesNewlyAcked*8);
  152. UpdateBytesInFlightHistory();
  153. bytesAcked+=bytesNewlyAcked;
  154. //LOGV("Scream: qdelay = %f, newly acked = %u, in flight = %u, losses = %u", qdelay, bytesNewlyAcked, bytesInFlight, lossCount);
  155. if(currentTime-lastVariablesUpdateTime>=0.050){
  156. lastVariablesUpdateTime=currentTime;
  157. UpdateVariables(qdelay);
  158. }
  159. if(currentTime-lastRateAdjustmentTime>=RATE_ADJUST_INTERVAL){
  160. lastRateAdjustmentTime=currentTime;
  161. AdjustBitrate();
  162. //LOGV("Scream: target bitrate = %u", targetBitrate);
  163. }
  164. if(lossCount>prevLossCount && currentTime>ignoreLossesUntil){
  165. LOGD("Scream: loss detected");
  166. ignoreLossesUntil=currentTime+rtt;
  167. inFastIncrease=false;
  168. cwnd=std::max(MIN_CWND, (uint32_t)(cwnd*BETA_LOSS));
  169. AdjustQDelayTarget(qdelay);
  170. CalculateSendWindow(qdelay);
  171. lossPending=true;
  172. prevLossCount=lossCount;
  173. lastTimeQDelayTrendWasGreaterThanLo=currentTime;
  174. }else{
  175. this->bytesNewlyAcked+=bytesNewlyAcked;
  176. if(currentTime-lastCWndUpdateTime>=0.15){
  177. lastCWndUpdateTime=currentTime;
  178. UpdateCWnd(qdelay);
  179. //LOGI("Scream: cwnd = %u", cwnd);
  180. this->bytesNewlyAcked=0;
  181. }
  182. AdjustQDelayTarget(qdelay);
  183. CalculateSendWindow(qdelay);
  184. if(!inFastIncrease){
  185. if(currentTime-lastTimeQDelayTrendWasGreaterThanLo>=T_RESUME_FAST_INCREASE){
  186. inFastIncrease=true;
  187. }
  188. }
  189. }
  190. }
  191. prevOneWayDelay=oneWayDelay;
  192. }
  193. void ScreamCongestionController::ProcessPacketSent(uint32_t size){
  194. bytesInFlight+=size;
  195. rtpQueueSize+=(size*8);
  196. bytesSent+=size;
  197. double currentTime=VoIPController::GetCurrentTime();
  198. if(currentTime-rateTransmitUpdateTime>=0.2){
  199. rateTransmit=(float)(bytesSent*8)/(float)(currentTime-rateTransmitUpdateTime);
  200. rateAck=(float)(bytesAcked*8)/(float)(currentTime-rateTransmitUpdateTime);
  201. rateTransmitUpdateTime=currentTime;
  202. bytesSent=0;
  203. bytesAcked=0;
  204. //LOGV("rateTransmit %f, rateAck %f", rateTransmit, rateAck);
  205. }
  206. UpdateBytesInFlightHistory();
  207. }
  208. void ScreamCongestionController::ProcessPacketLost(uint32_t size){
  209. bytesInFlight-=size;
  210. rtpQueueSize-=(size*8);
  211. UpdateBytesInFlightHistory();
  212. }
  213. double ScreamCongestionController::GetPacingInterval(){
  214. float paceBitrate=std::max((float)RATE_PACE_MIN, cwnd*8.0f/sRTT);
  215. //LOGV("RTT=%f cwnd=%u paceBitrate=%f fastIncrease=%d", sRTT, cwnd, paceBitrate, inFastIncrease);
  216. double pacingInterval=rtpSize*8.0f/paceBitrate;
  217. return std::min(0.010, pacingInterval);
  218. }
  219. void ScreamCongestionController::UpdateBytesInFlightHistory(){
  220. double currentTime=VoIPController::GetCurrentTime();
  221. ValueSample now={bytesInFlight, currentTime};
  222. bytesInFlightHistory.push_back(now);
  223. uint32_t max=0;
  224. for(std::vector<ValueSample>::iterator i=bytesInFlightHistory.begin();i!=bytesInFlightHistory.end();){
  225. if(currentTime-i->time>=5.0){
  226. i=bytesInFlightHistory.erase(i);
  227. }else{
  228. max=std::max(max, i->sample);
  229. ++i;
  230. }
  231. }
  232. maxBytesInFlight=max;
  233. }
  234. void ScreamCongestionController::UpdateMediaRate(uint32_t frameSize){
  235. bytesMedia+=frameSize;
  236. double currentTime=VoIPController::GetCurrentTime();
  237. if(currentTime-rateMediaUpdateTime>=0.5){
  238. rateMedia=(float)(bytesMedia*8)/(float)(currentTime-rateMediaUpdateTime);
  239. bytesMedia=0;
  240. rateMediaUpdateTime=currentTime;
  241. LOGV("rateMedia %f", rateMedia);
  242. rateMediaHistory.Add(rateMedia);
  243. rateMediaMedian=rateMediaHistory.NonZeroAverage();
  244. }
  245. }
  246. uint32_t ScreamCongestionController::GetBitrate(){
  247. return targetBitrate;
  248. }