mirror of
				https://github.com/ossrs/srs.git
				synced 2025-03-09 15:49:59 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			360 lines
		
	
	
	
		
			8.7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			360 lines
		
	
	
	
		
			8.7 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 02/21/2013
 | |
| modified by
 | |
|    Haivision Systems Inc.
 | |
| *****************************************************************************/
 | |
| 
 | |
| 
 | |
| #include "core.h"
 | |
| #include "ccc.h"
 | |
| #include <cmath>
 | |
| #include <cstring>
 | |
| 
 | |
| CCC::CCC():
 | |
| m_iSYNInterval(CUDT::m_iSYNInterval),
 | |
| m_dPktSndPeriod(1.0),
 | |
| m_dCWndSize(16.0),
 | |
| m_iBandwidth(),
 | |
| m_dMaxCWndSize(),
 | |
| m_iMSS(),
 | |
| m_iSndCurrSeqNo(),
 | |
| m_iRcvRate(),
 | |
| m_iRTT(),
 | |
| m_pcParam(NULL),
 | |
| m_iPSize(0),
 | |
| m_UDT(),
 | |
| m_iACKPeriod(0),
 | |
| m_iACKInterval(0),
 | |
| m_bUserDefinedRTO(false),
 | |
| m_iRTO(-1),
 | |
| m_PerfInfo()
 | |
| {
 | |
| }
 | |
| 
 | |
| CCC::~CCC()
 | |
| {
 | |
|    delete [] m_pcParam;
 | |
| }
 | |
| 
 | |
| void CCC::setACKTimer(int msINT)
 | |
| {
 | |
|    m_iACKPeriod = msINT > m_iSYNInterval ? m_iSYNInterval : msINT;
 | |
| }
 | |
| 
 | |
| void CCC::setACKInterval(int pktINT)
 | |
| {
 | |
|    m_iACKInterval = pktINT;
 | |
| }
 | |
| 
 | |
| void CCC::setRTO(int usRTO)
 | |
| {
 | |
|    m_bUserDefinedRTO = true;
 | |
|    m_iRTO = usRTO;
 | |
| }
 | |
| 
 | |
| void CCC::sendCustomMsg(CPacket& pkt) const
 | |
| {
 | |
|    CUDT* u = CUDT::getUDTHandle(m_UDT);
 | |
| 
 | |
|    if (NULL != u)
 | |
|    {
 | |
|       pkt.m_iID = u->m_PeerID;
 | |
| #ifdef SRT_ENABLE_CTRLTSTAMP
 | |
|       pkt.m_iTimeStamp = int(CTimer::getTime() - u->m_StartTime);
 | |
| #endif
 | |
|       u->m_pSndQueue->sendto(u->m_pPeerAddr, pkt);
 | |
|    }
 | |
| }
 | |
| 
 | |
| const CPerfMon* CCC::getPerfInfo()
 | |
| {
 | |
|    try
 | |
|    {
 | |
|       CUDT* u = CUDT::getUDTHandle(m_UDT);
 | |
|       if (NULL != u)
 | |
|          u->sample(&m_PerfInfo, false);
 | |
|    }
 | |
|    catch (...)
 | |
|    {
 | |
|       return NULL;
 | |
|    }
 | |
| 
 | |
|    return &m_PerfInfo;
 | |
| }
 | |
| 
 | |
| void CCC::setMSS(int mss)
 | |
| {
 | |
|    m_iMSS = mss;
 | |
| }
 | |
| 
 | |
| void CCC::setBandwidth(int bw)
 | |
| {
 | |
|    m_iBandwidth = bw;
 | |
| }
 | |
| 
 | |
| void CCC::setSndCurrSeqNo(int32_t seqno)
 | |
| {
 | |
|    m_iSndCurrSeqNo = seqno;
 | |
| }
 | |
| 
 | |
| void CCC::setRcvRate(int rcvrate)
 | |
| {
 | |
|    m_iRcvRate = rcvrate;
 | |
| }
 | |
| 
 | |
| void CCC::setMaxCWndSize(int cwnd)
 | |
| {
 | |
|    m_dMaxCWndSize = cwnd;
 | |
| }
 | |
| 
 | |
| void CCC::setRTT(int rtt)
 | |
| {
 | |
|    m_iRTT = rtt;
 | |
| }
 | |
| 
 | |
| void CCC::setUserParam(const char* param, int size)
 | |
