mirror of
				https://github.com/ossrs/srs.git
				synced 2025-03-09 15:49:59 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			206 lines
		
	
	
	
		
			6.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			206 lines
		
	
	
	
		
			6.6 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/.
 | |
|  * 
 | |
|  */
 | |
| 
 | |
| #ifndef INC__CONGCTL_H
 | |
| #define INC__CONGCTL_H
 | |
| 
 | |
| #include <map>
 | |
| #include <string>
 | |
| #include <utility>
 | |
| 
 | |
| class CUDT;
 | |
| class SrtCongestionControlBase;
 | |
| 
 | |
| typedef SrtCongestionControlBase* srtcc_create_t(CUDT* parent);
 | |
| 
 | |
| class SrtCongestion
 | |
| {
 | |
|     // Temporarily changed to linear searching, until this is exposed
 | |
|     // for a user-defined controller.
 | |
|     // Note that this is a pointer to function :)
 | |
| 
 | |
|     static const size_t N_CONTROLLERS = 2;
 | |
|     // The first/second is to mimic the map.
 | |
|     typedef struct { const char* first; srtcc_create_t* second; } NamePtr;
 | |
|     static NamePtr congctls[N_CONTROLLERS];
 | |
| 
 | |
|     // This is a congctl container.
 | |
|     SrtCongestionControlBase* congctl;
 | |
|     size_t selector;
 | |
| 
 | |
|     void Check();
 | |
| 
 | |
| public:
 | |
| 
 | |
|     // If you predict to allow something to be done on controller also
 | |
|     // before it is configured, call this first. If you need it configured,
 | |
|     // you can rely on Check().
 | |
|     bool ready() { return congctl; }
 | |
|     SrtCongestionControlBase* operator->() { Check(); return congctl; }
 | |
| 
 | |
|     // In the beginning it's uninitialized
 | |
|     SrtCongestion(): congctl(), selector(N_CONTROLLERS) {}
 | |
| 
 | |
|     struct IsName
 | |
|     {
 | |
|         std::string n;
 | |
|         IsName(std::string nn): n(nn) {}
 | |
|         bool operator()(NamePtr np) { return n == np.first; }
 | |
|     };
 | |
| 
 | |
|     // You can call select() multiple times, until finally
 | |
|     // the 'configure' method is called.
 | |
|     bool select(const std::string& name)
 | |
|     {
 | |
|         NamePtr* end = congctls+N_CONTROLLERS;
 | |
|         NamePtr* try_selector = std::find_if(congctls, end, IsName(name));
 | |
|         if (try_selector == end)
 | |
|             return false;
 | |
|         selector = try_selector - congctls;
 | |
|         return true;
 | |
|     }
 | |
| 
 | |
|     std::string selected_name()
 | |
|     {
 | |
|         if (selector == N_CONTROLLERS)
 | |
|             return "";
 | |
|         return congctls[selector].first;
 | |
|     }
 | |
| 
 | |
|     // Copy constructor - important when listener-spawning
 | |
|     // Things being done:
 | |
|     // 1. The congctl is individual, so don't copy it. Set NULL.
 | |
|     // 2. The selected name is copied so that it's configured correctly.
 | |
|     SrtCongestion(const SrtCongestion& source): congctl(), selector(source.selector) {}
 | |
| 
 | |
|     // This function will be called by the parent CUDT
 | |
|     // in appropriate time. It should select appropriate
 | |
|     // congctl basing on the value in selector, then
 | |
|     // pin oneself in into CUDT for receiving event signals.
 | |
|     bool configure(CUDT* parent);
 | |
| 
 | |
|     // Will delete the pinned in congctl object.
 | |
|     // This must be defined in *.cpp file due to virtual
 | |
|     // destruction.
 | |
|     ~SrtCongestion();
 | |
| 
 | |
|     enum RexmitMethod
 | |
|     {
 | |
|         SRM_LATEREXMIT,
 | |
|         SRM_FASTREXMIT
 | |
|     };
 | |
| 
 | |
|     enum TransAPI
 | |
|     {
 | |
|         STA_MESSAGE = 0x1, // sendmsg/recvmsg functions
 | |
|         STA_BUFFER  = 0x2,  // send/recv functions
 | |
|         STA_FILE    = 0x3, // sendfile/recvfile functions
 | |
|     };
 | |
| 
 | |
|     enum TransDir
 | |
|     {
 | |
|         STAD_RECV = 0,
 | |
|         STAD_SEND = 1
 | |
|     };
 | |
| };
 | |
| 
 | |
| 
 | |
| class SrtCongestionControlBase
 | |
