test implementation for automatic network buffer size setting
This commit is contained in:
parent
4e94893aa0
commit
d741bc6e30
5 changed files with 133 additions and 31 deletions
112
src/client.cpp
112
src/client.cpp
|
@ -35,7 +35,8 @@ CClient::CClient ( const quint16 iPortNumber ) : bRun ( false ),
|
||||||
bReverbOnLeftChan ( false ),
|
bReverbOnLeftChan ( false ),
|
||||||
iNetwBufSizeFactIn ( DEF_NET_BLOCK_SIZE_FACTOR ),
|
iNetwBufSizeFactIn ( DEF_NET_BLOCK_SIZE_FACTOR ),
|
||||||
strIPAddress ( "" ), strName ( "" ),
|
strIPAddress ( "" ), strName ( "" ),
|
||||||
bOpenChatOnNewMessage ( true )
|
bOpenChatOnNewMessage ( true ),
|
||||||
|
bDoAutoSockBufSize ( false )
|
||||||
{
|
{
|
||||||
// connection for protocol
|
// connection for protocol
|
||||||
QObject::connect ( &Channel,
|
QObject::connect ( &Channel,
|
||||||
|
@ -391,20 +392,9 @@ fflush(pFileDelay);
|
||||||
PostWinMessage ( MS_SOUND_OUT, MUL_COL_LED_GREEN );
|
PostWinMessage ( MS_SOUND_OUT, MUL_COL_LED_GREEN );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// update response time measurement and socket buffer size
|
||||||
// update response time measurement ------------------------------------
|
UpdateTimeResponseMeasurement();
|
||||||
// add time difference
|
UpdateSocketBufferSize();
|
||||||
const int CurTime = PreciseTime.elapsed();
|
|
||||||
|
|
||||||
// we want to calculate the standard deviation (we assume that the mean
|
|
||||||
// is correct at the block period time)
|
|
||||||
const double dCurAddVal =
|
|
||||||
( (double) ( CurTime - TimeLastBlock ) - MIN_BLOCK_DURATION_MS );
|
|
||||||
|
|
||||||
RespTimeMoAvBuf.Add ( dCurAddVal * dCurAddVal ); // add squared value
|
|
||||||
|
|
||||||
// store old time value
|
|
||||||
TimeLastBlock = CurTime;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// disable channel
|
// disable channel
|
||||||
|
@ -427,3 +417,95 @@ bool CClient::Stop()
|
||||||
// give thread some time to terminate, return status
|
// give thread some time to terminate, return status
|
||||||
return wait ( 5000 );
|
return wait ( 5000 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CClient::UpdateTimeResponseMeasurement()
|
||||||
|
{
|
||||||
|
// add time difference
|
||||||
|
const int CurTime = PreciseTime.elapsed();
|
||||||
|
|
||||||
|
// we want to calculate the standard deviation (we assume that the mean
|
||||||
|
// is correct at the block period time)
|
||||||
|
const double dCurAddVal =
|
||||||
|
( (double) ( CurTime - TimeLastBlock ) - MIN_BLOCK_DURATION_MS );
|
||||||
|
|
||||||
|
RespTimeMoAvBuf.Add ( dCurAddVal * dCurAddVal ); // add squared value
|
||||||
|
|
||||||
|
// store old time value
|
||||||
|
TimeLastBlock = CurTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CClient::UpdateSocketBufferSize()
|
||||||
|
{
|
||||||
|
|
||||||
|
// TEST
|
||||||
|
static double test = 4;
|
||||||
|
|
||||||
|
// just update the socket buffer size if auto setting is enabled, otherwise
|
||||||
|
// do nothing
|
||||||
|
|
||||||
|
|
||||||
|
//if ( bDoAutoSockBufSize )
|
||||||
|
{
|
||||||
|
// we use the time response measurement for the automatic setting
|
||||||
|
// Assumptions:
|
||||||
|
// - the network jitter can be neglected compared to the audio
|
||||||
|
// interface jitter
|
||||||
|
// - the audio interface jitter is assumed to be Gaussian
|
||||||
|
// - the buffer size is set to two times the standard deviation of
|
||||||
|
// the audio interface jitter (~95% of the jitter should be fit in the
|
||||||
|
// buffer)
|
||||||
|
// - introduce a hysteresis to avoid switching the buffer sizes all the
|
||||||
|
// time in case the time response measurement is close to a bound
|
||||||
|
// - only use time response measurement results if averaging buffer is
|
||||||
|
// completely filled
|
||||||
|
const double dHysteresis = 0.3;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//if ( RespTimeMoAvBuf.IsInitialized() )
|
||||||
|
{
|
||||||
|
// calculate current buffer setting
|
||||||
|
|
||||||
|
// TODO 2* seems not give optimal results, maybe use 3*?
|
||||||
|
|
||||||
|
//const double dEstCurBufSet = 2 * GetTimingStdDev();
|
||||||
|
|
||||||
|
|
||||||
|
// TEST
|
||||||
|
test = test + 0.01 * (2*LlconMath().round ( (double)rand()/RAND_MAX )-1);
|
||||||
|
if ( test < 0.5 ) test = 0.5;
|
||||||
|
if ( test > 10 ) test = 10;
|
||||||
|
const double dEstCurBufSet = test;
|
||||||
|
|
||||||
|
|
||||||
|
// upper/lower hysteresis decision
|
||||||
|
const int iUpperHystDec = LlconMath().round ( dEstCurBufSet - dHysteresis );
|
||||||
|
const int iLowerHystDec = LlconMath().round ( dEstCurBufSet + dHysteresis );
|
||||||
|
|
||||||
|
// if both decisions are equal than use the result
|
||||||
|
if ( iUpperHystDec == iLowerHystDec )
|
||||||
|
{
|
||||||
|
|
||||||
|
SetSockBufSize ( iUpperHystDec );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// we are in the middle of the decision region, use
|
||||||
|
// previous setting for determing the new decision
|
||||||
|
if ( !( ( GetSockBufSize() == iUpperHystDec ) ||
|
||||||
|
( GetSockBufSize() == iLowerHystDec ) ) )
|
||||||
|
{
|
||||||
|
// the old result is not near the new decision,
|
||||||
|
// use per definition the upper decision
|
||||||
|
SetSockBufSize ( iUpperHystDec );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static FILE* pFile = fopen("test.dat", "w");
|
||||||
|
fprintf(pFile, "%e %d\n",test,GetSockBufSize());
|
||||||
|
fflush(pFile);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
18
src/client.h
18
src/client.h
|
@ -92,13 +92,18 @@ public:
|
||||||
AudioReverb.Clear();
|
AudioReverb.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SetDoAutoSockBufSize ( const bool bValue )
|
||||||
|
{ bDoAutoSockBufSize = bValue; }
|
||||||
void SetSockBufSize ( const int iNumBlocks )
|
void SetSockBufSize ( const int iNumBlocks )
|
||||||
{
|
{
|
||||||
// set the new socket size
|
if ( Channel.GetSockBufSize() != iNumBlocks )
|
||||||
Channel.SetSockBufSize ( iNumBlocks );
|
{
|
||||||
|
// set the new socket size
|
||||||
|
Channel.SetSockBufSize ( iNumBlocks );
|
||||||
|
|
||||||
// tell the server that size has changed
|
// tell the server that size has changed
|
||||||
Channel.CreateJitBufMes ( iNumBlocks );
|
Channel.CreateJitBufMes ( iNumBlocks );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
int GetSockBufSize() { return Channel.GetSockBufSize(); }
|
int GetSockBufSize() { return Channel.GetSockBufSize(); }
|
||||||
|
|
||||||
|
@ -138,10 +143,13 @@ public:
|
||||||
QString strName;
|
QString strName;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void run();
|
virtual void run();
|
||||||
|
void UpdateTimeResponseMeasurement();
|
||||||
|
void UpdateSocketBufferSize();
|
||||||
|
|
||||||
// only one channel is needed for client application
|
// only one channel is needed for client application
|
||||||
CChannel Channel;
|
CChannel Channel;
|
||||||
|
bool bDoAutoSockBufSize;
|
||||||
|
|
||||||
CSocket Socket;
|
CSocket Socket;
|
||||||
CSound Sound;
|
CSound Sound;
|
||||||
|
|
|
@ -84,8 +84,7 @@ CClientSettingsDlg::CClientSettingsDlg ( CClient* pNCliP, QWidget* parent,
|
||||||
// network buffer
|
// network buffer
|
||||||
SliderNetBuf->setRange ( 0, MAX_NET_BUF_SIZE_NUM_BL );
|
SliderNetBuf->setRange ( 0, MAX_NET_BUF_SIZE_NUM_BL );
|
||||||
const int iCurNumNetBuf = pClient->GetSockBufSize();
|
const int iCurNumNetBuf = pClient->GetSockBufSize();
|
||||||
SliderNetBuf->setValue ( iCurNumNetBuf );
|
UpdateNetworkBufSlider ( iCurNumNetBuf );
|
||||||
TextNetBuf->setText ( "Size: " + QString().setNum ( iCurNumNetBuf ) );
|
|
||||||
|
|
||||||
// network buffer size factor in
|
// network buffer size factor in
|
||||||
SliderNetBufSiFactIn->setRange ( 1, MAX_NET_BLOCK_SIZE_FACTOR );
|
SliderNetBufSiFactIn->setRange ( 1, MAX_NET_BLOCK_SIZE_FACTOR );
|
||||||
|
@ -184,6 +183,12 @@ CClientSettingsDlg::CClientSettingsDlg ( CClient* pNCliP, QWidget* parent,
|
||||||
TimerStatus.start ( DISPLAY_UPDATE_TIME );
|
TimerStatus.start ( DISPLAY_UPDATE_TIME );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CClientSettingsDlg::UpdateNetworkBufSlider ( const int iCurNumNetBuf )
|
||||||
|
{
|
||||||
|
SliderNetBuf->setValue ( iCurNumNetBuf );
|
||||||
|
TextNetBuf->setText ( "Size: " + QString().setNum ( iCurNumNetBuf ) );
|
||||||
|
}
|
||||||
|
|
||||||
void CClientSettingsDlg::UpdateSndBufInSlider ( const int iCurNumInBuf )
|
void CClientSettingsDlg::UpdateSndBufInSlider ( const int iCurNumInBuf )
|
||||||
{
|
{
|
||||||
SliderSndBufIn->setValue ( iCurNumInBuf );
|
SliderSndBufIn->setValue ( iCurNumInBuf );
|
||||||
|
@ -348,8 +353,9 @@ void CClientSettingsDlg::OnPingTimeResult ( int iPingTime )
|
||||||
void CClientSettingsDlg::UpdateDisplay()
|
void CClientSettingsDlg::UpdateDisplay()
|
||||||
{
|
{
|
||||||
// update slider controls (settings might have been changed by sound interface)
|
// update slider controls (settings might have been changed by sound interface)
|
||||||
UpdateSndBufInSlider ( pClient->GetSndInterface()->GetInNumBuf() );
|
UpdateSndBufInSlider ( pClient->GetSndInterface()->GetInNumBuf() );
|
||||||
UpdateSndBufOutSlider ( pClient->GetSndInterface()->GetOutNumBuf() );
|
UpdateSndBufOutSlider ( pClient->GetSndInterface()->GetOutNumBuf() );
|
||||||
|
UpdateNetworkBufSlider ( pClient->GetSockBufSize() );
|
||||||
|
|
||||||
if ( !pClient->IsRunning() )
|
if ( !pClient->IsRunning() )
|
||||||
{
|
{
|
||||||
|
|
|
@ -72,8 +72,9 @@ protected:
|
||||||
virtual void showEvent ( QShowEvent* showEvent );
|
virtual void showEvent ( QShowEvent* showEvent );
|
||||||
virtual void hideEvent ( QHideEvent* hideEvent );
|
virtual void hideEvent ( QHideEvent* hideEvent );
|
||||||
|
|
||||||
void UpdateSndBufInSlider ( const int iCurNumInBuf );
|
void UpdateSndBufInSlider ( const int iCurNumInBuf );
|
||||||
void UpdateSndBufOutSlider ( const int iCurNumOutBuf );
|
void UpdateSndBufOutSlider ( const int iCurNumOutBuf );
|
||||||
|
void UpdateNetworkBufSlider ( const int iCurNumNetBuf );
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void OnTimerStatus() { UpdateDisplay(); }
|
void OnTimerStatus() { UpdateDisplay(); }
|
||||||
|
|
15
src/util.h
15
src/util.h
|
@ -447,15 +447,20 @@ protected:
|
||||||
class LlconMath
|
class LlconMath
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static int NextPowerOfTwo ( const int& iSizeIn )
|
static int NextPowerOfTwo ( const int& x )
|
||||||
{
|
{
|
||||||
// calculate the next power of 2 of the given size
|
// calculate the next power of 2 of the given size
|
||||||
int iPowerOfTwo = 1;
|
int y = 1;
|
||||||
while ( iPowerOfTwo < iSizeIn )
|
while ( y < x )
|
||||||
{
|
{
|
||||||
iPowerOfTwo <<= 1; // multiply by 2
|
y <<= 1; // multiply by 2
|
||||||
}
|
}
|
||||||
return iPowerOfTwo;
|
return y;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int round ( double x )
|
||||||
|
{
|
||||||
|
return (int) ( ( x - floor ( x ) ) >= 0.5 ) ? ceil(x) : floor(x);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue