mirror of
				https://github.com/ossrs/srs.git
				synced 2025-03-09 15:49:59 +00:00 
			
		
		
		
	fix https://github.com/ossrs/srs/issues/3155 Build srt-1-fit fails with `standard attributes in middle of decl-specifiers` on GCC 12,Arch Linux. See https://github.com/Haivision/srt/releases/tag/v1.5.3
		
			
				
	
	
		
			256 lines
		
	
	
	
		
			8.2 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			256 lines
		
	
	
	
		
			8.2 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/*
 | 
						|
 * 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/.
 | 
						|
 * 
 | 
						|
 */
 | 
						|
 | 
						|
/*****************************************************************************
 | 
						|
Copyright (c) 2001 - 2011, The Board of Trustees of the University of Illinois.
 | 
						|
All rights reserved.
 | 
						|
 | 
						|
Redistribution and use in source and binary forms, with or without
 | 
						|
modification, are permitted provided that the following conditions are
 | 
						|
met:
 | 
						|
 | 
						|
* Redistributions of source code must retain the above
 | 
						|
  copyright notice, this list of conditions and the
 | 
						|
  following disclaimer.
 | 
						|
 | 
						|
* Redistributions in binary form must reproduce the
 | 
						|
  above copyright notice, this list of conditions
 | 
						|
  and the following disclaimer in the documentation
 | 
						|
  and/or other materials provided with the distribution.
 | 
						|
 | 
						|
* Neither the name of the University of Illinois
 | 
						|
  nor the names of its contributors may be used to
 | 
						|
  endorse or promote products derived from this
 | 
						|
  software without specific prior written permission.
 | 
						|
 | 
						|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 | 
						|
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 | 
						|
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 | 
						|
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 | 
						|
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 | 
						|
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 | 
						|
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 | 
						|
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 | 
						|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 | 
						|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 | 
						|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
						|
*****************************************************************************/
 | 
						|
 | 
						|
/*****************************************************************************
 | 
						|
written by
 | 
						|
   Yunhong Gu, last updated 01/22/2011
 | 
						|
modified by
 | 
						|
   Haivision Systems Inc.
 | 
						|
*****************************************************************************/
 | 
						|
 | 
						|
#include "platform_sys.h"
 | 
						|
 | 
						|
#include <cmath>
 | 
						|
#include <cstring>
 | 
						|
#include "common.h"
 | 
						|
#include "window.h"
 | 
						|
#include <algorithm>
 | 
						|
 | 
						|
using namespace std;
 | 
						|
using namespace srt::sync;
 | 
						|
 | 
						|
