use larger buffers for error rate estimation

This commit is contained in:
Volker Fischer 2011-06-11 18:47:48 +00:00
parent 9fbe334d8a
commit a133156c0b

View file

@ -1,480 +1,475 @@
/******************************************************************************\ /******************************************************************************\
* Copyright (c) 2004-2011 * Copyright (c) 2004-2011
* *
* Author(s): * Author(s):
* Volker Fischer * Volker Fischer
* *
****************************************************************************** ******************************************************************************
* *
* 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
* *
\******************************************************************************/ \******************************************************************************/
#if !defined ( BUFFER_H__3B123453_4344_BB23945IUHF1912__INCLUDED_ ) #if !defined ( BUFFER_H__3B123453_4344_BB23945IUHF1912__INCLUDED_ )
#define BUFFER_H__3B123453_4344_BB23945IUHF1912__INCLUDED_ #define BUFFER_H__3B123453_4344_BB23945IUHF1912__INCLUDED_
#include "util.h" #include "util.h"
#include "global.h" #include "global.h"
/* Definitions ****************************************************************/ /* Definitions ****************************************************************/
// each regular buffer access lead to a count for put and get, assuming 2.33 ms // 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 // blocks we have 5 * 60 s / 2.33 ms * 2 = 22500
//#define MAX_STATISTIC_COUNT 25714 #define MAX_STATISTIC_COUNT 225000
// TEST // number of simulation network jitter buffers for evaluating the statistic
// 7 / 0.00266 * 2 = 5263.1579 #define NUM_STAT_SIMULATION_BUFFERS 13
#define MAX_STATISTIC_COUNT 3759
/* Classes ********************************************************************/
// number of simulation network jitter buffers for evaluating the statistic // Buffer base class -----------------------------------------------------------
#define NUM_STAT_SIMULATION_BUFFERS 13 template<class TData> class CBufferBase
{
public:
/* Classes ********************************************************************/ CBufferBase ( const bool bNIsSim = false ) :
// Buffer base class ----------------------------------------------------------- bIsSimulation ( bNIsSim ), bIsInitialized ( false ) {}
template<class TData> class CBufferBase
{ void SetIsSimulation ( const bool bNIsSim ) { bIsSimulation = bNIsSim; }
public:
CBufferBase ( const bool bNIsSim = false ) : virtual void Init ( const int iNewMemSize,
bIsSimulation ( bNIsSim ), bIsInitialized ( false ) {} const bool bPreserve = false )
{
void SetIsSimulation ( const bool bNIsSim ) { bIsSimulation = bNIsSim; } // in simulation mode the size is not changed during operation -> we do
// not have to implement special code for this case
virtual void Init ( const int iNewMemSize, // only enter the "preserve" branch, if object was already initialized
const bool bPreserve = false ) if ( bPreserve && ( !bIsSimulation ) && bIsInitialized )
{ {
// in simulation mode the size is not changed during operation -> we do // copy old data in new vector using get pointer as zero per
// not have to implement special code for this case // definition
// only enter the "preserve" branch, if object was already initialized
if ( bPreserve && ( !bIsSimulation ) && bIsInitialized ) int iCurPos;
{
// copy old data in new vector using get pointer as zero per // copy current data in temporary vector
// definition CVector<TData> vecTempMemory ( vecMemory );
int iCurPos; // resize actual buffer memory
vecMemory.Init ( iNewMemSize );
// copy current data in temporary vector
CVector<TData> vecTempMemory ( vecMemory ); // get maximum number of data to be copied
int iCopyLen = GetAvailData();
// resize actual buffer memory if ( iCopyLen > iNewMemSize )
vecMemory.Init ( iNewMemSize ); {
iCopyLen = iNewMemSize;
// get maximum number of data to be copied }
int iCopyLen = GetAvailData();
if ( iCopyLen > iNewMemSize ) // set correct buffer state
{ if ( iCopyLen >= iNewMemSize )
iCopyLen = iNewMemSize; {
} eBufState = CBufferBase<TData>::BS_FULL;
}
// set correct buffer state else
if ( iCopyLen >= iNewMemSize ) {
{ if ( iCopyLen == 0 )
eBufState = CBufferBase<TData>::BS_FULL; {
} eBufState = CBufferBase<TData>::BS_EMPTY;
else }
{ else
if ( iCopyLen == 0 ) {
{ eBufState = CBufferBase<TData>::BS_OK;
eBufState = CBufferBase<TData>::BS_EMPTY; }
} }
else
{ if ( iGetPos < iPutPos )
eBufState = CBufferBase<TData>::BS_OK; {
} // "get" position is before "put" position -> no wrap around
} for ( iCurPos = 0; iCurPos < iCopyLen; iCurPos++ )
{
if ( iGetPos < iPutPos ) vecMemory[iCurPos] = vecTempMemory[iGetPos + iCurPos];
{ }
// "get" position is before "put" position -> no wrap around
for ( iCurPos = 0; iCurPos < iCopyLen; iCurPos++ ) // update put pointer
{ if ( eBufState == CBufferBase<TData>::BS_FULL )
vecMemory[iCurPos] = vecTempMemory[iGetPos + iCurPos]; {
} iPutPos = 0;
}
// update put pointer else
if ( eBufState == CBufferBase<TData>::BS_FULL ) {
{ iPutPos -= iGetPos;
iPutPos = 0; }
} }
else else
{ {
iPutPos -= iGetPos; // "put" position is before "get" position -> wrap around
} bool bEnoughSpaceForSecondPart = true;
} int iFirstPartLen = iMemSize - iGetPos;
else
{ // check that first copy length is not larger then new memory
// "put" position is before "get" position -> wrap around if ( iFirstPartLen > iCopyLen )
bool bEnoughSpaceForSecondPart = true; {
int iFirstPartLen = iMemSize - iGetPos; iFirstPartLen = iCopyLen;
bEnoughSpaceForSecondPart = false;
// check that first copy length is not larger then new memory }
if ( iFirstPartLen > iCopyLen )
{ for ( iCurPos = 0; iCurPos < iFirstPartLen; iCurPos++ )
iFirstPartLen = iCopyLen; {
bEnoughSpaceForSecondPart = false; vecMemory[iCurPos] = vecTempMemory[iGetPos + iCurPos];
} }
for ( iCurPos = 0; iCurPos < iFirstPartLen; iCurPos++ ) if ( bEnoughSpaceForSecondPart )
{ {
vecMemory[iCurPos] = vecTempMemory[iGetPos + iCurPos]; // calculate remaining copy length
} const int iRemainingCopyLen = iCopyLen - iFirstPartLen;
if ( bEnoughSpaceForSecondPart ) // perform copying of second part
{ for ( iCurPos = 0; iCurPos < iRemainingCopyLen; iCurPos++ )
// calculate remaining copy length {
const int iRemainingCopyLen = iCopyLen - iFirstPartLen; vecMemory[iCurPos + iFirstPartLen] =
vecTempMemory[iCurPos];
// perform copying of second part }
for ( iCurPos = 0; iCurPos < iRemainingCopyLen; iCurPos++ ) }
{
vecMemory[iCurPos + iFirstPartLen] = // update put pointer
vecTempMemory[iCurPos]; if ( eBufState == CBufferBase<TData>::BS_FULL )
} {
} iPutPos = 0;
}
// update put pointer else
if ( eBufState == CBufferBase<TData>::BS_FULL ) {
{ iPutPos += iFirstPartLen;
iPutPos = 0; }
} }
else
{ // update get position -> zero per definition
iPutPos += iFirstPartLen; iGetPos = 0;
} }
} else
{
// update get position -> zero per definition // allocate memory for actual data buffer
iGetPos = 0; if ( !bIsSimulation )
} {
else vecMemory.Init ( iNewMemSize );
{ }
// allocate memory for actual data buffer
if ( !bIsSimulation ) // init buffer pointers and buffer state (empty buffer)
{ iGetPos = 0;
vecMemory.Init ( iNewMemSize ); iPutPos = 0;
} eBufState = CBufferBase<TData>::BS_EMPTY;
}
// init buffer pointers and buffer state (empty buffer)
iGetPos = 0; // store total memory size value
iPutPos = 0; iMemSize = iNewMemSize;
eBufState = CBufferBase<TData>::BS_EMPTY;
} // set initialized flag
bIsInitialized = true;
// store total memory size value }
iMemSize = iNewMemSize;
virtual bool Put ( const CVector<TData>& vecData,
// set initialized flag const int iInSize )
bIsInitialized = true; {
} if ( bIsSimulation )
{
virtual bool Put ( const CVector<TData>& vecData, // in this simulation only the buffer pointers and the buffer state
const int iInSize ) // is updated, no actual data is transferred
{ iPutPos += iInSize;
if ( bIsSimulation ) if ( iPutPos >= iMemSize )
{ {
// in this simulation only the buffer pointers and the buffer state iPutPos -= iMemSize;
// is updated, no actual data is transferred }
iPutPos += iInSize; }
if ( iPutPos >= iMemSize ) else
{ {
iPutPos -= iMemSize; // copy new data in internal buffer
} int iCurPos = 0;
} if ( iPutPos + iInSize > iMemSize )
else {
{ // remaining space size for second block
// copy new data in internal buffer const int iRemSpace = iPutPos + iInSize - iMemSize;
int iCurPos = 0;
if ( iPutPos + iInSize > iMemSize ) // data must be written in two steps because of wrap around
{ while ( iPutPos < iMemSize )
// remaining space size for second block {
const int iRemSpace = iPutPos + iInSize - iMemSize; vecMemory[iPutPos++] = vecData[iCurPos++];
}
// data must be written in two steps because of wrap around
while ( iPutPos < iMemSize ) for ( iPutPos = 0; iPutPos < iRemSpace; iPutPos++ )
{ {
vecMemory[iPutPos++] = vecData[iCurPos++]; vecMemory[iPutPos] = vecData[iCurPos++];
} }
}
for ( iPutPos = 0; iPutPos < iRemSpace; iPutPos++ ) else
{ {
vecMemory[iPutPos] = vecData[iCurPos++]; // data can be written in one step
} const int iEnd = iPutPos + iInSize;
} while ( iPutPos < iEnd )
else {
{ vecMemory[iPutPos++] = vecData[iCurPos++];
// data can be written in one step }
const int iEnd = iPutPos + iInSize; }
while ( iPutPos < iEnd ) }
{
vecMemory[iPutPos++] = vecData[iCurPos++]; // set buffer state flag
} if ( iPutPos == iGetPos )
} {
} eBufState = CBufferBase<TData>::BS_FULL;
}
// set buffer state flag else
if ( iPutPos == iGetPos ) {
{ eBufState = CBufferBase<TData>::BS_OK;
eBufState = CBufferBase<TData>::BS_FULL; }
}
else return true; // no error check in base class, alyways return ok
{ }
eBufState = CBufferBase<TData>::BS_OK;
} virtual bool Get ( CVector<TData>& vecData )
{
return true; // no error check in base class, alyways return ok // get size of data to be get from the buffer
} const int iInSize = vecData.Size();
virtual bool Get ( CVector<TData>& vecData ) if ( bIsSimulation )
{ {
// get size of data to be get from the buffer // in this simulation only the buffer pointers and the buffer state
const int iInSize = vecData.Size(); // is updated, no actual data is transferred
iGetPos += iInSize;
if ( bIsSimulation ) if ( iGetPos >= iMemSize )
{ {
// in this simulation only the buffer pointers and the buffer state iGetPos -= iMemSize;
// is updated, no actual data is transferred }
iGetPos += iInSize; }
if ( iGetPos >= iMemSize ) else
{ {
iGetPos -= iMemSize; // copy data from internal buffer in output buffer
} int iCurPos = 0;
} if ( iGetPos + iInSize > iMemSize )
else {
{ // remaining data size for second block
// copy data from internal buffer in output buffer const int iRemData = iGetPos + iInSize - iMemSize;
int iCurPos = 0;
if ( iGetPos + iInSize > iMemSize ) // data must be read in two steps because of wrap around
{ while ( iGetPos < iMemSize )
// remaining data size for second block {
const int iRemData = iGetPos + iInSize - iMemSize; vecData[iCurPos++] = vecMemory[iGetPos++];
}
// data must be read in two steps because of wrap around
while ( iGetPos < iMemSize ) for ( iGetPos = 0; iGetPos < iRemData; iGetPos++ )
{ {
vecData[iCurPos++] = vecMemory[iGetPos++]; vecData[iCurPos++] = vecMemory[iGetPos];
} }
}
for ( iGetPos = 0; iGetPos < iRemData; iGetPos++ ) else
{ {
vecData[iCurPos++] = vecMemory[iGetPos]; // data can be read in one step
} const int iEnd = iGetPos + iInSize;
} while ( iGetPos < iEnd )
else {
{ vecData[iCurPos++] = vecMemory[iGetPos++];
// data can be read in one step }
const int iEnd = iGetPos + iInSize; }
while ( iGetPos < iEnd ) }
{
vecData[iCurPos++] = vecMemory[iGetPos++]; // set buffer state flag
} if ( iPutPos == iGetPos )
} {
} eBufState = CBufferBase<TData>::BS_EMPTY;
}
// set buffer state flag else
if ( iPutPos == iGetPos ) {
{ eBufState = CBufferBase<TData>::BS_OK;
eBufState = CBufferBase<TData>::BS_EMPTY; }
}
else return true; // no error check in base class, alyways return ok
{ }
eBufState = CBufferBase<TData>::BS_OK;
} virtual int GetAvailSpace() const
{
return true; // no error check in base class, alyways return ok // calculate available space in buffer
} int iAvSpace = iGetPos - iPutPos;
virtual int GetAvailSpace() const // check for special case and wrap around
{ if ( iAvSpace < 0 )
// calculate available space in buffer {
int iAvSpace = iGetPos - iPutPos; iAvSpace += iMemSize; // wrap around
}
// check for special case and wrap around else
if ( iAvSpace < 0 ) {
{ if ( ( iAvSpace == 0 ) && ( eBufState == BS_EMPTY ) )
iAvSpace += iMemSize; // wrap around {
} iAvSpace = iMemSize;
else }
{ }
if ( ( iAvSpace == 0 ) && ( eBufState == BS_EMPTY ) )
{ return iAvSpace;
iAvSpace = iMemSize; }
}
} virtual int GetAvailData() const
{
return iAvSpace; // calculate available data in buffer
} int iAvData = iPutPos - iGetPos;
virtual int GetAvailData() const // check for special case and wrap around
{ if ( iAvData < 0 )
// calculate available data in buffer {
int iAvData = iPutPos - iGetPos; iAvData += iMemSize; // wrap around
}
// check for special case and wrap around else
if ( iAvData < 0 ) {
{ if ( ( iAvData == 0 ) && ( eBufState == BS_FULL ) )
iAvData += iMemSize; // wrap around {
} iAvData = iMemSize;
else }
{ }
if ( ( iAvData == 0 ) && ( eBufState == BS_FULL ) )
{ return iAvData;
iAvData = iMemSize; }
}
} protected:
enum EBufState { BS_OK, BS_FULL, BS_EMPTY };
return iAvData; enum EClearType { CT_PUT, CT_GET };
}
virtual void Clear ( const EClearType eClearType )
protected: {
enum EBufState { BS_OK, BS_FULL, BS_EMPTY }; // clear memory
enum EClearType { CT_PUT, CT_GET }; if ( !bIsSimulation )
{
virtual void Clear ( const EClearType eClearType ) vecMemory.Reset ( 0 );
{ }
// clear memory
if ( !bIsSimulation ) // init buffer pointers and buffer state (empty buffer)
{ iGetPos = 0;
vecMemory.Reset ( 0 ); iPutPos = 0;
} eBufState = CBufferBase<TData>::BS_EMPTY;
}
// init buffer pointers and buffer state (empty buffer)
iGetPos = 0; CVector<TData> vecMemory;
iPutPos = 0; int iMemSize;
eBufState = CBufferBase<TData>::BS_EMPTY; int iGetPos;
} int iPutPos;
EBufState eBufState;
CVector<TData> vecMemory; bool bIsSimulation;
int iMemSize; bool bIsInitialized;
int iGetPos; };
int iPutPos;
EBufState eBufState;
bool bIsSimulation; // Network buffer (jitter buffer) ----------------------------------------------
bool bIsInitialized; class CNetBuf : public CBufferBase<uint8_t>
}; {
public:
CNetBuf ( const bool bNewIsSim = false ) :
// Network buffer (jitter buffer) ---------------------------------------------- CBufferBase<uint8_t> ( bNewIsSim ) {}
class CNetBuf : public CBufferBase<uint8_t>
{ virtual void Init ( const int iNewBlockSize,
public: const int iNewNumBlocks,
CNetBuf ( const bool bNewIsSim = false ) : const bool bPreserve = false );
CBufferBase<uint8_t> ( bNewIsSim ) {}
int GetSize() { return iMemSize / iBlockSize; }
virtual void Init ( const int iNewBlockSize,
const int iNewNumBlocks, virtual bool Put ( const CVector<uint8_t>& vecbyData, const int iInSize );
const bool bPreserve = false ); virtual bool Get ( CVector<uint8_t>& vecbyData );
int GetSize() { return iMemSize / iBlockSize; } protected:
virtual void Clear ( const EClearType eClearType );
virtual bool Put ( const CVector<uint8_t>& vecbyData, const int iInSize );
virtual bool Get ( CVector<uint8_t>& vecbyData ); int iBlockSize;
int iNumInvalidElements;
protected: };
virtual void Clear ( const EClearType eClearType );
int iBlockSize; // Network buffer (jitter buffer) with statistic calculations ------------------
int iNumInvalidElements; class CNetBufWithStats : public CNetBuf
}; {
public:
CNetBufWithStats();
// Network buffer (jitter buffer) with statistic calculations ------------------
class CNetBufWithStats : public CNetBuf virtual void Init ( const int iNewBlockSize,
{ const int iNewNumBlocks,
public: const bool bPreserve = false );
CNetBufWithStats();
virtual bool Put ( const CVector<uint8_t>& vecbyData, const int iInSize );
virtual void Init ( const int iNewBlockSize, virtual bool Get ( CVector<uint8_t>& vecbyData );
const int iNewNumBlocks,
const bool bPreserve = false ); // TEST
void StoreAllSimAverages();
virtual bool Put ( const CVector<uint8_t>& vecbyData, const int iInSize ); int GetAutoSetting();
virtual bool Get ( CVector<uint8_t>& vecbyData );
protected:
// TEST // statistic (do not use the vector class since the classes do not have
void StoreAllSimAverages(); // appropriate copy constructor/operator)
int GetAutoSetting(); CErrorRate ErrorRateStatistic[NUM_STAT_SIMULATION_BUFFERS];
CNetBuf SimulationBuffer[NUM_STAT_SIMULATION_BUFFERS];
protected: int viBufSizesForSim[NUM_STAT_SIMULATION_BUFFERS];
// statistic (do not use the vector class since the classes do not have };
// appropriate copy constructor/operator)
CErrorRate ErrorRateStatistic[NUM_STAT_SIMULATION_BUFFERS];
CNetBuf SimulationBuffer[NUM_STAT_SIMULATION_BUFFERS]; // Conversion buffer (very simple buffer) --------------------------------------
int viBufSizesForSim[NUM_STAT_SIMULATION_BUFFERS]; // For this very simple buffer no wrap around mechanism is implemented. We
}; // assume here, that the applied buffers are an integer fraction of the total
// buffer size.
template<class TData> class CConvBuf
// Conversion buffer (very simple buffer) -------------------------------------- {
// For this very simple buffer no wrap around mechanism is implemented. We public:
// assume here, that the applied buffers are an integer fraction of the total CConvBuf() { Init ( 0 ); }
// buffer size.
template<class TData> class CConvBuf void Init ( const int iNewMemSize )
{ {
public: // set memory size
CConvBuf() { Init ( 0 ); } iMemSize = iNewMemSize;
void Init ( const int iNewMemSize ) // allocate and clear memory for actual data buffer
{ vecsMemory.Init ( iMemSize );
// set memory size
iMemSize = iNewMemSize; iPutPos = 0;
}
// allocate and clear memory for actual data buffer
vecsMemory.Init ( iMemSize ); int GetSize() const { return iMemSize; }
iPutPos = 0; bool Put ( const CVector<TData>& vecsData )
} {
const int iVecSize = vecsData.Size();
int GetSize() const { return iMemSize; }
// copy new data in internal buffer
bool Put ( const CVector<TData>& vecsData ) int iCurPos = 0;
{ const int iEnd = iPutPos + iVecSize;
const int iVecSize = vecsData.Size();
// first check for buffer overrun
// copy new data in internal buffer if ( iEnd <= iMemSize )
int iCurPos = 0; {
const int iEnd = iPutPos + iVecSize; // actual copy operation
while ( iPutPos < iEnd )
// first check for buffer overrun {
if ( iEnd <= iMemSize ) vecsMemory[iPutPos++] = vecsData[iCurPos++];
{ }
// actual copy operation
while ( iPutPos < iEnd ) // return "buffer is ready for readout" flag
{ return ( iEnd == iMemSize );
vecsMemory[iPutPos++] = vecsData[iCurPos++]; }
} else
{
// return "buffer is ready for readout" flag // buffer overrun or not initialized, return "not ready"
return ( iEnd == iMemSize ); return false;
} }
else }
{
// buffer overrun or not initialized, return "not ready" CVector<TData> Get()
return false; {
} iPutPos = 0;
} return vecsMemory;
}
CVector<TData> Get()
{ protected:
iPutPos = 0; CVector<TData> vecsMemory;
return vecsMemory; int iMemSize;
} int iPutPos;
};
protected:
CVector<TData> vecsMemory; #endif /* !defined ( BUFFER_H__3B123453_4344_BB23945IUHF1912__INCLUDED_ ) */
int iMemSize;
int iPutPos;
};
#endif /* !defined ( BUFFER_H__3B123453_4344_BB23945IUHF1912__INCLUDED_ ) */