| {
 | |
|    delete [] m_pcParam;
 | |
|    m_pcParam = new char[size];
 | |
|    memcpy(m_pcParam, param, size);
 | |
|    m_iPSize = size;
 | |
| }
 | |
| 
 | |
| //
 | |
| CUDTCC::CUDTCC():
 | |
| m_iRCInterval(),
 | |
| m_LastRCTime(),
 | |
| m_bSlowStart(),
 | |
| m_iLastAck(),
 | |
| m_bLoss(),
 | |
| m_iLastDecSeq(),
 | |
| m_dLastDecPeriod(),
 | |
| m_iNAKCount(),
 | |
| m_iDecRandom(),
 | |
| m_iAvgNAKNum(),
 | |
| m_iDecCount()
 | |
| {
 | |
| }
 | |
| 
 | |
| void CUDTCC::init()
 | |
| {
 | |
|    m_iRCInterval = m_iSYNInterval;
 | |
|    m_LastRCTime = CTimer::getTime();
 | |
|    setACKTimer(m_iRCInterval);
 | |
| 
 | |
|    m_bSlowStart = true;
 | |
|    m_iLastAck = m_iSndCurrSeqNo;
 | |
|    m_bLoss = false;
 | |
|    m_iLastDecSeq = CSeqNo::decseq(m_iLastAck);
 | |
|    m_dLastDecPeriod = 1;
 | |
|    m_iAvgNAKNum = 0;
 | |
|    m_iNAKCount = 0;
 | |
|    m_iDecRandom = 1;
 | |
| 
 | |
|    m_dCWndSize = 16;
 | |
|    m_dPktSndPeriod = 1;
 | |
| }
 | |
| 
 | |
| void CUDTCC::onACK(int32_t ack)
 | |
| {
 | |
|    int64_t B = 0;
 | |
|    double inc = 0;
 | |
|    // Note: 1/24/2012
 | |
|    // The minimum increase parameter is increased from "1.0 / m_iMSS" to 0.01
 | |
|    // because the original was too small and caused sending rate to stay at low level
 | |
|    // for long time.
 | |
|    const double min_inc = 0.01;
 | |
| 
 | |
|    uint64_t currtime = CTimer::getTime();
 | |
|    if (currtime - m_LastRCTime < (uint64_t)m_iRCInterval)
 | |
|       return;
 | |
| 
 | |
|    m_LastRCTime = currtime;
 | |
| 
 | |
| #ifdef SRT_ENABLE_BSTATS
 | |
|    //m_iRcvRate is bytes/sec
 | |
|    if (m_bSlowStart)
 | |
|    {
 | |
|       m_dCWndSize += CSeqNo::seqlen(m_iLastAck, ack);
 | |
|       m_iLastAck = ack;
 | |
| 
 | |
|       if (m_dCWndSize > m_dMaxCWndSize)
 | |
|       {
 | |
|          m_bSlowStart = false;
 | |
|          if (m_iRcvRate > 0)
 | |
|             m_dPktSndPeriod = 1000000.0 / ((m_iRcvRate + m_iMSS - 1) / m_iMSS);
 | |
|          else
 | |
|             m_dPktSndPeriod = (m_iRTT + m_iRCInterval) / m_dCWndSize;
 | |
|       }
 | |
|    }
 | |
|    else
 | |
|       m_dCWndSize = ((m_iRcvRate + m_iMSS -1) / m_iMSS) / 1000000.0 * (m_iRTT + m_iRCInterval) + 16;
 | |
| #else
 | |
|    if (m_bSlowStart)
 | |
|    {
 | |
|       m_dCWndSize += CSeqNo::seqlen(m_iLastAck, ack);
 | |
|       m_iLastAck = ack;
 | |
| 
 | |
|       if (m_dCWndSize > m_dMaxCWndSize)
 | |
|       {
 | |
|          m_bSlowStart = false;
 | |
|          if (m_iRcvRate > 0)
 | |
|             m_dPktSndPeriod = 1000000.0 / m_iRcvRate;
 | |
|          else
 | |
|             m_dPktSndPeriod = (m_iRTT + m_iRCInterval) / m_dCWndSize;
 | |
|       }
 | |
|    }
 | |
|    else
 | |
|       m_dCWndSize = m_iRcvRate / 1000000.0 * (m_iRTT + m_iRCInterval) + 16;
 | |
| #endif
 | |
| 
 | |
|    // During Slow Start, no rate increase
 | |
|    if (m_bSlowStart)
 | |
|       return;
 | |
| 
 | |
|    if (m_bLoss)
 | |
|    {
 | |
|       m_bLoss = false;
 | |
|       return;
 | |
|    }
 | |
| 
 | |
|    //m_iBandwidth is pkts/sec
 | |
|    B = (int64_t)(m_iBandwidth - 1000000.0 / m_dPktSndPeriod);
 | |
|    if ((m_dPktSndPeriod > m_dLastDecPeriod) && ((m_iBandwidth / 9) < B))
 | |
|       B = m_iBandwidth / 9;
 | |
|    if (B <= 0)
 | |
|       inc = min_inc;
 | |
|    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_iMSS * 8.0))) * 0.0000015 / m_iMSS;
 | |
