diff --git a/linux/sound.h b/linux/sound.h index dfebf742..79e9fe81 100755 --- a/linux/sound.h +++ b/linux/sound.h @@ -48,12 +48,12 @@ class CSound : public CSoundBase public: CSound ( void (*fpNewCallback) ( CVector& psData, void* arg ), void* arg ) : #if WITH_SOUND - CSoundBase ( fpNewCallback, arg ), rhandle ( NULL ), + CSoundBase ( false, fpNewCallback, arg ), rhandle ( NULL ), phandle ( NULL ), iCurPeriodSizeIn ( NUM_PERIOD_BLOCKS_IN ), iCurPeriodSizeOut ( NUM_PERIOD_BLOCKS_OUT ), bChangParamIn ( true ), bChangParamOut ( true ) {} #else - CSoundBase ( fpNewCallback, arg ) {} + CSoundBase ( false, fpNewCallback, arg ) {} #endif virtual ~CSound() { Close(); } diff --git a/src/audiocompr.h b/src/audiocompr.h index 26351a03..cdb4d43e 100755 --- a/src/audiocompr.h +++ b/src/audiocompr.h @@ -134,13 +134,6 @@ protected: class CAudioCompression { public: - enum EAudComprType - { - CT_NONE = 0, - CT_IMAADPCM = 1, - CT_MSADPCM = 2 - }; - CAudioCompression() {} virtual ~CAudioCompression() {} diff --git a/src/audiomixerboard.cpp b/src/audiomixerboard.cpp index 7fff2ba7..b9cfc86a 100755 --- a/src/audiomixerboard.cpp +++ b/src/audiomixerboard.cpp @@ -128,18 +128,22 @@ CAudioMixerBoard::CAudioMixerBoard ( QWidget* parent, Qt::WindowFlags f ) : QFra // connections ------------------------------------------------------------- // CODE TAG: MAX_NUM_CHANNELS_TAG // make sure we have MAX_NUM_CHANNELS connections!!! - QObject::connect(vecpChanFader[0],SIGNAL(valueChanged(double)),this,SLOT(OnValueChangedCh0(double))); - QObject::connect(vecpChanFader[1],SIGNAL(valueChanged(double)),this,SLOT(OnValueChangedCh1(double))); - QObject::connect(vecpChanFader[2],SIGNAL(valueChanged(double)),this,SLOT(OnValueChangedCh2(double))); - QObject::connect(vecpChanFader[3],SIGNAL(valueChanged(double)),this,SLOT(OnValueChangedCh3(double))); - QObject::connect(vecpChanFader[4],SIGNAL(valueChanged(double)),this,SLOT(OnValueChangedCh4(double))); - QObject::connect(vecpChanFader[5],SIGNAL(valueChanged(double)),this,SLOT(OnValueChangedCh5(double))); + QObject::connect ( vecpChanFader[0], SIGNAL ( valueChanged ( double ) ), this, SLOT ( OnValueChangedCh0 ( double ) ) ); + QObject::connect ( vecpChanFader[1], SIGNAL ( valueChanged ( double ) ), this, SLOT ( OnValueChangedCh1 ( double ) ) ); + QObject::connect ( vecpChanFader[2], SIGNAL ( valueChanged ( double ) ), this, SLOT ( OnValueChangedCh2 ( double ) ) ); + QObject::connect ( vecpChanFader[3], SIGNAL ( valueChanged ( double ) ), this, SLOT ( OnValueChangedCh3 ( double ) ) ); + QObject::connect ( vecpChanFader[4], SIGNAL ( valueChanged ( double ) ), this, SLOT ( OnValueChangedCh4 ( double ) ) ); + QObject::connect ( vecpChanFader[5], SIGNAL ( valueChanged ( double ) ), this, SLOT ( OnValueChangedCh5 ( double ) ) ); + QObject::connect ( vecpChanFader[6], SIGNAL ( valueChanged ( double ) ), this, SLOT ( OnValueChangedCh6 ( double ) ) ); + QObject::connect ( vecpChanFader[7], SIGNAL ( valueChanged ( double ) ), this, SLOT ( OnValueChangedCh7 ( double ) ) ); + QObject::connect ( vecpChanFader[8], SIGNAL ( valueChanged ( double ) ), this, SLOT ( OnValueChangedCh8 ( double ) ) ); + QObject::connect ( vecpChanFader[9], SIGNAL ( valueChanged ( double ) ), this, SLOT ( OnValueChangedCh9 ( double ) ) ); } void CAudioMixerBoard::HideAll() { // make old controls invisible - for ( int i = 0; i < MAX_NUM_CHANNELS; i++ ) + for ( int i = 0; i < USED_NUM_CHANNELS; i++ ) { vecpChanFader[i]->Hide(); } @@ -149,7 +153,7 @@ void CAudioMixerBoard::ApplyNewConClientList ( CVector& vecCh { // search for channels with are already present and preserver their gain // setting, for all other channels, reset gain - for ( int i = 0; i < MAX_NUM_CHANNELS; i++ ) + for ( int i = 0; i < USED_NUM_CHANNELS; i++ ) { bool bFaderIsUsed = false; diff --git a/src/audiomixerboard.h b/src/audiomixerboard.h index a61c99f4..9dd7390e 100755 --- a/src/audiomixerboard.h +++ b/src/audiomixerboard.h @@ -105,6 +105,10 @@ public slots: void OnValueChangedCh3 ( double dValue ) { emit ChangeChanGain ( 3, dValue ); } void OnValueChangedCh4 ( double dValue ) { emit ChangeChanGain ( 4, dValue ); } void OnValueChangedCh5 ( double dValue ) { emit ChangeChanGain ( 5, dValue ); } + void OnValueChangedCh6 ( double dValue ) { emit ChangeChanGain ( 6, dValue ); } + void OnValueChangedCh7 ( double dValue ) { emit ChangeChanGain ( 7, dValue ); } + void OnValueChangedCh8 ( double dValue ) { emit ChangeChanGain ( 8, dValue ); } + void OnValueChangedCh9 ( double dValue ) { emit ChangeChanGain ( 9, dValue ); } signals: void ChangeChanGain ( int iId, double dGain ); diff --git a/src/channel.cpp b/src/channel.cpp index dee94df2..85aae405 100755 --- a/src/channel.cpp +++ b/src/channel.cpp @@ -32,10 +32,9 @@ CChannelSet::CChannelSet ( const bool bForceLowUploadRate ) : bWriteStatusHTMLFile ( false ) { // enable all channels and set server flag - for ( int i = 0; i < MAX_NUM_CHANNELS; i++ ) + for ( int i = 0; i < USED_NUM_CHANNELS; i++ ) { vecChannels[i].SetEnable ( true ); - vecChannels[i].SetIsServer ( true ); vecChannels[i].SetForceLowUploadRate ( bForceLowUploadRate ); } @@ -57,6 +56,10 @@ CChannelSet::CChannelSet ( const bool bForceLowUploadRate ) : QObject::connect ( &vecChannels[3], SIGNAL ( MessReadyForSending ( CVector ) ), this, SLOT ( OnSendProtMessCh3 ( CVector ) ) ); QObject::connect ( &vecChannels[4], SIGNAL ( MessReadyForSending ( CVector ) ), this, SLOT ( OnSendProtMessCh4 ( CVector ) ) ); QObject::connect ( &vecChannels[5], SIGNAL ( MessReadyForSending ( CVector ) ), this, SLOT ( OnSendProtMessCh5 ( CVector ) ) ); + QObject::connect ( &vecChannels[6], SIGNAL ( MessReadyForSending ( CVector ) ), this, SLOT ( OnSendProtMessCh6 ( CVector ) ) ); + QObject::connect ( &vecChannels[7], SIGNAL ( MessReadyForSending ( CVector ) ), this, SLOT ( OnSendProtMessCh7 ( CVector ) ) ); + QObject::connect ( &vecChannels[8], SIGNAL ( MessReadyForSending ( CVector ) ), this, SLOT ( OnSendProtMessCh8 ( CVector ) ) ); + QObject::connect ( &vecChannels[9], SIGNAL ( MessReadyForSending ( CVector ) ), this, SLOT ( OnSendProtMessCh9 ( CVector ) ) ); // request jitter buffer size QObject::connect ( &vecChannels[0], SIGNAL ( NewConnection() ), this, SLOT ( OnNewConnectionCh0() ) ); @@ -65,6 +68,10 @@ CChannelSet::CChannelSet ( const bool bForceLowUploadRate ) : QObject::connect ( &vecChannels[3], SIGNAL ( NewConnection() ), this, SLOT ( OnNewConnectionCh3() ) ); QObject::connect ( &vecChannels[4], SIGNAL ( NewConnection() ), this, SLOT ( OnNewConnectionCh4() ) ); QObject::connect ( &vecChannels[5], SIGNAL ( NewConnection() ), this, SLOT ( OnNewConnectionCh5() ) ); + QObject::connect ( &vecChannels[6], SIGNAL ( NewConnection() ), this, SLOT ( OnNewConnectionCh6() ) ); + QObject::connect ( &vecChannels[7], SIGNAL ( NewConnection() ), this, SLOT ( OnNewConnectionCh7() ) ); + QObject::connect ( &vecChannels[8], SIGNAL ( NewConnection() ), this, SLOT ( OnNewConnectionCh8() ) ); + QObject::connect ( &vecChannels[9], SIGNAL ( NewConnection() ), this, SLOT ( OnNewConnectionCh9() ) ); // request connected clients list QObject::connect ( &vecChannels[0], SIGNAL ( ReqConnClientsList() ), this, SLOT ( OnReqConnClientsListCh0() ) ); @@ -73,6 +80,10 @@ CChannelSet::CChannelSet ( const bool bForceLowUploadRate ) : QObject::connect ( &vecChannels[3], SIGNAL ( ReqConnClientsList() ), this, SLOT ( OnReqConnClientsListCh3() ) ); QObject::connect ( &vecChannels[4], SIGNAL ( ReqConnClientsList() ), this, SLOT ( OnReqConnClientsListCh4() ) ); QObject::connect ( &vecChannels[5], SIGNAL ( ReqConnClientsList() ), this, SLOT ( OnReqConnClientsListCh5() ) ); + QObject::connect ( &vecChannels[6], SIGNAL ( ReqConnClientsList() ), this, SLOT ( OnReqConnClientsListCh6() ) ); + QObject::connect ( &vecChannels[7], SIGNAL ( ReqConnClientsList() ), this, SLOT ( OnReqConnClientsListCh7() ) ); + QObject::connect ( &vecChannels[8], SIGNAL ( ReqConnClientsList() ), this, SLOT ( OnReqConnClientsListCh8() ) ); + QObject::connect ( &vecChannels[9], SIGNAL ( ReqConnClientsList() ), this, SLOT ( OnReqConnClientsListCh9() ) ); // channel name has changed QObject::connect ( &vecChannels[0], SIGNAL ( NameHasChanged() ), this, SLOT ( OnNameHasChangedCh0() ) ); @@ -81,6 +92,10 @@ CChannelSet::CChannelSet ( const bool bForceLowUploadRate ) : QObject::connect ( &vecChannels[3], SIGNAL ( NameHasChanged() ), this, SLOT ( OnNameHasChangedCh3() ) ); QObject::connect ( &vecChannels[4], SIGNAL ( NameHasChanged() ), this, SLOT ( OnNameHasChangedCh4() ) ); QObject::connect ( &vecChannels[5], SIGNAL ( NameHasChanged() ), this, SLOT ( OnNameHasChangedCh5() ) ); + QObject::connect ( &vecChannels[6], SIGNAL ( NameHasChanged() ), this, SLOT ( OnNameHasChangedCh6() ) ); + QObject::connect ( &vecChannels[7], SIGNAL ( NameHasChanged() ), this, SLOT ( OnNameHasChangedCh7() ) ); + QObject::connect ( &vecChannels[8], SIGNAL ( NameHasChanged() ), this, SLOT ( OnNameHasChangedCh8() ) ); + QObject::connect ( &vecChannels[9], SIGNAL ( NameHasChanged() ), this, SLOT ( OnNameHasChangedCh9() ) ); // chat text received QObject::connect ( &vecChannels[0], SIGNAL ( ChatTextReceived ( QString ) ), this, SLOT ( OnChatTextReceivedCh0 ( QString ) ) ); @@ -89,6 +104,10 @@ CChannelSet::CChannelSet ( const bool bForceLowUploadRate ) : QObject::connect ( &vecChannels[3], SIGNAL ( ChatTextReceived ( QString ) ), this, SLOT ( OnChatTextReceivedCh3 ( QString ) ) ); QObject::connect ( &vecChannels[4], SIGNAL ( ChatTextReceived ( QString ) ), this, SLOT ( OnChatTextReceivedCh4 ( QString ) ) ); QObject::connect ( &vecChannels[5], SIGNAL ( ChatTextReceived ( QString ) ), this, SLOT ( OnChatTextReceivedCh5 ( QString ) ) ); + QObject::connect ( &vecChannels[6], SIGNAL ( ChatTextReceived ( QString ) ), this, SLOT ( OnChatTextReceivedCh6 ( QString ) ) ); + QObject::connect ( &vecChannels[7], SIGNAL ( ChatTextReceived ( QString ) ), this, SLOT ( OnChatTextReceivedCh7 ( QString ) ) ); + QObject::connect ( &vecChannels[8], SIGNAL ( ChatTextReceived ( QString ) ), this, SLOT ( OnChatTextReceivedCh8 ( QString ) ) ); + QObject::connect ( &vecChannels[9], SIGNAL ( ChatTextReceived ( QString ) ), this, SLOT ( OnChatTextReceivedCh9 ( QString ) ) ); // ping message received QObject::connect ( &vecChannels[0], SIGNAL ( PingReceived ( int ) ), this, SLOT ( OnPingReceivedCh0 ( int ) ) ); @@ -97,6 +116,10 @@ CChannelSet::CChannelSet ( const bool bForceLowUploadRate ) : QObject::connect ( &vecChannels[3], SIGNAL ( PingReceived ( int ) ), this, SLOT ( OnPingReceivedCh3 ( int ) ) ); QObject::connect ( &vecChannels[4], SIGNAL ( PingReceived ( int ) ), this, SLOT ( OnPingReceivedCh4 ( int ) ) ); QObject::connect ( &vecChannels[5], SIGNAL ( PingReceived ( int ) ), this, SLOT ( OnPingReceivedCh5 ( int ) ) ); + QObject::connect ( &vecChannels[6], SIGNAL ( PingReceived ( int ) ), this, SLOT ( OnPingReceivedCh6 ( int ) ) ); + QObject::connect ( &vecChannels[7], SIGNAL ( PingReceived ( int ) ), this, SLOT ( OnPingReceivedCh7 ( int ) ) ); + QObject::connect ( &vecChannels[8], SIGNAL ( PingReceived ( int ) ), this, SLOT ( OnPingReceivedCh8 ( int ) ) ); + QObject::connect ( &vecChannels[9], SIGNAL ( PingReceived ( int ) ), this, SLOT ( OnPingReceivedCh9 ( int ) ) ); } CVector CChannelSet::CreateChannelList() @@ -104,7 +127,7 @@ CVector CChannelSet::CreateChannelList() CVector vecChanInfo ( 0 ); // look for free channels - for ( int i = 0; i < MAX_NUM_CHANNELS; i++ ) + for ( int i = 0; i < USED_NUM_CHANNELS; i++ ) { if ( vecChannels[i].IsConnected() ) { @@ -125,7 +148,7 @@ void CChannelSet::CreateAndSendChanListForAllConChannels() CVector vecChanInfo ( CChannelSet::CreateChannelList() ); // now send connected channels list to all connected clients - for ( int i = 0; i < MAX_NUM_CHANNELS; i++ ) + for ( int i = 0; i < USED_NUM_CHANNELS; i++ ) { if ( vecChannels[i].IsConnected() ) { @@ -148,7 +171,7 @@ void CChannelSet::CreateAndSendChanListForAllExceptThisChan ( const int iCurChan // now send connected channels list to all connected clients except for // the channel with the ID "iCurChanID" - for ( int i = 0; i < MAX_NUM_CHANNELS; i++ ) + for ( int i = 0; i < USED_NUM_CHANNELS; i++ ) { if ( ( vecChannels[i].IsConnected() ) && ( i != iCurChanID ) ) { @@ -196,7 +219,7 @@ void CChannelSet::CreateAndSendChatTextForAllConChannels ( const int iCurChanID, // send chat text to all connected clients --------------------------------- - for ( int i = 0; i < MAX_NUM_CHANNELS; i++ ) + for ( int i = 0; i < USED_NUM_CHANNELS; i++ ) { if ( vecChannels[i].IsConnected() ) { @@ -209,7 +232,7 @@ void CChannelSet::CreateAndSendChatTextForAllConChannels ( const int iCurChanID, int CChannelSet::GetFreeChan() { // look for a free channel - for ( int i = 0; i < MAX_NUM_CHANNELS; i++ ) + for ( int i = 0; i < USED_NUM_CHANNELS; i++ ) { if ( !vecChannels[i].IsConnected() ) { @@ -226,7 +249,7 @@ int CChannelSet::CheckAddr ( const CHostAddress& Addr ) CHostAddress InetAddr; // check for all possible channels if IP is already in use - for ( int i = 0; i < MAX_NUM_CHANNELS; i++ ) + for ( int i = 0; i < USED_NUM_CHANNELS; i++ ) { if ( vecChannels[i].GetAddress ( InetAddr ) ) { @@ -246,8 +269,8 @@ bool CChannelSet::PutData ( const CVector& vecbyRecBuf, const int iNumBytesRead, const CHostAddress& HostAdr ) { - bool bRet = false; - bool bCreateChanList = false; + bool bAudioOK = false; + bool bNewChannelReserved = false; Mutex.lock(); { @@ -270,7 +293,7 @@ bool CChannelSet::PutData ( const CVector& vecbyRecBuf, // reset the channel gains of current channel, at the same // time reset gains of this channel ID for all other channels - for ( int i = 0; i < MAX_NUM_CHANNELS; i++ ) + for ( int i = 0; i < USED_NUM_CHANNELS; i++ ) { vecChannels[iCurChanID].SetGain ( i, (double) 1.0 ); @@ -279,14 +302,8 @@ bool CChannelSet::PutData ( const CVector& vecbyRecBuf, vecChannels[i].SetGain ( iCurChanID, (double) 1.0 ); } - // a new client connected to the server, set flag to create and - // send all clients the updated channel list, we cannot create - // the message here since the received data has to be put to the - // channel first so that this channel is marked as connected - bCreateChanList = true; - - // send message about new channel - emit ChannelConnected ( HostAdr ); + // set flag for new reserved channel + bNewChannelReserved = true; } else { @@ -309,25 +326,36 @@ bool CChannelSet::PutData ( const CVector& vecbyRecBuf, { case PS_AUDIO_OK: PostWinMessage ( MS_JIT_BUF_PUT, MUL_COL_LED_GREEN, iCurChanID ); - bRet = true; // in case we have an audio packet, return true + bAudioOK = true; // in case we have an audio packet, return true break; case PS_AUDIO_ERR: PostWinMessage ( MS_JIT_BUF_PUT, MUL_COL_LED_RED, iCurChanID ); - bRet = true; // in case we have an audio packet, return true + bAudioOK = true; // in case we have an audio packet, return true break; case PS_PROT_ERR: PostWinMessage ( MS_JIT_BUF_PUT, MUL_COL_LED_YELLOW, iCurChanID ); + +// TEST +bAudioOK = true; + break; } } - // after data is put in channel buffer, create channel list message if // requested - if ( bCreateChanList ) + if ( bNewChannelReserved && bAudioOK ) { + // send message about new channel + emit ChannelConnected ( HostAdr ); + + // A new client connected to the server, create and + // send all clients the updated channel list (the list has to + // be created after the received data has to be put to the + // channel first so that this channel is marked as connected) + // // connected clients list is only send for new connected clients after // request, only the already connected clients get the list // automatically, because they don't know when new clients connect @@ -336,7 +364,7 @@ bool CChannelSet::PutData ( const CVector& vecbyRecBuf, } Mutex.unlock(); - return bRet; + return bAudioOK; } void CChannelSet::GetBlockAllConC ( CVector& vecChanID, @@ -347,7 +375,7 @@ void CChannelSet::GetBlockAllConC ( CVector& vecChanID, bool bCreateChanList = false; // init temporal data vector and clear input buffers - CVector vecdData ( MIN_BLOCK_SIZE_SAMPLES ); + CVector vecdData ( MIN_SERVER_BLOCK_SIZE_SAMPLES ); vecChanID.Init ( 0 ); vecvecdData.Init ( 0 ); @@ -358,7 +386,7 @@ void CChannelSet::GetBlockAllConC ( CVector& vecChanID, Mutex.lock(); { // check all possible channels - for ( i = 0; i < MAX_NUM_CHANNELS; i++ ) + for ( i = 0; i < USED_NUM_CHANNELS; i++ ) { // read out all input buffers to decrease timeout counter on // disconnected channels @@ -424,20 +452,18 @@ void CChannelSet::GetBlockAllConC ( CVector& vecChanID, void CChannelSet::GetConCliParam ( CVector& vecHostAddresses, CVector& vecsName, CVector& veciJitBufSize, - CVector& veciNetwOutBlSiFact, - CVector& veciNetwInBlSiFact ) + CVector& veciNetwOutBlSiFact ) { CHostAddress InetAddr; // init return values - vecHostAddresses.Init ( MAX_NUM_CHANNELS ); - vecsName.Init ( MAX_NUM_CHANNELS ); - veciJitBufSize.Init ( MAX_NUM_CHANNELS ); - veciNetwOutBlSiFact.Init ( MAX_NUM_CHANNELS ); - veciNetwInBlSiFact.Init ( MAX_NUM_CHANNELS ); + vecHostAddresses.Init ( USED_NUM_CHANNELS ); + vecsName.Init ( USED_NUM_CHANNELS ); + veciJitBufSize.Init ( USED_NUM_CHANNELS ); + veciNetwOutBlSiFact.Init ( USED_NUM_CHANNELS ); // check all possible channels - for ( int i = 0; i < MAX_NUM_CHANNELS; i++ ) + for ( int i = 0; i < USED_NUM_CHANNELS; i++ ) { if ( vecChannels[i].GetAddress ( InetAddr ) ) { @@ -446,7 +472,6 @@ void CChannelSet::GetConCliParam ( CVector& vecHostAddresses, vecsName[i] = vecChannels[i].GetName(); veciJitBufSize[i] = vecChannels[i].GetSockBufSize(); veciNetwOutBlSiFact[i] = vecChannels[i].GetNetwBufSizeFactOut(); - veciNetwInBlSiFact[i] = vecChannels[i].GetNetwBufSizeFactIn(); } } } @@ -482,7 +507,7 @@ void CChannelSet::WriteHTMLChannelList() // get the number of connected clients int iNumConnClients = 0; - for ( int i = 0; i < MAX_NUM_CHANNELS; i++ ) + for ( int i = 0; i < USED_NUM_CHANNELS; i++ ) { if ( vecChannels[i].IsConnected() ) { @@ -499,7 +524,7 @@ void CChannelSet::WriteHTMLChannelList() else { // write entry for each connected client - for ( int i = 0; i < MAX_NUM_CHANNELS; i++ ) + for ( int i = 0; i < USED_NUM_CHANNELS; i++ ) { if ( vecChannels[i].IsConnected() ) { @@ -530,13 +555,10 @@ void CChannelSet::WriteHTMLChannelList() /******************************************************************************\ * CChannel * \******************************************************************************/ -CChannel::CChannel() : sName ( "" ), - vecdGains ( MAX_NUM_CHANNELS, (double) 1.0 ), bIsServer ( false ), - bForceLowUploadRate ( false ), - // it is important to give the following parameters meaningful initial - // values because they are dependend on each other - iCurSockBufSize ( DEF_NET_BUF_SIZE_NUM_BL ), - iCurNetwInBlSiFact ( DEF_NET_BLOCK_SIZE_FACTOR ) +CChannel::CChannel ( const bool bNIsServer ) : bIsServer ( bNIsServer ), + sName ( "" ), vecdGains ( USED_NUM_CHANNELS, (double) 1.0 ), + bIsEnabled ( false ), bForceLowUploadRate ( false ), + iCurNetwOutBlSiFact ( DEF_NET_BLOCK_SIZE_FACTOR ) { // query all possible network in buffer sizes for determining if an // audio packet was received (the following code only works if all @@ -549,11 +571,11 @@ CChannel::CChannel() : sName ( "" ), // init special mode -// TEST -> 64 -vecNetwBufferInProps[0].iBlockSizeFactor = 1; -vecNetwBufferInProps[0].eAudComprType = CAudioCompression::CT_NONE; +// TEST -> 128 +vecNetwBufferInProps[0].iAudioBlockSize = 128; +vecNetwBufferInProps[0].eAudComprType = CT_NONE; vecNetwBufferInProps[0].iNetwInBufSize = AudioCompressionIn.Init ( - vecNetwBufferInProps[0].iBlockSizeFactor * 64, + vecNetwBufferInProps[0].iAudioBlockSize, vecNetwBufferInProps[0].eAudComprType ); @@ -567,26 +589,26 @@ vecNetwBufferInProps[0].iNetwInBufSize = AudioCompressionIn.Init ( // network block size factor must start from 1 -> i + 1 const int iCurNetBlockSizeFact = i + 1; - vecNetwBufferInProps[iNoneIdx].iBlockSizeFactor = iCurNetBlockSizeFact; - vecNetwBufferInProps[iIMAIdx].iBlockSizeFactor = iCurNetBlockSizeFact; - vecNetwBufferInProps[iMSIdx].iBlockSizeFactor = iCurNetBlockSizeFact; + vecNetwBufferInProps[iNoneIdx].iAudioBlockSize = iCurNetBlockSizeFact * MIN_SERVER_BLOCK_SIZE_SAMPLES; + vecNetwBufferInProps[iIMAIdx].iAudioBlockSize = iCurNetBlockSizeFact * MIN_SERVER_BLOCK_SIZE_SAMPLES; + vecNetwBufferInProps[iMSIdx].iAudioBlockSize = iCurNetBlockSizeFact * MIN_SERVER_BLOCK_SIZE_SAMPLES; // None (no audio compression) - vecNetwBufferInProps[iNoneIdx].eAudComprType = CAudioCompression::CT_NONE; + vecNetwBufferInProps[iNoneIdx].eAudComprType = CT_NONE; vecNetwBufferInProps[iNoneIdx].iNetwInBufSize = AudioCompressionIn.Init ( - vecNetwBufferInProps[iNoneIdx].iBlockSizeFactor * MIN_BLOCK_SIZE_SAMPLES, + vecNetwBufferInProps[iNoneIdx].iAudioBlockSize, vecNetwBufferInProps[iNoneIdx].eAudComprType ); // IMA ADPCM - vecNetwBufferInProps[iIMAIdx].eAudComprType = CAudioCompression::CT_IMAADPCM; + vecNetwBufferInProps[iIMAIdx].eAudComprType = CT_IMAADPCM; vecNetwBufferInProps[iIMAIdx].iNetwInBufSize = AudioCompressionIn.Init ( - vecNetwBufferInProps[iIMAIdx].iBlockSizeFactor * MIN_BLOCK_SIZE_SAMPLES, + vecNetwBufferInProps[iIMAIdx].iAudioBlockSize, vecNetwBufferInProps[iIMAIdx].eAudComprType ); // MS ADPCM - vecNetwBufferInProps[iMSIdx].eAudComprType = CAudioCompression::CT_MSADPCM; + vecNetwBufferInProps[iMSIdx].eAudComprType = CT_MSADPCM; vecNetwBufferInProps[iMSIdx].iNetwInBufSize = AudioCompressionIn.Init ( - vecNetwBufferInProps[iMSIdx].iBlockSizeFactor * MIN_BLOCK_SIZE_SAMPLES, + vecNetwBufferInProps[iMSIdx].iAudioBlockSize, vecNetwBufferInProps[iMSIdx].eAudComprType ); } @@ -594,11 +616,14 @@ vecNetwBufferInProps[0].iNetwInBufSize = AudioCompressionIn.Init ( SetSockBufSize ( DEF_NET_BUF_SIZE_NUM_BL ); // set initial input and output block size factors - SetNetwInBlSiFactAndCompr ( DEF_NET_BLOCK_SIZE_FACTOR, CAudioCompression::CT_MSADPCM ); - SetNetwBufSizeFactOut ( DEF_NET_BLOCK_SIZE_FACTOR ); + SetAudioBlockSizeAndComprIn ( + MIN_SERVER_BLOCK_SIZE_SAMPLES * DEF_NET_BLOCK_SIZE_FACTOR, + CT_MSADPCM ); + + SetNetwBufSizeFactOut ( DEF_NET_BLOCK_SIZE_FACTOR ); // set initial audio compression format for output - SetAudioCompressionOut ( CAudioCompression::CT_MSADPCM ); + SetAudioCompressionOut ( CT_MSADPCM ); // init time-out for the buffer with zero -> no connection iConTimeOut = 0; @@ -640,6 +665,26 @@ vecNetwBufferInProps[0].iNetwInBufSize = AudioCompressionIn.Init ( QObject::connect( &Protocol, SIGNAL ( PingReceived ( int ) ), this, SIGNAL ( PingReceived ( int ) ) ); + + QObject::connect ( &Protocol, + SIGNAL ( NetTranspPropsReceived ( CNetworkTransportProps ) ), + this, SLOT ( OnNetTranspPropsReceived ( CNetworkTransportProps ) ) ); +} + +bool CChannel::ProtocolIsEnabled() +{ + // for the server, only enable protocol if the channel is connected, i.e., + // successfully audio packets are received from a client + // for the client, enable protocol if the channel is enabled, i.e., the + // connection button was hit by the user + if ( bIsServer ) + { + return IsConnected(); + } + else + { + return bIsEnabled; + } } void CChannel::SetEnable ( const bool bNEnStat ) @@ -649,10 +694,11 @@ void CChannel::SetEnable ( const bool bNEnStat ) // set internal parameter bIsEnabled = bNEnStat; - // if channel is not enabled, reset time out count + // if channel is not enabled, reset time out count and protocol if ( !bNEnStat ) { iConTimeOut = 0; + Protocol.Reset(); } } @@ -669,55 +715,73 @@ void CChannel::SetForceLowUploadRate ( const bool bNFoLoUpRat ) bForceLowUploadRate = bNFoLoUpRat; } -void CChannel::SetNetwInBlSiFactAndCompr ( const int iNewBlockSizeFactor, - const CAudioCompression::EAudComprType eNewAudComprType ) +void CChannel::SetAudioBlockSizeAndComprIn ( const int iNewBlockSize, + const EAudComprType eNewAudComprType ) { QMutexLocker locker ( &Mutex ); - // store new value - iCurNetwInBlSiFact = iNewBlockSizeFactor; + // store block size value + iCurAudioBlockSizeIn = iNewBlockSize; // init audio compression unit - AudioCompressionIn.Init ( iNewBlockSizeFactor * MIN_BLOCK_SIZE_SAMPLES, - eNewAudComprType ); + AudioCompressionIn.Init ( iNewBlockSize, eNewAudComprType ); // initial value for connection time out counter - iConTimeOutStartVal = ( CON_TIME_OUT_SEC_MAX * 1000 ) / - ( iNewBlockSizeFactor * MIN_BLOCK_DURATION_MS ); + iConTimeOutStartVal = + ( CON_TIME_OUT_SEC_MAX * SYSTEM_SAMPLE_RATE ) / iNewBlockSize; +} - // socket buffer must be adjusted - SetSockBufSizeIntern ( GetSockBufSize() ); +void CChannel::SetNetwBufSizeOut ( const int iNewAudioBlockSizeOut ) +{ + // this function is intended for the client (not the server) + QMutexLocker locker ( &Mutex ); + + // store new value + iCurAudioBlockSizeOut = iNewAudioBlockSizeOut; + + iAudComprSizeOut = + AudioCompressionOut.Init ( iNewAudioBlockSizeOut, eAudComprTypeOut ); } void CChannel::SetNetwBufSizeFactOut ( const int iNewNetwBlSiFactOut ) { + // this function is intended for the server (not the client) QMutexLocker locker ( &Mutex ); - if ( !bForceLowUploadRate ) + // use the network block size factor only for the server + if ( ( !bForceLowUploadRate ) && bIsServer ) { // store new value iCurNetwOutBlSiFact = iNewNetwBlSiFactOut; // init audio compression and get audio compression block size iAudComprSizeOut = AudioCompressionOut.Init ( - iNewNetwBlSiFactOut * MIN_BLOCK_SIZE_SAMPLES, eAudComprTypeOut ); + iNewNetwBlSiFactOut * MIN_SERVER_BLOCK_SIZE_SAMPLES, eAudComprTypeOut ); // init conversion buffer - ConvBuf.Init ( iNewNetwBlSiFactOut * MIN_BLOCK_SIZE_SAMPLES ); + ConvBuf.Init ( iNewNetwBlSiFactOut * MIN_SERVER_BLOCK_SIZE_SAMPLES ); } } -void CChannel::SetAudioCompressionOut ( const CAudioCompression::EAudComprType eNewAudComprTypeOut ) +void CChannel::SetAudioCompressionOut ( const EAudComprType eNewAudComprTypeOut ) { if ( !bForceLowUploadRate ) { // store new value eAudComprTypeOut = eNewAudComprTypeOut; - // call "set network buffer size factor" function because its initialization - // depends on the audio compression format and implicitely, the audio compression - // is initialized - SetNetwBufSizeFactOut ( iCurNetwOutBlSiFact ); + if ( bIsServer ) + { + // call "set network buffer size factor" function because its + // initialization depends on the audio compression format and + // implicitely, the audio compression is initialized + SetNetwBufSizeFactOut ( iCurNetwOutBlSiFact ); + } + else + { + // for client set arbitrary block size + SetNetwBufSizeOut ( iCurAudioBlockSizeOut ); + } } } @@ -725,21 +789,11 @@ void CChannel::SetSockBufSize ( const int iNumBlocks ) { QMutexLocker locker ( &Mutex ); // this opperation must be done with mutex - SetSockBufSizeIntern ( iNumBlocks ); -} - -void CChannel::SetSockBufSizeIntern ( const int iNumBlocks ) -{ iCurSockBufSize = iNumBlocks; - // the idea of setting the jitter buffer is as follows: - // The network block size is a multiple of the internal minimal - // block size. Therefore, the minimum jitter buffer size must be - // so that it can take one network buffer -> NET_BLOCK_SIZE_FACTOR. - // The actual jitter compensation are then the additional blocks of - // the internal block size, which is set with SetSockBufSize - SockBuf.Init ( MIN_BLOCK_SIZE_SAMPLES, - iNumBlocks + iCurNetwInBlSiFact ); + // the network block size is a multiple of the internal minimal + // block size + SockBuf.Init ( MIN_SERVER_BLOCK_SIZE_SAMPLES, iNumBlocks ); } void CChannel::SetGain ( const int iChanID, const double dNewGain ) @@ -747,7 +801,7 @@ void CChannel::SetGain ( const int iChanID, const double dNewGain ) QMutexLocker locker ( &Mutex ); // set value (make sure channel ID is in range) - if ( ( iChanID >= 0 ) && ( iChanID < MAX_NUM_CHANNELS ) ) + if ( ( iChanID >= 0 ) && ( iChanID < USED_NUM_CHANNELS ) ) { vecdGains[iChanID] = dNewGain; } @@ -758,7 +812,7 @@ double CChannel::GetGain ( const int iChanID ) QMutexLocker locker ( &Mutex ); // get value (make sure channel ID is in range) - if ( ( iChanID >= 0 ) && ( iChanID < MAX_NUM_CHANNELS ) ) + if ( ( iChanID >= 0 ) && ( iChanID < USED_NUM_CHANNELS ) ) { return vecdGains[iChanID]; } @@ -801,8 +855,9 @@ QString CChannel::GetName() void CChannel::OnSendProtMessage ( CVector vecMessage ) { - // only send messages if we are connected, otherwise delete complete queue - if ( IsConnected() ) + // only send messages if protocol is enabled, otherwise delete complete + // queue + if ( ProtocolIsEnabled() ) { // emit message to actually send the data emit MessReadyForSending ( vecMessage ); @@ -810,7 +865,7 @@ void CChannel::OnSendProtMessage ( CVector vecMessage ) else { // delete send message queue - Protocol.DeleteSendMessQueue(); + Protocol.Reset(); } } @@ -834,6 +889,26 @@ void CChannel::OnChangeChanName ( QString strName ) SetName ( strName ); } + + + +void CChannel::OnNetTranspPropsReceived ( CNetworkTransportProps NetworkTransportProps ) +{ + QMutexLocker locker ( &Mutex ); + +// TEST +// TODO use mutex in Put function +// TODO check possiblity of received parameter -> error checking +vecNetwBufferInProps[0].iAudioBlockSize = NetworkTransportProps.iMonoAudioBlockSize; +vecNetwBufferInProps[0].eAudComprType = NetworkTransportProps.eAudioCodingType; +vecNetwBufferInProps[0].iNetwInBufSize = AudioCompressionIn.Init ( + vecNetwBufferInProps[0].iAudioBlockSize, + vecNetwBufferInProps[0].eAudComprType ); +} + + + + bool CChannel::GetAddress(CHostAddress& RetAddr) { QMutexLocker locker ( &Mutex ); @@ -863,8 +938,8 @@ EPutDataStat CChannel::PutData ( const CVector& vecbyData, if ( bIsEnabled ) { // first check if this is protocol data - // only use protocol data if channel is connected - if ( IsConnected() ) + // only use protocol data if protocol mechanism is enabled + if ( ProtocolIsEnabled() ) { // parse the message assuming this is a protocol message if ( !Protocol.ParseMessage ( vecbyData, iNumBytes ) ) @@ -889,18 +964,18 @@ EPutDataStat CChannel::PutData ( const CVector& vecbyData, bIsAudioPacket = true; // check if we are correctly initialized - const int iNewNetwInBlSiFact = - vecNetwBufferInProps[i].iBlockSizeFactor; + const int iNewAudioBlockSize = + vecNetwBufferInProps[i].iAudioBlockSize; - const CAudioCompression::EAudComprType eNewAudComprType = + const EAudComprType eNewAudComprType = vecNetwBufferInProps[i].eAudComprType; - if ( ( iNewNetwInBlSiFact != iCurNetwInBlSiFact ) || + if ( ( iNewAudioBlockSize != iCurAudioBlockSizeIn ) || ( eNewAudComprType != AudioCompressionIn.GetType() ) ) { // re-initialize to new value - SetNetwInBlSiFactAndCompr ( iNewNetwInBlSiFact, - eNewAudComprType ); + SetAudioBlockSizeAndComprIn ( + iNewAudioBlockSize, eNewAudComprType ); } // in case of a server channel, use the same audio @@ -915,17 +990,18 @@ EPutDataStat CChannel::PutData ( const CVector& vecbyData, } } - // only process if packet has correct size - if ( bIsAudioPacket ) + Mutex.lock(); { - Mutex.lock(); + // only process audio if packet has correct size + if ( bIsAudioPacket ) { // decompress audio CVector vecsDecomprAudio ( AudioCompressionIn.Decode ( vecbyData ) ); // convert received data from short to double - CVector vecdDecomprAudio ( iCurNetwInBlSiFact * MIN_BLOCK_SIZE_SAMPLES ); - for ( int i = 0; i < iCurNetwInBlSiFact * MIN_BLOCK_SIZE_SAMPLES; i++ ) + const int iAudioSize = vecsDecomprAudio.Size(); + CVector vecdDecomprAudio ( iAudioSize ); + for ( int i = 0; i < iAudioSize; i++ ) { vecdDecomprAudio[i] = static_cast ( vecsDecomprAudio[i] ); } @@ -938,21 +1014,28 @@ EPutDataStat CChannel::PutData ( const CVector& vecbyData, { eRet = PS_AUDIO_ERR; } - - // check if channel was not connected, this is a new connection - bNewConnection = !IsConnected(); - - // reset time-out counter - iConTimeOut = iConTimeOutStartVal; } - Mutex.unlock(); - } - else - { - // the protocol parsing failed and this was no audio block, - // we treat this as protocol error (unkown packet) - eRet = PS_PROT_ERR; + else + { + // the protocol parsing failed and this was no audio block, + // we treat this as protocol error (unkown packet) + eRet = PS_PROT_ERR; + } + + // all network packets except of valid llcon protocol messages + // regardless if they are valid or invalid audio packets lead to + // a state change to a connected channel + // this is because protocol messages can only be sent on a + // connected channel and the client has to inform the server + // about the audio packet properties via the protocol + + // check if channel was not connected, this is a new connection + bNewConnection = !IsConnected(); + + // reset time-out counter + iConTimeOut = iConTimeOutStartVal; } + Mutex.unlock(); } // inform other objects that new connection was established @@ -1008,13 +1091,22 @@ CVector CChannel::PrepSendPacket ( const CVector& vecsNPac // tell the following network send routine that nothing should be sent CVector vecbySendBuf ( 0 ); - // use conversion buffer to convert sound card block size in network - // block size - if ( ConvBuf.Put ( vecsNPacket ) ) + if ( bIsServer ) + { + // use conversion buffer to convert sound card block size in network + // block size + if ( ConvBuf.Put ( vecsNPacket ) ) + { + // a packet is ready, compress audio + vecbySendBuf.Init ( iAudComprSizeOut ); + vecbySendBuf = AudioCompressionOut.Encode ( ConvBuf.Get() ); + } + } + else { // a packet is ready, compress audio vecbySendBuf.Init ( iAudComprSizeOut ); - vecbySendBuf = AudioCompressionOut.Encode ( ConvBuf.Get() ); + vecbySendBuf = AudioCompressionOut.Encode ( vecsNPacket ); } return vecbySendBuf; diff --git a/src/channel.h b/src/channel.h index b8c727e8..44b4d347 100755 --- a/src/channel.h +++ b/src/channel.h @@ -64,7 +64,7 @@ enum EGetDataStat }; // low upload data rate settings -#define LOW_UPL_SET_AUDIO_COMPRESSION CAudioCompression::CT_MSADPCM +#define LOW_UPL_SET_AUDIO_COMPRESSION CT_MSADPCM #define LOW_UPL_SET_BLOCK_SIZE_FACTOR_OUT MAX_NET_BLOCK_SIZE_FACTOR @@ -75,7 +75,9 @@ class CChannel : public QObject Q_OBJECT public: - CChannel(); + // we have to make "server" the default since I do not see a chance to + // use constructor initialization in the server for a vector of channels + CChannel ( const bool bNIsServer = true ); virtual ~CChannel() {} EPutDataStat PutData ( const CVector& vecbyData, @@ -87,7 +89,6 @@ public: bool IsConnected() const { return iConTimeOut > 0; } void SetEnable ( const bool bNEnStat ); - void SetIsServer ( const bool bNIsServer ) { bIsServer = bNIsServer; } void SetForceLowUploadRate ( const bool bNFoLoUpRat ); void SetAddress ( const CHostAddress NAddr ) { InetAddr = NAddr; } @@ -109,18 +110,19 @@ public: void SetSockBufSize ( const int iNumBlocks ); int GetSockBufSize() { return iCurSockBufSize; } +// TEST +void SetNetwBufSizeOut ( const int iNewAudioBlockSizeOut ); + void SetNetwBufSizeFactOut ( const int iNewNetwBlSiFactOut ); int GetNetwBufSizeFactOut() { return iCurNetwOutBlSiFact; } - int GetNetwBufSizeFactIn() { return iCurNetwInBlSiFact; } - - void SetAudioCompressionOut ( const CAudioCompression::EAudComprType eNewAudComprTypeOut ); - CAudioCompression::EAudComprType GetAudioCompressionOut() { return eAudComprTypeOut; } + void SetAudioCompressionOut ( const EAudComprType eNewAudComprTypeOut ); + EAudComprType GetAudioCompressionOut() { return eAudComprTypeOut; } // network protocol interface void CreateJitBufMes ( const int iJitBufSize ) { - if ( IsConnected() ) + if ( ProtocolIsEnabled() ) { Protocol.CreateJitBufMes ( iJitBufSize ); } @@ -132,7 +134,7 @@ public: void CreateNetwBlSiFactMes ( const int iNetwBlSiFact ) { - if ( IsConnected() ) + if ( ProtocolIsEnabled() ) { Protocol.CreateNetwBlSiFactMes ( iNetwBlSiFact ); } @@ -144,10 +146,10 @@ public: } protected: - void SetNetwInBlSiFactAndCompr ( const int iNewBlockSizeFactor, - const CAudioCompression::EAudComprType eNewAudComprType ); + void SetAudioBlockSizeAndComprIn ( const int iNewBlockSize, + const EAudComprType eNewAudComprType ); - void SetSockBufSizeIntern ( const int iNumBlocks ); + bool ProtocolIsEnabled(); // audio compression CAudioCompression AudioCompressionIn; @@ -180,20 +182,21 @@ protected: bool bIsServer; bool bForceLowUploadRate; - int iCurNetwInBlSiFact; + int iCurAudioBlockSizeIn; int iCurNetwOutBlSiFact; + int iCurAudioBlockSizeOut; QMutex Mutex; struct sNetwBufferInProps { - int iNetwInBufSize; - int iBlockSizeFactor; - CAudioCompression::EAudComprType eAudComprType; + int iNetwInBufSize; + int iAudioBlockSize; + EAudComprType eAudComprType; }; CVector vecNetwBufferInProps; - CAudioCompression::EAudComprType eAudComprTypeOut; + EAudComprType eAudComprTypeOut; public slots: void OnSendProtMessage ( CVector vecMessage ); @@ -201,6 +204,7 @@ public slots: void OnNetwBlSiFactChange ( int iNewNetwBlSiFact ); void OnChangeChanGain ( int iChanID, double dNewGain ); void OnChangeChanName ( QString strName ); + void OnNetTranspPropsReceived ( CNetworkTransportProps NetworkTransportProps ); signals: void MessReadyForSending ( CVector vecMessage ); @@ -237,8 +241,7 @@ public: void GetConCliParam ( CVector& vecHostAddresses, CVector& vecsName, CVector& veciJitBufSize, - CVector& veciNetwOutBlSiFact, - CVector& veciNetwInBlSiFact ); + CVector& veciNetwOutBlSiFact ); // access functions for actual channels bool IsConnected ( const int iChanNum ) @@ -284,6 +287,10 @@ public slots: void OnSendProtMessCh3 ( CVector mess ) { emit MessReadyForSending ( 3, mess ); } void OnSendProtMessCh4 ( CVector mess ) { emit MessReadyForSending ( 4, mess ); } void OnSendProtMessCh5 ( CVector mess ) { emit MessReadyForSending ( 5, mess ); } + void OnSendProtMessCh6 ( CVector mess ) { emit MessReadyForSending ( 6, mess ); } + void OnSendProtMessCh7 ( CVector mess ) { emit MessReadyForSending ( 7, mess ); } + void OnSendProtMessCh8 ( CVector mess ) { emit MessReadyForSending ( 8, mess ); } + void OnSendProtMessCh9 ( CVector mess ) { emit MessReadyForSending ( 9, mess ); } void OnNewConnectionCh0() { vecChannels[0].CreateReqJitBufMes(); } void OnNewConnectionCh1() { vecChannels[1].CreateReqJitBufMes(); } @@ -291,6 +298,10 @@ public slots: void OnNewConnectionCh3() { vecChannels[3].CreateReqJitBufMes(); } void OnNewConnectionCh4() { vecChannels[4].CreateReqJitBufMes(); } void OnNewConnectionCh5() { vecChannels[5].CreateReqJitBufMes(); } + void OnNewConnectionCh6() { vecChannels[6].CreateReqJitBufMes(); } + void OnNewConnectionCh7() { vecChannels[7].CreateReqJitBufMes(); } + void OnNewConnectionCh8() { vecChannels[8].CreateReqJitBufMes(); } + void OnNewConnectionCh9() { vecChannels[9].CreateReqJitBufMes(); } void OnReqConnClientsListCh0() { CreateAndSendChanListForThisChan ( 0 ); } void OnReqConnClientsListCh1() { CreateAndSendChanListForThisChan ( 1 ); } @@ -298,6 +309,10 @@ public slots: void OnReqConnClientsListCh3() { CreateAndSendChanListForThisChan ( 3 ); } void OnReqConnClientsListCh4() { CreateAndSendChanListForThisChan ( 4 ); } void OnReqConnClientsListCh5() { CreateAndSendChanListForThisChan ( 5 ); } + void OnReqConnClientsListCh6() { CreateAndSendChanListForThisChan ( 6 ); } + void OnReqConnClientsListCh7() { CreateAndSendChanListForThisChan ( 7 ); } + void OnReqConnClientsListCh8() { CreateAndSendChanListForThisChan ( 8 ); } + void OnReqConnClientsListCh9() { CreateAndSendChanListForThisChan ( 9 ); } void OnNameHasChangedCh0() { CreateAndSendChanListForAllConChannels(); } void OnNameHasChangedCh1() { CreateAndSendChanListForAllConChannels(); } @@ -305,6 +320,10 @@ public slots: void OnNameHasChangedCh3() { CreateAndSendChanListForAllConChannels(); } void OnNameHasChangedCh4() { CreateAndSendChanListForAllConChannels(); } void OnNameHasChangedCh5() { CreateAndSendChanListForAllConChannels(); } + void OnNameHasChangedCh6() { CreateAndSendChanListForAllConChannels(); } + void OnNameHasChangedCh7() { CreateAndSendChanListForAllConChannels(); } + void OnNameHasChangedCh8() { CreateAndSendChanListForAllConChannels(); } + void OnNameHasChangedCh9() { CreateAndSendChanListForAllConChannels(); } void OnChatTextReceivedCh0 ( QString strChatText ) { CreateAndSendChatTextForAllConChannels ( 0, strChatText ); } void OnChatTextReceivedCh1 ( QString strChatText ) { CreateAndSendChatTextForAllConChannels ( 1, strChatText ); } @@ -312,6 +331,10 @@ public slots: void OnChatTextReceivedCh3 ( QString strChatText ) { CreateAndSendChatTextForAllConChannels ( 3, strChatText ); } void OnChatTextReceivedCh4 ( QString strChatText ) { CreateAndSendChatTextForAllConChannels ( 4, strChatText ); } void OnChatTextReceivedCh5 ( QString strChatText ) { CreateAndSendChatTextForAllConChannels ( 5, strChatText ); } + void OnChatTextReceivedCh6 ( QString strChatText ) { CreateAndSendChatTextForAllConChannels ( 6, strChatText ); } + void OnChatTextReceivedCh7 ( QString strChatText ) { CreateAndSendChatTextForAllConChannels ( 7, strChatText ); } + void OnChatTextReceivedCh8 ( QString strChatText ) { CreateAndSendChatTextForAllConChannels ( 8, strChatText ); } + void OnChatTextReceivedCh9 ( QString strChatText ) { CreateAndSendChatTextForAllConChannels ( 9, strChatText ); } void OnPingReceivedCh0 ( int iMs ) { vecChannels[0].CreatePingMes ( iMs ); } void OnPingReceivedCh1 ( int iMs ) { vecChannels[1].CreatePingMes ( iMs ); } @@ -319,6 +342,10 @@ public slots: void OnPingReceivedCh3 ( int iMs ) { vecChannels[3].CreatePingMes ( iMs ); } void OnPingReceivedCh4 ( int iMs ) { vecChannels[4].CreatePingMes ( iMs ); } void OnPingReceivedCh5 ( int iMs ) { vecChannels[5].CreatePingMes ( iMs ); } + void OnPingReceivedCh6 ( int iMs ) { vecChannels[6].CreatePingMes ( iMs ); } + void OnPingReceivedCh7 ( int iMs ) { vecChannels[7].CreatePingMes ( iMs ); } + void OnPingReceivedCh8 ( int iMs ) { vecChannels[8].CreatePingMes ( iMs ); } + void OnPingReceivedCh9 ( int iMs ) { vecChannels[9].CreatePingMes ( iMs ); } signals: void MessReadyForSending ( int iChID, CVector vecMessage ); diff --git a/src/client.cpp b/src/client.cpp index 964c7012..32f5f8eb 100755 --- a/src/client.cpp +++ b/src/client.cpp @@ -27,6 +27,7 @@ /* Implementation *************************************************************/ CClient::CClient ( const quint16 iPortNumber ) : + Channel ( false ), /* we need a client channel -> "false" */ Sound ( AudioCallback, this ), Socket ( &Channel, iPortNumber ), iAudioInFader ( AUD_FADER_IN_MIDDLE ), @@ -111,7 +112,7 @@ void CClient::OnReceivePingMessage ( int iMs ) bool CClient::SetServerAddr ( QString strNAddr ) { QHostAddress InetAddr; - quint16 iNetPort = LLCON_PORT_NUMBER; + quint16 iNetPort = LLCON_DFAULT_PORT_NUMBER; // parse input address for the type [IP address]:[port number] QString strPort = strNAddr.section ( ":", 1, 1 ); @@ -189,10 +190,13 @@ void CClient::AudioCallback ( CVector& psData, void* arg ) void CClient::Init() { // set block size (in samples) - iMonoBlockSizeSam = MIN_BLOCK_SIZE_SAMPLES; + +// TEST + iMonoBlockSizeSam = 128;//64;//MIN_SERVER_BLOCK_SIZE_SAMPLES; + iStereoBlockSizeSam = 2 * iMonoBlockSizeSam; - iSndCrdMonoBlockSizeSam = MIN_BLOCK_DURATION_MS * SND_CRD_SAMPLE_RATE / 1000; + iSndCrdMonoBlockSizeSam = iMonoBlockSizeSam * SND_CRD_SAMPLE_RATE / SYSTEM_SAMPLE_RATE; iSndCrdStereoBlockSizeSam = 2 * iSndCrdMonoBlockSizeSam; vecsAudioSndCrdStereo.Init ( iSndCrdStereoBlockSizeSam ); @@ -203,6 +207,11 @@ void CClient::Init() Sound.Init ( iSndCrdStereoBlockSizeSam ); + +// TEST +Channel.SetNetwBufSizeOut ( iMonoBlockSizeSam ); + + // resample objects are always initialized with the input block size // record ResampleObjDown.Init ( iSndCrdMonoBlockSizeSam, SND_CRD_SAMPLE_RATE, SYSTEM_SAMPLE_RATE ); @@ -362,7 +371,7 @@ void CClient::UpdateTimeResponseMeasurement() // we want to calculate the standard deviation (we assume that the mean // is correct at the block period time) const double dCurAddVal = - ( (double) ( CurTime - TimeLastBlock ) - MIN_BLOCK_DURATION_MS ); + ( (double) ( CurTime - TimeLastBlock ) - MIN_SERVER_BLOCK_DURATION_MS ); RespTimeMoAvBuf.Add ( dCurAddVal * dCurAddVal ); // add squared value diff --git a/src/client.h b/src/client.h index 0c52be7b..41dca427 100755 --- a/src/client.h +++ b/src/client.h @@ -101,7 +101,8 @@ public: if ( Channel.GetSockBufSize() != iNumBlocks ) { // check for valid values - if ( ( iNumBlocks >= 0 ) && ( iNumBlocks <= MAX_NET_BUF_SIZE_NUM_BL ) ) + if ( ( iNumBlocks >= MIN_NET_BUF_SIZE_NUM_BL ) && + ( iNumBlocks <= MAX_NET_BUF_SIZE_NUM_BL ) ) { // set the new socket size Channel.SetSockBufSize ( iNumBlocks ); @@ -125,9 +126,9 @@ public: { Channel.SetNetwBufSizeFactOut ( iNetNetwBlSiFact ); } int GetNetwBufSizeFactOut() { return Channel.GetNetwBufSizeFactOut(); } - void SetAudioCompressionOut ( const CAudioCompression::EAudComprType eNewAudComprTypeOut ) + void SetAudioCompressionOut ( const EAudComprType eNewAudComprTypeOut ) { Channel.SetAudioCompressionOut ( eNewAudComprTypeOut ); } - CAudioCompression::EAudComprType GetAudioCompressionOut() { return Channel.GetAudioCompressionOut(); } + EAudComprType GetAudioCompressionOut() { return Channel.GetAudioCompressionOut(); } void SetRemoteChanGain ( const int iId, const double dGain ) { Channel.SetRemoteChanGain ( iId, dGain ); } diff --git a/src/clientsettingsdlg.cpp b/src/clientsettingsdlg.cpp index a9903579..56fece54 100755 --- a/src/clientsettingsdlg.cpp +++ b/src/clientsettingsdlg.cpp @@ -52,9 +52,7 @@ CClientSettingsDlg::CClientSettingsDlg ( CClient* pNCliP, QWidget* parent, "for the audio stream bandwidth, audio dropouts occur and the " "ping time will increase significantly (the connection is stodged)." ); SliderNetBufSiFactIn->setWhatsThis ( strNetwBlockSize ); - SliderNetBufSiFactOut->setWhatsThis ( strNetwBlockSize ); TextNetBufSiFactIn->setWhatsThis ( strNetwBlockSize ); - TextNetBufSiFactOut->setWhatsThis ( strNetwBlockSize ); GroupBoxNetwBuf->setWhatsThis ( strNetwBlockSize ); // init delay information controls @@ -65,24 +63,8 @@ CClientSettingsDlg::CClientSettingsDlg ( CClient* pNCliP, QWidget* parent, TextLabelOverallDelay->setText ( "" ); // init slider controls --- - // sound buffer in -#ifdef _WIN32 - SliderSndBufIn->setRange ( 1, AUD_SLIDER_LENGTH ); // for ASIO we only need one buffer -#else - SliderSndBufIn->setRange ( 2, AUD_SLIDER_LENGTH ); -#endif - UpdateSndBufInSlider ( pClient->GetSndInterface()->GetInNumBuf() ); - - // sound buffer out -#ifdef _WIN32 - SliderSndBufOut->setRange ( 1, AUD_SLIDER_LENGTH ); // for ASIO we only need one buffer -#else - SliderSndBufOut->setRange ( 2, AUD_SLIDER_LENGTH ); -#endif - UpdateSndBufOutSlider ( pClient->GetSndInterface()->GetOutNumBuf() ); - // network buffer - SliderNetBuf->setRange ( 0, MAX_NET_BUF_SIZE_NUM_BL ); + SliderNetBuf->setRange ( MIN_NET_BUF_SIZE_NUM_BL, MAX_NET_BUF_SIZE_NUM_BL ); UpdateJitterBufferFrame(); // network buffer size factor in @@ -90,15 +72,7 @@ CClientSettingsDlg::CClientSettingsDlg ( CClient* pNCliP, QWidget* parent, const int iCurNetBufSiFactIn = pClient->GetNetwBufSizeFactIn(); SliderNetBufSiFactIn->setValue ( iCurNetBufSiFactIn ); TextNetBufSiFactIn->setText ( "In:\n" + QString().setNum ( - double ( iCurNetBufSiFactIn * MIN_BLOCK_DURATION_MS ), 'f', 2 ) + - " ms" ); - - // network buffer size factor out - SliderNetBufSiFactOut->setRange ( 1, MAX_NET_BLOCK_SIZE_FACTOR ); - const int iCurNetBufSiFactOut = pClient->GetNetwBufSizeFactOut(); - SliderNetBufSiFactOut->setValue ( iCurNetBufSiFactOut ); - TextNetBufSiFactOut->setText ( "Out:\n" + QString().setNum ( - double ( iCurNetBufSiFactOut * MIN_BLOCK_DURATION_MS), 'f', 2 ) + + double ( iCurNetBufSiFactIn * MIN_SERVER_BLOCK_DURATION_MS ), 'f', 2 ) + " ms" ); // init combo box containing all available sound cards in the system @@ -122,15 +96,15 @@ CClientSettingsDlg::CClientSettingsDlg ( CClient* pNCliP, QWidget* parent, // audio compression type switch ( pClient->GetAudioCompressionOut() ) { - case CAudioCompression::CT_NONE: + case CT_NONE: radioButtonNoAudioCompr->setChecked ( true ); break; - case CAudioCompression::CT_IMAADPCM: + case CT_IMAADPCM: radioButtonIMA_ADPCM->setChecked ( true ); break; - case CAudioCompression::CT_MSADPCM: + case CT_MSADPCM: radioButtonMS_ADPCM->setChecked ( true ); break; } @@ -146,19 +120,11 @@ CClientSettingsDlg::CClientSettingsDlg ( CClient* pNCliP, QWidget* parent, QObject::connect ( &TimerPing, SIGNAL ( timeout() ), this, SLOT ( OnTimerPing() ) ); - // sliders - QObject::connect ( SliderSndBufIn, SIGNAL ( valueChanged ( int ) ), - this, SLOT ( OnSliderSndBufInChange ( int ) ) ); - QObject::connect ( SliderSndBufOut, SIGNAL ( valueChanged ( int ) ), - this, SLOT ( OnSliderSndBufOutChange ( int ) ) ); - QObject::connect ( SliderNetBuf, SIGNAL ( valueChanged ( int ) ), this, SLOT ( OnSliderNetBuf ( int ) ) ); QObject::connect ( SliderNetBufSiFactIn, SIGNAL ( valueChanged ( int ) ), this, SLOT ( OnSliderNetBufSiFactIn ( int ) ) ); - QObject::connect ( SliderNetBufSiFactOut, SIGNAL ( valueChanged ( int ) ), - this, SLOT ( OnSliderNetBufSiFactOut ( int ) ) ); // check boxes QObject::connect ( cbOpenChatOnNewMessage, SIGNAL ( stateChanged ( int ) ), @@ -196,18 +162,6 @@ void CClientSettingsDlg::UpdateJitterBufferFrame() TextNetBuf->setEnabled ( !pClient->GetDoAutoSockBufSize() ); } -void CClientSettingsDlg::UpdateSndBufInSlider ( const int iCurNumInBuf ) -{ - SliderSndBufIn->setValue ( iCurNumInBuf ); - TextSndBufIn->setText ( "In: " + QString().setNum ( iCurNumInBuf ) ); -} - -void CClientSettingsDlg::UpdateSndBufOutSlider ( const int iCurNumOutBuf ) -{ - SliderSndBufOut->setValue ( iCurNumOutBuf ); - TextSndBufOut->setText ( "Out: " + QString().setNum ( iCurNumOutBuf ) ); -} - void CClientSettingsDlg::showEvent ( QShowEvent* showEvent ) { // only activate ping timer if window is actually shown @@ -220,20 +174,6 @@ void CClientSettingsDlg::hideEvent ( QHideEvent* hideEvent ) TimerPing.stop(); } -void CClientSettingsDlg::OnSliderSndBufInChange ( int value ) -{ - pClient->GetSndInterface()->SetInNumBuf ( value ); - TextSndBufIn->setText ( "In: " + QString().setNum ( value ) ); - UpdateDisplay(); -} - -void CClientSettingsDlg::OnSliderSndBufOutChange ( int value ) -{ - pClient->GetSndInterface()->SetOutNumBuf ( value ); - TextSndBufOut->setText ( "Out: " + QString().setNum ( value ) ); - UpdateDisplay(); -} - void CClientSettingsDlg::OnSliderNetBuf ( int value ) { pClient->SetSockBufSize ( value ); @@ -245,16 +185,7 @@ void CClientSettingsDlg::OnSliderNetBufSiFactIn ( int value ) { pClient->SetNetwBufSizeFactIn ( value ); TextNetBufSiFactIn->setText ( "In:\n" + QString().setNum ( - double ( value * MIN_BLOCK_DURATION_MS ), 'f', 2 ) + - " ms" ); - UpdateDisplay(); -} - -void CClientSettingsDlg::OnSliderNetBufSiFactOut ( int value ) -{ - pClient->SetNetwBufSizeFactOut ( value ); - TextNetBufSiFactOut->setText ( "Out:\n" + QString().setNum ( - double ( value * MIN_BLOCK_DURATION_MS ), 'f', 2 ) + + double ( value * MIN_SERVER_BLOCK_DURATION_MS ), 'f', 2 ) + " ms" ); UpdateDisplay(); } @@ -294,17 +225,17 @@ void CClientSettingsDlg::OnAudioCompressionButtonGroupClicked ( QAbstractButton* { if ( button == radioButtonNoAudioCompr ) { - pClient->SetAudioCompressionOut ( CAudioCompression::CT_NONE ); + pClient->SetAudioCompressionOut ( CT_NONE ); } if ( button == radioButtonIMA_ADPCM ) { - pClient->SetAudioCompressionOut ( CAudioCompression::CT_IMAADPCM ); + pClient->SetAudioCompressionOut ( CT_IMAADPCM ); } if ( button == radioButtonMS_ADPCM ) { - pClient->SetAudioCompressionOut ( CAudioCompression::CT_MSADPCM ); + pClient->SetAudioCompressionOut ( CT_MSADPCM ); } UpdateDisplay(); } @@ -322,17 +253,17 @@ void CClientSettingsDlg::OnPingTimeResult ( int iPingTime ) - the mean delay of a cyclic buffer is half the buffer size (since for the average it is assumed that the buffer is half filled) - consider the jitter buffer on the server side, too - - assume that the sound card introduces an additional delay of 2 * MIN_BLOCK_DURATION_MS + - assume that the sound card introduces an additional delay of 2 * MIN_SERVER_BLOCK_DURATION_MS */ - const int iTotalJitterBufferDelayMS = MIN_BLOCK_DURATION_MS * + const int iTotalJitterBufferDelayMS = MIN_SERVER_BLOCK_DURATION_MS * ( 2 * pClient->GetSockBufSize() + pClient->GetNetwBufSizeFactIn() + pClient->GetNetwBufSizeFactOut() ) / 2; - const int iTotalSoundCardDelayMS = 2 * MIN_BLOCK_DURATION_MS + - MIN_BLOCK_DURATION_MS * ( pClient->GetSndInterface()->GetInNumBuf() + + const int iTotalSoundCardDelayMS = 2 * MIN_SERVER_BLOCK_DURATION_MS + + MIN_SERVER_BLOCK_DURATION_MS * ( pClient->GetSndInterface()->GetInNumBuf() + pClient->GetSndInterface()->GetOutNumBuf() ) / 2; - const int iDelayToFillNetworkPackets = MIN_BLOCK_DURATION_MS * + const int iDelayToFillNetworkPackets = MIN_SERVER_BLOCK_DURATION_MS * ( pClient->GetNetwBufSizeFactIn() + pClient->GetNetwBufSizeFactOut() ); const int iTotalBufferDelay = iDelayToFillNetworkPackets + @@ -375,9 +306,7 @@ void CClientSettingsDlg::OnPingTimeResult ( int iPingTime ) void CClientSettingsDlg::UpdateDisplay() { - // update slider controls (settings might have been changed by sound interface) - UpdateSndBufInSlider ( pClient->GetSndInterface()->GetInNumBuf() ); - UpdateSndBufOutSlider ( pClient->GetSndInterface()->GetOutNumBuf() ); + // update slider controls (settings might have been changed) UpdateJitterBufferFrame(); if ( !pClient->IsRunning() ) @@ -393,6 +322,7 @@ void CClientSettingsDlg::SetStatus ( const int iMessType, const int iStatus ) { switch ( iMessType ) { +/* case MS_SOUND_IN: CLEDSoundIn->SetLight ( iStatus ); break; @@ -400,6 +330,7 @@ void CClientSettingsDlg::SetStatus ( const int iMessType, const int iStatus ) case MS_SOUND_OUT: CLEDSoundOut->SetLight ( iStatus ); break; +*/ case MS_JIT_BUF_PUT: CLEDNetwPut->SetLight ( iStatus ); @@ -410,8 +341,10 @@ void CClientSettingsDlg::SetStatus ( const int iMessType, const int iStatus ) break; case MS_RESET_ALL: +/* CLEDSoundIn->Reset(); CLEDSoundOut->Reset(); +*/ CLEDNetwPut->Reset(); CLEDNetwGet->Reset(); break; diff --git a/src/clientsettingsdlg.h b/src/clientsettingsdlg.h index d2d3d17a..be5304db 100755 --- a/src/clientsettingsdlg.h +++ b/src/clientsettingsdlg.h @@ -72,18 +72,13 @@ protected: virtual void showEvent ( QShowEvent* showEvent ); virtual void hideEvent ( QHideEvent* hideEvent ); - void UpdateSndBufInSlider ( const int iCurNumInBuf ); - void UpdateSndBufOutSlider ( const int iCurNumOutBuf ); void UpdateJitterBufferFrame(); public slots: void OnTimerStatus() { UpdateDisplay(); } void OnTimerPing(); - void OnSliderSndBufInChange ( int value ); - void OnSliderSndBufOutChange ( int value ); void OnSliderNetBuf ( int value ); void OnSliderNetBufSiFactIn ( int value ); - void OnSliderNetBufSiFactOut ( int value ); void OnAutoJitBuf ( int value ); void OnOpenChatOnNewMessageStateChanged ( int value ); void OnAudioCompressionButtonGroupClicked ( QAbstractButton* button ); diff --git a/src/clientsettingsdlgbase.ui b/src/clientsettingsdlgbase.ui index 5c86ebff..ebd3c595 100755 --- a/src/clientsettingsdlgbase.ui +++ b/src/clientsettingsdlgbase.ui @@ -5,8 +5,8 @@ 0 0 - 544 - 306 + 421 + 313 @@ -286,426 +286,6 @@ - - - - Size - - - Qt::AlignCenter - - - false - - - - - - - 6 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - 1 - - - Qt::Vertical - - - QSlider::TicksBothSides - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - Check Ping - - - Qt::AlignCenter - - - false - - - - - - - Time! - - - Qt::AlignCenter - - - false - - - - - - - - - - Soundcard Buffers - - - - 6 - - - 9 - - - 9 - - - 9 - - - 9 - - - - - 6 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - 6 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 0 - 0 - - - - - 30 - 0 - - - - Out - - - Qt::AlignCenter - - - false - - - - - - - 6 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - 1 - - - Qt::Vertical - - - QSlider::TicksBothSides - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - 6 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 0 - 0 - - - - - 30 - 0 - - - - In - - - Qt::AlignCenter - - - false - - - - - - - 6 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - 1 - - - Qt::Vertical - - - QSlider::TicksBothSides - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - - - Out / In: - - - Qt::AlignCenter - - - false - - - - - - - 6 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 0 - 0 - - - - - 13 - 13 - - - - - 13 - 13 - - - - - - - - - 0 - 0 - - - - - 13 - 13 - - - - - 13 - 13 - - - - - - diff --git a/src/global.h b/src/global.h index e8dc8c25..a6f41ef5 100755 --- a/src/global.h +++ b/src/global.h @@ -43,7 +43,7 @@ // version and application name (always use this version) #undef VERSION -#define VERSION "2.1.5cvs" +#define VERSION "2.2.0cvs" #define APP_NAME "llcon" // file name for logging file @@ -53,7 +53,7 @@ #define DEFAULT_SERVER_ADDRESS "llcon.dyndns.org" // defined port number for client and server -#define LLCON_PORT_NUMBER 22122 +#define LLCON_DFAULT_PORT_NUMBER 22122 // system sample rate #define SYSTEM_SAMPLE_RATE 24000 @@ -62,11 +62,18 @@ // internal sample rate conversion which might be buggy #define SND_CRD_SAMPLE_RATE 48000 -// minimum block duration - all other buffer durations must be a multiple +// minimum server block duration - all other buffer durations must be a multiple // of this duration -#define MIN_BLOCK_DURATION_MS 2 // ms +#define MIN_SERVER_BLOCK_DURATION_MS 2 // ms -#define MIN_BLOCK_SIZE_SAMPLES ( MIN_BLOCK_DURATION_MS * SYSTEM_SAMPLE_RATE / 1000 ) +#define MIN_SERVER_BLOCK_SIZE_SAMPLES ( MIN_SERVER_BLOCK_DURATION_MS * SYSTEM_SAMPLE_RATE / 1000 ) + +// define the maximum mono audio buffer size at a sample rate +// of 48 kHz, this is important for defining the maximum number +// of bytes to be expected from the network interface (we assume +// here that "MAX_NET_BLOCK_SIZE_FACTOR * MIN_SERVER_BLOCK_SIZE_SAMPLES" +// is smaller than this value here) +#define MAX_MONO_AUD_BUFF_SIZE_AT_48KHZ 4096 // maximum value of factor for network block size #define MAX_NET_BLOCK_SIZE_FACTOR 3 @@ -74,8 +81,9 @@ // default network block size factor #define DEF_NET_BLOCK_SIZE_FACTOR 3 -// maximum network buffer size (which can be chosen by slider) -#define MAX_NET_BUF_SIZE_NUM_BL 12 // number of blocks +// minimum/maximum network buffer size (which can be chosen by slider) +#define MIN_NET_BUF_SIZE_NUM_BL 1 // number of blocks +#define MAX_NET_BUF_SIZE_NUM_BL 20 // number of blocks // default network buffer size #define DEF_NET_BUF_SIZE_NUM_BL 6 // number of blocks @@ -88,17 +96,22 @@ #define MAX_NUMBER_SOUND_CARDS 10 #define INVALID_SNC_CARD_DEVICE -1 + // maximum number of internet connections (channels) // if you want to change this paramter, there has to be done code modifications // on other places, too! The code tag "MAX_NUM_CHANNELS_TAG" shows these places // (just search for the tag in the entire code) -// note: since in the protocol messages the channel ID is only a byte, a -// maximum of 8 channels are possible, see e.g. "PROTMESSID_CHANNEL_GAIN"! -#define MAX_NUM_CHANNELS 6 // max number channels for server +#define MAX_NUM_CHANNELS 10 // max number channels for server + +// actual number of used channels in the server +// this parameter can safely be changed from 1 to MAX_NUM_CHANNELS +// without any other changes in the code +#define USED_NUM_CHANNELS 6 // used number channels for server + // length of the moving average buffer for response time measurement #define TIME_MOV_AV_RESPONSE 30 // seconds -#define LEN_MOV_AV_RESPONSE ( TIME_MOV_AV_RESPONSE * 1000 / MIN_BLOCK_DURATION_MS ) +#define LEN_MOV_AV_RESPONSE ( TIME_MOV_AV_RESPONSE * 1000 / MIN_SERVER_BLOCK_DURATION_MS ) // GUI definition: width/heigth size of LED pixmaps #define LED_WIDTH_HEIGHT_SIZE_PIXEL 13 diff --git a/src/llconserverdlg.cpp b/src/llconserverdlg.cpp index ce9ef6ca..29ef97a1 100755 --- a/src/llconserverdlg.cpp +++ b/src/llconserverdlg.cpp @@ -45,22 +45,13 @@ CLlconServerDlg::CLlconServerDlg ( CServer* pNServP, QWidget* parent ) // set up list view for connected clients ListViewClients->setColumnWidth ( 0, 170 ); - -// TODO QT4 - -// ListViewClients->setColumnAlignment ( 1, Qt::AlignLeft ); ListViewClients->setColumnWidth ( 1, 150 ); -// ListViewClients->setColumnAlignment ( 2, Qt::AlignCenter ); -// ListViewClients->setColumnAlignment ( 3, Qt::AlignCenter ); -// ListViewClients->setColumnAlignment ( 4, Qt::AlignRight ); -// ListViewClients->setColumnAlignment ( 5, Qt::AlignRight ); -// ListViewClients->setColumnAlignment ( 6, Qt::AlignRight ); ListViewClients->clear(); - /* insert items in reverse order because in Windows all of them are - always visible -> put first item on the top */ - vecpListViewItems.Init(MAX_NUM_CHANNELS); - for ( int i = MAX_NUM_CHANNELS - 1; i >= 0; i-- ) + // insert items in reverse order because in Windows all of them are + // always visible -> put first item on the top + vecpListViewItems.Init ( USED_NUM_CHANNELS ); + for ( int i = USED_NUM_CHANNELS - 1; i >= 0; i-- ) { vecpListViewItems[i] = new CServerListViewItem ( ListViewClients ); vecpListViewItems[i]->setHidden ( true ); @@ -94,16 +85,15 @@ void CLlconServerDlg::OnTimer() CVector vecsName; CVector veciJitBufSize; CVector veciNetwOutBlSiFact; - CVector veciNetwInBlSiFact; double dCurTiStdDev; ListViewMutex.lock(); pServer->GetConCliParam ( vecHostAddresses, vecsName, veciJitBufSize, - veciNetwOutBlSiFact, veciNetwInBlSiFact ); + veciNetwOutBlSiFact ); // fill list with connected clients - for ( int i = 0; i < MAX_NUM_CHANNELS; i++ ) + for ( int i = 0; i < USED_NUM_CHANNELS; i++ ) { if ( !( vecHostAddresses[i].InetAddr == QHostAddress ( (quint32) 0 ) ) ) { @@ -119,13 +109,10 @@ void CLlconServerDlg::OnTimer() vecpListViewItems[i]->setText ( 4, QString().setNum ( veciJitBufSize[i] ) ); - // in/out network block sizes + // out network block size vecpListViewItems[i]->setText ( 5, QString().setNum ( - double ( veciNetwInBlSiFact[i] * MIN_BLOCK_DURATION_MS ), 'f', 2 ) ); - vecpListViewItems[i]->setText ( 6, - QString().setNum ( - double ( veciNetwOutBlSiFact[i] * MIN_BLOCK_DURATION_MS ), 'f', 2 ) ); + double ( veciNetwOutBlSiFact[i] * MIN_SERVER_BLOCK_DURATION_MS ), 'f', 2 ) ); vecpListViewItems[i]->setHidden ( false ); } diff --git a/src/llconserverdlgbase.ui b/src/llconserverdlgbase.ui index c1035d2d..3aae6a62 100755 --- a/src/llconserverdlgbase.ui +++ b/src/llconserverdlgbase.ui @@ -5,8 +5,8 @@ 0 0 - 699 - 291 + 767 + 280 @@ -19,12 +19,21 @@ true - - 9 - 6 + + 9 + + + 9 + + + 9 + + + 9 + @@ -55,11 +64,6 @@ Jitter buffer size - - - Block Size In - - Block Size Out @@ -69,12 +73,21 @@ - - 0 - 6 + + 0 + + + 0 + + + 0 + + + 0 + diff --git a/src/main.cpp b/src/main.cpp index c9ed351c..2de2ced4 100755 --- a/src/main.cpp +++ b/src/main.cpp @@ -46,7 +46,7 @@ int main ( int argc, char** argv ) bool bIsClient = true; bool bUseGUI = true; bool bForceLowUploadRate = false; - quint16 iPortNumber = LLCON_PORT_NUMBER; + quint16 iPortNumber = LLCON_DFAULT_PORT_NUMBER; std::string strIniFileName = ""; std::string strHTMLStatusFileName = ""; std::string strServerName = ""; @@ -61,7 +61,7 @@ int main ( int argc, char** argv ) if ( GetFlagArgument ( argc, argv, i, "-s", "--server" ) ) { bIsClient = false; - cerr << "server mode chosen" << std::endl; + cout << "server mode chosen" << std::endl; continue; } @@ -69,7 +69,7 @@ int main ( int argc, char** argv ) if ( GetFlagArgument ( argc, argv, i, "-n", "--nogui" ) ) { bUseGUI = false; - cerr << "no GUI mode chosen" << std::endl; + cout << "no GUI mode chosen" << std::endl; continue; } @@ -77,7 +77,7 @@ int main ( int argc, char** argv ) if ( GetStringArgument ( argc, argv, i, "-l", "--log", strArgument ) ) { strLoggingFileName = strArgument; - cerr << "logging file name: " << strLoggingFileName << std::endl; + cout << "logging file name: " << strLoggingFileName << std::endl; continue; } @@ -85,7 +85,7 @@ int main ( int argc, char** argv ) if ( GetFlagArgument ( argc, argv, i, "-u", "--lowuploadrate" ) ) { bForceLowUploadRate = true; - cerr << "force low upload rate" << std::endl; + cout << "force low upload rate" << std::endl; continue; } @@ -94,7 +94,7 @@ int main ( int argc, char** argv ) 0, 65535, rDbleArgument ) ) { iPortNumber = static_cast ( rDbleArgument ); - cerr << "selected port number: " << iPortNumber << std::endl; + cout << "selected port number: " << iPortNumber << std::endl; continue; } @@ -102,14 +102,14 @@ int main ( int argc, char** argv ) if ( GetStringArgument ( argc, argv, i, "-m", "--htmlstatus", strArgument ) ) { strHTMLStatusFileName = strArgument; - cerr << "HTML status file name: " << strHTMLStatusFileName << std::endl; + cout << "HTML status file name: " << strHTMLStatusFileName << std::endl; continue; } if ( GetStringArgument ( argc, argv, i, "-a", "--servername", strArgument ) ) { strServerName = strArgument; - cerr << "server name for HTML status file: " << strServerName << std::endl; + cout << "server name for HTML status file: " << strServerName << std::endl; continue; } @@ -117,7 +117,7 @@ int main ( int argc, char** argv ) if ( GetStringArgument ( argc, argv, i, "-i", "--inifile", strArgument ) ) { strIniFileName = strArgument; - cerr << "initialization file name: " << strIniFileName << std::endl; + cout << "initialization file name: " << strIniFileName << std::endl; continue; } @@ -126,7 +126,7 @@ int main ( int argc, char** argv ) ( !strcmp ( argv[i], "-h" ) ) || ( !strcmp ( argv[i], "-?" ) ) ) { const std::string strHelp = UsageArguments(argv); - cerr << strHelp; + cout << strHelp; exit ( 1 ); } @@ -212,7 +212,7 @@ int main ( int argc, char** argv ) else { // only start application without using the GUI - qDebug() << CAboutDlg::GetVersionAndNameStr ( false ); + cout << CAboutDlg::GetVersionAndNameStr ( false ).toStdString(); app.exec(); } } diff --git a/src/protocol.cpp b/src/protocol.cpp index ece0edcd..26adf92e 100755 --- a/src/protocol.cpp +++ b/src/protocol.cpp @@ -147,16 +147,28 @@ MESSAGES /* Implementation *************************************************************/ -CProtocol::CProtocol() : iCounter ( 0 ), iOldRecID ( PROTMESSID_ILLEGAL ), - iOldRecCnt ( 0 ) +CProtocol::CProtocol() { - SendMessQueue.clear(); + Reset(); // connections QObject::connect ( &TimerSendMess, SIGNAL ( timeout() ), this, SLOT ( OnTimerSendMess() ) ); } +void CProtocol::Reset() +{ + QMutexLocker locker ( &Mutex ); + + // prepare internal variables for initial protocol transfer + iCounter = 0; + iOldRecID = PROTMESSID_ILLEGAL; + iOldRecCnt = 0; + + // delete complete "send message queue" + SendMessQueue.clear(); +} + void CProtocol::EnqueueMessage ( CVector& vecMessage, const int iCnt, const int iID ) @@ -259,14 +271,6 @@ void CProtocol::CreateAndSendAcknMess ( const int& iID, const int& iCnt ) emit MessReadyForSending ( vecAcknMessage ); } -void CProtocol::DeleteSendMessQueue() -{ - QMutexLocker locker ( &Mutex ); - - // delete complete "send message queue" - SendMessQueue.clear(); -} - bool CProtocol::ParseMessage ( const CVector& vecbyData, const int iNumBytes ) { @@ -315,18 +319,18 @@ for ( int i = 0; i < iNumBytes; i++ ) { Mutex.lock(); { // check if this is the correct acknowledgment - if ( ( SendMessQueue.front().iCnt == iRecCounter ) && - ( SendMessQueue.front().iID == iData ) ) + bSendNextMess = false; + if ( !SendMessQueue.empty() ) { - // message acknowledged, remove from queue - SendMessQueue.pop_front(); + if ( ( SendMessQueue.front().iCnt == iRecCounter ) && + ( SendMessQueue.front().iID == iData ) ) + { + // message acknowledged, remove from queue + SendMessQueue.pop_front(); - // send next message in queue - bSendNextMess = true; - } - else - { - bSendNextMess = false; + // send next message in queue + bSendNextMess = true; + } } } Mutex.unlock(); @@ -878,9 +882,9 @@ bool CProtocol::EvaluateNetwTranspPropsMes ( const CVector& vecData ) const int iRecCodingType = static_cast ( GetValFromStream ( vecData, iPos, 2 ) ); - if ( ( iRecCodingType != CNetworkTransportProps::ACT_NONE ) && - ( iRecCodingType != CNetworkTransportProps::ACT_IMA_ADPCM ) && - ( iRecCodingType != CNetworkTransportProps::ACT_MS_ADPCM ) ) + if ( ( iRecCodingType != CT_NONE ) && + ( iRecCodingType != CT_IMAADPCM ) && + ( iRecCodingType != CT_MSADPCM ) ) { return true; } diff --git a/src/protocol.h b/src/protocol.h index bbf4859b..8b2e01a2 100755 --- a/src/protocol.h +++ b/src/protocol.h @@ -68,6 +68,8 @@ class CProtocol : public QObject public: CProtocol(); + void Reset(); + void CreateJitBufMes ( const int iJitBufSize ); void CreateReqJitBufMes(); void CreateNetwBlSiFactMes ( const int iNetwBlSiFact ); @@ -86,8 +88,6 @@ public: bool ParseMessage ( const CVector& vecbyData, const int iNumBytes ); - void DeleteSendMessQueue(); - protected: class CSendMessage { diff --git a/src/server.cpp b/src/server.cpp index 1b5a0c34..2ce1e45f 100755 --- a/src/server.cpp +++ b/src/server.cpp @@ -34,7 +34,7 @@ CServer::CServer ( const QString& strLoggingFileName, Socket ( &ChannelSet, this, iPortNumber ), ChannelSet ( bForceLowUploadRate ) { - vecsSendData.Init ( MIN_BLOCK_SIZE_SAMPLES ); + vecsSendData.Init ( MIN_SERVER_BLOCK_SIZE_SAMPLES ); // init moving average buffer for response time evaluation RespTimeMoAvBuf.Init ( LEN_MOV_AV_RESPONSE ); @@ -103,7 +103,7 @@ void CServer::Start() if ( !IsRunning() ) { // start main timer - Timer.start ( MIN_BLOCK_DURATION_MS ); + Timer.start ( MIN_SERVER_BLOCK_DURATION_MS ); // init time for response time evaluation TimeLastBlock = PreciseTime.elapsed(); @@ -137,7 +137,7 @@ void CServer::OnNewChannel ( CHostAddress ChanAddr ) void CServer::OnTimer() { CVector vecChanID; - CVector > vecvecdData ( MIN_BLOCK_SIZE_SAMPLES ); + CVector > vecvecdData ( MIN_SERVER_BLOCK_SIZE_SAMPLES ); CVector > vecvecdGains; // get data from all connected clients @@ -178,7 +178,7 @@ void CServer::OnTimer() // we want to calculate the standard deviation (we assume that the mean // is correct at the block period time) const double dCurAddVal = - ( (double) ( CurTime - TimeLastBlock ) - MIN_BLOCK_DURATION_MS ); + ( (double) ( CurTime - TimeLastBlock ) - MIN_SERVER_BLOCK_DURATION_MS ); RespTimeMoAvBuf.Add ( dCurAddVal * dCurAddVal ); // add squared value @@ -189,7 +189,7 @@ void CServer::OnTimer() CVector CServer::ProcessData ( CVector >& vecvecdData, CVector& vecdGains ) { - CVector vecsOutData ( MIN_BLOCK_SIZE_SAMPLES ); + CVector vecsOutData ( MIN_SERVER_BLOCK_SIZE_SAMPLES ); const int iNumClients = vecvecdData.Size(); @@ -197,7 +197,7 @@ CVector CServer::ProcessData ( CVector >& vecvecdData, const double dNorm = (double) 2.0; // mix all audio data from all clients together - for ( int i = 0; i < MIN_BLOCK_SIZE_SAMPLES; i++ ) + for ( int i = 0; i < MIN_SERVER_BLOCK_SIZE_SAMPLES; i++ ) { double dMixedData = 0.0; diff --git a/src/server.h b/src/server.h index ee06c3ee..8387a634 100755 --- a/src/server.h +++ b/src/server.h @@ -54,11 +54,10 @@ public: void GetConCliParam ( CVector& vecHostAddresses, CVector& vecsName, - CVector& veciJitBufSize, CVector& veciNetwOutBlSiFact, - CVector& veciNetwInBlSiFact ) + CVector& veciJitBufSize, CVector& veciNetwOutBlSiFact ) { ChannelSet.GetConCliParam ( vecHostAddresses, vecsName, - veciJitBufSize, veciNetwOutBlSiFact, veciNetwInBlSiFact ); + veciJitBufSize, veciNetwOutBlSiFact ); } bool GetTimingStdDev ( double& dCurTiStdDev ); diff --git a/src/settings.cpp b/src/settings.cpp index 616b8e8b..ff8e638c 100755 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -112,7 +112,7 @@ void CSettings::ReadIniFile ( const QString& sFileName ) } // network jitter buffer size - if ( GetNumericIniSet ( IniXMLDocument, "client", "jitbuf", 0, MAX_NET_BUF_SIZE_NUM_BL, iValue ) ) + if ( GetNumericIniSet ( IniXMLDocument, "client", "jitbuf", MIN_NET_BUF_SIZE_NUM_BL, MAX_NET_BUF_SIZE_NUM_BL, iValue ) ) { pClient->SetSockBufSize ( iValue ); } @@ -142,16 +142,16 @@ void CSettings::ReadIniFile ( const QString& sFileName ) switch ( iValue ) { case 0: - pClient->SetAudioCompressionOut ( CAudioCompression::CT_NONE ); + pClient->SetAudioCompressionOut ( CT_NONE ); break; case 1: - pClient->SetAudioCompressionOut ( CAudioCompression::CT_IMAADPCM ); + pClient->SetAudioCompressionOut ( CT_IMAADPCM ); break; case 2: break; - pClient->SetAudioCompressionOut ( CAudioCompression::CT_MSADPCM ); + pClient->SetAudioCompressionOut ( CT_MSADPCM ); } } } @@ -206,15 +206,15 @@ void CSettings::WriteIniFile ( const QString& sFileName ) // for integer numbers!) switch ( pClient->GetAudioCompressionOut() ) { - case CAudioCompression::CT_NONE: + case CT_NONE: SetNumericIniSet ( IniXMLDocument, "client", "audiocompression", 0 ); break; - case CAudioCompression::CT_IMAADPCM: + case CT_IMAADPCM: SetNumericIniSet ( IniXMLDocument, "client", "audiocompression", 1 ); break; - case CAudioCompression::CT_MSADPCM: + case CT_MSADPCM: SetNumericIniSet ( IniXMLDocument, "client", "audiocompression", 2 ); break; } diff --git a/src/socket.h b/src/socket.h index 8e21e64a..6e99320d 100755 --- a/src/socket.h +++ b/src/socket.h @@ -36,8 +36,9 @@ /* Definitions ****************************************************************/ -// Maximum block size for network input buffer. Consider two bytes per sample. -#define MAX_SIZE_BYTES_NETW_BUF ( MAX_NET_BLOCK_SIZE_FACTOR * MIN_BLOCK_SIZE_SAMPLES * 2 ) +// Maximum block size for network input buffer. Consider a maximum sample rate +// of 48 kHz and two audio channels and two bytes per sample. +#define MAX_SIZE_BYTES_NETW_BUF ( MAX_MONO_AUD_BUFF_SIZE_AT_48KHZ * 4 ) /* Classes ********************************************************************/ @@ -57,7 +58,7 @@ public: const CHostAddress& HostAddr ); protected: - void Init ( const quint16 iPortNumber = LLCON_PORT_NUMBER ); + void Init ( const quint16 iPortNumber = LLCON_DFAULT_PORT_NUMBER ); QUdpSocket SocketDevice; diff --git a/src/soundbase.cpp b/src/soundbase.cpp index 16d25a6f..56465165 100755 --- a/src/soundbase.cpp +++ b/src/soundbase.cpp @@ -29,16 +29,24 @@ void CSoundBase::Init ( const int iNewStereoBufferSize ) { // init audio sound card buffer - vecsAudioSndCrdStereo.Init ( iNewStereoBufferSize ); + if ( !bIsCallbackAudioInterface ) + { + vecsAudioSndCrdStereo.Init ( iNewStereoBufferSize ); + } } void CSoundBase::Start() { + bRun = true; // TODO start audio interface - // start the audio thread - start(); + // start the audio thread in case we do not have an callback + // based audio interface + if ( !bIsCallbackAudioInterface ) + { + start(); + } } void CSoundBase::Stop() @@ -47,7 +55,10 @@ void CSoundBase::Stop() bRun = false; // give thread some time to terminate - wait ( 5000 ); + if ( !bIsCallbackAudioInterface ) + { + wait ( 5000 ); + } // TODO stop audio interface (previously done in Close function, we @@ -74,7 +85,6 @@ void CSoundBase::run() #endif // main loop of working thread - bRun = true; while ( bRun ) { // get audio from sound card (blocking function) diff --git a/src/soundbase.h b/src/soundbase.h index d446a249..d8290c30 100755 --- a/src/soundbase.h +++ b/src/soundbase.h @@ -34,9 +34,11 @@ class CSoundBase : public QThread { public: - CSoundBase ( void (*fpNewCallback) ( CVector& psData, void* arg ), + CSoundBase ( const bool bNewIsCallbackAudioInterface, + void (*fpNewCallback) ( CVector& psData, void* arg ), void* arg ) : fpCallback ( fpNewCallback ), pCallbackArg ( arg ), - bRun ( false ) {} + bRun ( false ), + bIsCallbackAudioInterface ( bNewIsCallbackAudioInterface ) {} virtual ~CSoundBase() {} virtual void Init ( const int iNewStereoBufferSize ); @@ -50,6 +52,12 @@ protected: void (*fpCallback) ( CVector& psData, void* arg ); void* pCallbackArg; + // callback function call for derived classes + void Callback ( CVector& psData ) + { + (*fpCallback) ( psData, pCallbackArg ); + } + // these functions should be overwritten by derived class for // non callback based audio interfaces virtual bool Read ( CVector& psData ) { printf ( "no sound!" ); return false; } @@ -57,6 +65,7 @@ protected: void run(); bool bRun; + bool bIsCallbackAudioInterface; CVector vecsAudioSndCrdStereo; }; diff --git a/src/util.h b/src/util.h index c71d84b7..6b86f3ff 100755 --- a/src/util.h +++ b/src/util.h @@ -407,23 +407,23 @@ public: QString strName; }; +enum EAudComprType +{ + CT_NONE = 0, + CT_IMAADPCM = 1, + CT_MSADPCM = 2 +}; + class CNetworkTransportProps { public: - enum EAudioCodingType - { - ACT_NONE = 0, - ACT_IMA_ADPCM = 1, - ACT_MS_ADPCM = 2 - }; - CNetworkTransportProps() : iNetworkPacketSize ( 0 ), iMonoAudioBlockSize ( 0 ), iNumAudioChannels ( 0 ), iSampleRate ( 0 ), - eAudioCodingType ( ACT_NONE ), iAudioCodingArg ( 0 ) {} + eAudioCodingType ( CT_NONE ), iAudioCodingArg ( 0 ) {} CNetworkTransportProps ( const unsigned int iNNPS, const unsigned int iNMABS, const unsigned int iNNACH, const unsigned int iNSR, - const EAudioCodingType eNACT, const int iNACA ) : + const EAudComprType eNACT, const int iNACA ) : iNetworkPacketSize ( iNNPS ), iMonoAudioBlockSize ( iNMABS ), iNumAudioChannels ( iNNACH ), iSampleRate ( iNSR ), eAudioCodingType ( eNACT ), iAudioCodingArg ( iNACA ) {} @@ -432,7 +432,7 @@ public: unsigned int iMonoAudioBlockSize; unsigned int iNumAudioChannels; unsigned int iSampleRate; - EAudioCodingType eAudioCodingType; + EAudComprType eAudioCodingType; int iAudioCodingArg; }; diff --git a/windows/sound.cpp b/windows/sound.cpp index c975226e..8c98942b 100755 --- a/windows/sound.cpp +++ b/windows/sound.cpp @@ -29,15 +29,10 @@ /* Implementation *************************************************************/ -#include - // external references extern AsioDrivers* asioDrivers; bool loadAsioDriver ( char *name ); -// mutex -QMutex ASIOMutex; - // TODO the following variables should be in the class definition but we cannot // do it here since we have static callback functions which cannot access the // class members :-((( @@ -52,188 +47,12 @@ int iBufferSizeMono; int iBufferSizeStereo; int iASIOBufferSizeMono; -// event -HANDLE m_ASIOEvent; +CVector vecsTmpAudioSndCrdStereo; -// wave in -short* psCaptureBuffer; -int iBufferPosCapture; -bool bCaptureBufferOverrun; +QMutex ASIOMutex; -// wave out -short* psPlayBuffer; -int iBufferPosPlay; -bool bPlayBufferUnderrun; - -int iMinNumSndBuf; -int iCurNumSndBufIn; -int iCurNumSndBufOut; -int iNewNumSndBufIn; -int iNewNumSndBufOut; -bool bSetNumSndBufToMinimumValue; - -// we must implement these functions here to get access to global variables -int CSound::GetOutNumBuf() { return iNewNumSndBufOut; } -int CSound::GetInNumBuf() { return iNewNumSndBufIn; } - - -/******************************************************************************\ -* Wave in * -\******************************************************************************/ -bool CSound::Read ( CVector& psData ) -{ - int i; - bool bError; - - // check if device must be opened or reinitialized - if ( bChangParamIn ) - { - // reinit sound interface - Init ( iBufferSizeStereo ); - - // reset flag - bChangParamIn = false; - } - - // wait until enough data is available - int iWaitCount = 0; - while ( iBufferPosCapture < iBufferSizeStereo ) - { - if ( !bCaptureBufferOverrun ) - { - // regular case - WaitForSingleObject ( m_ASIOEvent, INFINITE ); - } - else - { - // it seems that the buffers are too small, wait - // just one time to avoid CPU to go up to 100% and - // then leave this function - if ( iWaitCount == 0 ) - { - WaitForSingleObject ( m_ASIOEvent, INFINITE ); - iWaitCount++; - } - else - { - return true; - } - } - } - - ASIOMutex.lock(); // get mutex lock - { - // check for buffer overrun in ASIO thread - bError = bCaptureBufferOverrun; - if ( bCaptureBufferOverrun ) - { - // reset flag - bCaptureBufferOverrun = false; - } - - // copy data from sound card capture buffer in function output buffer - for ( i = 0; i < iBufferSizeStereo; i++ ) - { - psData[i] = psCaptureBuffer[i]; - } - - // move all other data in buffer - const int iLenCopyRegion = iBufferPosCapture - iBufferSizeStereo; - for ( i = 0; i < iLenCopyRegion; i++ ) - { - psCaptureBuffer[i] = psCaptureBuffer[iBufferSizeStereo + i]; - } - - // adjust "current block to write" pointer - iBufferPosCapture -= iBufferSizeStereo; - - // in case more than one buffer was ready, reset event - ResetEvent ( m_ASIOEvent ); - } - ASIOMutex.unlock(); - - return bError; -} - -void CSound::SetInNumBuf ( int iNewNum ) -{ - // check new parameter - if ( ( iNewNum < MAX_SND_BUF_IN ) && ( iNewNum >= iMinNumSndBuf ) ) - { - // change only if parameter is different - if ( iNewNum != iNewNumSndBufIn ) - { - iNewNumSndBufIn = iNewNum; - bChangParamIn = true; - } - } -} - - -/******************************************************************************\ -* Wave out * -\******************************************************************************/ -bool CSound::Write ( CVector& psData ) -{ - bool bError; - - // check if device must be opened or reinitialized - if ( bChangParamOut ) - { - // reinit sound interface - Init ( iBufferSizeStereo ); - - // reset flag - bChangParamOut = false; - } - - ASIOMutex.lock(); // get mutex lock - { - // check for buffer underrun in ASIO thread - bError = bPlayBufferUnderrun; - if ( bPlayBufferUnderrun ) - { - // reset flag - bPlayBufferUnderrun = false; - } - - // first check if enough data in buffer is available - const int iPlayBufferLen = iCurNumSndBufOut * iBufferSizeStereo; - - if ( iBufferPosPlay + iBufferSizeStereo > iPlayBufferLen ) - { - // buffer overrun, return error - bError = true; - } - else - { - // copy stereo data from function input in soundcard play buffer - for ( int i = 0; i < iBufferSizeStereo; i++ ) - { - psPlayBuffer[iBufferPosPlay + i] = psData[i]; - } - - iBufferPosPlay += iBufferSizeStereo; - } - } - ASIOMutex.unlock(); - - return bError; -} - -void CSound::SetOutNumBuf ( int iNewNum ) -{ - // check new parameter - if ( ( iNewNum < MAX_SND_BUF_OUT ) && ( iNewNum >= iMinNumSndBuf ) ) - { - // change only if parameter is different - if ( iNewNum != iNewNumSndBufOut ) - { - iNewNumSndBufOut = iNewNum; - bChangParamOut = true; - } - } -} +// TEST +CSound* pSound; /******************************************************************************\ @@ -244,24 +63,11 @@ void CSound::SetDev ( const int iNewDev ) // check if an ASIO driver was already initialized if ( lCurDev >= 0 ) { - // the new driver was not selected before, use default settings for - // buffer sizes - bSetNumSndBufToMinimumValue = true; - // a device was already been initialized and is used, kill working // thread and clean up // stop driver ASIOStop(); - // set event to ensure that thread leaves the waiting function - if ( m_ASIOEvent != NULL ) - { - SetEvent ( m_ASIOEvent ); - } - - // wait for the thread to terminate - Sleep ( 500 ); - // dispose ASIO buffers ASIODisposeBuffers(); @@ -273,14 +79,6 @@ void CSound::SetDev ( const int iNewDev ) if ( !strErrorMessage.empty() ) { - // The new driver initializing was not successful, try to preserve - // the old buffer settings -> this is possible, if errornous driver - // had failed before the buffer setting was done. If it failed after - // setting the minimum buffer sizes, the following flag modification - // does not have any effect which means the old settings cannot be - // recovered anymore (TODO better solution) - bSetNumSndBufToMinimumValue = false; - // loading and initializing the new driver failed, go back to original // driver and display error message LoadAndInitializeDriver ( lCurDev ); @@ -313,10 +111,6 @@ void CSound::SetDev ( const int iNewDev ) } else { - // the new driver was not selected before, use default settings for - // buffer sizes - bSetNumSndBufToMinimumValue = true; - // try to find one usable driver (select the first valid driver) if ( !LoadAndInitializeFirstValidDriver() ) { @@ -510,40 +304,7 @@ const bool bPreferPowerOfTwoAudioBufferSize = false; } } - // calculate the minimum required number of soundcard buffers - iMinNumSndBuf = static_cast ( - ceil ( static_cast ( iASIOBufferSizeMono ) / iBufferSizeMono ) ); - -// TODO better solution -// For some ASIO buffer sizes, the above calculation seems not to work although -// it should be correct. Maybe there is a misunderstanding or a bug in the -// sound interface implementation. As a workaround, we implement a table here, to -// get working parameters for the most common ASIO buffer settings -// Interesting observation: only 256 samples seems to be wrong, all other tested -// buffer sizes like 192, 512, 384, etc. are correct... -if ( iASIOBufferSizeMono == 256 ) -{ - iMinNumSndBuf = 4; -} - Q_ASSERT ( iMinNumSndBuf < MAX_SND_BUF_IN ); - Q_ASSERT ( iMinNumSndBuf < MAX_SND_BUF_OUT ); - - // set or just check the sound card buffer sizes - if ( bSetNumSndBufToMinimumValue ) - { - // use minimum buffer sizes as default - iNewNumSndBufIn = iMinNumSndBuf; - iNewNumSndBufOut = iMinNumSndBuf; - } - else - { - // correct number of sound card buffers if required - iNewNumSndBufIn = max ( iMinNumSndBuf, iNewNumSndBufIn ); - iNewNumSndBufOut = max ( iMinNumSndBuf, iNewNumSndBufOut ); - } - iCurNumSndBufIn = iNewNumSndBufIn; - iCurNumSndBufOut = iNewNumSndBufOut; - +/* // display warning in case the ASIO buffer is too big if ( iMinNumSndBuf > 6 ) { @@ -557,6 +318,7 @@ if ( iASIOBufferSizeMono == 256 ) "before you try to change the ASIO driver buffer size all ASIO " "applications including llcon are closed." ), "Ok", 0 ); } +*/ // prepare input channels for ( i = 0; i < NUM_IN_OUT_CHANNELS; i++ ) @@ -621,40 +383,11 @@ void CSound::Init ( const int iNewStereoBufferSize ) iBufferSizeStereo = iNewStereoBufferSize; iBufferSizeMono = iBufferSizeStereo / 2; - // store new buffer number values - iCurNumSndBufIn = iNewNumSndBufIn; - iCurNumSndBufOut = iNewNumSndBufOut; +// TEST +PrepareDriver(); - // initialize write block pointer in and overrun flag - iBufferPosCapture = 0; - bCaptureBufferOverrun = false; - - // create memory for capture buffer - if ( psCaptureBuffer != NULL ) - { - delete[] psCaptureBuffer; - } - psCaptureBuffer = new short[iCurNumSndBufIn * iBufferSizeStereo]; - - // initialize write block pointer out and underrun flag - iBufferPosPlay = 0; - bPlayBufferUnderrun = false; - - // create memory for play buffer - if ( psPlayBuffer != NULL ) - { - delete[] psPlayBuffer; - } - psPlayBuffer = new short[iCurNumSndBufOut * iBufferSizeStereo]; - - // clear new buffer - for ( int i = 0; i < iCurNumSndBufOut * iBufferSizeStereo; i++ ) - { - psPlayBuffer[i] = 0; - } - - // reset event - ResetEvent ( m_ASIOEvent ); + // create memory for intermediate audio buffer + vecsTmpAudioSndCrdStereo.Init ( iBufferSizeStereo ); } ASIOMutex.unlock(); @@ -666,33 +399,15 @@ void CSound::Close() { // stop driver ASIOStop(); - - // set event to ensure that thread leaves the waiting function - if ( m_ASIOEvent != NULL ) - { - SetEvent ( m_ASIOEvent ); - } - - // wait for the thread to terminate - Sleep ( 500 ); - - // set flag to open devices the next time it is initialized - bChangParamIn = true; - bChangParamOut = true; } CSound::CSound ( void (*fpNewCallback) ( CVector& psData, void* arg ), void* arg ) : - CSoundBase ( fpNewCallback, arg ) + CSoundBase ( true, fpNewCallback, arg ) { - // init number of sound buffers - iNewNumSndBufIn = NUM_SOUND_BUFFERS_IN; - iCurNumSndBufIn = NUM_SOUND_BUFFERS_IN; - iNewNumSndBufOut = NUM_SOUND_BUFFERS_OUT; - iCurNumSndBufOut = NUM_SOUND_BUFFERS_OUT; - iMinNumSndBuf = 1; - // should be initialized because an error can occur during init - m_ASIOEvent = NULL; +// TEST +pSound = this; + // get available ASIO driver names in system for ( int i = 0; i < MAX_NUMBER_SOUND_CARDS; i++ ) @@ -719,19 +434,6 @@ CSound::CSound ( void (*fpNewCallback) ( CVector& psData, void* arg ), vo asioCallbacks.sampleRateDidChange = &sampleRateChanged; asioCallbacks.asioMessage = &asioMessages; asioCallbacks.bufferSwitchTimeInfo = &bufferSwitchTimeInfo; - - // init buffer pointer to zero - psCaptureBuffer = NULL; - psPlayBuffer = NULL; - - // we use an event controlled structure - // create event - m_ASIOEvent = CreateEvent ( NULL, FALSE, FALSE, NULL ); - - // init flags - bChangParamIn = false; - bChangParamOut = false; - bSetNumSndBufToMinimumValue = false; } CSound::~CSound() @@ -741,22 +443,6 @@ CSound::~CSound() ASIODisposeBuffers(); ASIOExit(); asioDrivers->removeCurrentDriver(); - - // delete allocated memory - if ( psCaptureBuffer != NULL ) - { - delete[] psCaptureBuffer; - } - if ( psPlayBuffer != NULL ) - { - delete[] psPlayBuffer; - } - - // close the handle for the event - if ( m_ASIOEvent != NULL ) - { - CloseHandle ( m_ASIOEvent ); - } } // ASIO callbacks ------------------------------------------------------------- @@ -774,141 +460,106 @@ void CSound::bufferSwitch ( long index, ASIOBool processNow ) ASIOMutex.lock(); // get mutex lock { - // first check buffer state of capture and play buffers - const int iCaptureBufferLen = iCurNumSndBufIn * iBufferSizeStereo; - - bCaptureBufferOverrun = - ( iBufferPosCapture + 2 * iASIOBufferSizeMono > iCaptureBufferLen ); - - bPlayBufferUnderrun = ( 2 * iASIOBufferSizeMono > iBufferPosPlay ); - // perform the processing for input and output for ( int i = 0; i < 2 * NUM_IN_OUT_CHANNELS; i++ ) // stereo { if ( bufferInfos[i].isInput == ASIOTrue ) { // CAPTURE ----------------------------------------------------- - // first check if space in buffer is available - if ( !bCaptureBufferOverrun ) + // copy new captured block in thread transfer buffer (copy + // mono data interleaved in stereo buffer) + switch ( channelInfos[i].type ) { - // copy new captured block in thread transfer buffer (copy - // mono data interleaved in stereo buffer) - switch ( channelInfos[i].type ) + case ASIOSTInt16LSB: + for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ ) { - case ASIOSTInt16LSB: - for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ ) - { - psCaptureBuffer[iBufferPosCapture + - 2 * iCurSample + bufferInfos[i].channelNum] = - ( (short*) bufferInfos[i].buffers[index] )[iCurSample]; - } - break; + vecsTmpAudioSndCrdStereo[2 * iCurSample + bufferInfos[i].channelNum] = + ( (short*) bufferInfos[i].buffers[index] )[iCurSample]; + } + break; - case ASIOSTInt24LSB: + case ASIOSTInt24LSB: // not yet tested, horrible things might happen with the following code ;-) - for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ ) - { - // convert current sample in 16 bit format - int iCurSam = 0; - memcpy ( &iCurSam, ( (char*) bufferInfos[i].buffers[index] ) + iCurSample * 3, 3 ); - iCurSam >>= 8; + for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ ) + { + // convert current sample in 16 bit format + int iCurSam = 0; + memcpy ( &iCurSam, ( (char*) bufferInfos[i].buffers[index] ) + iCurSample * 3, 3 ); + iCurSam >>= 8; - psCaptureBuffer[iBufferPosCapture + - 2 * iCurSample + bufferInfos[i].channelNum] = static_cast ( iCurSam ); - } - break; - - case ASIOSTInt32LSB: - for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ ) - { - // convert to 16 bit - psCaptureBuffer[iBufferPosCapture + - 2 * iCurSample + bufferInfos[i].channelNum] = - (((int*) bufferInfos[i].buffers[index])[iCurSample] >> 16); - } - break; + vecsTmpAudioSndCrdStereo[2 * iCurSample + bufferInfos[i].channelNum] = + static_cast ( iCurSam ); } + break; + + case ASIOSTInt32LSB: + for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ ) + { + // convert to 16 bit + vecsTmpAudioSndCrdStereo[2 * iCurSample + bufferInfos[i].channelNum] = + (((int*) bufferInfos[i].buffers[index])[iCurSample] >> 16); + } + break; } } - else + } + + // call processing callback function + pSound->Callback( vecsTmpAudioSndCrdStereo ); + + // perform the processing for input and output + for ( int i = 0; i < 2 * NUM_IN_OUT_CHANNELS; i++ ) // stereo + { + if ( bufferInfos[i].isInput != ASIOTrue ) { // PLAYBACK ---------------------------------------------------- - if ( !bPlayBufferUnderrun ) + // copy data from sound card in output buffer (copy + // interleaved stereo data in mono sound card buffer) + switch ( channelInfos[i].type ) { - // copy data from sound card in output buffer (copy - // interleaved stereo data in mono sound card buffer) - switch ( channelInfos[i].type ) + case ASIOSTInt16LSB: + for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ ) { - case ASIOSTInt16LSB: - for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ ) - { - ( (short*) bufferInfos[i].buffers[index] )[iCurSample] = - psPlayBuffer[2 * iCurSample + bufferInfos[i].channelNum]; - } - break; + ( (short*) bufferInfos[i].buffers[index] )[iCurSample] = + vecsTmpAudioSndCrdStereo[2 * iCurSample + bufferInfos[i].channelNum]; + } + break; - case ASIOSTInt24LSB: + case ASIOSTInt24LSB: // not yet tested, horrible things might happen with the following code ;-) - for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ ) - { - // convert current sample in 24 bit format - int iCurSam = static_cast ( psPlayBuffer[2 * iCurSample + bufferInfos[i].channelNum] ); - iCurSam <<= 8; + for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ ) + { + // convert current sample in 24 bit format + int iCurSam = static_cast ( vecsTmpAudioSndCrdStereo[2 * iCurSample + bufferInfos[i].channelNum] ); + iCurSam <<= 8; - memcpy ( ( (char*) bufferInfos[i].buffers[index] ) + iCurSample * 3, &iCurSam, 3 ); - } - break; - - case ASIOSTInt32LSB: - for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ ) - { - // convert to 32 bit - int iCurSam = static_cast ( psPlayBuffer[2 * iCurSample + bufferInfos[i].channelNum] ); - ( (int*) bufferInfos[i].buffers[index] )[iCurSample] = ( iCurSam << 16 ); - } - break; + memcpy ( ( (char*) bufferInfos[i].buffers[index] ) + iCurSample * 3, &iCurSam, 3 ); } + break; + + case ASIOSTInt32LSB: + for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ ) + { + // convert to 32 bit + int iCurSam = static_cast ( vecsTmpAudioSndCrdStereo[2 * iCurSample + bufferInfos[i].channelNum] ); + ( (int*) bufferInfos[i].buffers[index] )[iCurSample] = ( iCurSam << 16 ); + } + break; } } } - // Manage thread interface buffers for input and output ---------------- - // capture - if ( !bCaptureBufferOverrun ) - { - iBufferPosCapture += 2 * iASIOBufferSizeMono; - } - - // play - if ( !bPlayBufferUnderrun ) - { - // move all other data in play buffer - const int iLenCopyRegion = iBufferPosPlay - 2 * iASIOBufferSizeMono; - for ( iCurSample = 0; iCurSample < iLenCopyRegion; iCurSample++ ) - { - psPlayBuffer[iCurSample] = - psPlayBuffer[2 * iASIOBufferSizeMono + iCurSample]; - } - - // adjust "current block to write" pointer - iBufferPosPlay -= 2 * iASIOBufferSizeMono; - } - - // finally if the driver supports the ASIOOutputReady() optimization, // do it here, all data are in place ----------------------------------- if ( bASIOPostOutput ) { ASIOOutputReady(); } - - // set event - SetEvent ( m_ASIOEvent ); } ASIOMutex.unlock(); } diff --git a/windows/sound.h b/windows/sound.h index e0620341..1a641502 100755 --- a/windows/sound.h +++ b/windows/sound.h @@ -28,6 +28,7 @@ #include #include +#include #include #include "../src/util.h" #include "../src/global.h" @@ -59,8 +60,6 @@ public: virtual ~CSound(); virtual void Init ( const int iNewStereoBufferSize ); - virtual bool Read ( CVector& psData ); - virtual bool Write ( CVector& psData ); virtual void Close(); int GetNumDev() { return lNumDevs; } @@ -69,10 +68,10 @@ public: void SetDev ( const int iNewDev ); int GetDev() { return lCurDev; } - void SetOutNumBuf ( const int iNewNum ); - int GetOutNumBuf(); - void SetInNumBuf ( const int iNewNum ); - int GetInNumBuf(); + void SetOutNumBuf ( const int iNewNum ) {} + int GetOutNumBuf() { return 1; } + void SetInNumBuf ( const int iNewNum ) {} + int GetInNumBuf() { return 1; } protected: bool LoadAndInitializeFirstValidDriver(); @@ -97,9 +96,6 @@ protected: long lNumDevs; long lCurDev; char* cDriverNames[MAX_NUMBER_SOUND_CARDS]; - - bool bChangParamIn; - bool bChangParamOut; }; #endif // !defined ( AFX_SOUNDIN_H__9518A621_7F78_11D3_8C0D_EEBF182CF549__INCLUDED_ )