some code cleanup

This commit is contained in:
Volker Fischer 2011-06-11 18:48:32 +00:00
parent a133156c0b
commit bd47dfa355

View file

@ -1,437 +1,426 @@
/******************************************************************************\ /******************************************************************************\
* Copyright (c) 2004-2011 * Copyright (c) 2004-2011
* *
* Author(s): * Author(s):
* Volker Fischer * Volker Fischer
* *
* Note: We are assuming here that put and get operations are secured by a mutex * Note: We are assuming here that put and get operations are secured by a mutex
* and accessing does not occur at the same time. * and accessing does not occur at the same time.
* *
****************************************************************************** ******************************************************************************
* *
* 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
* *
\******************************************************************************/ \******************************************************************************/
#include "buffer.h" #include "buffer.h"
/* Network buffer implementation **********************************************/ /* Network buffer implementation **********************************************/
void CNetBuf::Init ( const int iNewBlockSize, void CNetBuf::Init ( const int iNewBlockSize,
const int iNewNumBlocks, const int iNewNumBlocks,
const bool bPreserve ) const bool bPreserve )
{ {
// store block size value // store block size value
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 // use the "get" flag to make sure the buffer is cleared
if ( !bPreserve ) if ( !bPreserve )
{ {
Clear ( CT_GET ); Clear ( CT_GET );
} }
} }
bool CNetBuf::Put ( const CVector<uint8_t>& vecbyData, bool CNetBuf::Put ( const CVector<uint8_t>& vecbyData,
const int iInSize ) const int iInSize )
{ {
bool bPutOK = true; bool bPutOK = true;
// Check if there is not enough space available -> correct // Check if there is not enough space available -> correct
if ( GetAvailSpace() < iInSize ) if ( GetAvailSpace() < iInSize )
{ {
/* /*
// not enough space in buffer for put operation, correct buffer to // not enough space in buffer for put operation, correct buffer to
// prepare for new data // prepare for new data
Clear ( CT_PUT ); Clear ( CT_PUT );
bPutOK = false; // return error flag bPutOK = false; // return error flag
*/ */
/* /*
// TEST invalidate last written block for better PLC // TEST invalidate last written block for better PLC
// ATTENTION: We assume that mem size is factor of block size here!!!! // ATTENTION: We assume that mem size is factor of block size here!!!!
if ( !bIsSimulation ) if ( !bIsSimulation )
{ {
if ( iPutPos == 0 ) if ( iPutPos == 0 )
{ {
for ( int iPos = iMemSize - iInSize; iPos < iMemSize; iPos++ ) for ( int iPos = iMemSize - iInSize; iPos < iMemSize; iPos++ )
{ {
vecMemory[iPos] = 0; vecMemory[iPos] = 0;
} }
} }
else else
{ {
for ( int iPos = iPutPos - iInSize; iPos < iPutPos; iPos++ ) for ( int iPos = iPutPos - iInSize; iPos < iPutPos; iPos++ )
{ {
vecMemory[iPos] = 0; vecMemory[iPos] = 0;
} }
} }
} }
*/ */
return false; return false;
// check for special case: buffer memory is not sufficient // check for special case: buffer memory is not sufficient
if ( iInSize > iMemSize ) if ( iInSize > iMemSize )
{ {
// do nothing here, just return error code // do nothing here, just return error code
return bPutOK; return bPutOK;
} }
} }
// copy new data in internal buffer (implemented in base class) // copy new data in internal buffer (implemented in base class)
CBufferBase<uint8_t>::Put ( vecbyData, iInSize ); CBufferBase<uint8_t>::Put ( vecbyData, iInSize );
return bPutOK; return bPutOK;
} }
bool CNetBuf::Get ( CVector<uint8_t>& vecbyData ) bool CNetBuf::Get ( CVector<uint8_t>& vecbyData )
{ {
bool bGetOK = true; // init return value bool bGetOK = true; // init return value
// get size of data to be get from the buffer // get size of data to be get from the buffer
const int iInSize = vecbyData.Size(); const int iInSize = vecbyData.Size();
// check size // check size
if ( ( iInSize == 0 ) || ( iInSize != iBlockSize ) ) if ( ( iInSize == 0 ) || ( iInSize != iBlockSize ) )
{ {
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 the queried number (input
// size) // size)
iNumInvalidElements -= iInSize; iNumInvalidElements -= iInSize;
bGetOK = false; // return error flag bGetOK = false; // return error flag
} }
*/ */
// Check if there is not enough data available -> correct // Check if there is not enough data available -> correct
if ( GetAvailData() < iInSize ) if ( GetAvailData() < iInSize )
{ {
/* /*
// not enough data in buffer for get operation, correct buffer to // not enough data in buffer for get operation, correct buffer to
// prepare for getting data // prepare for getting data
Clear ( CT_GET ); Clear ( CT_GET );
bGetOK = false; // return error flag bGetOK = false; // return error flag
*/ */
return false; return false;
// check for special case: buffer memory is not sufficient // check for special case: buffer memory is not sufficient
if ( iInSize > iMemSize ) if ( iInSize > iMemSize )
{ {
// do nothing here, just return error code // do nothing here, just return error code
return bGetOK; 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 // TEST check for all zero packet
bool bAllZeroPacket = true; bool bAllZeroPacket = true;
for ( int iPos = 0; iPos < iInSize; iPos++ ) for ( int iPos = 0; iPos < iInSize; iPos++ )
{ {
if ( vecbyData[iPos] != 0 ) if ( vecbyData[iPos] != 0 )
{ {
bAllZeroPacket = false; bAllZeroPacket = false;
} }
} }
if ( bAllZeroPacket ) if ( bAllZeroPacket )
{ {
return false; return false;
} }
*/ */
return bGetOK; return bGetOK;
} }
void CNetBuf::Clear ( const EClearType eClearType ) void CNetBuf::Clear ( const EClearType eClearType )
{ {
// TEST // TEST
CBufferBase<uint8_t>::Clear ( eClearType ); CBufferBase<uint8_t>::Clear ( eClearType );
/* /*
// Define the number of blocks bound for the "random offset" (1) algorithm. // 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. // 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 // Test results (with different jitter buffer sizes), given is the error
// probability of jitter buffer (probability of corrections in the buffer): // probability of jitter buffer (probability of corrections in the buffer):
// kX, 128 samples, WLAN: // kX, 128 samples, WLAN:
// 2: (1) 5 %, (2) 12.3 % // 2: (1) 5 %, (2) 12.3 %
// 3: (1) 18.3 %, (2) 17.1 % // 3: (1) 18.3 %, (2) 17.1 %
// 5: (1) 0.9 %, (2) 0.8 % // 5: (1) 0.9 %, (2) 0.8 %
// kX, 128 samples, localhost: // kX, 128 samples, localhost:
// 2: (1) 2.5 %, (2) 13 % // 2: (1) 2.5 %, (2) 13 %
// 3: (1) 0.9 %, (2) 1.1 % // 3: (1) 0.9 %, (2) 1.1 %
// 5: (1) 0.7 %, (2) 0.6 % // 5: (1) 0.7 %, (2) 0.6 %
// Behringer, 128 samples, WLAN: // Behringer, 128 samples, WLAN:
// 2: (1) 5.8 %, (2) 9.4 % // 2: (1) 5.8 %, (2) 9.4 %
// 3: (1) 0.9 %, (2) 0.8 % // 3: (1) 0.9 %, (2) 0.8 %
// 5: (1) 0.4 %, (2) 0.3 % // 5: (1) 0.4 %, (2) 0.3 %
// Behringer, 128 samples, localhost: // Behringer, 128 samples, localhost:
// 2: (1) 1 %, (2) 9.8 % // 2: (1) 1 %, (2) 9.8 %
// 3: (1) 0.57 %, (2) 0.6 % // 3: (1) 0.57 %, (2) 0.6 %
// 5: (1) 0.6 %, (2) 0.56 % // 5: (1) 0.6 %, (2) 0.56 %
// kX, 256 samples, WLAN: // kX, 256 samples, WLAN:
// 3: (1) 24.2 %, (2) 18.4 % // 3: (1) 24.2 %, (2) 18.4 %
// 4: (1) 1.5 %, (2) 2.5 % // 4: (1) 1.5 %, (2) 2.5 %
// 5: (1) 1 %, (2) 1 % // 5: (1) 1 %, (2) 1 %
// ASIO4All, 256 samples, WLAN: // ASIO4All, 256 samples, WLAN:
// 3: (1) 14.9 %, (2) 11.9 % // 3: (1) 14.9 %, (2) 11.9 %
// 4: (1) 1.5 %, (2) 7 % // 4: (1) 1.5 %, (2) 7 %
// 5: (1) 1.2 %, (2) 1.3 % // 5: (1) 1.2 %, (2) 1.3 %
const int iNumBlocksBoundInclForRandom = 4; // by extensive testing: 4 const int iNumBlocksBoundInclForRandom = 4; // by extensive testing: 4
int iNewFillLevel = 0; int iNewFillLevel = 0;
if ( iBlockSize != 0 ) if ( iBlockSize != 0 )
{ {
const int iNumBlocks = iMemSize / iBlockSize; const int iNumBlocks = iMemSize / iBlockSize;
if ( iNumBlocks <= iNumBlocksBoundInclForRandom ) // just for small buffers if ( iNumBlocks <= iNumBlocksBoundInclForRandom ) // just for small buffers
{ {
// Random position algorithm. // Random position algorithm.
// overwrite fill level with random value, the range // overwrite fill level with random value, the range
// is 0 to (iMemSize - iBlockSize) // is 0 to (iMemSize - iBlockSize)
iNewFillLevel = static_cast<int> ( static_cast<double> ( rand() ) * iNewFillLevel = static_cast<int> ( static_cast<double> ( rand() ) *
iNumBlocks / RAND_MAX ) * iBlockSize; iNumBlocks / RAND_MAX ) * iBlockSize;
} }
else else
{ {
// Middle of buffer algorithm. // Middle of buffer algorithm.
// with the following operation we set the fill level to a block // 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 // boundary (one block below the middle of the buffer in case of odd
// number of blocks, e.g.: // number of blocks, e.g.:
// [buffer size]: [get pos] // [buffer size]: [get pos]
// 1: 0 / 2: 0 / 3: 1 / 4: 1 / 5: 2 ...) // 1: 0 / 2: 0 / 3: 1 / 4: 1 / 5: 2 ...)
iNewFillLevel = iNewFillLevel =
( ( ( iMemSize - iBlockSize) / 2 ) / iBlockSize ) * iBlockSize; ( ( ( iMemSize - iBlockSize) / 2 ) / iBlockSize ) * iBlockSize;
// TEST // TEST
iNewFillLevel += static_cast<int> ( static_cast<double> ( rand() ) * iNewFillLevel += static_cast<int> ( static_cast<double> ( rand() ) *
iNumBlocksBoundInclForRandom / RAND_MAX ) * iBlockSize - iNumBlocksBoundInclForRandom / RAND_MAX ) * iBlockSize -
iNumBlocksBoundInclForRandom / 2 * iBlockSize; iNumBlocksBoundInclForRandom / 2 * iBlockSize;
} }
} }
// different behaviour for get and put corrections // different behaviour for get and put corrections
if ( eClearType == CT_GET ) if ( eClearType == CT_GET )
{ {
// clear buffer since we had a buffer underrun // clear buffer since we had a buffer underrun
if ( !bIsSimulation ) if ( !bIsSimulation )
{ {
vecMemory.Reset ( 0 ); vecMemory.Reset ( 0 );
} }
// reset buffer pointers so that they are at maximum distance after // reset buffer pointers so that they are at maximum distance after
// the get operation (assign new fill level value to the get pointer) // the get operation (assign new fill level value to the get pointer)
iPutPos = 0; iPutPos = 0;
iGetPos = iNewFillLevel; iGetPos = iNewFillLevel;
// The buffer was cleared, the next time blocks are read from the // The buffer was cleared, the next time blocks are read from the
// buffer, these are invalid ones. Calculate the number of invalid // buffer, these are invalid ones. Calculate the number of invalid
// elements // elements
iNumInvalidElements = iMemSize - iNewFillLevel; iNumInvalidElements = iMemSize - iNewFillLevel;
// check for special case // check for special case
if ( iPutPos == iGetPos ) if ( iPutPos == iGetPos )
{ {
eBufState = CNetBuf::BS_FULL; eBufState = CNetBuf::BS_FULL;
} }
else else
{ {
eBufState = CNetBuf::BS_OK; eBufState = CNetBuf::BS_OK;
} }
} }
else else
{ {
// in case of "put" correction, do not delete old data but only shift // in case of "put" correction, do not delete old data but only shift
// the pointers // the pointers
iPutPos = iNewFillLevel; iPutPos = iNewFillLevel;
// adjust put pointer relative to current get pointer, take care of // adjust put pointer relative to current get pointer, take care of
// wrap around // wrap around
iPutPos += iGetPos; iPutPos += iGetPos;
if ( iPutPos > iMemSize ) if ( iPutPos > iMemSize )
{ {
iPutPos -= iMemSize; iPutPos -= iMemSize;
} }
// in case of put correction, no invalid blocks are inserted // in case of put correction, no invalid blocks are inserted
iNumInvalidElements = 0; iNumInvalidElements = 0;
// check for special case // check for special case
if ( iPutPos == iGetPos ) if ( iPutPos == iGetPos )
{ {
eBufState = CNetBuf::BS_EMPTY; eBufState = CNetBuf::BS_EMPTY;
} }
else else
{ {
eBufState = CNetBuf::BS_OK; eBufState = CNetBuf::BS_OK;
} }
} }
// TEST // TEST
//iNumInvalidElements = 8 * iMemSize; //iNumInvalidElements = 8 * iMemSize;
*/ */
} }
/* Network buffer with statistic calculations implementation ******************/ /* Network buffer with statistic calculations implementation ******************/
CNetBufWithStats::CNetBufWithStats() : CNetBufWithStats::CNetBufWithStats() :
CNetBuf ( false ) // base class init: no simulation mode CNetBuf ( false ) // base class init: no simulation mode
{ {
// define the sizes of the simulation buffers, // define the sizes of the simulation buffers,
// must be NUM_STAT_SIMULATION_BUFFERS elements! // must be NUM_STAT_SIMULATION_BUFFERS elements!
viBufSizesForSim[0] = 2; viBufSizesForSim[0] = 2;
viBufSizesForSim[1] = 3; viBufSizesForSim[1] = 3;
viBufSizesForSim[2] = 4; viBufSizesForSim[2] = 4;
viBufSizesForSim[3] = 5; viBufSizesForSim[3] = 5;
viBufSizesForSim[4] = 6; viBufSizesForSim[4] = 6;
viBufSizesForSim[5] = 7; viBufSizesForSim[5] = 7;
viBufSizesForSim[6] = 8; viBufSizesForSim[6] = 8;
viBufSizesForSim[7] = 9; viBufSizesForSim[7] = 9;
viBufSizesForSim[8] = 10; viBufSizesForSim[8] = 10;
viBufSizesForSim[9] = 12; viBufSizesForSim[9] = 12;
viBufSizesForSim[10] = 14; viBufSizesForSim[10] = 14;
viBufSizesForSim[11] = 17; viBufSizesForSim[11] = 17;
viBufSizesForSim[12] = 20; viBufSizesForSim[12] = 20;
// set all simulation buffers in simulation mode // set all simulation buffers in simulation mode
for ( int i = 0; i < NUM_STAT_SIMULATION_BUFFERS; i++ ) for ( int i = 0; i < NUM_STAT_SIMULATION_BUFFERS; i++ )
{ {
SimulationBuffer[i].SetIsSimulation ( true ); SimulationBuffer[i].SetIsSimulation ( true );
} }
} }
void CNetBufWithStats::Init ( const int iNewBlockSize, void CNetBufWithStats::Init ( const int iNewBlockSize,
const int iNewNumBlocks, const int iNewNumBlocks,
const bool bPreserve ) const bool bPreserve )
{ {
// call base class Init // call base class Init
CNetBuf::Init ( iNewBlockSize, iNewNumBlocks, bPreserve ); CNetBuf::Init ( iNewBlockSize, iNewNumBlocks, bPreserve );
// inits for statistics calculation // inits for statistics calculation
if ( !bPreserve ) if ( !bPreserve )
{ {
for ( int i = 0; i < NUM_STAT_SIMULATION_BUFFERS; i++ ) for ( int i = 0; i < NUM_STAT_SIMULATION_BUFFERS; i++ )
{ {
// init simulation buffers with the correct size // init simulation buffers with the correct size
SimulationBuffer[i].Init ( iNewBlockSize, viBufSizesForSim[i] ); SimulationBuffer[i].Init ( iNewBlockSize, viBufSizesForSim[i] );
// init statistics // init statistics
ErrorRateStatistic[i].Init ( 80000, true );//TEST!!!!!//MAX_STATISTIC_COUNT ); ErrorRateStatistic[i].Init ( MAX_STATISTIC_COUNT, true );
} }
} }
} }
bool CNetBufWithStats::Put ( const CVector<uint8_t>& vecbyData, bool CNetBufWithStats::Put ( const CVector<uint8_t>& vecbyData,
const int iInSize ) const int iInSize )
{ {
// call base class Put // call base class Put
const bool bPutOK = CNetBuf::Put ( vecbyData, iInSize ); const bool bPutOK = CNetBuf::Put ( vecbyData, iInSize );
// update statistics calculations // update statistics calculations
for ( int i = 0; i < NUM_STAT_SIMULATION_BUFFERS; i++ ) for ( int i = 0; i < NUM_STAT_SIMULATION_BUFFERS; i++ )
{ {
ErrorRateStatistic[i].Update ( ErrorRateStatistic[i].Update (
!SimulationBuffer[i].Put ( vecbyData, iInSize ) ); !SimulationBuffer[i].Put ( vecbyData, iInSize ) );
} }
return bPutOK; return bPutOK;
} }
bool CNetBufWithStats::Get ( CVector<uint8_t>& vecbyData ) bool CNetBufWithStats::Get ( CVector<uint8_t>& vecbyData )
{ {
// call base class Get // call base class Get
const bool bGetOK = CNetBuf::Get ( vecbyData ); const bool bGetOK = CNetBuf::Get ( vecbyData );
// update statistics calculations // update statistics calculations
for ( int i = 0; i < NUM_STAT_SIMULATION_BUFFERS; i++ ) for ( int i = 0; i < NUM_STAT_SIMULATION_BUFFERS; i++ )
{ {
ErrorRateStatistic[i].Update ( ErrorRateStatistic[i].Update (
!SimulationBuffer[i].Get ( vecbyData ) ); !SimulationBuffer[i].Get ( vecbyData ) );
} }
return bGetOK; return bGetOK;
} }
// TEST int CNetBufWithStats::GetAutoSetting()
int CNetBufWithStats::GetAutoSetting() {
{ // Use a specified error bound to identify the best buffer size for the
// current network situation. Start with the smallest buffer and
/* // test for the error rate until the rate is below the bound.
// TEST for ( int i = 0; i < NUM_STAT_SIMULATION_BUFFERS - 1; i++ )
if ( ErrorRateStatistic[NUM_STAT_SIMULATION_BUFFERS - 1].GetAverage() > 0.06 ) {
{ if ( ErrorRateStatistic[i].GetAverage() <= 0.005 )
for ( int i = 0; i < NUM_STAT_SIMULATION_BUFFERS; i++ ) {
{ return viBufSizesForSim[i];
ErrorRateStatistic[i].Reset(); }
} }
} return viBufSizesForSim[NUM_STAT_SIMULATION_BUFFERS - 1];
*/ }
for ( int i = 0; i < NUM_STAT_SIMULATION_BUFFERS - 1; i++ ) // TEST for debugging
{ void CNetBufWithStats::StoreAllSimAverages()
if ( ErrorRateStatistic[i].GetAverage() <= 0.005)//TEST!!!!! 0.005 ) {
{
return viBufSizesForSim[i]; FILE* pFile = fopen ( "c:\\temp\\test.dat", "w" );
}
}
return viBufSizesForSim[NUM_STAT_SIMULATION_BUFFERS - 1]; for ( int i = 0; i < NUM_STAT_SIMULATION_BUFFERS - 1; i++ )
} {
fprintf ( pFile, "%e, ", ErrorRateStatistic[i].GetAverage() );
}
// TEST for debugging fprintf ( pFile, "%e", ErrorRateStatistic[NUM_STAT_SIMULATION_BUFFERS - 1].GetAverage() );
void CNetBufWithStats::StoreAllSimAverages() fprintf ( pFile, "\n" );
{
FILE* pFile = fopen ( "c:\\temp\\test.dat", "w" ); /*
const int iLen = ErrorRateStatistic[4].ErrorsMovAvBuf.Size();
for ( int i = 0; i < iLen; i++ )
for ( int i = 0; i < NUM_STAT_SIMULATION_BUFFERS - 1; i++ ) {
{ fprintf ( pFile, "%e\n", ErrorRateStatistic[4].ErrorsMovAvBuf[i] );
fprintf ( pFile, "%e, ", ErrorRateStatistic[i].GetAverage() ); }
} */
fprintf ( pFile, "%e", ErrorRateStatistic[NUM_STAT_SIMULATION_BUFFERS - 1].GetAverage() ); fclose ( pFile );
fprintf ( pFile, "\n" );
// scilab:
// close;x=read('c:/temp/test.dat',-1,13);plot2d([2,3,4,5,6,7,8,9,10,12,14,17,20], x, style=-1 , logflag = 'nl');plot2d([2 20],[1 1]*0.01);plot2d([2 20],[1 1]*0.005);x
/* }
const int iLen = ErrorRateStatistic[4].ErrorsMovAvBuf.Size();
for ( int i = 0; i < iLen; i++ )
{
fprintf ( pFile, "%e\n", ErrorRateStatistic[4].ErrorsMovAvBuf[i] );
}
*/
fclose ( pFile );
// scilab:
// close;x=read('c:/temp/test.dat',-1,13);plot2d([2,3,4,5,6,7,8,9,10,12,14,17,20], x, style=-1 , logflag = 'nl');plot2d([2 20],[1 1]*0.01);plot2d([2 20],[1 1]*0.005);x
}