#ifndef INC_SRT_WINDOW_H
#define INC_SRT_WINDOW_H
#ifndef _WIN32
#include <sys/time.h>
#include <time.h>
#endif
#include "udt.h"
#include "packet.h"
namespace ACKWindowTools
{
struct Seq
{
int32_t iACKSeqNo; int32_t iACK; srt::sync::steady_clock::time_point tsTimeStamp; };
void store(Seq* r_aSeq, const size_t size, int& r_iHead, int& r_iTail, int32_t seq, int32_t ack);
int acknowledge(Seq* r_aSeq, const size_t size, int& r_iHead, int& r_iTail, int32_t seq, int32_t& r_ack);
}
template <size_t SIZE>
class CACKWindow
{
public:
CACKWindow() :
m_aSeq(),
m_iHead(0),
m_iTail(0)
{
m_aSeq[0].iACKSeqNo = SRT_SEQNO_NONE;
}
~CACKWindow() {}
void store(int32_t seq, int32_t ack)
{
return ACKWindowTools::store(m_aSeq, SIZE, m_iHead, m_iTail, seq, ack);
}
int acknowledge(int32_t seq, int32_t& r_ack)
{
return ACKWindowTools::acknowledge(m_aSeq, SIZE, m_iHead, m_iTail, seq, r_ack);
}
private:
typedef ACKWindowTools::Seq Seq;
Seq m_aSeq[SIZE];
int m_iHead; int m_iTail;
private:
CACKWindow(const CACKWindow&);
CACKWindow& operator=(const CACKWindow&);
};
class CPktTimeWindowTools
{
public:
static int getPktRcvSpeed_in(const int* window, int* replica, const int* bytes, size_t asize, int& bytesps);
static int getBandwidth_in(const int* window, int* replica, size_t psize);
static void initializeWindowArrays(int* r_pktWindow, int* r_probeWindow, int* r_bytesWindow, size_t asize, size_t psize);
};
template <size_t ASIZE = 16, size_t PSIZE = 16>
class CPktTimeWindow: CPktTimeWindowTools
{
public:
CPktTimeWindow():
m_aPktWindow(),
m_aBytesWindow(),
m_iPktWindowPtr(0),
m_aProbeWindow(),
m_iProbeWindowPtr(0),
m_iLastSentTime(0),
m_iMinPktSndInt(1000000),
m_tsLastArrTime(srt::sync::steady_clock::now()),
m_tsCurrArrTime(),
m_tsProbeTime(),
m_Probe1Sequence(SRT_SEQNO_NONE)
{
srt::sync::setupMutex(m_lockPktWindow, "PktWindow");
srt::sync::setupMutex(m_lockProbeWindow, "ProbeWindow");
CPktTimeWindowTools::initializeWindowArrays(m_aPktWindow, m_aProbeWindow, m_aBytesWindow, ASIZE, PSIZE);
}
~CPktTimeWindow()
{
}
public:
int getMinPktSndInt() const { return m_iMinPktSndInt; }
int getPktRcvSpeed(int& w_bytesps) const
{
srt::sync::ScopedLock cg(m_lockPktWindow);
int pktReplica[ASIZE]; return getPktRcvSpeed_in(m_aPktWindow, pktReplica, m_aBytesWindow, ASIZE, (w_bytesps));
}
int getPktRcvSpeed() const
{
int bytesps;
return getPktRcvSpeed((bytesps));
}
int getBandwidth() const
{
srt::sync::ScopedLock cg(m_lockProbeWindow);
int probeReplica[PSIZE];
return getBandwidth_in(m_aProbeWindow, probeReplica, PSIZE);
}
void onPktSent(int currtime)
{
int interval = currtime - m_iLastSentTime;
if ((interval < m_iMinPktSndInt) && (interval > 0))
m_iMinPktSndInt = interval;
m_iLastSentTime = currtime;
}
void onPktArrival(int pktsz = 0)
{
srt::sync::ScopedLock cg(m_lockPktWindow);
m_tsCurrArrTime = srt::sync::steady_clock::now();
m_aPktWindow[m_iPktWindowPtr] = srt::sync::count_microseconds(m_tsCurrArrTime - m_tsLastArrTime);
m_aBytesWindow[m_iPktWindowPtr] = pktsz;
++ m_iPktWindowPtr;
if (m_iPktWindowPtr == ASIZE)
m_iPktWindowPtr = 0;
m_tsLastArrTime = m_tsCurrArrTime;
}
void probeArrival(const CPacket& pkt, bool unordered)
{
const int inorder16 = pkt.m_iSeqNo & PUMASK_SEQNO_PROBE;
if (inorder16 == 0)
{
probe1Arrival(pkt, unordered);
}
if (unordered)
return;
if (inorder16 == 1)
{
probe2Arrival(pkt);
}
}
void probe1Arrival(const CPacket& pkt, bool unordered)
{
if (unordered && pkt.m_iSeqNo == m_Probe1Sequence)
{
m_Probe1Sequence = SRT_SEQNO_NONE;
return;
}
m_tsProbeTime = srt::sync::steady_clock::now();
m_Probe1Sequence = pkt.m_iSeqNo; }
void probe2Arrival(const CPacket& pkt)
{
if (m_Probe1Sequence == SRT_SEQNO_NONE || CSeqNo::incseq(m_Probe1Sequence) != pkt.m_iSeqNo)
return;
const srt::sync::steady_clock::time_point now = srt::sync::steady_clock::now();
srt::sync::ScopedLock cg(m_lockProbeWindow);
m_tsCurrArrTime = now;
m_Probe1Sequence = SRT_SEQNO_NONE;
const int64_t timediff = srt::sync::count_microseconds(m_tsCurrArrTime - m_tsProbeTime);
const int64_t timediff_times_pl_size = timediff * CPacket::SRT_MAX_PAYLOAD_SIZE;
const size_t pktsz = pkt.getLength();
m_aProbeWindow[m_iProbeWindowPtr] = pktsz ? timediff_times_pl_size / pktsz : int(timediff);
++ m_iProbeWindowPtr;
if (m_iProbeWindowPtr == PSIZE)
m_iProbeWindowPtr = 0;
}
private:
int m_aPktWindow[ASIZE]; int m_aBytesWindow[ASIZE]; int m_iPktWindowPtr; mutable srt::sync::Mutex m_lockPktWindow;
int m_aProbeWindow[PSIZE]; int m_iProbeWindowPtr; mutable srt::sync::Mutex m_lockProbeWindow;
int m_iLastSentTime; int m_iMinPktSndInt;
srt::sync::steady_clock::time_point m_tsLastArrTime; srt::sync::steady_clock::time_point m_tsCurrArrTime; srt::sync::steady_clock::time_point m_tsProbeTime; int32_t m_Probe1Sequence;
private:
CPktTimeWindow(const CPktTimeWindow&);
CPktTimeWindow &operator=(const CPktTimeWindow&);
};
#endif