moved the socket buffer size update from the client in the channel because it shall be also used in the server in the future, bug fix with connect/disconnect
This commit is contained in:
parent
a770b75a06
commit
b7ce6c3193
6 changed files with 159 additions and 99 deletions
|
@ -30,6 +30,7 @@ CChannel::CChannel ( const bool bNIsServer ) :
|
||||||
vecdGains ( MAX_NUM_CHANNELS, (double) 1.0 ),
|
vecdGains ( MAX_NUM_CHANNELS, (double) 1.0 ),
|
||||||
bIsEnabled ( false ),
|
bIsEnabled ( false ),
|
||||||
bIsServer ( bNIsServer ),
|
bIsServer ( bNIsServer ),
|
||||||
|
bDoAutoSockBufSize ( true ),
|
||||||
iNetwFrameSizeFact ( FRAME_SIZE_FACTOR_PREFERRED ),
|
iNetwFrameSizeFact ( FRAME_SIZE_FACTOR_PREFERRED ),
|
||||||
iNetwFrameSize ( 20 ), // must be > 0 and should be close to a valid size
|
iNetwFrameSize ( 20 ), // must be > 0 and should be close to a valid size
|
||||||
iNumAudioChannels ( 1 ) // mono
|
iNumAudioChannels ( 1 ) // mono
|
||||||
|
@ -171,6 +172,9 @@ bool CChannel::SetSockBufNumFrames ( const int iNewNumFrames,
|
||||||
// first check for valid input parameter range
|
// first check for valid input parameter range
|
||||||
if ( ( iNewNumFrames >= MIN_NET_BUF_SIZE_NUM_BL ) &&
|
if ( ( iNewNumFrames >= MIN_NET_BUF_SIZE_NUM_BL ) &&
|
||||||
( iNewNumFrames <= MAX_NET_BUF_SIZE_NUM_BL ) )
|
( iNewNumFrames <= MAX_NET_BUF_SIZE_NUM_BL ) )
|
||||||
|
{
|
||||||
|
// only apply parameter if new parameter is different from current one
|
||||||
|
if ( iCurSockBufNumFrames != iNewNumFrames )
|
||||||
{
|
{
|
||||||
// store new value
|
// store new value
|
||||||
iCurSockBufNumFrames = iNewNumFrames;
|
iCurSockBufNumFrames = iNewNumFrames;
|
||||||
|
@ -179,8 +183,22 @@ bool CChannel::SetSockBufNumFrames ( const int iNewNumFrames,
|
||||||
// block size
|
// block size
|
||||||
SockBuf.Init ( iNetwFrameSize, iNewNumFrames, bPreserve );
|
SockBuf.Init ( iNetwFrameSize, iNewNumFrames, bPreserve );
|
||||||
|
|
||||||
|
|
||||||
|
// TEST in case we are the client, tell the server that the size has changed
|
||||||
|
if ( !bIsServer && bPreserve )
|
||||||
|
{
|
||||||
|
|
||||||
|
// TODO this function call causes the lock up of the protocol mechanism when the
|
||||||
|
// SetSockBufNumFrames is called directly from UpdateSocketBufferSize
|
||||||
|
// -> find and fix the problem!
|
||||||
|
|
||||||
|
CreateJitBufMes ( iNewNumFrames );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return false; // -> no error
|
return false; // -> no error
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true; // set error flag
|
return true; // set error flag
|
||||||
}
|
}
|
||||||
|
@ -549,3 +567,81 @@ int CChannel::GetUploadRateKbps()
|
||||||
8 /* bits per byte */ *
|
8 /* bits per byte */ *
|
||||||
SYSTEM_SAMPLE_RATE_HZ / iAudioSizeOut / 1000;
|
SYSTEM_SAMPLE_RATE_HZ / iAudioSizeOut / 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// TEST
|
||||||
|
void CChannel::UpdateSocketBufferSize ( const double dAudioBufferDurationMs,
|
||||||
|
const double dLocalStdDev )
|
||||||
|
{
|
||||||
|
// 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 audio interface/network jitter is assumed to be Gaussian
|
||||||
|
// - the buffer size is set to 3.3 times the standard deviation of
|
||||||
|
// the jitter (~98% 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;
|
||||||
|
|
||||||
|
// jitter introduced in the server by the timer implementation
|
||||||
|
|
||||||
|
// TODO remove this!
|
||||||
|
const double dServerJitterMs = 0.666666; // ms
|
||||||
|
|
||||||
|
|
||||||
|
// accumulate the standard deviations of input network stream and
|
||||||
|
// internal timer,
|
||||||
|
// add 0.5 to "round up" -> ceil,
|
||||||
|
// divide by MIN_SERVER_BLOCK_DURATION_MS because this is the size of
|
||||||
|
// one block in the jitter buffer
|
||||||
|
const double dEstCurBufSet = ( dAudioBufferDurationMs + dServerJitterMs +
|
||||||
|
3.3 * ( GetTimingStdDev() + dLocalStdDev ) ) /
|
||||||
|
SYSTEM_BLOCK_DURATION_MS_FLOAT + 0.5;
|
||||||
|
|
||||||
|
// 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 )
|
||||||
|
{
|
||||||
|
// set the socket buffer via the main window thread since somehow
|
||||||
|
// it gives a protocol deadlock if we call the SetSocketBufSize()
|
||||||
|
// function directly
|
||||||
|
|
||||||
|
// TEST
|
||||||
|
PostWinMessage ( MS_SET_JIT_BUF_SIZE, iUpperHystDec );
|
||||||
|
|
||||||
|
//SetSockBufNumFrames ( iUpperHystDec, true );
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// we are in the middle of the decision region, use
|
||||||
|
// previous setting for determing the new decision
|
||||||
|
if ( !( ( GetSockBufNumFrames() == iUpperHystDec ) ||
|
||||||
|
( GetSockBufNumFrames() == iLowerHystDec ) ) )
|
||||||
|
{
|
||||||
|
// The old result is not near the new decision,
|
||||||
|
// use per definition the upper decision.
|
||||||
|
// Set the socket buffer via the main window thread since somehow
|
||||||
|
// it gives a protocol deadlock if we call the SetSocketBufSize()
|
||||||
|
// function directly.
|
||||||
|
|
||||||
|
// TEST
|
||||||
|
PostWinMessage ( MS_SET_JIT_BUF_SIZE, iUpperHystDec );
|
||||||
|
|
||||||
|
//SetSockBufNumFrames ( iUpperHystDec, true );
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -96,6 +96,12 @@ public:
|
||||||
const bool bPreserve = false );
|
const bool bPreserve = false );
|
||||||
int GetSockBufNumFrames() const { return iCurSockBufNumFrames; }
|
int GetSockBufNumFrames() const { return iCurSockBufNumFrames; }
|
||||||
|
|
||||||
|
|
||||||
|
// TEST
|
||||||
|
void UpdateSocketBufferSize ( const double dAudioBufferDurationMs,
|
||||||
|
const double dLocalStdDev );
|
||||||
|
|
||||||
|
|
||||||
int GetUploadRateKbps();
|
int GetUploadRateKbps();
|
||||||
|
|
||||||
double GetTimingStdDev() { return CycleTimeVariance.GetStdDev(); }
|
double GetTimingStdDev() { return CycleTimeVariance.GetStdDev(); }
|
||||||
|
@ -104,8 +110,13 @@ public:
|
||||||
void SetAudioStreamProperties ( const int iNewNetwFrameSize,
|
void SetAudioStreamProperties ( const int iNewNetwFrameSize,
|
||||||
const int iNewNetwFrameSizeFact,
|
const int iNewNetwFrameSizeFact,
|
||||||
const int iNewNumAudioChannels );
|
const int iNewNumAudioChannels );
|
||||||
|
|
||||||
|
void SetDoAutoSockBufSize ( const bool bValue ) { bDoAutoSockBufSize = bValue; }
|
||||||
|
bool GetDoAutoSockBufSize() const { return bDoAutoSockBufSize; }
|
||||||
|
|
||||||
int GetNetwFrameSizeFact() const { return iNetwFrameSizeFact; }
|
int GetNetwFrameSizeFact() const { return iNetwFrameSizeFact; }
|
||||||
int GetNetwFrameSize() const { return iNetwFrameSize; }
|
int GetNetwFrameSize() const { return iNetwFrameSize; }
|
||||||
|
|
||||||
int GetNumAudioChannels() const { return iNumAudioChannels; }
|
int GetNumAudioChannels() const { return iNumAudioChannels; }
|
||||||
|
|
||||||
// network protocol interface
|
// network protocol interface
|
||||||
|
@ -160,6 +171,7 @@ protected:
|
||||||
bool bIsEnabled;
|
bool bIsEnabled;
|
||||||
bool bIsServer;
|
bool bIsServer;
|
||||||
|
|
||||||
|
bool bDoAutoSockBufSize;
|
||||||
int iNetwFrameSizeFact;
|
int iNetwFrameSizeFact;
|
||||||
int iNetwFrameSize;
|
int iNetwFrameSize;
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,6 @@ CClient::CClient ( const quint16 iPortNumber ) :
|
||||||
vstrIPAddress ( MAX_NUM_SERVER_ADDR_ITEMS, "" ),
|
vstrIPAddress ( MAX_NUM_SERVER_ADDR_ITEMS, "" ),
|
||||||
strName ( "" ),
|
strName ( "" ),
|
||||||
Channel ( false ), /* we need a client channel -> "false" */
|
Channel ( false ), /* we need a client channel -> "false" */
|
||||||
bDoAutoSockBufSize ( true ),
|
|
||||||
iCeltNumCodedBytes ( CELT_NUM_BYTES_MONO_NORMAL_QUALITY ),
|
iCeltNumCodedBytes ( CELT_NUM_BYTES_MONO_NORMAL_QUALITY ),
|
||||||
bCeltDoHighQuality ( false ),
|
bCeltDoHighQuality ( false ),
|
||||||
bUseStereo ( false ),
|
bUseStereo ( false ),
|
||||||
|
@ -428,7 +427,12 @@ void CClient::Stop()
|
||||||
QTime DieTime = QTime::currentTime().addMSecs ( 100 );
|
QTime DieTime = QTime::currentTime().addMSecs ( 100 );
|
||||||
while ( QTime::currentTime() < DieTime )
|
while ( QTime::currentTime() < DieTime )
|
||||||
{
|
{
|
||||||
QCoreApplication::processEvents ( QEventLoop::AllEvents, 100 );
|
// exclude user input events because if we use AllEvents, it happens
|
||||||
|
// that if the user initiates a connection and disconnection quickly
|
||||||
|
// (e.g. quickly pressing enter five times), the software can get into
|
||||||
|
// an unknown state
|
||||||
|
QCoreApplication::processEvents (
|
||||||
|
QEventLoop::ExcludeUserInputEvents, 100 );
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send disconnect message to server (Since we disable our protocol
|
// Send disconnect message to server (Since we disable our protocol
|
||||||
|
@ -877,28 +881,8 @@ void CClient::ProcessAudioDataIntern ( CVector<int16_t>& vecsStereoSndCrd )
|
||||||
vecsStereoSndCrd.Reset ( 0 );
|
vecsStereoSndCrd.Reset ( 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
// update response time measurement and socket buffer size
|
// update response time measurement
|
||||||
CycleTimeVariance.Update();
|
CycleTimeVariance.Update();
|
||||||
UpdateSocketBufferSize();
|
|
||||||
}
|
|
||||||
|
|
||||||
void CClient::UpdateSocketBufferSize()
|
|
||||||
{
|
|
||||||
// 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 audio interface/network jitter is assumed to be Gaussian
|
|
||||||
// - the buffer size is set to 3.3 times the standard deviation of
|
|
||||||
// the jitter (~98% 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;
|
|
||||||
|
|
||||||
// calculate current buffer setting
|
// calculate current buffer setting
|
||||||
const double dAudioBufferDurationMs =
|
const double dAudioBufferDurationMs =
|
||||||
|
@ -906,46 +890,9 @@ void CClient::UpdateSocketBufferSize()
|
||||||
GetSndCrdConvBufAdditionalDelayMonoBlSize() ) *
|
GetSndCrdConvBufAdditionalDelayMonoBlSize() ) *
|
||||||
1000 / SYSTEM_SAMPLE_RATE_HZ;
|
1000 / SYSTEM_SAMPLE_RATE_HZ;
|
||||||
|
|
||||||
// jitter introduced in the server by the timer implementation
|
// update and socket buffer size
|
||||||
const double dServerJitterMs = 0.666666; // ms
|
Channel.UpdateSocketBufferSize ( dAudioBufferDurationMs,
|
||||||
|
CycleTimeVariance.GetStdDev() );
|
||||||
// accumulate the standard deviations of input network stream and
|
|
||||||
// internal timer,
|
|
||||||
// add 0.5 to "round up" -> ceil,
|
|
||||||
// divide by MIN_SERVER_BLOCK_DURATION_MS because this is the size of
|
|
||||||
// one block in the jitter buffer
|
|
||||||
const double dEstCurBufSet = ( dAudioBufferDurationMs + dServerJitterMs +
|
|
||||||
3.3 * ( Channel.GetTimingStdDev() + CycleTimeVariance.GetStdDev() ) ) /
|
|
||||||
SYSTEM_BLOCK_DURATION_MS_FLOAT + 0.5;
|
|
||||||
|
|
||||||
// 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 )
|
|
||||||
{
|
|
||||||
// set the socket buffer via the main window thread since somehow
|
|
||||||
// it gives a protocol deadlock if we call the SetSocketBufSize()
|
|
||||||
// function directly
|
|
||||||
PostWinMessage ( MS_SET_JIT_BUF_SIZE, iUpperHystDec );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// we are in the middle of the decision region, use
|
|
||||||
// previous setting for determing the new decision
|
|
||||||
if ( !( ( GetSockBufNumFrames() == iUpperHystDec ) ||
|
|
||||||
( GetSockBufNumFrames() == iLowerHystDec ) ) )
|
|
||||||
{
|
|
||||||
// The old result is not near the new decision,
|
|
||||||
// use per definition the upper decision.
|
|
||||||
// Set the socket buffer via the main window thread since somehow
|
|
||||||
// it gives a protocol deadlock if we call the SetSocketBufSize()
|
|
||||||
// function directly.
|
|
||||||
PostWinMessage ( MS_SET_JIT_BUF_SIZE, iUpperHystDec );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int CClient::EstimatedOverallDelay ( const int iPingTimeMs )
|
int CClient::EstimatedOverallDelay ( const int iPingTimeMs )
|
||||||
|
|
21
src/client.h
21
src/client.h
|
@ -132,21 +132,24 @@ public:
|
||||||
AudioReverbR.Clear();
|
AudioReverbR.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetDoAutoSockBufSize ( const bool bValue ) { bDoAutoSockBufSize = bValue; }
|
void SetDoAutoSockBufSize ( const bool bValue )
|
||||||
bool GetDoAutoSockBufSize() const { return bDoAutoSockBufSize; }
|
{ Channel.SetDoAutoSockBufSize ( bValue ); }
|
||||||
|
|
||||||
|
bool GetDoAutoSockBufSize() const { return Channel.GetDoAutoSockBufSize(); }
|
||||||
|
|
||||||
void SetSockBufNumFrames ( const int iNumBlocks,
|
void SetSockBufNumFrames ( const int iNumBlocks,
|
||||||
const bool bPreserve = false )
|
const bool bPreserve = false )
|
||||||
{
|
|
||||||
// only change parameter if new parameter is different from current one
|
|
||||||
if ( Channel.GetSockBufNumFrames() != iNumBlocks )
|
|
||||||
{
|
{
|
||||||
// set the new socket size (number of frames)
|
// set the new socket size (number of frames)
|
||||||
if ( !Channel.SetSockBufNumFrames ( iNumBlocks, bPreserve ) )
|
if ( !Channel.SetSockBufNumFrames ( iNumBlocks, bPreserve ) )
|
||||||
{
|
{
|
||||||
// if setting of socket buffer size was successful,
|
// if setting of socket buffer size was successful,
|
||||||
// tell the server that size has changed
|
// tell the server that the size has changed
|
||||||
Channel.CreateJitBufMes ( iNumBlocks );
|
|
||||||
}
|
// TEST is done in channel now
|
||||||
|
// Channel.CreateJitBufMes ( iNumBlocks );
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
int GetSockBufNumFrames() { return Channel.GetSockBufNumFrames(); }
|
int GetSockBufNumFrames() { return Channel.GetSockBufNumFrames(); }
|
||||||
|
@ -250,7 +253,6 @@ protected:
|
||||||
void Init();
|
void Init();
|
||||||
void ProcessSndCrdAudioData ( CVector<short>& vecsStereoSndCrd );
|
void ProcessSndCrdAudioData ( CVector<short>& vecsStereoSndCrd );
|
||||||
void ProcessAudioDataIntern ( CVector<short>& vecsStereoSndCrd );
|
void ProcessAudioDataIntern ( CVector<short>& vecsStereoSndCrd );
|
||||||
void UpdateSocketBufferSize();
|
|
||||||
|
|
||||||
int PreparePingMessage();
|
int PreparePingMessage();
|
||||||
int EvaluatePingMessage ( const int iMs );
|
int EvaluatePingMessage ( const int iMs );
|
||||||
|
@ -258,7 +260,6 @@ protected:
|
||||||
// only one channel is needed for client application
|
// only one channel is needed for client application
|
||||||
CChannel Channel;
|
CChannel Channel;
|
||||||
CProtocol ConnLessProtocol;
|
CProtocol ConnLessProtocol;
|
||||||
bool bDoAutoSockBufSize;
|
|
||||||
|
|
||||||
// audio encoder/decoder
|
// audio encoder/decoder
|
||||||
CELTMode* CeltModeMono;
|
CELTMode* CeltModeMono;
|
||||||
|
|
|
@ -79,6 +79,9 @@ CConnectDlg::CConnectDlg ( QWidget* parent, Qt::WindowFlags f )
|
||||||
lvwServers->setColumnWidth ( 3, 130 );
|
lvwServers->setColumnWidth ( 3, 130 );
|
||||||
lvwServers->clear();
|
lvwServers->clear();
|
||||||
|
|
||||||
|
// make sure the connect button has the focus
|
||||||
|
butConnect->setFocus();
|
||||||
|
|
||||||
|
|
||||||
// Connections -------------------------------------------------------------
|
// Connections -------------------------------------------------------------
|
||||||
// list view
|
// list view
|
||||||
|
|
|
@ -140,10 +140,11 @@ void CSocket::OnDataReceived()
|
||||||
|
|
||||||
|
|
||||||
// TEST old code -> to be removed because this is not working!!!
|
// TEST old code -> to be removed because this is not working!!!
|
||||||
|
/*
|
||||||
pChannel->SetEnable ( true );
|
pChannel->SetEnable ( true );
|
||||||
pChannel->CreateAndImmSendDisconnectionMes();
|
pChannel->CreateAndImmSendDisconnectionMes();
|
||||||
pChannel->SetEnable ( false );
|
pChannel->SetEnable ( false );
|
||||||
|
*/
|
||||||
|
|
||||||
// TODO this does not work because for a connected channel at the server, no
|
// TODO this does not work because for a connected channel at the server, no
|
||||||
// connection less protocol messages are accepted
|
// connection less protocol messages are accepted
|
||||||
|
|
Loading…
Reference in a new issue