window.cpp 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  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. /*****************************************************************************
  11. Copyright (c) 2001 - 2011, The Board of Trustees of the University of Illinois.
  12. All rights reserved.
  13. Redistribution and use in source and binary forms, with or without
  14. modification, are permitted provided that the following conditions are
  15. met:
  16. * Redistributions of source code must retain the above
  17. copyright notice, this list of conditions and the
  18. following disclaimer.
  19. * Redistributions in binary form must reproduce the
  20. above copyright notice, this list of conditions
  21. and the following disclaimer in the documentation
  22. and/or other materials provided with the distribution.
  23. * Neither the name of the University of Illinois
  24. nor the names of its contributors may be used to
  25. endorse or promote products derived from this
  26. software without specific prior written permission.
  27. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  28. IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  29. THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  30. PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  31. CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  32. EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  33. PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  34. PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  35. LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  36. NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  37. SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  38. *****************************************************************************/
  39. /*****************************************************************************
  40. written by
  41. Yunhong Gu, last updated 01/22/2011
  42. modified by
  43. Haivision Systems Inc.
  44. *****************************************************************************/
  45. #include "platform_sys.h"
  46. #include <cmath>
  47. #include <cstring>
  48. #include "common.h"
  49. #include "window.h"
  50. #include <algorithm>
  51. using namespace std;
  52. using namespace srt::sync;
  53. namespace srt
  54. {
  55. namespace ACKWindowTools
  56. {
  57. void store(Seq* r_aSeq, const size_t size, int& r_iHead, int& r_iTail, int32_t seq, int32_t ack)
  58. {
  59. r_aSeq[r_iHead].iACKSeqNo = seq;
  60. r_aSeq[r_iHead].iACK = ack;
  61. r_aSeq[r_iHead].tsTimeStamp = steady_clock::now();
  62. r_iHead = (r_iHead + 1) % size;
  63. // overwrite the oldest ACK since it is not likely to be acknowledged
  64. if (r_iHead == r_iTail)
  65. r_iTail = (r_iTail + 1) % size;
  66. }
  67. int acknowledge(Seq* r_aSeq, const size_t size, int& r_iHead, int& r_iTail, int32_t seq, int32_t& r_ack, const steady_clock::time_point& currtime)
  68. {
  69. // Head has not exceeded the physical boundary of the window
  70. if (r_iHead >= r_iTail)
  71. {
  72. for (int i = r_iTail, n = r_iHead; i < n; ++ i)
  73. {
  74. // Looking for an identical ACK Seq. No.
  75. if (seq == r_aSeq[i].iACKSeqNo)
  76. {
  77. // Return the Data ACK it carried
  78. r_ack = r_aSeq[i].iACK;
  79. // Calculate RTT estimate
  80. const int rtt = (int)count_microseconds(currtime - r_aSeq[i].tsTimeStamp);
  81. if (i + 1 == r_iHead)
  82. {
  83. r_iTail = r_iHead = 0;
  84. r_aSeq[0].iACKSeqNo = SRT_SEQNO_NONE;
  85. }
  86. else
  87. r_iTail = (i + 1) % size;
  88. return rtt;
  89. }
  90. }
  91. // The record about ACK is not found in the buffer, RTT can not be calculated
  92. return -1;
  93. }
  94. // Head has exceeded the physical window boundary, so it is behind tail
  95. for (int j = r_iTail, n = r_iHead + (int)size; j < n; ++ j)
  96. {
  97. // Looking for an identical ACK Seq. No.
  98. if (seq == r_aSeq[j % size].iACKSeqNo)
  99. {
  100. // Return the Data ACK it carried
  101. j %= size;
  102. r_ack = r_aSeq[j].iACK;
  103. // Calculate RTT estimate
  104. const int rtt = (int)count_microseconds(currtime - r_aSeq[j].tsTimeStamp);
  105. if (j == r_iHead)
  106. {
  107. r_iTail = r_iHead = 0;
  108. r_aSeq[0].iACKSeqNo = -1;
  109. }
  110. else
  111. r_iTail = (j + 1) % size;
  112. return rtt;
  113. }
  114. }
  115. // The record about ACK is not found in the buffer, RTT can not be calculated
  116. return -1;
  117. }
  118. } // namespace AckTools
  119. } // namespace srt
  120. ////////////////////////////////////////////////////////////////////////////////
  121. void srt::CPktTimeWindowTools::initializeWindowArrays(int* r_pktWindow, int* r_probeWindow, int* r_bytesWindow, size_t asize, size_t psize)
  122. {
  123. for (size_t i = 0; i < asize; ++ i)
  124. r_pktWindow[i] = 1000000; //1 sec -> 1 pkt/sec
  125. for (size_t k = 0; k < psize; ++ k)
  126. r_probeWindow[k] = 1000; //1 msec -> 1000 pkts/sec
  127. for (size_t i = 0; i < asize; ++ i)
  128. r_bytesWindow[i] = srt::CPacket::SRT_MAX_PAYLOAD_SIZE; //based on 1 pkt/sec set in r_pktWindow[i]
  129. }
  130. int srt::CPktTimeWindowTools::getPktRcvSpeed_in(const int* window, int* replica, const int* abytes, size_t asize, int& bytesps)
  131. {
  132. // get median value, but cannot change the original value order in the window
  133. std::copy(window, window + asize, replica);
  134. std::nth_element(replica, replica + (asize / 2), replica + asize);
  135. //std::sort(replica, replica + asize);
  136. int median = replica[asize / 2];
  137. unsigned count = 0;
  138. int sum = 0;
  139. int upper = median << 3;
  140. int lower = median >> 3;
  141. bytesps = 0;
  142. unsigned long bytes = 0;
  143. const int* bp = abytes;
  144. // median filtering
  145. const int* p = window;
  146. for (int i = 0, n = (int)asize; i < n; ++ i)
  147. {
  148. if ((*p < upper) && (*p > lower))
  149. {
  150. ++ count; //packet counter
  151. sum += *p; //usec counter
  152. bytes += (unsigned long)*bp; //byte counter
  153. }
  154. ++ p; //advance packet pointer
  155. ++ bp; //advance bytes pointer
  156. }
  157. // claculate speed, or return 0 if not enough valid value
  158. if (count > (asize >> 1))
  159. {
  160. bytes += (srt::CPacket::SRT_DATA_HDR_SIZE * count); //Add protocol headers to bytes received
  161. bytesps = (int)ceil(1000000.0 / (double(sum) / double(bytes)));
  162. return (int)ceil(1000000.0 / (sum / count));
  163. }
  164. else
  165. {
  166. bytesps = 0;
  167. return 0;
  168. }
  169. }
  170. int srt::CPktTimeWindowTools::getBandwidth_in(const int* window, int* replica, size_t psize)
  171. {
  172. // This calculation does more-less the following:
  173. //
  174. // 1. Having example window:
  175. // - 50, 51, 100, 55, 80, 1000, 600, 1500, 1200, 10, 90
  176. // 2. This window is now sorted, but we only know the value in the middle:
  177. // - 10, 50, 51, 55, 80, [[90]], 100, 600, 1000, 1200, 1500
  178. // 3. Now calculate:
  179. // - lower: 90/8 = 11.25
  180. // - upper: 90*8 = 720
  181. // 4. Now calculate the arithmetic median from all these values,
  182. // but drop those from outside the <lower, upper> range:
  183. // - 10, (11<) [ 50, 51, 55, 80, 90, 100, 600, ] (>720) 1000, 1200, 1500
  184. // 5. Calculate the median from the extracted range,
  185. // NOTE: the median is actually repeated once, so size is +1.
  186. //
  187. // values = { 50, 51, 55, 80, 90, 100, 600 };
  188. // sum = 90 + accumulate(values); ==> 1026
  189. // median = sum/(1 + values.size()); ==> 147
  190. //
  191. // For comparison: the overall arithmetic median from this window == 430
  192. //
  193. // 6. Returned value = 1M/median
  194. // get median value, but cannot change the original value order in the window
  195. std::copy(window, window + psize - 1, replica);
  196. std::nth_element(replica, replica + (psize / 2), replica + psize - 1);
  197. //std::sort(replica, replica + psize); <--- was used for debug, just leave it as a mark
  198. int median = replica[psize / 2];
  199. int count = 1;
  200. int sum = median;
  201. int upper = median << 3; // median*8
  202. int lower = median >> 3; // median/8
  203. // median filtering
  204. const int* p = window;
  205. for (int i = 0, n = (int)psize; i < n; ++ i)
  206. {
  207. if ((*p < upper) && (*p > lower))
  208. {
  209. ++ count;
  210. sum += *p;
  211. }
  212. ++ p;
  213. }
  214. return (int)ceil(1000000.0 / (double(sum) / double(count)));
  215. }