improved jitter buffer correction algorithm
This commit is contained in:
parent
52fc35357e
commit
ca945124cf
5 changed files with 121 additions and 41 deletions
|
@ -41,6 +41,9 @@ void CNetBuf::Init ( const int iNewBlockSize,
|
|||
|
||||
// use the "get" flag to make sure the buffer is cleared
|
||||
Clear ( CT_GET );
|
||||
|
||||
// init statistic
|
||||
ErrorRateStatistic.Init ( MAX_STATISTIC_COUNT );
|
||||
}
|
||||
|
||||
bool CNetBuf::Put ( const CVector<uint8_t>& vecbyData,
|
||||
|
@ -103,6 +106,9 @@ bool CNetBuf::Put ( const CVector<uint8_t>& vecbyData,
|
|||
eBufState = CNetBuf::BS_OK;
|
||||
}
|
||||
|
||||
// update statistic
|
||||
ErrorRateStatistic.Update ( !bPutOK );
|
||||
|
||||
return bPutOK;
|
||||
}
|
||||
|
||||
|
@ -184,6 +190,9 @@ bool CNetBuf::Get ( CVector<uint8_t>& vecbyData )
|
|||
eBufState = CNetBuf::BS_OK;
|
||||
}
|
||||
|
||||
// update statistic
|
||||
ErrorRateStatistic.Update ( !bGetOK );
|
||||
|
||||
return bGetOK;
|
||||
}
|
||||
|
||||
|
@ -231,14 +240,52 @@ int CNetBuf::GetAvailData() const
|
|||
|
||||
void CNetBuf::Clear ( const EClearType eClearType )
|
||||
{
|
||||
// TEST defines
|
||||
const bool bUseRandomInit = false;
|
||||
const int iNumBlocksBoundForRandom = 6;
|
||||
// Define the number of blocks bound for the "random offset" (1) algorithm.
|
||||
// If we are above the bound, we use the "middle of buffer" (2) algorithm.
|
||||
// Test results (with different jitter buffer sizes), given is the error
|
||||
// probability of jitter buffer (probability of corrections in the buffer):
|
||||
// kX, 128 samples, WLAN:
|
||||
// 2: (1) 5 %, (2) 12.3 %
|
||||
// 3: (1) 18.3 %, (2) 17.1 %
|
||||
// 5: (1) 0.9 %, (2) 0.8 %
|
||||
// kX, 128 samples, localhost:
|
||||
// 2: (1) 2.5 %, (2) 13 %
|
||||
// 3: (1) 0.9 %, (2) 1.1 %
|
||||
// 5: (1) 0.7 %, (2) 0.6 %
|
||||
// Behringer, 128 samples, WLAN:
|
||||
// 2: (1) 5.8 %, (2) 9.4 %
|
||||
// 3: (1) 0.9 %, (2) 0.8 %
|
||||
// 5: (1) 0.4 %, (2) 0.3 %
|
||||
// Behringer, 128 samples, localhost:
|
||||
// 2: (1) 1 %, (2) 9.8 %
|
||||
// 3: (1) 0.57 %, (2) 0.6 %
|
||||
// 5: (1) 0.6 %, (2) 0.56 %
|
||||
// kX, 256 samples, WLAN:
|
||||
// 3: (1) 24.2 %, (2) 18.4 %
|
||||
// 4: (1) 1.5 %, (2) 2.5 %
|
||||
// 5: (1) 1 %, (2) 1 %
|
||||
// ASIO4All, 256 samples, WLAN:
|
||||
// 3: (1) 14.9 %, (2) 11.9 %
|
||||
// 4: (1) 1.5 %, (2) 7 %
|
||||
// 5: (1) 1.2 %, (2) 1.3 %
|
||||
const int iNumBlocksBoundInclForRandom = 4; // by extensive testing: 4
|
||||
|
||||
int iNewFillLevel = 0;
|
||||
|
||||
if ( iBlockSize != 0 )
|
||||
{
|
||||
const int iNumBlocks = iMemSize / iBlockSize;
|
||||
if ( iNumBlocks <= iNumBlocksBoundInclForRandom ) // just for small buffers
|
||||
{
|
||||
// random position algorithm
|
||||
// overwrite fill level with random value, the range
|
||||
// is 0 to (iMemSize - iBlockSize)
|
||||
iNewFillLevel = static_cast<int> ( static_cast<double> ( rand() ) *
|
||||
iNumBlocks / RAND_MAX ) * iBlockSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
// middle of buffer algorithm
|
||||
// with the following operation we set the fill level to a block
|
||||
// boundary (one block below the middle of the buffer in case of odd
|
||||
// number of blocks, e.g.:
|
||||
|
@ -246,26 +293,7 @@ const int iNumBlocksBoundForRandom = 6;
|
|||
// 1: 0 / 2: 0 / 3: 1 / 4: 1 / 5: 2 ...)
|
||||
iNewFillLevel =
|
||||
( ( ( iMemSize - iBlockSize) / 2 ) / iBlockSize ) * iBlockSize;
|
||||
|
||||
// TEST random init position
|
||||
if ( bUseRandomInit )
|
||||
{
|
||||
const int iNumBlocks = iMemSize / iBlockSize;
|
||||
if ( iNumBlocks < iNumBlocksBoundForRandom ) // just for very small buffers
|
||||
{
|
||||
// overwrite fill level with random value, the range
|
||||
// is 0 to (iMemSize - iBlockSize)
|
||||
iNewFillLevel = static_cast<int> ( static_cast<double> ( rand() ) *
|
||||
iNumBlocks / RAND_MAX ) * iBlockSize;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
// TEST
|
||||
static FILE* pFile = fopen ( "test.dat", "w" );
|
||||
fprintf ( pFile, "%d %d %d\n", iMemSize, iBlockSize, iNewFillLevel );
|
||||
fflush ( pFile );
|
||||
*/
|
||||
}
|
||||
|
||||
// different behaviour for get and put corrections
|
||||
|
|
14
src/buffer.h
14
src/buffer.h
|
@ -29,7 +29,14 @@
|
|||
#include "global.h"
|
||||
|
||||
|
||||
/* Definitions ****************************************************************/
|
||||
// each regular buffer access lead to a count for put and get, assuming 2.33 ms
|
||||
// blocks we have 30 s / 2.33 ms * 2 = 25714
|
||||
#define MAX_STATISTIC_COUNT 25714
|
||||
|
||||
|
||||
/* Classes ********************************************************************/
|
||||
// Network buffer (jitter buffer) ----------------------------------------------
|
||||
class CNetBuf
|
||||
{
|
||||
public:
|
||||
|
@ -42,6 +49,8 @@ public:
|
|||
bool Put ( const CVector<uint8_t>& vecbyData, const int iInSize );
|
||||
bool Get ( CVector<uint8_t>& vecbyData );
|
||||
|
||||
double GetErrorRate() { return ErrorRateStatistic.GetAverage(); }
|
||||
|
||||
protected:
|
||||
enum EBufState { BS_OK, BS_FULL, BS_EMPTY };
|
||||
enum EClearType { CT_PUT, CT_GET };
|
||||
|
@ -55,10 +64,13 @@ protected:
|
|||
int iNumInvalidElements;
|
||||
int iGetPos, iPutPos;
|
||||
EBufState eBufState;
|
||||
|
||||
// statistic
|
||||
CErrorRate ErrorRateStatistic;
|
||||
};
|
||||
|
||||
|
||||
// conversion buffer (very simple buffer)
|
||||
// Conversion buffer (very simple buffer) --------------------------------------
|
||||
template<class TData> class CConvBuf
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -104,6 +104,7 @@ public:
|
|||
int GetNetwFrameSizeFact() const { return iNetwFrameSizeFact; }
|
||||
int GetNetwFrameSize() const { return iNetwFrameSize; }
|
||||
|
||||
double GetJitterBufferErrorRate() { return SockBuf.GetErrorRate(); }
|
||||
|
||||
// network protocol interface
|
||||
void CreateJitBufMes ( const int iJitBufSize )
|
||||
|
|
|
@ -704,6 +704,7 @@ void CLlconClientDlg::UpdateDisplay()
|
|||
|
||||
// TEST
|
||||
//TextLabelStatus->setText ( QString( "Time: %1, Netw: %2" ).arg ( pClient->GetTimingStdDev() ).arg ( pClient->GetChannel()->GetTimingStdDev() ) );
|
||||
//TextLabelStatus->setText ( QString( "Buf. Err. Rate: %1 %" ).arg ( pClient->GetChannel()->GetJitterBufferErrorRate() * 100.0 ) );
|
||||
|
||||
}
|
||||
|
||||
|
|
42
src/util.h
42
src/util.h
|
@ -562,15 +562,15 @@ public:
|
|||
|
||||
|
||||
/******************************************************************************\
|
||||
* Cycle Time Variance Measurement *
|
||||
* Statistics *
|
||||
\******************************************************************************/
|
||||
// Cycle time variance measurement ---------------------------------------------
|
||||
// use for, e.g., measuring the variance of a timer
|
||||
class CCycleTimeVariance
|
||||
{
|
||||
public:
|
||||
CCycleTimeVariance() : iBlockLengthAtSystemSampleRate ( 0 ),
|
||||
dIntervalTime ( 0.0 ), iNewValueBoundFactor ( 0 ) {}
|
||||
virtual ~CCycleTimeVariance() {}
|
||||
|
||||
void Init ( const int iNewBlockLengthAtSystemSampleRate,
|
||||
const int iNewSystemSampleRate,
|
||||
|
@ -644,4 +644,42 @@ protected:
|
|||
int iNewValueBoundFactor;
|
||||
};
|
||||
|
||||
// Error rate measurement ------------------------------------------------------
|
||||
class CErrorRate
|
||||
{
|
||||
public:
|
||||
CErrorRate() {}
|
||||
|
||||
void Init ( const int iHistoryLength )
|
||||
{
|
||||
// initialize buffer
|
||||
ErrorsMovAvBuf.Init ( iHistoryLength );
|
||||
}
|
||||
|
||||
void Reset()
|
||||
{
|
||||
ErrorsMovAvBuf.Reset();
|
||||
}
|
||||
|
||||
void Update ( const bool bState )
|
||||
{
|
||||
// add errors as values 0 and 1 to get correct error rate average
|
||||
if ( bState )
|
||||
{
|
||||
ErrorsMovAvBuf.Add ( 1.0 );
|
||||
}
|
||||
else
|
||||
{
|
||||
ErrorsMovAvBuf.Add ( 0.0 );
|
||||
}
|
||||
}
|
||||
|
||||
// return the standard deviation, for that we need to calculate
|
||||
// the sqaure root
|
||||
double GetAverage() { return ErrorsMovAvBuf.GetAverage(); }
|
||||
|
||||
protected:
|
||||
CMovingAv<double> ErrorsMovAvBuf;
|
||||
};
|
||||
|
||||
#endif /* !defined ( UTIL_HOIH934256GEKJH98_3_43445KJIUHF1912__INCLUDED_ ) */
|
||||
|
|
Loading…
Reference in a new issue