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:
parent
4220b492d6
commit
c61b9d593a
7 changed files with 174 additions and 77 deletions
126
src/channel.cpp
126
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<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 );
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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 );
|
||||
|
|
Loading…
Reference in a new issue