1
0
Fork 0
mirror of https://github.com/ossrs/srs.git synced 2025-03-09 15:49:59 +00:00

SRT: Upgrade libsrt from 1.4.1 to 1.5.1. v6.0.12 (#3362)

Co-authored-by: winlin <winlin@vip.126.com>
This commit is contained in:
john 2023-01-04 19:56:33 +08:00 committed by GitHub
parent 7a56208f2f
commit fe086dfc31
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
143 changed files with 38185 additions and 15108 deletions

View file

@ -1,11 +1,11 @@
/*
* 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/.
*
*
*/
/*****************************************************************************
@ -50,461 +50,562 @@ modified by
Haivision Systems Inc.
*****************************************************************************/
#ifndef __UDT_BUFFER_H__
#define __UDT_BUFFER_H__
#ifndef INC_SRT_BUFFER_H
#define INC_SRT_BUFFER_H
#include "udt.h"
#include "list.h"
#include "queue.h"
#include "tsbpd_time.h"
#include "utilities.h"
#include <fstream>
class CSndBuffer
// The notation used for "circular numbers" in comments:
// The "cicrular numbers" are numbers that when increased up to the
// maximum become zero, and similarly, when the zero value is decreased,
// it turns into the maximum value minus one. This wrapping works the
// same for adding and subtracting. Circular numbers cannot be multiplied.
// Operations done on these numbers are marked with additional % character:
// a %> b : a is later than b
// a ++% (++%a) : shift a by 1 forward
// a +% b : shift a by b
// a == b : equality is same as for just numbers
namespace srt {
/// The AvgBufSize class is used to calculate moving average of the buffer (RCV or SND)
class AvgBufSize
{
public:
// XXX There's currently no way to access the socket ID set for
// whatever the buffer is currently working for. Required to find
// some way to do this, possibly by having a "reverse pointer".
// Currently just "unimplemented".
std::string CONID() const { return ""; }
CSndBuffer(int size = 32, int mss = 1500);
~CSndBuffer();
typedef sync::steady_clock::time_point time_point;
public:
AvgBufSize()
: m_dBytesCountMAvg(0.0)
, m_dCountMAvg(0.0)
, m_dTimespanMAvg(0.0)
{
}
/// Insert a user buffer into the sending list.
/// @param [in] data pointer to the user data block.
/// @param [in] len size of the block.
/// @param [in] ttl time to live in milliseconds
/// @param [in] order if the block should be delivered in order, for DGRAM only
void addBuffer(const char* data, int len, int ttl, bool order, uint64_t srctime, ref_t<int32_t> r_msgno);
/// Read a block of data from file and insert it into the sending list.
/// @param [in] ifs input file stream.
/// @param [in] len size of the block.
/// @return actual size of data added from the file.
int addBufferFromFile(std::fstream& ifs, int len);
/// Find data position to pack a DATA packet from the furthest reading point.
/// @param [out] data the pointer to the data position.
/// @param [out] msgno message number of the packet.
/// @param [out] origintime origin time stamp of the message
/// @param [in] kflags Odd|Even crypto key flag
/// @return Actual length of data read.
int readData(char** data, int32_t& msgno, uint64_t& origintime, int kflgs);
/// Find data position to pack a DATA packet for a retransmission.
/// @param [out] data the pointer to the data position.
/// @param [in] offset offset from the last ACK point.
/// @param [out] msgno message number of the packet.
/// @param [out] origintime origin time stamp of the message
/// @param [out] msglen length of the message
/// @return Actual length of data read.
int readData(char** data, const int offset, int32_t& msgno, uint64_t& origintime, int& msglen);
/// Update the ACK point and may release/unmap/return the user data according to the flag.
/// @param [in] offset number of packets acknowledged.
void ackData(int offset);
/// Read size of data still in the sending list.
/// @return Current size of the data in the sending list.
int getCurrBufSize() const;
int dropLateData(int &bytes, uint64_t latetime);
#ifdef SRT_ENABLE_SNDBUFSZ_MAVG
void updAvgBufSize(uint64_t time);
int getAvgBufSize(ref_t<int> bytes, ref_t<int> timespan);
#endif /* SRT_ENABLE_SNDBUFSZ_MAVG */
int getCurrBufSize(ref_t<int> bytes, ref_t<int> timespan);
uint64_t getInRatePeriod() const { return m_InRatePeriod; }
/// Retrieve input bitrate in bytes per second
int getInputRate() const { return m_iInRateBps; }
/// 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(uint64_t time, int pkts = 0, int bytes = 0);
void resetInputRateSmpPeriod(bool disable = false)
{
setInputRateSmpPeriod(disable ? 0 : INPUTRATE_FAST_START_US);
}
public:
bool isTimeToUpdate(const time_point& now) const;
void update(const time_point& now, int pkts, int bytes, int timespan_ms);
public:
inline double pkts() const { return m_dCountMAvg; }
inline double timespan_ms() const { return m_dTimespanMAvg; }
inline double bytes() const { return m_dBytesCountMAvg; }
private:
time_point m_tsLastSamplingTime;
double m_dBytesCountMAvg;
double m_dCountMAvg;
double m_dTimespanMAvg;
};
void increase();
void setInputRateSmpPeriod(int period);
/// 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();
private: // Constants
public:
uint64_t getInRatePeriod() const { return m_InRatePeriod; }
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
/// 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:
pthread_mutex_t m_BufLock; // used to synchronize buffer operation
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
};
struct Block
{
char* m_pcData; // pointer to the data block
int m_iLength; // length of the block
class CSndBuffer
{
typedef sync::steady_clock::time_point time_point;
typedef sync::steady_clock::duration duration;
int32_t m_iMsgNoBitset; // message number
uint64_t m_ullOriginTime_us; // original request time
uint64_t m_ullSourceTime_us;
int m_iTTL; // time to live (milliseconds)
public:
// XXX There's currently no way to access the socket ID set for
// whatever the buffer is currently working for. Required to find
// some way to do this, possibly by having a "reverse pointer".
// Currently just "unimplemented".
std::string CONID() const { return ""; }
Block* m_pNext; // next block
/// @brief CSndBuffer constructor.
/// @param size initial number of blocks (each block to store one packet payload).
/// @param maxpld maximum packet payload.
CSndBuffer(int size = 32, int maxpld = 1500);
~CSndBuffer();
int32_t getMsgSeq()
{
// NOTE: this extracts message ID with regard to REXMIT flag.
// This is valid only for message ID that IS GENERATED in this instance,
// not provided by the peer. This can be otherwise sent to the peer - it doesn't matter
// for the peer that it uses LESS bits to represent the message.
return m_iMsgNoBitset & MSGNO_SEQ::mask;
}
public:
/// Insert a user buffer into the sending list.
/// For @a w_mctrl the following fields are used:
/// INPUT:
/// - msgttl: timeout for retransmitting the message, if lost
/// - inorder: request to deliver the message in order of sending
/// - srctime: local time as a base for packet's timestamp (0 if unused)
/// - pktseq: sequence number to be stamped on the packet (-1 if unused)
/// - msgno: message number to be stamped on the packet (-1 if unused)
/// OUTPUT:
/// - srctime: local time stamped on the packet (same as input, if input wasn't 0)
/// - pktseq: sequence number to be stamped on the next packet
/// - msgno: message number stamped on the packet
/// @param [in] data pointer to the user data block.
/// @param [in] len size of the block.
/// @param [inout] w_mctrl Message control data
SRT_ATTR_EXCLUDES(m_BufLock)
void addBuffer(const char* data, int len, SRT_MSGCTRL& w_mctrl);
} *m_pBlock, *m_pFirstBlock, *m_pCurrBlock, *m_pLastBlock;
/// Read a block of data from file and insert it into the sending list.
/// @param [in] ifs input file stream.
/// @param [in] len size of the block.
/// @return actual size of data added from the file.
SRT_ATTR_EXCLUDES(m_BufLock)
int addBufferFromFile(std::fstream& ifs, int len);
// m_pBlock: The head pointer
// m_pFirstBlock: The first block
// m_pCurrBlock: The current block
// m_pLastBlock: The last block (if first == last, buffer is empty)
/// Find data position to pack a DATA packet from the furthest reading point.
/// @param [out] packet the packet to read.
/// @param [out] origintime origin time stamp of the message
/// @param [in] kflags Odd|Even crypto key flag
/// @param [out] seqnoinc the number of packets skipped due to TTL, so that seqno should be incremented.
/// @return Actual length of data read.
SRT_ATTR_EXCLUDES(m_BufLock)
int readData(CPacket& w_packet, time_point& w_origintime, int kflgs, int& w_seqnoinc);
struct Buffer
{
char* m_pcData; // buffer
int m_iSize; // size
Buffer* m_pNext; // next buffer
} *m_pBuffer; // physical buffer
/// Peek an information on the next original data packet to send.
/// @return origin time stamp of the next packet; epoch start time otherwise.
SRT_ATTR_EXCLUDES(m_BufLock)
time_point peekNextOriginal() const;
int32_t m_iNextMsgNo; // next message number
/// Find data position to pack a DATA packet for a retransmission.
/// @param [in] offset offset from the last ACK point (backward sequence number difference)
/// @param [out] packet the packet to read.
/// @param [out] origintime origin time stamp of the message
/// @param [out] msglen length of the message
/// @return Actual length of data read (return 0 if offset too large, -1 if TTL exceeded).
SRT_ATTR_EXCLUDES(m_BufLock)
int readData(const int offset, CPacket& w_packet, time_point& w_origintime, int& w_msglen);
int m_iSize; // buffer size (number of packets)
int m_iMSS; // maximum seqment/packet size
/// Get the time of the last retransmission (if any) of the DATA packet.
/// @param [in] offset offset from the last ACK point (backward sequence number difference)
///
/// @return Last time of the last retransmission event for the corresponding DATA packet.
SRT_ATTR_EXCLUDES(m_BufLock)
time_point getPacketRexmitTime(const int offset);
int m_iCount; // number of used blocks
/// Update the ACK point and may release/unmap/return the user data according to the flag.
/// @param [in] offset number of packets acknowledged.
int32_t getMsgNoAt(const int offset);
int m_iBytesCount; // number of payload bytes in queue
uint64_t m_ullLastOriginTime_us;
void ackData(int offset);
#ifdef SRT_ENABLE_SNDBUFSZ_MAVG
uint64_t m_LastSamplingTime;
int m_iCountMAvg;
int m_iBytesCountMAvg;
int m_TimespanMAvg;
#endif /* SRT_ENABLE_SNDBUFSZ_MAVG */
/// Read size of data still in the sending list.
/// @return Current size of the data in the sending list.
int getCurrBufSize() const;
int m_iInRatePktsCount; // number of payload bytes added since InRateStartTime
int m_iInRateBytesCount; // number of payload bytes added since InRateStartTime
uint64_t m_InRateStartTime;
uint64_t m_InRatePeriod; // usec
int m_iInRateBps; // Input Rate in Bytes/sec
int m_iAvgPayloadSz; // Average packet payload size
SRT_ATTR_EXCLUDES(m_BufLock)
int dropLateData(int& bytes, int32_t& w_first_msgno, const time_point& too_late_time);
void updAvgBufSize(const time_point& time);
int getAvgBufSize(int& bytes, int& timespan);
int getCurrBufSize(int& bytes, int& timespan);
/// @brief Get the buffering delay of the oldest message in the buffer.
/// @return the delay value.
SRT_ATTR_EXCLUDES(m_BufLock)
duration getBufferingDelay(const time_point& tnow) const;
uint64_t getInRatePeriod() const { return m_rateEstimator.getInRatePeriod(); }
/// Retrieve input bitrate in bytes per second
int getInputRate() const { return m_rateEstimator.getInputRate(); }
void resetInputRateSmpPeriod(bool disable = false) { m_rateEstimator.resetInputRateSmpPeriod(disable); }
const CRateEstimator& getRateEstimator() const { return m_rateEstimator; }
void setRateEstimator(const CRateEstimator& other) { m_rateEstimator = other; }
private:
CSndBuffer(const CSndBuffer&);
CSndBuffer& operator=(const CSndBuffer&);
void increase();
private:
mutable sync::Mutex m_BufLock; // used to synchronize buffer operation
struct Block
{
char* m_pcData; // pointer to the data block
int m_iLength; // payload length of the block.
int32_t m_iMsgNoBitset; // message number
int32_t m_iSeqNo; // sequence number for scheduling
time_point m_tsOriginTime; // block origin time (either provided from above or equals the time a message was submitted for sending.
time_point m_tsRexmitTime; // packet retransmission time
int m_iTTL; // time to live (milliseconds)
Block* m_pNext; // next block
int32_t getMsgSeq()
{
// NOTE: this extracts message ID with regard to REXMIT flag.
// This is valid only for message ID that IS GENERATED in this instance,
// not provided by the peer. This can be otherwise sent to the peer - it doesn't matter
// for the peer that it uses LESS bits to represent the message.
return m_iMsgNoBitset & MSGNO_SEQ::mask;
}
} * m_pBlock, *m_pFirstBlock, *m_pCurrBlock, *m_pLastBlock;
// m_pBlock: The head pointer
// m_pFirstBlock: The first block
// m_pCurrBlock: The current block
// m_pLastBlock: The last block (if first == last, buffer is empty)
struct Buffer
{
char* m_pcData; // buffer
int m_iSize; // size
Buffer* m_pNext; // next buffer
} * m_pBuffer; // physical buffer
int32_t m_iNextMsgNo; // next message number
int m_iSize; // buffer size (number of packets)
const int m_iBlockLen; // maximum length of a block holding packet payload (excluding packet header).
int m_iCount; // number of used blocks
int m_iBytesCount; // number of payload bytes in queue
time_point m_tsLastOriginTime;
AvgBufSize m_mavg;
CRateEstimator m_rateEstimator;
private:
CSndBuffer(const CSndBuffer&);
CSndBuffer& operator=(const CSndBuffer&);
};
////////////////////////////////////////////////////////////////////////////////
#if (!ENABLE_NEW_RCVBUFFER)
class CRcvBuffer
{
public:
typedef sync::steady_clock::time_point time_point;
typedef sync::steady_clock::duration duration;
public:
// XXX There's currently no way to access the socket ID set for
// whatever the queue is currently working for. Required to find
// some way to do this, possibly by having a "reverse pointer".
// Currently just "unimplemented".
std::string CONID() const { return ""; }
/// Construct the buffer.
/// @param [in] queue CUnitQueue that actually holds the units (packets)
/// @param [in] bufsize_pkts in units (packets)
CRcvBuffer(CUnitQueue* queue, int bufsize_pkts = 65536);
~CRcvBuffer();
static const int DEFAULT_SIZE = 65536;
/// Construct the buffer.
/// @param [in] queue CUnitQueue that actually holds the units (packets)
/// @param [in] bufsize_pkts in units (packets)
CRcvBuffer(CUnitQueue* queue, int bufsize_pkts = DEFAULT_SIZE);
~CRcvBuffer();
public:
/// Write data into the buffer.
/// @param [in] unit pointer to a data unit containing new packet
/// @param [in] offset offset from last ACK point.
/// @return 0 is success, -1 if data is repeated.
int addData(CUnit* unit, int offset);
/// Write data into the buffer.
/// @param [in] unit pointer to a data unit containing new packet
/// @param [in] offset offset from last ACK point.
/// @return 0 is success, -1 if data is repeated.
/// Read data into a user buffer.
/// @param [in] data pointer to user buffer.
/// @param [in] len length of user buffer.
/// @return size of data read.
int readBuffer(char* data, int len);
int addData(CUnit* unit, int offset);
/// Read data directly into file.
/// @param [in] file C++ file stream.
/// @param [in] len expected length of data to write into the file.
/// @return size of data read.
int readBufferToFile(std::fstream& ofs, int len);
/// Read data into a user buffer.
/// @param [in] data pointer to user buffer.
/// @param [in] len length of user buffer.
/// @return size of data read.
/// Update the ACK point of the buffer.
/// @param [in] len number of units to be acknowledged.
/// @return 1 if a user buffer is fulfilled, otherwise 0.
int ackData(int len);
int readBuffer(char* data, int len);
/// Query how many buffer space left for data receiving.
/// Actually only acknowledged packets, that are still in the buffer,
/// are considered to take buffer space.
///
/// @return size of available buffer space (including user buffer) for data receiving.
/// Not counting unacknowledged packets.
int getAvailBufSize() const;
/// Read data directly into file.
/// @param [in] file C++ file stream.
/// @param [in] len expected length of data to write into the file.
/// @return size of data read.
/// Query how many data has been continuously received (for reading) and ready to play (tsbpdtime < now).
/// @return size of valid (continous) data for reading.
int getRcvDataSize() const;
int readBufferToFile(std::fstream& ofs, int len);
/// Query how many data was received and acknowledged.
/// @param [out] bytes bytes
/// @param [out] spantime spantime
/// @return size in pkts of acked data.
int getRcvDataSize(int& bytes, int& spantime);
/// Update the ACK point of the buffer.
/// @param [in] len number of units to be acknowledged.
/// @return 1 if a user buffer is fulfilled, otherwise 0.
/// Query a 1 sec moving average of how many data was received and acknowledged.
/// @param [out] bytes bytes
/// @param [out] spantime spantime
/// @return size in pkts of acked data.
int getRcvAvgDataSize(int& bytes, int& spantime);
void ackData(int len);
/// Query how many data of the receive buffer is acknowledged.
/// @param [in] now current time in us.
/// @return none.
void updRcvAvgDataSize(const time_point& now);
/// Query how many buffer space left for data receiving.
/// Actually only acknowledged packets, that are still in the buffer,
/// are considered to take buffer space.
///
/// @return size of available buffer space (including user buffer) for data receiving.
/// Not counting unacknowledged packets.
/// Query the received average payload size.
/// @return size (bytes) of payload size
unsigned getRcvAvgPayloadSize() const;
int getAvailBufSize() const;
struct ReadingState
{
time_point tsStart;
time_point tsLastAck;
time_point tsEnd;
int iNumAcknowledged;
int iNumUnacknowledged;
};
/// Query how many data has been continuously received (for reading) and ready to play (tsbpdtime < now).
/// @return size of valid (continous) data for reading.
ReadingState debugGetReadingState() const;
int getRcvDataSize() const;
/// Form a string of the current buffer fullness state.
/// number of packets acknowledged, TSBPD readiness, etc.
std::string strFullnessState(const time_point& tsNow) const;
/// Query how many data was received and acknowledged.
/// @param [out] bytes bytes
/// @param [out] spantime spantime
/// @return size in pkts of acked data.
/// Mark the message to be dropped from the message list.
/// @param [in] msgno message number.
/// @param [in] using_rexmit_flag whether the MSGNO field uses rexmit flag (if not, one more bit is part of the
/// msgno value)
void dropMsg(int32_t msgno, bool using_rexmit_flag);
int getRcvDataSize(int &bytes, int &spantime);
#if SRT_ENABLE_RCVBUFSZ_MAVG
/// Query a 1 sec moving average of how many data was received and acknowledged.
/// @param [out] bytes bytes
/// @param [out] spantime spantime
/// @return size in pkts of acked data.
int getRcvAvgDataSize(int &bytes, int &spantime);
/// Query how many data of the receive buffer is acknowledged.
/// @param [in] now current time in us.
/// @return none.
void updRcvAvgDataSize(uint64_t now);
#endif /* SRT_ENABLE_RCVBUFSZ_MAVG */
/// Query the received average payload size.
/// @return size (bytes) of payload size
int getRcvAvgPayloadSize() const;
/// Mark the message to be dropped from the message list.
/// @param [in] msgno message number.
/// @param [in] using_rexmit_flag whether the MSGNO field uses rexmit flag (if not, one more bit is part of the msgno value)
void dropMsg(int32_t msgno, bool using_rexmit_flag);
/// read a message.
/// @param [out] data buffer to write the message into.
/// @param [in] len size of the buffer.
/// @return actuall size of data read.
int readMsg(char* data, int len);
/// read a message.
/// @param [out] data buffer to write the message into.
/// @param [in] len size of the buffer.
/// @param [out] tsbpdtime localtime-based (uSec) packet time stamp including buffering delay
/// @return actuall size of data read.
int readMsg(char* data, int len, ref_t<SRT_MSGCTRL> mctrl);
/// Query if data is ready to read (tsbpdtime <= now if TsbPD is active).
/// @param [out] tsbpdtime localtime-based (uSec) packet time stamp including buffering delay
/// of next packet in recv buffer, ready or not.
/// @param [out] curpktseq Sequence number of the packet if there is one ready to play
/// @return true if ready to play, false otherwise (tsbpdtime may be !0 in
/// both cases).
bool isRcvDataReady(ref_t<uint64_t> tsbpdtime, ref_t<int32_t> curpktseq);
bool isRcvDataReady();
bool isRcvDataAvailable()
{
return m_iLastAckPos != m_iStartPos;
}
CPacket* getRcvReadyPacket();
/// Set TimeStamp-Based Packet Delivery Rx Mode
/// @param [in] timebase localtime base (uSec) of packet time stamps including buffering delay
/// @param [in] delay aggreed TsbPD delay
/// @return 0
int setRcvTsbPdMode(uint64_t timebase, uint32_t delay);
/// Add packet timestamp for drift caclculation and compensation
/// @param [in] timestamp packet time stamp
/// @param [ref] lock Mutex that should be locked for the operation
void addRcvTsbPdDriftSample(uint32_t timestamp, pthread_mutex_t& lock);
#ifdef SRT_DEBUG_TSBPD_DRIFT
void printDriftHistogram(int64_t iDrift);
void printDriftOffset(int tsbPdOffset, int tsbPdDriftAvg);
#endif
/// Get information on the 1st message in queue.
// Parameters (of the 1st packet queue, ready to play or not):
/// @param [out] tsbpdtime localtime-based (uSec) packet time stamp including buffering delay of 1st packet or 0 if none
/// @param [out] passack true if 1st ready packet is not yet acknowleged (allowed to be delivered to the app)
/// @param [out] skipseqno -1 or seq number of 1st unacknowledged pkt ready to play preceeded by missing packets.
/// @retval true 1st packet ready to play (tsbpdtime <= now). Not yet acknowledged if passack == true
/// @retval false IF tsbpdtime = 0: rcv buffer empty; ELSE:
/// IF skipseqno != -1, packet ready to play preceeded by missing packets.;
/// IF skipseqno == -1, no missing packet but 1st not ready to play.
bool getRcvFirstMsg(ref_t<uint64_t> tsbpdtime, ref_t<bool> passack, ref_t<int32_t> skipseqno, ref_t<int32_t> curpktseq);
/// Update the ACK point of the buffer.
/// @param [in] len size of data to be skip & acknowledged.
void skipData(int len);
/// read a message.
/// @param [out] data buffer to write the message into.
/// @param [in] len size of the buffer.
/// @return actuall size of data read.
int readMsg(char* data, int len);
#if ENABLE_HEAVY_LOGGING
void reportBufferStats(); // Heavy logging Debug only
void readMsgHeavyLogging(int p);
#endif
private:
/// Adjust receive queue to 1st ready to play message (tsbpdtime < now).
// Parameters (of the 1st packet queue, ready to play or not):
/// @param [out] tsbpdtime localtime-based (uSec) packet time stamp including buffering delay of 1st packet or 0 if none
/// @retval true 1st packet ready to play without discontinuity (no hole)
/// @retval false tsbpdtime = 0: no packet ready to play
/// read a message.
/// @param [out] data buffer to write the message into.
/// @param [in] len size of the buffer.
/// @param [out] tsbpdtime localtime-based (uSec) packet time stamp including buffering delay
/// @return actuall size of data read.
int readMsg(char* data, int len, SRT_MSGCTRL& w_mctrl, int upto);
bool getRcvReadyMsg(ref_t<uint64_t> tsbpdtime, ref_t<int32_t> curpktseq);
public:
// (This is exposed as used publicly in logs)
/// Get packet delivery local time base (adjusted for wrap around)
/// @param [in] timestamp packet timestamp (relative to peer StartTime), wrapping around every ~72 min
/// @return local delivery time (usec)
uint64_t getTsbPdTimeBase(uint32_t timestamp_us);
/// Get packet local delivery time
/// @param [in] timestamp packet timestamp (relative to peer StartTime), wrapping around every ~72 min
/// @return local delivery time (usec)
public:
uint64_t getPktTsbPdTime(uint32_t timestamp);
int debugGetSize() const;
bool empty() const;
// Required by PacketFilter facility to use as a storage
// for provided packets
CUnitQueue* getUnitQueue()
{
return m_pUnitQueue;
}
private:
/// thread safe bytes counter of the Recv & Ack buffer
/// @param [in] pkts acked or removed pkts from rcv buffer (used with acked = true)
/// @param [in] bytes number of bytes added/delete (if negative) to/from rcv buffer.
/// @param [in] acked true when adding new pkt in RcvBuffer; false when acking/removing pkts to/from buffer
void countBytes(int pkts, int bytes, bool acked = false);
private:
bool scanMsg(ref_t<int> start, ref_t<int> end, ref_t<bool> passack);
private:
CUnit** m_pUnit; // pointer to the protocol buffer (array of CUnit* items)
const int m_iSize; // size of the array of CUnit* items
CUnitQueue* m_pUnitQueue; // the shared unit queue
int m_iStartPos; // the head position for I/O (inclusive)
int m_iLastAckPos; // the last ACKed position (exclusive)
// EMPTY: m_iStartPos = m_iLastAckPos FULL: m_iStartPos = m_iLastAckPos + 1
int m_iMaxPos; // the furthest data position
int m_iNotch; // the starting read point of the first unit
pthread_mutex_t m_BytesCountLock; // used to protect counters operations
int m_iBytesCount; // Number of payload bytes in the buffer
int m_iAckedPktsCount; // Number of acknowledged pkts in the buffer
int m_iAckedBytesCount; // Number of acknowledged payload bytes in the buffer
int m_iAvgPayloadSz; // Average payload size for dropped bytes estimation
bool m_bTsbPdMode; // true: apply TimeStamp-Based Rx Mode
uint32_t m_uTsbPdDelay; // aggreed delay
uint64_t m_ullTsbPdTimeBase; // localtime base for TsbPd mode
// Note: m_ullTsbPdTimeBase cumulates values from:
// 1. Initial SRT_CMD_HSREQ packet returned value diff to current time:
// == (NOW - PACKET_TIMESTAMP), at the time of HSREQ reception
// 2. Timestamp overflow (@c CRcvBuffer::getTsbPdTimeBase), when overflow on packet detected
// += CPacket::MAX_TIMESTAMP+1 (it's a hex round value, usually 0x1*e8).
// 3. Time drift (CRcvBuffer::addRcvTsbPdDriftSample, executed exclusively
// from UMSG_ACKACK handler). This is updated with (positive or negative) TSBPD_DRIFT_MAX_VALUE
// once the value of average drift exceeds this value in whatever direction.
// += (+/-)CRcvBuffer::TSBPD_DRIFT_MAX_VALUE
//
// XXX Application-supplied timestamps won't work therefore. This requires separate
// calculation of all these things above.
bool m_bTsbPdWrapCheck; // true: check packet time stamp wrap around
static const uint32_t TSBPD_WRAP_PERIOD = (30*1000000); //30 seconds (in usec)
static const int TSBPD_DRIFT_MAX_VALUE = 5000; // Max drift (usec) above which TsbPD Time Offset is adjusted
static const int TSBPD_DRIFT_MAX_SAMPLES = 1000; // Number of samples (UMSG_ACKACK packets) to perform drift caclulation and compensation
//int m_iTsbPdDrift; // recent drift in the packet time stamp
//int64_t m_TsbPdDriftSum; // Sum of sampled drift
//int m_iTsbPdDriftNbSamples; // Number of samples in sum and histogram
DriftTracer<TSBPD_DRIFT_MAX_SAMPLES, TSBPD_DRIFT_MAX_VALUE> m_DriftTracer;
#ifdef SRT_ENABLE_RCVBUFSZ_MAVG
uint64_t m_LastSamplingTime;
int m_TimespanMAvg;
int m_iCountMAvg;
int m_iBytesCountMAvg;
#endif /* SRT_ENABLE_RCVBUFSZ_MAVG */
#ifdef SRT_DEBUG_TSBPD_DRIFT
int m_TsbPdDriftHisto100us[22]; // Histogram of 100us TsbPD drift (-1.0 .. +1.0 ms in 0.1ms increment)
int m_TsbPdDriftHisto1ms[22]; // Histogram of TsbPD drift (-10.0 .. +10.0 ms, in 1.0 ms increment)
static const int TSBPD_DRIFT_PRT_SAMPLES = 200; // Number of samples (UMSG_ACKACK packets) to print hostogram
#endif /* SRT_DEBUG_TSBPD_DRIFT */
/// Query if data is ready to read (tsbpdtime <= now if TsbPD is active).
/// @param [out] tsbpdtime localtime-based (uSec) packet time stamp including buffering delay
/// of next packet in recv buffer, ready or not.
/// @param [out] curpktseq Sequence number of the packet if there is one ready to play
/// @return true if ready to play, false otherwise (tsbpdtime may be !0 in
/// both cases).
bool isRcvDataReady(time_point& w_tsbpdtime, int32_t& w_curpktseq, int32_t seqdistance);
#ifdef SRT_DEBUG_TSBPD_OUTJITTER
unsigned long m_ulPdHisto[4][10];
#endif /* SRT_DEBUG_TSBPD_OUTJITTER */
void debugTraceJitter(time_point t);
#else
void debugTraceJitter(time_point) {}
#endif /* SRT_DEBUG_TSBPD_OUTJITTER */
bool isRcvDataReady();
bool isRcvDataAvailable() { return m_iLastAckPos != m_iStartPos; }
CPacket* getRcvReadyPacket(int32_t seqdistance);
/// Set TimeStamp-Based Packet Delivery Rx Mode
/// @param [in] timebase localtime base (uSec) of packet time stamps including buffering delay
/// @param [in] delay aggreed TsbPD delay
void setRcvTsbPdMode(const time_point& timebase, const duration& delay);
/// Add packet timestamp for drift caclculation and compensation
/// @param [in] timestamp packet time stamp
/// @param [in] tsPktArrival arrival time of the packet used to extract the drift sample.
/// @param [in] rtt RTT sample
bool addRcvTsbPdDriftSample(uint32_t timestamp, const time_point& tsPktArrival, int rtt);
#ifdef SRT_DEBUG_TSBPD_DRIFT
void printDriftHistogram(int64_t iDrift);
void printDriftOffset(int tsbPdOffset, int tsbPdDriftAvg);
#endif
/// Get information on the 1st message in queue.
// Parameters (of the 1st packet queue, ready to play or not):
/// @param [out] w_tsbpdtime localtime-based (uSec) packet time stamp including buffering delay of 1st packet or 0
/// if none
/// @param [out] w_passack true if 1st ready packet is not yet acknowleged (allowed to be delivered to the app)
/// @param [out] w_skipseqno SRT_SEQNO_NONE or seq number of 1st unacknowledged pkt ready to play preceeded by
/// missing packets.
/// @param base_seq SRT_SEQNO_NONE or desired, ignore seq smaller than base if exist packet ready-to-play
/// and larger than base
/// @retval true 1st packet ready to play (tsbpdtime <= now). Not yet acknowledged if passack == true
/// @retval false IF tsbpdtime = 0: rcv buffer empty; ELSE:
/// IF skipseqno != SRT_SEQNO_NONE, packet ready to play preceeded by missing packets.;
/// IF skipseqno == SRT_SEQNO_NONE, no missing packet but 1st not ready to play.
bool getRcvFirstMsg(time_point& w_tsbpdtime,
bool& w_passack,
int32_t& w_skipseqno,
int32_t& w_curpktseq,
int32_t base_seq = SRT_SEQNO_NONE);
/// Update the ACK point of the buffer.
/// @param [in] len size of data to be skip & acknowledged.
void skipData(int len);
#if ENABLE_HEAVY_LOGGING
void reportBufferStats() const; // Heavy logging Debug only
#endif
bool empty() const
{
// This will not always return the intended value,
// that is, it may return false when the buffer really is
// empty - but it will return true then in one of next calls.
// This function will be always called again at some point
// if it returned false, and on true the connection
// is going to be broken - so this behavior is acceptable.
return m_iStartPos == m_iLastAckPos;
}
bool full() const { return m_iStartPos == (m_iLastAckPos + 1) % m_iSize; }
int capacity() const { return m_iSize; }
private:
CRcvBuffer();
CRcvBuffer(const CRcvBuffer&);
CRcvBuffer& operator=(const CRcvBuffer&);
/// This gives up unit at index p. The unit is given back to the
/// free unit storage for further assignment for the new incoming
/// data.
size_t freeUnitAt(size_t p)
{
CUnit* u = m_pUnit[p];
m_pUnit[p] = NULL;
size_t rmbytes = u->m_Packet.getLength();
m_pUnitQueue->makeUnitFree(u);
return rmbytes;
}
/// Adjust receive queue to 1st ready to play message (tsbpdtime < now).
/// Parameters (of the 1st packet queue, ready to play or not):
/// @param [out] tsbpdtime localtime-based (uSec) packet time stamp including buffering delay of 1st packet or 0 if
/// none
/// @param base_seq SRT_SEQNO_NONE or desired, ignore seq smaller than base
/// @retval true 1st packet ready to play without discontinuity (no hole)
/// @retval false tsbpdtime = 0: no packet ready to play
bool getRcvReadyMsg(time_point& w_tsbpdtime, int32_t& w_curpktseq, int upto, int base_seq = SRT_SEQNO_NONE);
public:
/// @brief Get clock drift in microseconds.
int64_t getDrift() const { return m_tsbpd.drift(); }
public:
int32_t getTopMsgno() const;
void getInternalTimeBase(time_point& w_tb, bool& w_wrp, duration& w_udrift);
void applyGroupTime(const time_point& timebase, bool wrapcheck, uint32_t delay, const duration& udrift);
void applyGroupDrift(const time_point& timebase, bool wrapcheck, const duration& udrift);
time_point getPktTsbPdTime(uint32_t timestamp);
int debugGetSize() const;
time_point debugGetDeliveryTime(int offset);
size_t dropData(int len);
private:
int extractData(char* data, int len, int p, int q, bool passack);
bool accessMsg(int& w_p, int& w_q, bool& w_passack, int64_t& w_playtime, int upto);
/// Describes the state of the first N packets
std::string debugTimeState(size_t first_n_pkts) const;
/// thread safe bytes counter of the Recv & Ack buffer
/// @param [in] pkts acked or removed pkts from rcv buffer (used with acked = true)
/// @param [in] bytes number of bytes added/delete (if negative) to/from rcv buffer.
/// @param [in] acked true when adding new pkt in RcvBuffer; false when acking/removing pkts to/from buffer
void countBytes(int pkts, int bytes, bool acked = false);
private:
bool scanMsg(int& w_start, int& w_end, bool& w_passack);
int shift(int basepos, int shift) const { return (basepos + shift) % m_iSize; }
/// Simplified versions with ++ and --; avoid using division instruction
int shiftFwd(int basepos) const
{
if (++basepos == m_iSize)
return 0;
return basepos;
}
int shiftBack(int basepos) const
{
if (basepos == 0)
return m_iSize - 1;
return --basepos;
}
private:
CUnit** m_pUnit; // Array of pointed units collected in the buffer
const int m_iSize; // Size of the internal array of CUnit* items
CUnitQueue* m_pUnitQueue; // the shared unit queue
int m_iStartPos; // HEAD: first packet available for reading
int m_iLastAckPos; // the last ACKed position (exclusive), follows the last readable
// EMPTY: m_iStartPos = m_iLastAckPos FULL: m_iStartPos = m_iLastAckPos + 1
int m_iMaxPos; // delta between acked-TAIL and reception-TAIL
int m_iNotch; // the starting read point of the first unit
// (this is required for stream reading mode; it's
// the position in the first unit in the list
// up to which data are already retrieved;
// in message reading mode it's unused and always 0)
sync::Mutex m_BytesCountLock; // used to protect counters operations
int m_iBytesCount; // Number of payload bytes in the buffer
int m_iAckedPktsCount; // Number of acknowledged pkts in the buffer
int m_iAckedBytesCount; // Number of acknowledged payload bytes in the buffer
unsigned m_uAvgPayloadSz; // Average payload size for dropped bytes estimation
CTsbpdTime m_tsbpd;
AvgBufSize m_mavg;
private:
CRcvBuffer();
CRcvBuffer(const CRcvBuffer&);
CRcvBuffer& operator=(const CRcvBuffer&);
};
#endif // !ENABLE_NEW_RCVBUFFER
} // namespace srt
#endif