| 
 | |
|       if (inc < min_inc)
 | |
|          inc = min_inc;
 | |
|    }
 | |
| 
 | |
|    m_dPktSndPeriod = (m_dPktSndPeriod * m_iRCInterval) / (m_dPktSndPeriod * inc + m_iRCInterval);
 | |
| }
 | |
| 
 | |
| void CUDTCC::onLoss(const int32_t* losslist, int)
 | |
| {
 | |
|    //Slow Start stopped, if it hasn't yet
 | |
|    if (m_bSlowStart)
 | |
|    {
 | |
|       m_bSlowStart = false;
 | |
|       if (m_iRcvRate > 0)
 | |
|       {
 | |
|          // Set the sending rate to the receiving rate.
 | |
| #ifdef SRT_ENABLE_BSTATS
 | |
|          //Need average packet size here for better send period
 | |
|          m_dPktSndPeriod = 1000000.0 / ((m_iRcvRate + m_iMSS - 1) / m_iMSS);
 | |
| #else
 | |
|          m_dPktSndPeriod = 1000000.0 / m_iRcvRate;
 | |
| #endif
 | |
|          return;
 | |
|       }
 | |
|       // If no receiving rate is observed, we have to compute the sending
 | |
|       // rate according to the current window size, and decrease it
 | |
|       // using the method below.
 | |
|       m_dPktSndPeriod = m_dCWndSize / (m_iRTT + m_iRCInterval);
 | |
|    }
 | |
| 
 | |
|    m_bLoss = true;
 | |
| 
 | |
|    if (CSeqNo::seqcmp(losslist[0] & 0x7FFFFFFF, m_iLastDecSeq) > 0)
 | |
|    {
 | |
|       m_dLastDecPeriod = m_dPktSndPeriod;
 | |
|       m_dPktSndPeriod = ceil(m_dPktSndPeriod * 1.125);
 | |
| 
 | |
|       m_iAvgNAKNum = (int)ceil(m_iAvgNAKNum * 0.875 + m_iNAKCount * 0.125);
 | |
|       m_iNAKCount = 1;
 | |
|       m_iDecCount = 1;
 | |
| 
 | |
|       m_iLastDecSeq = m_iSndCurrSeqNo;
 | |
| 
 | |
|       // remove global synchronization using randomization
 | |
|       srand(m_iLastDecSeq);
 | |
|       m_iDecRandom = (int)ceil(m_iAvgNAKNum * (double(rand()) / RAND_MAX));
 | |
|       if (m_iDecRandom < 1)
 | |
|          m_iDecRandom = 1;
 | |
|    }
 | |
|    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.125);
 | |
|       m_iLastDecSeq = m_iSndCurrSeqNo;
 | |
|    }
 | |
| }
 | |
| 
 | |
| void CUDTCC::onTimeout()
 | |
| {
 | |
|    if (m_bSlowStart)
 | |
|    {
 | |
|       m_bSlowStart = false;
 | |
|       if (m_iRcvRate > 0)
 | |
| #ifdef SRT_ENABLE_BSTATS
 | |
|          // Need average packet size here
 | |
|          m_dPktSndPeriod = 1000000.0 / ((m_iRcvRate + m_iMSS - 1) / m_iMSS);
 | |
| #else
 | |
|          m_dPktSndPeriod = 1000000.0 / m_iRcvRate;
 | |
| #endif
 | |
|       else
 | |
|          m_dPktSndPeriod = m_dCWndSize / (m_iRTT + m_iRCInterval);
 | |
|    }
 | |
|    else
 | |
|    {
 | |
|       /*
 | |
|       m_dLastDecPeriod = m_dPktSndPeriod;
 | |
|       m_dPktSndPeriod = ceil(m_dPktSndPeriod * 2);
 | |
|       m_iLastDecSeq = m_iLastAck;
 | |
|       */
 | |
|    }
 | |
| }
 |