From b7ce6c31938aebf46f5f9c1b8ac42952c49d0ad5 Mon Sep 17 00:00:00 2001 From: Volker Fischer Date: Sun, 22 May 2011 20:40:29 +0000 Subject: [PATCH] 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 --- src/channel.cpp | 118 ++++++++++++++++++++++++++++++++++++++++----- src/channel.h | 12 +++++ src/client.cpp | 83 ++++++------------------------- src/client.h | 39 +++++++-------- src/connectdlg.cpp | 3 ++ src/socket.cpp | 3 +- 6 files changed, 159 insertions(+), 99 deletions(-) diff --git a/src/channel.cpp b/src/channel.cpp index c722a03f..a3024e52 100755 --- a/src/channel.cpp +++ b/src/channel.cpp @@ -27,12 +27,13 @@ // CChannel implementation ***************************************************** CChannel::CChannel ( const bool bNIsServer ) : - vecdGains ( MAX_NUM_CHANNELS, (double) 1.0 ), - bIsEnabled ( false ), - bIsServer ( bNIsServer ), + vecdGains ( MAX_NUM_CHANNELS, (double) 1.0 ), + bIsEnabled ( false ), + bIsServer ( bNIsServer ), + bDoAutoSockBufSize ( true ), iNetwFrameSizeFact ( FRAME_SIZE_FACTOR_PREFERRED ), - iNetwFrameSize ( 20 ), // must be > 0 and should be close to a valid size - iNumAudioChannels ( 1 ) // mono + iNetwFrameSize ( 20 ), // must be > 0 and should be close to a valid size + iNumAudioChannels ( 1 ) // mono { // initial value for connection time out counter, we calculate the total // number of samples here and subtract the number of samples of the block @@ -172,14 +173,31 @@ bool CChannel::SetSockBufNumFrames ( const int iNewNumFrames, if ( ( iNewNumFrames >= MIN_NET_BUF_SIZE_NUM_BL ) && ( iNewNumFrames <= MAX_NET_BUF_SIZE_NUM_BL ) ) { - // store new value - iCurSockBufNumFrames = iNewNumFrames; + // only apply parameter if new parameter is different from current one + if ( iCurSockBufNumFrames != iNewNumFrames ) + { + // store new value + iCurSockBufNumFrames = iNewNumFrames; - // the network block size is a multiple of the minimum network - // block size - SockBuf.Init ( iNetwFrameSize, iNewNumFrames, bPreserve ); + // the network block size is a multiple of the minimum network + // block size + SockBuf.Init ( iNetwFrameSize, iNewNumFrames, bPreserve ); - return false; // -> no error + +// 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 true; // set error flag @@ -549,3 +567,81 @@ int CChannel::GetUploadRateKbps() 8 /* bits per byte */ * 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 ); + + } + } + } +} diff --git a/src/channel.h b/src/channel.h index 39baef97..253b3656 100755 --- a/src/channel.h +++ b/src/channel.h @@ -96,6 +96,12 @@ public: const bool bPreserve = false ); int GetSockBufNumFrames() const { return iCurSockBufNumFrames; } + +// TEST +void UpdateSocketBufferSize ( const double dAudioBufferDurationMs, + const double dLocalStdDev ); + + int GetUploadRateKbps(); double GetTimingStdDev() { return CycleTimeVariance.GetStdDev(); } @@ -104,8 +110,13 @@ public: void SetAudioStreamProperties ( const int iNewNetwFrameSize, const int iNewNetwFrameSizeFact, const int iNewNumAudioChannels ); + + void SetDoAutoSockBufSize ( const bool bValue ) { bDoAutoSockBufSize = bValue; } + bool GetDoAutoSockBufSize() const { return bDoAutoSockBufSize; } + int GetNetwFrameSizeFact() const { return iNetwFrameSizeFact; } int GetNetwFrameSize() const { return iNetwFrameSize; } + int GetNumAudioChannels() const { return iNumAudioChannels; } // network protocol interface @@ -160,6 +171,7 @@ protected: bool bIsEnabled; bool bIsServer; + bool bDoAutoSockBufSize; int iNetwFrameSizeFact; int iNetwFrameSize; diff --git a/src/client.cpp b/src/client.cpp index 134b2086..88e44262 100755 --- a/src/client.cpp +++ b/src/client.cpp @@ -30,7 +30,6 @@ CClient::CClient ( const quint16 iPortNumber ) : vstrIPAddress ( MAX_NUM_SERVER_ADDR_ITEMS, "" ), strName ( "" ), Channel ( false ), /* we need a client channel -> "false" */ - bDoAutoSockBufSize ( true ), iCeltNumCodedBytes ( CELT_NUM_BYTES_MONO_NORMAL_QUALITY ), bCeltDoHighQuality ( false ), bUseStereo ( false ), @@ -428,7 +427,12 @@ void CClient::Stop() QTime DieTime = QTime::currentTime().addMSecs ( 100 ); 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 @@ -877,75 +881,18 @@ void CClient::ProcessAudioDataIntern ( CVector& vecsStereoSndCrd ) vecsStereoSndCrd.Reset ( 0 ); } - // update response time measurement and socket buffer size + // update response time measurement 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 + const double dAudioBufferDurationMs = + ( GetSndCrdActualMonoBlSize() + + GetSndCrdConvBufAdditionalDelayMonoBlSize() ) * + 1000 / SYSTEM_SAMPLE_RATE_HZ; - // calculate current buffer setting - const double dAudioBufferDurationMs = - ( GetSndCrdActualMonoBlSize() + - GetSndCrdConvBufAdditionalDelayMonoBlSize() ) * - 1000 / SYSTEM_SAMPLE_RATE_HZ; - - // jitter introduced in the server by the timer implementation - 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 * ( 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 ); - } - } - } + // update and socket buffer size + Channel.UpdateSocketBufferSize ( dAudioBufferDurationMs, + CycleTimeVariance.GetStdDev() ); } int CClient::EstimatedOverallDelay ( const int iPingTimeMs ) diff --git a/src/client.h b/src/client.h index 76a33b89..fff8eaf7 100755 --- a/src/client.h +++ b/src/client.h @@ -132,21 +132,24 @@ public: AudioReverbR.Clear(); } - void SetDoAutoSockBufSize ( const bool bValue ) { bDoAutoSockBufSize = bValue; } - bool GetDoAutoSockBufSize() const { return bDoAutoSockBufSize; } + void SetDoAutoSockBufSize ( const bool bValue ) + { Channel.SetDoAutoSockBufSize ( bValue ); } + + bool GetDoAutoSockBufSize() const { return Channel.GetDoAutoSockBufSize(); } + void SetSockBufNumFrames ( const int iNumBlocks, 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) + if ( !Channel.SetSockBufNumFrames ( iNumBlocks, bPreserve ) ) { - // set the new socket size (number of frames) - if ( !Channel.SetSockBufNumFrames ( iNumBlocks, bPreserve ) ) - { - // if setting of socket buffer size was successful, - // tell the server that size has changed - Channel.CreateJitBufMes ( iNumBlocks ); - } + // if setting of socket buffer size was successful, + // tell the server that the size has changed + +// TEST is done in channel now +// Channel.CreateJitBufMes ( iNumBlocks ); + + } } int GetSockBufNumFrames() { return Channel.GetSockBufNumFrames(); } @@ -245,20 +248,18 @@ public: protected: // callback function must be static, otherwise it does not work - static void AudioCallback ( CVector& psData, void* arg ); + static void AudioCallback ( CVector& psData, void* arg ); - void Init(); - void ProcessSndCrdAudioData ( CVector& vecsStereoSndCrd ); - void ProcessAudioDataIntern ( CVector& vecsStereoSndCrd ); - void UpdateSocketBufferSize(); + void Init(); + void ProcessSndCrdAudioData ( CVector& vecsStereoSndCrd ); + void ProcessAudioDataIntern ( CVector& vecsStereoSndCrd ); - int PreparePingMessage(); - int EvaluatePingMessage ( const int iMs ); + int PreparePingMessage(); + int EvaluatePingMessage ( const int iMs ); // only one channel is needed for client application CChannel Channel; CProtocol ConnLessProtocol; - bool bDoAutoSockBufSize; // audio encoder/decoder CELTMode* CeltModeMono; diff --git a/src/connectdlg.cpp b/src/connectdlg.cpp index 10bb7a99..24b60ab8 100755 --- a/src/connectdlg.cpp +++ b/src/connectdlg.cpp @@ -79,6 +79,9 @@ CConnectDlg::CConnectDlg ( QWidget* parent, Qt::WindowFlags f ) lvwServers->setColumnWidth ( 3, 130 ); lvwServers->clear(); + // make sure the connect button has the focus + butConnect->setFocus(); + // Connections ------------------------------------------------------------- // list view diff --git a/src/socket.cpp b/src/socket.cpp index ec3c073f..975651ef 100755 --- a/src/socket.cpp +++ b/src/socket.cpp @@ -140,10 +140,11 @@ void CSocket::OnDataReceived() // TEST old code -> to be removed because this is not working!!! +/* pChannel->SetEnable ( true ); pChannel->CreateAndImmSendDisconnectionMes(); pChannel->SetEnable ( false ); - +*/ // TODO this does not work because for a connected channel at the server, no // connection less protocol messages are accepted