Skip to content

Commit

Permalink
[core] Moved source rate estimation logic to CRateEstimator
Browse files Browse the repository at this point in the history
from CSndBuffer
  • Loading branch information
maxsharabayko committed Mar 14, 2022
1 parent a60d98a commit daf94c4
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 71 deletions.
93 changes: 48 additions & 45 deletions srtcore/buffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,53 @@ int round_val(double val)
return static_cast<int>(round(val));
}

CRateEstimator::CRateEstimator()
: m_iInRatePktsCount(0)
, m_iInRateBytesCount(0)
, m_InRatePeriod(INPUTRATE_FAST_START_US) // 0.5 sec (fast start)
, m_iInRateBps(INPUTRATE_INITIAL_BYTESPS)
{}

void CRateEstimator::setInputRateSmpPeriod(int period)
{
m_InRatePeriod = (uint64_t)period; //(usec) 0=no input rate calculation
}

void CRateEstimator::updateInputRate(const time_point& time, int pkts, int bytes)
{
// no input rate calculation
if (m_InRatePeriod == 0)
return;

if (is_zero(m_tsInRateStartTime))
{
m_tsInRateStartTime = time;
return;
}

m_iInRatePktsCount += pkts;
m_iInRateBytesCount += bytes;

// Trigger early update in fast start mode
const bool early_update = (m_InRatePeriod < INPUTRATE_RUNNING_US) && (m_iInRatePktsCount > INPUTRATE_MAX_PACKETS);

const uint64_t period_us = count_microseconds(time - m_tsInRateStartTime);
if (early_update || period_us > m_InRatePeriod)
{
// Required Byte/sec rate (payload + headers)
m_iInRateBytesCount += (m_iInRatePktsCount * CPacket::SRT_DATA_HDR_SIZE);
m_iInRateBps = (int)(((int64_t)m_iInRateBytesCount * 1000000) / period_us);
HLOGC(bslog.Debug,
log << "updateInputRate: pkts:" << m_iInRateBytesCount << " bytes:" << m_iInRatePktsCount
<< " rate=" << (m_iInRateBps * 8) / 1000 << "kbps interval=" << period_us);
m_iInRatePktsCount = 0;
m_iInRateBytesCount = 0;
m_tsInRateStartTime = time;

setInputRateSmpPeriod(INPUTRATE_RUNNING_US);
}
}

CSndBuffer::CSndBuffer(int size, int mss)
: m_BufLock()
, m_pBlock(NULL)
Expand All @@ -122,10 +169,6 @@ CSndBuffer::CSndBuffer(int size, int mss)
, m_iMSS(mss)
, m_iCount(0)
, m_iBytesCount(0)
, m_iInRatePktsCount(0)
, m_iInRateBytesCount(0)
, m_InRatePeriod(INPUTRATE_FAST_START_US) // 0.5 sec (fast start)
, m_iInRateBps(INPUTRATE_INITIAL_BYTESPS)
{
// initial physical buffer of "size"
m_pBuffer = new Buffer;
Expand Down Expand Up @@ -273,7 +316,7 @@ void CSndBuffer::addBuffer(const char* data, int len, SRT_MSGCTRL& w_mctrl)
m_iCount += size;
m_iBytesCount += len;

updateInputRate(m_tsLastOriginTime, size, len);
m_rateEstimator.updateInputRate(m_tsLastOriginTime, size, len);
updAvgBufSize(m_tsLastOriginTime);

// MSGNO_SEQ::mask has a form: 00000011111111...
Expand All @@ -287,46 +330,6 @@ void CSndBuffer::addBuffer(const char* data, int len, SRT_MSGCTRL& w_mctrl)
m_iNextMsgNo = nextmsgno;
}

void CSndBuffer::setInputRateSmpPeriod(int period)
{
m_InRatePeriod = (uint64_t)period; //(usec) 0=no input rate calculation
}

void CSndBuffer::updateInputRate(const steady_clock::time_point& time, int pkts, int bytes)
{
// no input rate calculation
if (m_InRatePeriod == 0)
return;

if (is_zero(m_tsInRateStartTime))
{
m_tsInRateStartTime = time;
return;
}

m_iInRatePktsCount += pkts;
m_iInRateBytesCount += bytes;

// Trigger early update in fast start mode
const bool early_update = (m_InRatePeriod < INPUTRATE_RUNNING_US) && (m_iInRatePktsCount > INPUTRATE_MAX_PACKETS);

const uint64_t period_us = count_microseconds(time - m_tsInRateStartTime);
if (early_update || period_us > m_InRatePeriod)
{
// Required Byte/sec rate (payload + headers)
m_iInRateBytesCount += (m_iInRatePktsCount * CPacket::SRT_DATA_HDR_SIZE);
m_iInRateBps = (int)(((int64_t)m_iInRateBytesCount * 1000000) / period_us);
HLOGC(bslog.Debug,
log << "updateInputRate: pkts:" << m_iInRateBytesCount << " bytes:" << m_iInRatePktsCount
<< " rate=" << (m_iInRateBps * 8) / 1000 << "kbps interval=" << period_us);
m_iInRatePktsCount = 0;
m_iInRateBytesCount = 0;
m_tsInRateStartTime = time;

setInputRateSmpPeriod(INPUTRATE_RUNNING_US);
}
}

