implemented auto output settings for server depending on maximum upload rate, bug fix in server, some code cleanup, new entry in server dialog table

This commit is contained in:
Volker Fischer 2009-03-10 10:47:55 +00:00
parent 4220b492d6
commit c61b9d593a
7 changed files with 174 additions and 77 deletions

View file

@ -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<int>& 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<int>& vecChanID,
Mutex.unlock(); // release mutex
}
void CChannelSet::GetConCliParam ( CVector<CHostAddress>& vecHostAddresses,
CVector<QString>& vecsName,
CVector<int>& veciJitBufSize,
CVector<int>& veciNetwOutBlSiFact )
void CChannelSet::GetConCliParam ( CVector<CHostAddress>& vecHostAddresses,
CVector<QString>& vecsName,
CVector<int>& veciJitBufSize,
CVector<int>& veciNetwOutBlSiFact,
CVector<EAudComprType>& veceAudComprType )
{
CHostAddress InetAddr;
@ -461,6 +541,7 @@ void CChannelSet::GetConCliParam ( CVector<CHostAddress>& 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<CHostAddress>& 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<unsigned char>& 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<unsigned char>& 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 );
}
}

View file

@ -247,7 +247,8 @@ public:
void GetConCliParam ( CVector<CHostAddress>& vecHostAddresses,
CVector<QString>& vecsName,
CVector<int>& veciJitBufSize,
CVector<int>& veciNetwOutBlSiFact );
CVector<int>& veciNetwOutBlSiFact,
CVector<EAudComprType>& 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<QString> vstrChatColors;
int iUploadRateLimit;
// HTML file server status
bool bWriteStatusHTMLFile;
QString strServerHTMLFileListName;

View file

@ -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 );
}
}
}
}
}

View file

@ -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

View file

@ -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<QString> vecsName;
CVector<int> veciJitBufSize;
CVector<int> veciNetwOutBlSiFact;
CVector<EAudComprType> 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

View file

@ -5,8 +5,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>767</width>
<height>280</height>
<width>765</width>
<height>315</height>
</rect>
</property>
<property name="windowTitle" >
@ -69,6 +69,11 @@
<string>Block Size Out</string>
</property>
</column>
<column>
<property name="text" >
<string>Audio Compr. Out</string>
</property>
</column>
</widget>
</item>
<item>

View file

@ -54,10 +54,12 @@ public:
void GetConCliParam ( CVector<CHostAddress>& vecHostAddresses,
CVector<QString>& vecsName,
CVector<int>& veciJitBufSize, CVector<int>& veciNetwOutBlSiFact )
CVector<int>& veciJitBufSize,
CVector<int>& veciNetwOutBlSiFact,
CVector<EAudComprType>& veceAudComprType )
{
ChannelSet.GetConCliParam ( vecHostAddresses, vecsName,
veciJitBufSize, veciNetwOutBlSiFact );
veciJitBufSize, veciNetwOutBlSiFact, veceAudComprType );
}
bool GetTimingStdDev ( double& dCurTiStdDev );