improved jitter buffer correction algorithm
This commit is contained in:
parent
52fc35357e
commit
ca945124cf
5 changed files with 121 additions and 41 deletions
|
@ -11,16 +11,16 @@
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it under
|
* This program is free software; you can redistribute it and/or modify it under
|
||||||
* the terms of the GNU General Public License as published by the Free Software
|
* the terms of the GNU General Public License as published by the Free Software
|
||||||
* Foundation; either version 2 of the License, or (at your option) any later
|
* Foundation; either version 2 of the License, or (at your option) any later
|
||||||
* version.
|
* version.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
* details.
|
* details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License along with
|
* You should have received a copy of the GNU General Public License along with
|
||||||
* this program; if not, write to the Free Software Foundation, Inc.,
|
* this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*
|
*
|
||||||
\******************************************************************************/
|
\******************************************************************************/
|
||||||
|
@ -41,6 +41,9 @@ void CNetBuf::Init ( const int iNewBlockSize,
|
||||||
|
|
||||||
// use the "get" flag to make sure the buffer is cleared
|
// use the "get" flag to make sure the buffer is cleared
|
||||||
Clear ( CT_GET );
|
Clear ( CT_GET );
|
||||||
|
|
||||||
|
// init statistic
|
||||||
|
ErrorRateStatistic.Init ( MAX_STATISTIC_COUNT );
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CNetBuf::Put ( const CVector<uint8_t>& vecbyData,
|
bool CNetBuf::Put ( const CVector<uint8_t>& vecbyData,
|
||||||
|
@ -103,6 +106,9 @@ bool CNetBuf::Put ( const CVector<uint8_t>& vecbyData,
|
||||||
eBufState = CNetBuf::BS_OK;
|
eBufState = CNetBuf::BS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// update statistic
|
||||||
|
ErrorRateStatistic.Update ( !bPutOK );
|
||||||
|
|
||||||
return bPutOK;
|
return bPutOK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,6 +190,9 @@ bool CNetBuf::Get ( CVector<uint8_t>& vecbyData )
|
||||||
eBufState = CNetBuf::BS_OK;
|
eBufState = CNetBuf::BS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// update statistic
|
||||||
|
ErrorRateStatistic.Update ( !bGetOK );
|
||||||
|
|
||||||
return bGetOK;
|
return bGetOK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -231,41 +240,60 @@ int CNetBuf::GetAvailData() const
|
||||||
|
|
||||||
void CNetBuf::Clear ( const EClearType eClearType )
|
void CNetBuf::Clear ( const EClearType eClearType )
|
||||||
{
|
{
|
||||||
// TEST defines
|
// Define the number of blocks bound for the "random offset" (1) algorithm.
|
||||||
const bool bUseRandomInit = false;
|
// If we are above the bound, we use the "middle of buffer" (2) algorithm.
|
||||||
const int iNumBlocksBoundForRandom = 6;
|
// 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;
|
int iNewFillLevel = 0;
|
||||||
|
|
||||||
if ( iBlockSize != 0 )
|
if ( iBlockSize != 0 )
|
||||||
{
|
{
|
||||||
// with the following operation we set the fill level to a block
|
const int iNumBlocks = iMemSize / iBlockSize;
|
||||||
// boundary (one block below the middle of the buffer in case of odd
|
if ( iNumBlocks <= iNumBlocksBoundInclForRandom ) // just for small buffers
|
||||||
// number of blocks, e.g.:
|
{
|
||||||
// [buffer size]: [get pos]
|
// random position algorithm
|
||||||
// 1: 0 / 2: 0 / 3: 1 / 4: 1 / 5: 2 ...)
|
// overwrite fill level with random value, the range
|
||||||
iNewFillLevel =
|
// is 0 to (iMemSize - iBlockSize)
|
||||||
( ( ( iMemSize - iBlockSize) / 2 ) / iBlockSize ) * iBlockSize;
|
iNewFillLevel = static_cast<int> ( static_cast<double> ( rand() ) *
|
||||||
|
iNumBlocks / RAND_MAX ) * iBlockSize;
|
||||||
// TEST random init position
|
}
|
||||||
if ( bUseRandomInit )
|
else
|
||||||
{
|
{
|
||||||
const int iNumBlocks = iMemSize / iBlockSize;
|
// middle of buffer algorithm
|
||||||
if ( iNumBlocks < iNumBlocksBoundForRandom ) // just for very small buffers
|
// 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
|
||||||
// overwrite fill level with random value, the range
|
// number of blocks, e.g.:
|
||||||
// is 0 to (iMemSize - iBlockSize)
|
// [buffer size]: [get pos]
|
||||||
iNewFillLevel = static_cast<int> ( static_cast<double> ( rand() ) *
|
// 1: 0 / 2: 0 / 3: 1 / 4: 1 / 5: 2 ...)
|
||||||
iNumBlocks / RAND_MAX ) * iBlockSize;
|
iNewFillLevel =
|
||||||
}
|
( ( ( iMemSize - iBlockSize) / 2 ) / iBlockSize ) * 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
|
// different behaviour for get and put corrections
|
||||||
|
|
22
src/buffer.h
22
src/buffer.h
|
@ -8,16 +8,16 @@
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it under
|
* This program is free software; you can redistribute it and/or modify it under
|
||||||
* the terms of the GNU General Public License as published by the Free Software
|
* the terms of the GNU General Public License as published by the Free Software
|
||||||
* Foundation; either version 2 of the License, or (at your option) any later
|
* Foundation; either version 2 of the License, or (at your option) any later
|
||||||
* version.
|
* version.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
* details.
|
* details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License along with
|
* You should have received a copy of the GNU General Public License along with
|
||||||
* this program; if not, write to the Free Software Foundation, Inc.,
|
* this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*
|
*
|
||||||
\******************************************************************************/
|
\******************************************************************************/
|
||||||
|
@ -29,7 +29,14 @@
|
||||||
#include "global.h"
|
#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 ********************************************************************/
|
/* Classes ********************************************************************/
|
||||||
|
// Network buffer (jitter buffer) ----------------------------------------------
|
||||||
class CNetBuf
|
class CNetBuf
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -42,6 +49,8 @@ public:
|
||||||
bool Put ( const CVector<uint8_t>& vecbyData, const int iInSize );
|
bool Put ( const CVector<uint8_t>& vecbyData, const int iInSize );
|
||||||
bool Get ( CVector<uint8_t>& vecbyData );
|
bool Get ( CVector<uint8_t>& vecbyData );
|
||||||
|
|
||||||
|
double GetErrorRate() { return ErrorRateStatistic.GetAverage(); }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
enum EBufState { BS_OK, BS_FULL, BS_EMPTY };
|
enum EBufState { BS_OK, BS_FULL, BS_EMPTY };
|
||||||
enum EClearType { CT_PUT, CT_GET };
|
enum EClearType { CT_PUT, CT_GET };
|
||||||
|
@ -55,10 +64,13 @@ protected:
|
||||||
int iNumInvalidElements;
|
int iNumInvalidElements;
|
||||||
int iGetPos, iPutPos;
|
int iGetPos, iPutPos;
|
||||||
EBufState eBufState;
|
EBufState eBufState;
|
||||||
|
|
||||||
|
// statistic
|
||||||
|
CErrorRate ErrorRateStatistic;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// conversion buffer (very simple buffer)
|
// Conversion buffer (very simple buffer) --------------------------------------
|
||||||
template<class TData> class CConvBuf
|
template<class TData> class CConvBuf
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -104,6 +104,7 @@ public:
|
||||||
int GetNetwFrameSizeFact() const { return iNetwFrameSizeFact; }
|
int GetNetwFrameSizeFact() const { return iNetwFrameSizeFact; }
|
||||||
int GetNetwFrameSize() const { return iNetwFrameSize; }
|
int GetNetwFrameSize() const { return iNetwFrameSize; }
|
||||||
|
|
||||||
|
double GetJitterBufferErrorRate() { return SockBuf.GetErrorRate(); }
|
||||||
|
|
||||||
// network protocol interface
|
// network protocol interface
|
||||||
void CreateJitBufMes ( const int iJitBufSize )
|
void CreateJitBufMes ( const int iJitBufSize )
|
||||||
|
|
|
@ -704,6 +704,7 @@ void CLlconClientDlg::UpdateDisplay()
|
||||||
|
|
||||||
// TEST
|
// TEST
|
||||||
//TextLabelStatus->setText ( QString( "Time: %1, Netw: %2" ).arg ( pClient->GetTimingStdDev() ).arg ( pClient->GetChannel()->GetTimingStdDev() ) );
|
//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
|
// use for, e.g., measuring the variance of a timer
|
||||||
class CCycleTimeVariance
|
class CCycleTimeVariance
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CCycleTimeVariance() : iBlockLengthAtSystemSampleRate ( 0 ),
|
CCycleTimeVariance() : iBlockLengthAtSystemSampleRate ( 0 ),
|
||||||
dIntervalTime ( 0.0 ), iNewValueBoundFactor ( 0 ) {}
|
dIntervalTime ( 0.0 ), iNewValueBoundFactor ( 0 ) {}
|
||||||
virtual ~CCycleTimeVariance() {}
|
|
||||||
|
|
||||||
void Init ( const int iNewBlockLengthAtSystemSampleRate,
|
void Init ( const int iNewBlockLengthAtSystemSampleRate,
|
||||||
const int iNewSystemSampleRate,
|
const int iNewSystemSampleRate,
|
||||||
|
@ -644,4 +644,42 @@ protected:
|
||||||
int iNewValueBoundFactor;
|
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_ ) */
|
#endif /* !defined ( UTIL_HOIH934256GEKJH98_3_43445KJIUHF1912__INCLUDED_ ) */
|
||||||
|
|
Loading…
Reference in a new issue