int CSndBuffer::addBufferFromFile(fstream& ifs, int len)
{
int size = len / m_iMSS;
Expand Down
75 changes: 49 additions & 26 deletions srtcore/buffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,47 @@ class AvgBufSize
double m_dTimespanMAvg;
};

/// The class to estimate source bitrate based on samples submitted to the buffer.
/// Is currently only used by the CSndBuffer.
class CRateEstimator
{
typedef sync::steady_clock::time_point time_point;
typedef sync::steady_clock::duration duration;
public:
CRateEstimator();

public:
uint64_t getInRatePeriod() const { return m_InRatePeriod; }

/// Retrieve input bitrate in bytes per second
int getInputRate() const { return m_iInRateBps; }

void setInputRateSmpPeriod(int period);

/// Update input rate calculation.
/// @param [in] time current time in microseconds
/// @param [in] pkts number of packets newly added to the buffer
/// @param [in] bytes number of payload bytes in those newly added packets
///
/// @return Current size of the data in the sending list.
void updateInputRate(const time_point& time, int pkts = 0, int bytes = 0);

void resetInputRateSmpPeriod(bool disable = false) { setInputRateSmpPeriod(disable ? 0 : INPUTRATE_FAST_START_US); }

private: // Constants
static const uint64_t INPUTRATE_FAST_START_US = 500000; // 500 ms
static const uint64_t INPUTRATE_RUNNING_US = 1000000; // 1000 ms
static const int64_t INPUTRATE_MAX_PACKETS = 2000; // ~ 21 Mbps of 1316 bytes payload
static const int INPUTRATE_INITIAL_BYTESPS = BW_INFINITE;

private:
int m_iInRatePktsCount; // number of payload bytes added since InRateStartTime
int m_iInRateBytesCount; // number of payload bytes added since InRateStartTime
time_point m_tsInRateStartTime;
uint64_t m_InRatePeriod; // usec
int m_iInRateBps; // Input Rate in Bytes/sec
};

class CSndBuffer
{
typedef sync::steady_clock::time_point time_point;
Expand Down Expand Up @@ -195,30 +236,19 @@ class CSndBuffer
SRT_ATTR_EXCLUDES(m_BufLock)
duration getBufferingDelay(const time_point& tnow) const;

uint64_t getInRatePeriod() const { return m_InRatePeriod; }
uint64_t getInRatePeriod() const { return m_rateEstimator.getInRatePeriod(); }

/// Retrieve input bitrate in bytes per second
int getInputRate() const { return m_iInRateBps; }
int getInputRate() const { return m_rateEstimator.getInputRate(); }

/// Update input rate calculation.
/// @param [in] time current time in microseconds
/// @param [in] pkts number of packets newly added to the buffer
/// @param [in] bytes number of payload bytes in those newly added packets
///
/// @return Current size of the data in the sending list.
void updateInputRate(const time_point& time, int pkts = 0, int bytes = 0);
void resetInputRateSmpPeriod(bool disable = false) { m_rateEstimator.resetInputRateSmpPeriod(disable); }

void resetInputRateSmpPeriod(bool disable = false) { setInputRateSmpPeriod(disable ? 0 : INPUTRATE_FAST_START_US); }
const CRateEstimator& getRateEstimator() const { return m_rateEstimator; }

void setRateEstimator(const CRateEstimator& other) { m_rateEstimator = other; }

private:
void increase();
void setInputRateSmpPeriod(int period);

private: // Constants
static const uint64_t INPUTRATE_FAST_START_US = 500000; // 500 ms
static const uint64_t INPUTRATE_RUNNING_US = 1000000; // 1000 ms
static const int64_t INPUTRATE_MAX_PACKETS = 2000; // ~ 21 Mbps of 1316 bytes payload
static const int INPUTRATE_INITIAL_BYTESPS = BW_INFINITE;

private:
mutable sync::Mutex m_BufLock; // used to synchronize buffer operation
Expand Down Expand Up @@ -249,7 +279,7 @@ class CSndBuffer

// m_pBlock: The head pointer
// m_pFirstBlock: The first block
// m_pCurrBlock: The current block
// m_pCurrBlock: The current block
// m_pLastBlock: The last block (if first == last, buffer is empty)

struct Buffer
Expand All @@ -263,20 +293,13 @@ class CSndBuffer

int m_iSize; // buffer size (number of packets)
int m_iMSS; // maximum seqment/packet size

int m_iCount; // number of used blocks

int m_iBytesCount; // number of payload bytes in queue
time_point m_tsLastOriginTime;

AvgBufSize m_mavg;

int m_iInRatePktsCount; // number of payload bytes added since InRateStartTime
int m_iInRateBytesCount; // number of payload bytes added since InRateStartTime
time_point m_tsInRateStartTime;
uint64_t m_InRatePeriod; // usec
int m_iInRateBps; // Input Rate in Bytes/sec
int m_iAvgPayloadSz; // Average packet payload size
CRateEstimator m_rateEstimator;

private:
CSndBuffer(const CSndBuffer&);
Expand Down

0 comments on commit daf94c4

Please sign in to comment.