namespace srt
 | 
						|
{
 | 
						|
namespace ACKWindowTools
 | 
						|
{
 | 
						|
 | 
						|
void store(Seq* r_aSeq, const size_t size, int& r_iHead, int& r_iTail, int32_t seq, int32_t ack)
 | 
						|
{
 | 
						|
   r_aSeq[r_iHead].iACKSeqNo = seq;
 | 
						|
   r_aSeq[r_iHead].iACK = ack;
 | 
						|
   r_aSeq[r_iHead].tsTimeStamp = steady_clock::now();
 | 
						|
 | 
						|
   r_iHead = (r_iHead + 1) % size;
 | 
						|
 | 
						|
   // overwrite the oldest ACK since it is not likely to be acknowledged
 | 
						|
   if (r_iHead == r_iTail)
 | 
						|
      r_iTail = (r_iTail + 1) % size;
 | 
						|
}
 | 
						|
 | 
						|
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)
 | 
						|
{
 | 
						|
   // Head has not exceeded the physical boundary of the window
 | 
						|
   if (r_iHead >= r_iTail)
 | 
						|
   {
 | 
						|
      for (int i = r_iTail, n = r_iHead; i < n; ++ i)
 | 
						|
      {
 | 
						|
         // Looking for an identical ACK Seq. No.
 | 
						|
         if (seq == r_aSeq[i].iACKSeqNo)
 | 
						|
         {
 | 
						|
            // Return the Data ACK it carried
 | 
						|
            r_ack = r_aSeq[i].iACK;
 | 
						|
 | 
						|
            // Calculate RTT estimate
 | 
						|
            const int rtt = (int)count_microseconds(currtime - r_aSeq[i].tsTimeStamp);
 | 
						|
 | 
						|
            if (i + 1 == r_iHead)
 | 
						|
            {
 | 
						|
               r_iTail = r_iHead = 0;
 | 
						|
               r_aSeq[0].iACKSeqNo = SRT_SEQNO_NONE;
 | 
						|
            }
 | 
						|
            else
 | 
						|
               r_iTail = (i + 1) % size;
 | 
						|
 | 
						|
            return rtt;
 | 
						|
         }
 | 
						|
      }
 | 
						|
 | 
						|
      // The record about ACK is not found in the buffer, RTT can not be calculated
 | 
						|
      return -1;
 | 
						|
   }
 | 
						|
 | 
						|
   // Head has exceeded the physical window boundary, so it is behind tail
 | 
						|
   for (int j = r_iTail, n = r_iHead + (int)size; j < n; ++ j)
 | 
						|
   {
 | 
						|
      // Looking for an identical ACK Seq. No.
 | 
						|
      if (seq == r_aSeq[j % size].iACKSeqNo)
 | 
						|
      {
 | 
						|
         // Return the Data ACK it carried
 | 
						|
         j %= size;
 | 
						|
         r_ack = r_aSeq[j].iACK;
 | 
						|
 | 
						|
         // Calculate RTT estimate
 | 
						|
         const int rtt = (int)count_microseconds(currtime - r_aSeq[j].tsTimeStamp);
 | 
						|
 | 
						|
         if (j == r_iHead)
 | 
						|
         {
 | 
						|
            r_iTail = r_iHead = 0;
 | 
						|
            r_aSeq[0].iACKSeqNo = -1;
 | 
						|
         }
 | 
						|
         else
 | 
						|
            r_iTail = (j + 1) % size;
 | 
						|
 | 
						|
         return rtt;
 | 
						|
      }
 | 
						|
   }
 | 
						|
 | 
						|
   // The record about ACK is not found in the buffer, RTT can not be calculated
 | 
						|
   return -1;
 | 
						|
}
 | 
						|
 | 
						|
} // namespace AckTools
 | 
						|
} // namespace srt
 | 
						|
 | 
						|
////////////////////////////////////////////////////////////////////////////////
 | 
						|
 | 
						|
