insert invalid elements when buffer underrun to improve PLC, some code clean up
This commit is contained in:
parent
130901ef39
commit
29f6684aba
1 changed files with 20 additions and 213 deletions
233
src/buffer.cpp
233
src/buffer.cpp
|
@ -37,12 +37,13 @@ void CNetBuf::Init ( const int iNewBlockSize,
|
||||||
iBlockSize = iNewBlockSize;
|
iBlockSize = iNewBlockSize;
|
||||||
|
|
||||||
// total size -> size of one block times the number of blocks
|
// total size -> size of one block times the number of blocks
|
||||||
CBufferBase<uint8_t>::Init ( iNewBlockSize * iNewNumBlocks, bPreserve );
|
CBufferBase<uint8_t>::Init ( iNewBlockSize * iNewNumBlocks,
|
||||||
|
bPreserve );
|
||||||
|
|
||||||
// use the "get" flag to make sure the buffer is cleared
|
// clear buffer if not preserved
|
||||||
if ( !bPreserve )
|
if ( !bPreserve )
|
||||||
{
|
{
|
||||||
Clear ( CT_GET );
|
Clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,47 +52,10 @@ bool CNetBuf::Put ( const CVector<uint8_t>& vecbyData,
|
||||||
{
|
{
|
||||||
bool bPutOK = true;
|
bool bPutOK = true;
|
||||||
|
|
||||||
// Check if there is not enough space available -> correct
|
// check if there is not enough space available
|
||||||
if ( GetAvailSpace() < iInSize )
|
if ( GetAvailSpace() < iInSize )
|
||||||
{
|
{
|
||||||
/*
|
return false;
|
||||||
// not enough space in buffer for put operation, correct buffer to
|
|
||||||
// prepare for new data
|
|
||||||
Clear ( CT_PUT );
|
|
||||||
|
|
||||||
bPutOK = false; // return error flag
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
// TEST invalidate last written block for better PLC
|
|
||||||
// ATTENTION: We assume that mem size is factor of block size here!!!!
|
|
||||||
if ( !bIsSimulation )
|
|
||||||
{
|
|
||||||
if ( iPutPos == 0 )
|
|
||||||
{
|
|
||||||
for ( int iPos = iMemSize - iInSize; iPos < iMemSize; iPos++ )
|
|
||||||
{
|
|
||||||
vecMemory[iPos] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for ( int iPos = iPutPos - iInSize; iPos < iPutPos; iPos++ )
|
|
||||||
{
|
|
||||||
vecMemory[iPos] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// check for special case: buffer memory is not sufficient
|
|
||||||
if ( iInSize > iMemSize )
|
|
||||||
{
|
|
||||||
// do nothing here, just return error code
|
|
||||||
return bPutOK;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// copy new data in internal buffer (implemented in base class)
|
// copy new data in internal buffer (implemented in base class)
|
||||||
|
@ -112,195 +76,38 @@ bool CNetBuf::Get ( CVector<uint8_t>& vecbyData )
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
// check for invalid data in buffer
|
// check for invalid data in buffer
|
||||||
if ( iNumInvalidElements > 0 )
|
if ( iNumInvalidElements > 0 )
|
||||||
{
|
{
|
||||||
// decrease number of invalid elements by the queried number (input
|
// decrease number of invalid elements by one
|
||||||
// size)
|
iNumInvalidElements -= 1;
|
||||||
iNumInvalidElements -= iInSize;
|
|
||||||
|
|
||||||
bGetOK = false; // return error flag
|
// return error flag, do not return function here since we have
|
||||||
|
// to call the base Get function to pick one block out of the
|
||||||
|
// buffer
|
||||||
|
bGetOK = false;
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
// Check if there is not enough data available -> correct
|
// check if there is not enough data available -> correct
|
||||||
if ( GetAvailData() < iInSize )
|
if ( GetAvailData() < iInSize )
|
||||||
{
|
{
|
||||||
/*
|
// in case we have a buffer underrun, invalidate the next 15 blocks
|
||||||
// not enough data in buffer for get operation, correct buffer to
|
// to avoid the unmusical noise resulting from a very short drop
|
||||||
// prepare for getting data
|
// out (note that if you want to change this value, also change
|
||||||
Clear ( CT_GET );
|
// the value in celt_decode_lost in celt.c)
|
||||||
|
iNumInvalidElements = 15;
|
||||||
|
|
||||||
bGetOK = false; // return error flag
|
return false;
|
||||||
*/
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// check for special case: buffer memory is not sufficient
|
|
||||||
if ( iInSize > iMemSize )
|
|
||||||
{
|
|
||||||
// do nothing here, just return error code
|
|
||||||
return bGetOK;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// copy data from internal buffer in output buffer (implemented in base
|
// copy data from internal buffer in output buffer (implemented in base
|
||||||
// class)
|
// class)
|
||||||
CBufferBase<uint8_t>::Get ( vecbyData );
|
CBufferBase<uint8_t>::Get ( vecbyData );
|
||||||
|
|
||||||
/*
|
|
||||||
// TEST check for all zero packet
|
|
||||||
bool bAllZeroPacket = true;
|
|
||||||
for ( int iPos = 0; iPos < iInSize; iPos++ )
|
|
||||||
{
|
|
||||||
if ( vecbyData[iPos] != 0 )
|
|
||||||
{
|
|
||||||
bAllZeroPacket = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ( bAllZeroPacket )
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
return bGetOK;
|
return bGetOK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CNetBuf::Clear ( const EClearType eClearType )
|
|
||||||
{
|
|
||||||
|
|
||||||
// TEST
|
|
||||||
CBufferBase<uint8_t>::Clear ( eClearType );
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
// 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.:
|
|
||||||
// [buffer size]: [get pos]
|
|
||||||
// 1: 0 / 2: 0 / 3: 1 / 4: 1 / 5: 2 ...)
|
|
||||||
iNewFillLevel =
|
|
||||||
( ( ( iMemSize - iBlockSize) / 2 ) / iBlockSize ) * iBlockSize;
|
|
||||||
|
|
||||||
|
|
||||||
// TEST
|
|
||||||
iNewFillLevel += static_cast<int> ( static_cast<double> ( rand() ) *
|
|
||||||
iNumBlocksBoundInclForRandom / RAND_MAX ) * iBlockSize -
|
|
||||||
iNumBlocksBoundInclForRandom / 2 * iBlockSize;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// different behaviour for get and put corrections
|
|
||||||
if ( eClearType == CT_GET )
|
|
||||||
{
|
|
||||||
// clear buffer since we had a buffer underrun
|
|
||||||
if ( !bIsSimulation )
|
|
||||||
{
|
|
||||||
vecMemory.Reset ( 0 );
|
|
||||||
}
|
|
||||||
|
|
||||||
// reset buffer pointers so that they are at maximum distance after
|
|
||||||
// the get operation (assign new fill level value to the get pointer)
|
|
||||||
iPutPos = 0;
|
|
||||||
iGetPos = iNewFillLevel;
|
|
||||||
|
|
||||||
// The buffer was cleared, the next time blocks are read from the
|
|
||||||
// buffer, these are invalid ones. Calculate the number of invalid
|
|
||||||
// elements
|
|
||||||
iNumInvalidElements = iMemSize - iNewFillLevel;
|
|
||||||
|
|
||||||
// check for special case
|
|
||||||
if ( iPutPos == iGetPos )
|
|
||||||
{
|
|
||||||
eBufState = CNetBuf::BS_FULL;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
eBufState = CNetBuf::BS_OK;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// in case of "put" correction, do not delete old data but only shift
|
|
||||||
// the pointers
|
|
||||||
iPutPos = iNewFillLevel;
|
|
||||||
|
|
||||||
// adjust put pointer relative to current get pointer, take care of
|
|
||||||
// wrap around
|
|
||||||
iPutPos += iGetPos;
|
|
||||||
if ( iPutPos > iMemSize )
|
|
||||||
{
|
|
||||||
iPutPos -= iMemSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
// in case of put correction, no invalid blocks are inserted
|
|
||||||
iNumInvalidElements = 0;
|
|
||||||
|
|
||||||
// check for special case
|
|
||||||
if ( iPutPos == iGetPos )
|
|
||||||
{
|
|
||||||
eBufState = CNetBuf::BS_EMPTY;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
eBufState = CNetBuf::BS_OK;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TEST
|
|
||||||
//iNumInvalidElements = 8 * iMemSize;
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Network buffer with statistic calculations implementation ******************/
|
/* Network buffer with statistic calculations implementation ******************/
|
||||||
CNetBufWithStats::CNetBufWithStats() :
|
CNetBufWithStats::CNetBufWithStats() :
|
||||||
|
|
Loading…
Reference in a new issue