| {
 | |
| protected:
 | |
|     // Here can be some common fields
 | |
|     CUDT* m_parent;
 | |
| 
 | |
|     double m_dPktSndPeriod;
 | |
|     double m_dCWndSize;
 | |
| 
 | |
|     //int m_iBandwidth; // NOT REQUIRED. Use m_parent->bandwidth() instead.
 | |
|     double m_dMaxCWndSize;
 | |
| 
 | |
|     //int m_iMSS;              // NOT REQUIRED. Use m_parent->MSS() instead.
 | |
|     //int32_t m_iSndCurrSeqNo; // NOT REQUIRED. Use m_parent->sndSeqNo().
 | |
|     //int m_iRcvRate;          // NOT REQUIRED. Use m_parent->deliveryRate() instead.
 | |
|     //int m_RTT;               // NOT REQUIRED. Use m_parent->RTT() instead.
 | |
|     //char* m_pcParam;         // Used to access m_llMaxBw. Use m_parent->maxBandwidth() instead.
 | |
| 
 | |
|     // Constructor in protected section so that this class is semi-abstract.
 | |
|     SrtCongestionControlBase(CUDT* parent);
 | |
| public:
 | |
| 
 | |
|     // This could be also made abstract, but this causes a linkage
 | |
|     // problem in C++: this would constitute the first virtual method,
 | |
|     // and C++ compiler uses the location of the first virtual method as the
 | |
|     // file to which it also emits the virtual call table. When this is
 | |
|     // abstract, there would have to be simultaneously either defined
 | |
|     // an empty method in congctl.cpp file (obviously never called),
 | |
|     // or simply left empty body here.
 | |
|     virtual ~SrtCongestionControlBase() { }
 | |
| 
 | |
|     // All these functions that return values interesting for processing
 | |
|     // by CUDT can be overridden. Normally they should refer to the fields
 | |
|     // and these fields should keep the values as a state.
 | |
|     virtual double pktSndPeriod_us() { return m_dPktSndPeriod; }
 | |
|     virtual double cgWindowSize() { return m_dCWndSize; }
 | |
|     virtual double cgWindowMaxSize() { return m_dMaxCWndSize; }
 | |
| 
 | |
|     virtual int64_t sndBandwidth() { return 0; }
 | |
| 
 | |
|     // If user-defined, will return nonzero value.
 | |
|     // If not, it will be internally calculated.
 | |
|     virtual int RTO() { return 0; }
 | |
| 
 | |
|     // Maximum number of packets to trigger ACK sending.
 | |
|     // Specifies the number of packets to receive before sending the ACK.
 | |
|     // Used by CUDT together with ACKTimeout_us() to trigger ACK packet sending.
 | |
|     virtual int ACKMaxPackets() const { return 0; }
 | |
| 
 | |
|     // Periodical interval to send an ACK, in microseconds.
 | |
|     // If user-defined, this value will be used to calculate
 | |
|     // the next ACK time every time ACK is considered to be sent (see CUDT::checkTimers).
 | |
|     // Otherwise this will be calculated internally in CUDT, normally taken
 | |
|     // from CUDT::COMM_SYN_INTERVAL_US.
 | |
|     virtual int ACKTimeout_us() const { return 0; }
 | |
| 
 | |
|     // Called when the settings concerning m_llMaxBW were changed.
 | |
|     // Arg 1: value of CUDT::m_llMaxBW
 | |
|     // Arg 2: value calculated out of CUDT::m_llInputBW and CUDT::m_iOverheadBW.
 | |
|     virtual void updateBandwidth(int64_t, int64_t) {}
 | |
| 
 | |
|     virtual bool needsQuickACK(const CPacket&)
 | |
|     {
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     // Particular controller is allowed to agree or disagree on the use of particular API.
 | |
|     virtual bool checkTransArgs(SrtCongestion::TransAPI , SrtCongestion::TransDir , const char* /*buffer*/, size_t /*size*/, int /*ttl*/, bool /*inorder*/)
 | |
|     {
 | |
|         return true;
 | |
|     }
 | |
| 
 | |
|     virtual SrtCongestion::RexmitMethod rexmitMethod() = 0; // Implementation enforced.
 | |
| 
 | |
|     virtual uint64_t updateNAKInterval(uint64_t nakint_tk, int rcv_speed, size_t loss_length)
 | |
|     {
 | |
|         if (rcv_speed > 0)
 | |
|             nakint_tk += (loss_length * uint64_t(1000000) / rcv_speed) * CTimer::getCPUFrequency();
 | |
| 
 | |
|         return nakint_tk;
 | |
|     }
 | |
| 
 | |
|     virtual uint64_t minNAKInterval()
 | |
|     {
 | |
|         return 0; // Leave default
 | |
|     }
 | |
| };
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| #endif
 |