void srt::CPktTimeWindowTools::initializeWindowArrays(int* r_pktWindow, int* r_probeWindow, int* r_bytesWindow, size_t asize, size_t psize)
 | 
						|
{
 | 
						|
   for (size_t i = 0; i < asize; ++ i)
 | 
						|
      r_pktWindow[i] = 1000000;   //1 sec -> 1 pkt/sec
 | 
						|
 | 
						|
   for (size_t k = 0; k < psize; ++ k)
 | 
						|
      r_probeWindow[k] = 1000;    //1 msec -> 1000 pkts/sec
 | 
						|
 | 
						|
   for (size_t i = 0; i < asize; ++ i)
 | 
						|
      r_bytesWindow[i] = srt::CPacket::SRT_MAX_PAYLOAD_SIZE; //based on 1 pkt/sec set in r_pktWindow[i]
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
int srt::CPktTimeWindowTools::getPktRcvSpeed_in(const int* window, int* replica, const int* abytes, size_t asize, int& bytesps)
 | 
						|
{
 | 
						|
   // get median value, but cannot change the original value order in the window
 | 
						|
   std::copy(window, window + asize, replica);
 | 
						|
   std::nth_element(replica, replica + (asize / 2), replica + asize);
 | 
						|
   //std::sort(replica, replica + asize);
 | 
						|
   int median = replica[asize / 2];
 | 
						|
 | 
						|
   unsigned count = 0;
 | 
						|
   int sum = 0;
 | 
						|
   int upper = median << 3;
 | 
						|
   int lower = median >> 3;
 | 
						|
 | 
						|
   bytesps = 0;
 | 
						|
   unsigned long bytes = 0;
 | 
						|
   const int* bp = abytes;
 | 
						|
   // median filtering
 | 
						|
   const int* p = window;
 | 
						|
   for (int i = 0, n = (int)asize; i < n; ++ i)
 | 
						|
   {
 | 
						|
      if ((*p < upper) && (*p > lower))
 | 
						|
      {
 | 
						|
         ++ count;  //packet counter
 | 
						|
         sum += *p; //usec counter
 | 
						|
         bytes += (unsigned long)*bp;   //byte counter
 | 
						|
      }
 | 
						|
      ++ p;     //advance packet pointer
 | 
						|
      ++ bp;    //advance bytes pointer
 | 
						|
   }
 | 
						|
 | 
						|
   // claculate speed, or return 0 if not enough valid value
 | 
						|
   if (count > (asize >> 1))
 | 
						|
   {
 | 
						|
      bytes += (srt::CPacket::SRT_DATA_HDR_SIZE * count); //Add protocol headers to bytes received
 | 
						|
      bytesps = (int)ceil(1000000.0 / (double(sum) / double(bytes)));
 | 
						|
      return (int)ceil(1000000.0 / (sum / count));
 | 
						|
   }
 | 
						|
   else
 | 
						|
   {
 | 
						|
      bytesps = 0;
 | 
						|
      return 0;
 | 
						|
   }
 | 
						|
}
 | 
						|
 | 
						|
int srt::CPktTimeWindowTools::getBandwidth_in(const int* window, int* replica, size_t psize)
 | 
						|
{
 | 
						|
    // This calculation does more-less the following:
 | 
						|
    //
 | 
						|
    // 1. Having example window:
 | 
						|
    //  - 50, 51, 100, 55, 80, 1000, 600, 1500, 1200, 10, 90
 | 
						|
    // 2. This window is now sorted, but we only know the value in the middle:
 | 
						|
    //  - 10, 50, 51, 55, 80, [[90]], 100, 600, 1000, 1200, 1500
 | 
						|
    // 3. Now calculate:
 | 
						|
    //   - lower: 90/8 = 11.25
 | 
						|
    //   - upper: 90*8 = 720
 | 
						|
    // 4. Now calculate the arithmetic median from all these values,
 | 
						|
    //    but drop those from outside the <lower, upper> range:
 | 
						|
    //  - 10, (11<) [ 50, 51, 55, 80, 90, 100, 600, ] (>720) 1000, 1200, 1500
 | 
						|
    // 5. Calculate the median from the extracted range,
 | 
						|
    //    NOTE: the median is actually repeated once, so size is +1.
 | 
						|
    //
 | 
						|
    //    values = { 50, 51, 55, 80, 90, 100, 600 };
 | 
						|
    //    sum = 90 + accumulate(values); ==> 1026
 | 
						|
    //    median = sum/(1 + values.size()); ==> 147
 | 
						|
    //
 | 
						|
    // For comparison: the overall arithmetic median from this window == 430
 | 
						|
    //
 | 
						|
    // 6. Returned value = 1M/median
 | 
						|
 | 
						|
   // get median value, but cannot change the original value order in the window
 | 
						|
   std::copy(window, window + psize - 1, replica);
 | 
						|
   std::nth_element(replica, replica + (psize / 2), replica + psize - 1);
 | 
						|
   //std::sort(replica, replica + psize); <--- was used for debug, just leave it as a mark
 | 
						|
   int median = replica[psize / 2];
 | 
						|
 | 
						|
   int count = 1;
 | 
						|
   int sum = median;
 | 
						|
   int upper = median << 3; // median*8
 | 
						|
   int lower = median >> 3; // median/8
 | 
						|
 | 
						|
   // median filtering
 | 
						|
   const int* p = window;
 | 
						|
   for (int i = 0, n = (int)psize; i < n; ++ i)
 | 
						|
   {
 | 
						|
      if ((*p < upper) && (*p > lower))
 | 
						|
      {
 | 
						|
         ++ count;
 | 
						|
         sum += *p;
 | 
						|
      }
 | 
						|
      ++ p;
 | 
						|
   }
 | 
						|
 | 
						|
   return (int)ceil(1000000.0 / (double(sum) / double(count)));
 | 
						|
}
 | 
						|
 | 
						|
 |