From c61b9d593a5a45a3e5cf2cb318ae457c87347393 Mon Sep 17 00:00:00 2001 From: Volker Fischer Date: Tue, 10 Mar 2009 10:47:55 +0000 Subject: [PATCH] implemented auto output settings for server depending on maximum upload rate, bug fix in server, some code cleanup, new entry in server dialog table --- src/channel.cpp | 126 ++++++++++++++++++++++++++++---------- src/channel.h | 6 +- src/client.cpp | 74 +++++++++++----------- src/global.h | 3 + src/llconserverdlg.cpp | 27 +++++++- src/llconserverdlgbase.ui | 9 ++- src/server.h | 6 +- 7 files changed, 174 insertions(+), 77 deletions(-) diff --git a/src/channel.cpp b/src/channel.cpp index f5e4f729..83693126 100755 --- a/src/channel.cpp +++ b/src/channel.cpp @@ -29,7 +29,8 @@ * CChannelSet * \******************************************************************************/ CChannelSet::CChannelSet ( const bool bForceLowUploadRate ) : - bWriteStatusHTMLFile ( false ) + bWriteStatusHTMLFile ( false ), + iUploadRateLimit ( DEF_MAX_UPLOAD_RATE_KBPS ) { // enable all channels and set server flag for ( int i = 0; i < USED_NUM_CHANNELS; i++ ) @@ -244,6 +245,75 @@ int CChannelSet::GetFreeChan() return INVALID_CHANNEL_ID; } +void CChannelSet::SetOutputParameters() +{ + // The strategy is as follows: Change the parameters for each channel + // until the total upload rate is lower than the limit. We first set the + // audio compression from None to MS-ADPCM for each channel and if this + // is not enough, we start to increase the buffer size factor out. + bool bUploadRateIsBelowLimit = false; + + const int iNumTrials = 4; + EAudComprType eCurAudComprType; + int iCurBlockSizeFact; + + for ( int iCurTrialIdx = 0; iCurTrialIdx < iNumTrials; iCurTrialIdx++ ) + { + switch ( iCurTrialIdx ) + { + case 0: + // highest data rate + eCurAudComprType = CT_NONE; + iCurBlockSizeFact = 1; + break; + + case 1: + // using other audio compression gives most reduction + eCurAudComprType = CT_MSADPCM; + iCurBlockSizeFact = 1; + break; + + case 2: + // trying to use larger block size factor to further reduce rate + eCurAudComprType = CT_MSADPCM; + iCurBlockSizeFact = 2; + break; + + case 3: + // trying to use larger block size factor to further reduce rate + eCurAudComprType = CT_MSADPCM; + iCurBlockSizeFact = 3; + break; + } + + int iCurCh = 0; + while ( ( iCurCh < USED_NUM_CHANNELS ) && ( !bUploadRateIsBelowLimit ) ) + { + if ( vecChannels[iCurCh].IsConnected() ) + { + // set new parameters + vecChannels[iCurCh].SetNetwBufSizeFactOut ( iCurBlockSizeFact ); + vecChannels[iCurCh].SetAudioCompressionOut ( eCurAudComprType ); + + // calculate and check total upload rate + int iTotalUploadRate = 0; + for ( int j = 0; j < USED_NUM_CHANNELS; j++ ) + { + if ( vecChannels[j].IsConnected() ) + { + // accumulate the upload rates from all channels + iTotalUploadRate += vecChannels[j].GetUploadRateKbps(); + } + } + bUploadRateIsBelowLimit = ( iTotalUploadRate <= iUploadRateLimit ); + } + + // next channel + iCurCh++; + } + } +} + int CChannelSet::CheckAddr ( const CHostAddress& Addr ) { CHostAddress InetAddr; @@ -251,12 +321,15 @@ int CChannelSet::CheckAddr ( const CHostAddress& Addr ) // check for all possible channels if IP is already in use for ( int i = 0; i < USED_NUM_CHANNELS; i++ ) { - if ( vecChannels[i].GetAddress ( InetAddr ) ) + if ( vecChannels[i].IsConnected() ) { - // IP found, return channel number - if ( InetAddr == Addr ) + if ( vecChannels[i].GetAddress ( InetAddr ) ) { - return i; + // IP found, return channel number + if ( InetAddr == Addr ) + { + return i; + } } } } @@ -348,6 +421,9 @@ bAudioOK = true; // requested if ( bNewChannelReserved && bAudioOK ) { + // update output network parameters for all connected clients + SetOutputParameters(); + // send message about new channel emit ChannelConnected ( HostAdr ); @@ -439,9 +515,12 @@ void CChannelSet::GetBlockAllConC ( CVector& vecChanID, } } - // create channel list message if requested + // a channel is now disconnected, take action on it if ( bChannelIsNowDisconnected ) { + // update output network parameters for all connected clients + SetOutputParameters(); + // update channel list for all currently connected clients CreateAndSendChanListForAllConChannels(); } @@ -449,10 +528,11 @@ void CChannelSet::GetBlockAllConC ( CVector& vecChanID, Mutex.unlock(); // release mutex } -void CChannelSet::GetConCliParam ( CVector& vecHostAddresses, - CVector& vecsName, - CVector& veciJitBufSize, - CVector& veciNetwOutBlSiFact ) +void CChannelSet::GetConCliParam ( CVector& vecHostAddresses, + CVector& vecsName, + CVector& veciJitBufSize, + CVector& veciNetwOutBlSiFact, + CVector& veceAudComprType ) { CHostAddress InetAddr; @@ -461,6 +541,7 @@ void CChannelSet::GetConCliParam ( CVector& vecHostAddresses, vecsName.Init ( USED_NUM_CHANNELS ); veciJitBufSize.Init ( USED_NUM_CHANNELS ); veciNetwOutBlSiFact.Init ( USED_NUM_CHANNELS ); + veceAudComprType.Init ( USED_NUM_CHANNELS ); // check all possible channels for ( int i = 0; i < USED_NUM_CHANNELS; i++ ) @@ -472,6 +553,7 @@ void CChannelSet::GetConCliParam ( CVector& vecHostAddresses, vecsName[i] = vecChannels[i].GetName(); veciJitBufSize[i] = vecChannels[i].GetSockBufSize(); veciNetwOutBlSiFact[i] = vecChannels[i].GetNetwBufSizeFactOut(); + veceAudComprType[i] = vecChannels[i].GetAudioCompressionOut(); } } } @@ -948,7 +1030,6 @@ EPutDataStat CChannel::PutData ( const CVector& vecbyData, bool bIsAudioPacket = false; bool bNewConnection = false; bool bReinitializeIn = false; - bool bReinitializeOut = false; // intermediate storage for new parameters int iNewAudioBlockSize; @@ -996,35 +1077,18 @@ EPutDataStat CChannel::PutData ( const CVector& vecbyData, { bReinitializeIn = true; } - - // in case of a server channel, use the same audio - // compression for output as for the input - if ( bIsServer ) - { - if ( GetAudioCompressionOut() != eNewAudComprType ) - { - bReinitializeOut = true; - } - } } } Mutex.unlock(); - // actual initialization calls have to be made - // outside the mutex region since they internally - // use the same mutex, too + // actual initialization call has to be made + // outside the mutex region since it internally + // usees the same mutex, too if ( bReinitializeIn ) { // re-initialize to new value SetAudioBlockSizeAndComprIn ( iNewAudioBlockSize, eNewAudComprType ); - - } - - if ( bReinitializeOut ) - { - SetAudioCompressionOut ( eNewAudComprType ); - } } diff --git a/src/channel.h b/src/channel.h index dc34c1b8..3aacc9da 100755 --- a/src/channel.h +++ b/src/channel.h @@ -247,7 +247,8 @@ public: void GetConCliParam ( CVector& vecHostAddresses, CVector& vecsName, CVector& veciJitBufSize, - CVector& veciNetwOutBlSiFact ); + CVector& veciNetwOutBlSiFact, + CVector& veceAudComprType ); // access functions for actual channels bool IsConnected ( const int iChanNum ) @@ -270,6 +271,7 @@ protected: void CreateAndSendChanListForThisChan ( const int iCurChanID ); void CreateAndSendChatTextForAllConChannels ( const int iCurChanID, const QString& strChatText ); void WriteHTMLChannelList(); + void SetOutputParameters(); /* do not use the vector class since CChannel does not have appropriate copy constructor/operator */ @@ -278,6 +280,8 @@ protected: CVector vstrChatColors; + int iUploadRateLimit; + // HTML file server status bool bWriteStatusHTMLFile; QString strServerHTMLFileListName; diff --git a/src/client.cpp b/src/client.cpp index 661598de..aac1fe2a 100755 --- a/src/client.cpp +++ b/src/client.cpp @@ -432,56 +432,52 @@ void CClient::UpdateSocketBufferSize() // completely filled const double dHysteresis = 0.3; -// it seems that it is better to update the jitter buffer as soon as possible -// even if the value is not optimal right from the beginning - if ( 1 ) // previously -> CycleTimeVariance.IsInitialized() - { - // calculate current buffer setting + // calculate current buffer setting // TODO 2* seems not give optimal results, maybe use 3*? // add .5 to "round up" -> ceil // divide by MIN_SERVER_BLOCK_DURATION_MS because this is the size of // one block in the jitter buffer +// add one block for actual network jitter - // Use worst case scenario: We add the block size of input and - // output. This is not required if the smaller block size is a - // multiple of the bigger size, but in the general case where - // the block sizes do not have this relation, we require to have - // a minimum buffer size of the sum of both sizes - const double dAudioBufferDurationMs = - ( iMonoBlockSizeSam + Channel.GetAudioBlockSizeIn() ) * 1000 / - SYSTEM_SAMPLE_RATE; + // Use worst case scenario: We add the block size of input and + // output. This is not required if the smaller block size is a + // multiple of the bigger size, but in the general case where + // the block sizes do not have this relation, we require to have + // a minimum buffer size of the sum of both sizes + const double dAudioBufferDurationMs = + ( iMonoBlockSizeSam + Channel.GetAudioBlockSizeIn() ) * 1000 / + SYSTEM_SAMPLE_RATE; - const double dEstCurBufSet = ( dAudioBufferDurationMs + - 2 * ( CycleTimeVariance.GetStdDev() + 0.5 ) ) / - MIN_SERVER_BLOCK_DURATION_MS; + const double dEstCurBufSet = 1 + ( dAudioBufferDurationMs + + 2 * ( CycleTimeVariance.GetStdDev() + 0.5 ) ) / + MIN_SERVER_BLOCK_DURATION_MS; - // upper/lower hysteresis decision - const int iUpperHystDec = LlconMath().round ( dEstCurBufSet - dHysteresis ); - const int iLowerHystDec = LlconMath().round ( dEstCurBufSet + dHysteresis ); + // 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 ) + // 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 ( !( ( GetSockBufSize() == iUpperHystDec ) || + ( GetSockBufSize() == iLowerHystDec ) ) ) { - // set the socket buffer via the main window thread since somehow + // 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 + // 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 ( !( ( GetSockBufSize() == iUpperHystDec ) || - ( GetSockBufSize() == 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 ); - } - } - } + } } } diff --git a/src/global.h b/src/global.h index af5e38cd..9f8c673e 100755 --- a/src/global.h +++ b/src/global.h @@ -88,6 +88,9 @@ // default network buffer size #define DEF_NET_BUF_SIZE_NUM_BL 10 // number of blocks +// default maximum upload rate at server (typical DSL upload for good DSL) +#define DEF_MAX_UPLOAD_RATE_KBPS 800 // kbps + // maximum number of recognized sound cards installed in the system, // definition for "no device" #define MAX_NUMBER_SOUND_CARDS 10 diff --git a/src/llconserverdlg.cpp b/src/llconserverdlg.cpp index 29ef97a1..279cc974 100755 --- a/src/llconserverdlg.cpp +++ b/src/llconserverdlg.cpp @@ -45,7 +45,9 @@ CLlconServerDlg::CLlconServerDlg ( CServer* pNServP, QWidget* parent ) // set up list view for connected clients ListViewClients->setColumnWidth ( 0, 170 ); - ListViewClients->setColumnWidth ( 1, 150 ); + ListViewClients->setColumnWidth ( 1, 130 ); + ListViewClients->setColumnWidth ( 2, 40 ); + ListViewClients->setColumnWidth ( 3, 40 ); ListViewClients->clear(); // insert items in reverse order because in Windows all of them are @@ -85,12 +87,13 @@ void CLlconServerDlg::OnTimer() CVector vecsName; CVector veciJitBufSize; CVector veciNetwOutBlSiFact; + CVector veceAudComprType; double dCurTiStdDev; ListViewMutex.lock(); pServer->GetConCliParam ( vecHostAddresses, vecsName, veciJitBufSize, - veciNetwOutBlSiFact ); + veciNetwOutBlSiFact, veceAudComprType ); // fill list with connected clients for ( int i = 0; i < USED_NUM_CHANNELS; i++ ) @@ -114,6 +117,26 @@ void CLlconServerDlg::OnTimer() QString().setNum ( double ( veciNetwOutBlSiFact[i] * MIN_SERVER_BLOCK_DURATION_MS ), 'f', 2 ) ); + // output audio compression + switch ( veceAudComprType[i] ) + { + case CT_NONE: + vecpListViewItems[i]->setText ( 6, "None" ); + break; + + case CT_IMAADPCM: + vecpListViewItems[i]->setText ( 6, "IMA-ADPCM" ); + break; + + case CT_MSADPCM: + vecpListViewItems[i]->setText ( 6, "MS-ADPCM" ); + break; + + default: + vecpListViewItems[i]->setText ( 6, "Unknown" ); + break; + } + vecpListViewItems[i]->setHidden ( false ); } else diff --git a/src/llconserverdlgbase.ui b/src/llconserverdlgbase.ui index 3aae6a62..814e1621 100755 --- a/src/llconserverdlgbase.ui +++ b/src/llconserverdlgbase.ui @@ -5,8 +5,8 @@ 0 0 - 767 - 280 + 765 + 315 @@ -69,6 +69,11 @@ Block Size Out + + + Audio Compr. Out + + diff --git a/src/server.h b/src/server.h index bf92ae8d..2e204c7f 100755 --- a/src/server.h +++ b/src/server.h @@ -54,10 +54,12 @@ public: void GetConCliParam ( CVector& vecHostAddresses, CVector& vecsName, - CVector& veciJitBufSize, CVector& veciNetwOutBlSiFact ) + CVector& veciJitBufSize, + CVector& veciNetwOutBlSiFact, + CVector& veceAudComprType ) { ChannelSet.GetConCliParam ( vecHostAddresses, vecsName, - veciJitBufSize, veciNetwOutBlSiFact ); + veciJitBufSize, veciNetwOutBlSiFact, veceAudComprType ); } bool GetTimingStdDev ( double& dCurTiStdDev );