diff --git a/src/buffer.cpp b/src/buffer.cpp index a46bff33..28f1fa7d 100755 --- a/src/buffer.cpp +++ b/src/buffer.cpp @@ -120,7 +120,7 @@ bool CNetBuf::Get ( CVector& vecbyData ) const int iInSize = vecbyData.Size(); // check size - if ( iInSize != iBlockSize ) + if ( ( iInSize == 0 ) || ( iInSize != iBlockSize ) ) { return false; } diff --git a/src/channel.cpp b/src/channel.cpp index a70038f8..ec4eea39 100755 --- a/src/channel.cpp +++ b/src/channel.cpp @@ -32,7 +32,7 @@ CChannel::CChannel ( const bool bNIsServer ) : vecdGains ( USED_NUM_CHANNELS, (double) 1.0 ), bIsEnabled ( false ), iNetwFrameSizeFact ( FRAME_SIZE_FACTOR_DEFAULT ), - iNetwFrameSize ( 0 ) + iNetwFrameSize ( 1 ) // any value > 0 { // initial value for connection time out counter, we calculate the total // number of samples here and subtract the number of samples of the block @@ -46,7 +46,7 @@ CChannel::CChannel ( const bool bNIsServer ) : SetSockBufNumFrames ( DEF_NET_BUF_SIZE_NUM_BL ); // initialize cycle time variance measurement with defaults - CycleTimeVariance.Init ( SYSTEM_BLOCK_FRAME_SAMPLES, + CycleTimeVariance.Init ( SYSTEM_FRAME_SIZE_SAMPLES, SYSTEM_SAMPLE_RATE, TIME_MOV_AV_RESPONSE ); @@ -140,7 +140,7 @@ void CChannel::SetNetwFrameSizeAndFact ( const int iNewNetwFrameSize, ConvBuf.Init ( iNetwFrameSize * iNetwFrameSizeFact ); // initialize and reset cycle time variance measurement - CycleTimeVariance.Init ( iNetwFrameSizeFact * SYSTEM_BLOCK_FRAME_SAMPLES, + CycleTimeVariance.Init ( iNetwFrameSizeFact * SYSTEM_FRAME_SIZE_SAMPLES, SYSTEM_SAMPLE_RATE, TIME_MOV_AV_RESPONSE ); CycleTimeVariance.Reset(); @@ -448,12 +448,12 @@ EGetDataStat CChannel::GetData ( CVector& vecbyData ) // subtract the number of samples of the current block since the // time out counter is based on samples not on blocks (definition: // always one atomic block is get by using the GetData() function - // where the atomic block size is "SYSTEM_BLOCK_FRAME_SAMPLES") + // where the atomic block size is "SYSTEM_FRAME_SIZE_SAMPLES") // TODO this code only works with the above assumption -> better // implementation so that we are not depending on assumptions - iConTimeOut -= SYSTEM_BLOCK_FRAME_SAMPLES; + iConTimeOut -= SYSTEM_FRAME_SIZE_SAMPLES; if ( iConTimeOut <= 0 ) { @@ -506,7 +506,7 @@ CVector CChannel::PrepSendPacket ( const CVector& vecbyNPacket int CChannel::GetUploadRateKbps() { - const int iAudioSizeOut = iNetwFrameSizeFact * SYSTEM_BLOCK_FRAME_SAMPLES; + const int iAudioSizeOut = iNetwFrameSizeFact * SYSTEM_FRAME_SIZE_SAMPLES; // we assume that the UDP packet which is transported via IP has an // additional header size of diff --git a/src/client.cpp b/src/client.cpp index 729d1f30..0bb8740e 100755 --- a/src/client.cpp +++ b/src/client.cpp @@ -40,7 +40,7 @@ CClient::CClient ( const quint16 iPortNumber ) : { // init audio endocder/decoder (mono) CeltMode = celt_mode_create ( - SYSTEM_SAMPLE_RATE, 1, SYSTEM_BLOCK_FRAME_SAMPLES, NULL ); + SYSTEM_SAMPLE_RATE, 1, SYSTEM_FRAME_SIZE_SAMPLES, NULL ); CeltEncoder = celt_encoder_create ( CeltMode ); CeltDecoder = celt_decoder_create ( CeltMode ); @@ -272,7 +272,7 @@ void CClient::Init() { // translate block size index in actual block size const int iPrefMonoFrameSize = - iSndCrdPrefMonoFrameSizeFactor * SYSTEM_BLOCK_FRAME_SAMPLES; + iSndCrdPrefMonoFrameSizeFactor * SYSTEM_FRAME_SIZE_SAMPLES; // get actual sound card buffer size using preferred size iMonoBlockSizeSam = Sound.Init ( iPrefMonoFrameSize ); @@ -395,7 +395,7 @@ void CClient::ProcessAudioData ( CVector& vecsStereoSndCrd ) { // encode current audio frame with CELT encoder celt_encode ( CeltEncoder, - &vecsNetwork[i * SYSTEM_BLOCK_FRAME_SAMPLES], + &vecsNetwork[i * SYSTEM_FRAME_SIZE_SAMPLES], NULL, &vecCeltData[0], iCeltNumCodedBytes ); @@ -431,7 +431,7 @@ void CClient::ProcessAudioData ( CVector& vecsStereoSndCrd ) celt_decode ( CeltDecoder, &vecbyNetwData[0], iCeltNumCodedBytes, - &vecsAudioSndCrdMono[i * SYSTEM_BLOCK_FRAME_SAMPLES] ); + &vecsAudioSndCrdMono[i * SYSTEM_FRAME_SIZE_SAMPLES] ); } else { @@ -439,7 +439,7 @@ void CClient::ProcessAudioData ( CVector& vecsStereoSndCrd ) celt_decode ( CeltDecoder, NULL, iCeltNumCodedBytes, - &vecsAudioSndCrdMono[i * SYSTEM_BLOCK_FRAME_SAMPLES] ); + &vecsAudioSndCrdMono[i * SYSTEM_FRAME_SIZE_SAMPLES] ); } } diff --git a/src/clientsettingsdlg.cpp b/src/clientsettingsdlg.cpp index 55ceaaf5..0bfa2775 100755 --- a/src/clientsettingsdlg.cpp +++ b/src/clientsettingsdlg.cpp @@ -85,15 +85,15 @@ CClientSettingsDlg::CClientSettingsDlg ( CClient* pNCliP, QWidget* parent, // set text for sound card buffer delay radio buttons rButBufferDelayPreferred->setText ( GenSndCrdBufferDelayString ( - FRAME_SIZE_FACTOR_PREFERRED * SYSTEM_BLOCK_FRAME_SAMPLES, + FRAME_SIZE_FACTOR_PREFERRED * SYSTEM_FRAME_SIZE_SAMPLES, ", preferred" ) ); rButBufferDelayDefault->setText ( GenSndCrdBufferDelayString ( - FRAME_SIZE_FACTOR_DEFAULT * SYSTEM_BLOCK_FRAME_SAMPLES, + FRAME_SIZE_FACTOR_DEFAULT * SYSTEM_FRAME_SIZE_SAMPLES, ", default" ) ); rButBufferDelaySafe->setText ( GenSndCrdBufferDelayString ( - FRAME_SIZE_FACTOR_SAFE * SYSTEM_BLOCK_FRAME_SAMPLES ) ); + FRAME_SIZE_FACTOR_SAFE * SYSTEM_FRAME_SIZE_SAMPLES ) ); // sound card buffer delay inits SndCrdBufferDelayButtonGroup.addButton ( rButBufferDelayPreferred ); @@ -192,7 +192,7 @@ void CClientSettingsDlg::UpdateSoundCardFrame() // preferred size const int iPrefBufSize = - iCurPrefFrameSizeFactor * SYSTEM_BLOCK_FRAME_SAMPLES; + iCurPrefFrameSizeFactor * SYSTEM_FRAME_SIZE_SAMPLES; // actual size (use yellow color if different from preferred size) const QString strActSizeValues = diff --git a/src/global.h b/src/global.h index 91b24562..44db89f3 100755 --- a/src/global.h +++ b/src/global.h @@ -60,14 +60,14 @@ // System block size, this is the block size on which the audio coder works. // All other block sizes must be a multiple of this size -#define SYSTEM_BLOCK_FRAME_SAMPLES 128 +#define SYSTEM_FRAME_SIZE_SAMPLES 128 #define SYSTEM_BLOCK_DURATION_MS_FLOAT \ - ( static_cast ( SYSTEM_BLOCK_FRAME_SAMPLES ) / \ + ( static_cast ( SYSTEM_FRAME_SIZE_SAMPLES ) / \ SYSTEM_SAMPLE_RATE * 1000 ) // define the allowed audio frame size factors (since the -// "SYSTEM_BLOCK_FRAME_SAMPLES" is quite small, it may be that on some +// "SYSTEM_FRAME_SIZE_SAMPLES" is quite small, it may be that on some // computers a larger value is required) #define FRAME_SIZE_FACTOR_PREFERRED 1 // 128 (for frame size 128) #define FRAME_SIZE_FACTOR_DEFAULT 2 // 256 (for frame size 128) @@ -78,6 +78,10 @@ // of bytes to be expected from the network interface #define MAX_MONO_AUD_BUFF_SIZE_AT_48KHZ 4096 +// 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 ) + // 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 diff --git a/src/protocol.cpp b/src/protocol.cpp index 0b3507da..7ebd2ced 100755 --- a/src/protocol.cpp +++ b/src/protocol.cpp @@ -878,14 +878,33 @@ bool CProtocol::EvaluateNetwTranspPropsMes ( const CVector& vecData ) ReceivedNetwTranspProps.iNetworkPacketSize = static_cast ( GetValFromStream ( vecData, iPos, 4 ) ); + if ( ( ReceivedNetwTranspProps.iNetworkPacketSize < 1 ) || + ( ReceivedNetwTranspProps.iNetworkPacketSize > MAX_SIZE_BYTES_NETW_BUF ) ) + { + return true; + } + // block size factor (2 bytes) ReceivedNetwTranspProps.iBlockSizeFact = static_cast ( GetValFromStream ( vecData, iPos, 2 ) ); + if ( ( ReceivedNetwTranspProps.iBlockSizeFact != FRAME_SIZE_FACTOR_PREFERRED ) && + ( ReceivedNetwTranspProps.iBlockSizeFact != FRAME_SIZE_FACTOR_DEFAULT ) && + ( ReceivedNetwTranspProps.iBlockSizeFact != FRAME_SIZE_FACTOR_SAFE ) ) + { + return true; + } + // number of channels of the audio signal, e.g. "2" is stereo (1 byte) ReceivedNetwTranspProps.iNumAudioChannels = static_cast ( GetValFromStream ( vecData, iPos, 1 ) ); + if ( ( ReceivedNetwTranspProps.iNumAudioChannels != 1 ) && + ( ReceivedNetwTranspProps.iNumAudioChannels != 2 ) ) + { + return true; + } + // sample rate of the audio stream (4 bytes) ReceivedNetwTranspProps.iSampleRate = static_cast ( GetValFromStream ( vecData, iPos, 4 ) ); diff --git a/src/server.cpp b/src/server.cpp index be9ea44e..0a4e1d3b 100755 --- a/src/server.cpp +++ b/src/server.cpp @@ -30,7 +30,7 @@ CHighPrecisionTimer::CHighPrecisionTimer() { // add some error checking, the high precision timer implementation only // supports 128 samples frame size at 48 kHz sampling rate -#if ( SYSTEM_BLOCK_FRAME_SAMPLES != 128 ) +#if ( SYSTEM_FRAME_SIZE_SAMPLES != 128 ) # error "Only system frame size of 128 samples is supported by this module" #endif #if SYSTEM_SAMPLE_RATE != 48000 @@ -112,24 +112,18 @@ CServer::CServer ( const QString& strLoggingFileName, { int i; - // create CELT encoder/decoder for each channel + // create CELT encoder/decoder for each channel (must be done before + // enabling the channels) for ( i = 0; i < USED_NUM_CHANNELS; i++ ) { // init audio endocder/decoder (mono) CeltMode[i] = celt_mode_create ( - SYSTEM_SAMPLE_RATE, 1, SYSTEM_BLOCK_FRAME_SAMPLES, NULL ); + SYSTEM_SAMPLE_RATE, 1, SYSTEM_FRAME_SIZE_SAMPLES, NULL ); CeltEncoder[i] = celt_encoder_create ( CeltMode[i] ); CeltDecoder[i] = celt_decoder_create ( CeltMode[i] ); } - // enable all channels (for the server all channel must be enabled the - // entire life time of the software - for ( i = 0; i < USED_NUM_CHANNELS; i++ ) - { - vecChannels[i].SetEnable ( true ); - } - // define colors for chat window identifiers vstrChatColors.Init ( 6 ); vstrChatColors[0] = "mediumblue"; @@ -139,10 +133,10 @@ CServer::CServer ( const QString& strLoggingFileName, vstrChatColors[4] = "maroon"; vstrChatColors[5] = "coral"; - vecsSendData.Init ( SYSTEM_BLOCK_FRAME_SAMPLES ); + vecsSendData.Init ( SYSTEM_FRAME_SIZE_SAMPLES ); // init moving average buffer for response time evaluation - CycleTimeVariance.Init ( SYSTEM_BLOCK_FRAME_SAMPLES, + CycleTimeVariance.Init ( SYSTEM_FRAME_SIZE_SAMPLES, SYSTEM_SAMPLE_RATE, TIME_MOV_AV_RESPONSE ); // enable logging (if requested) @@ -175,6 +169,13 @@ CServer::CServer ( const QString& strLoggingFileName, QString().number( static_cast ( iPortNumber ) ) ); } + // enable all channels (for the server all channel must be enabled the + // entire life time of the software + for ( i = 0; i < USED_NUM_CHANNELS; i++ ) + { + vecChannels[i].SetEnable ( true ); + } + // connections ------------------------------------------------------------- // connect timer timeout signal @@ -287,12 +288,112 @@ void CServer::Stop() void CServer::OnTimer() { - CVector vecChanID; - CVector > vecvecsData; - CVector > vecvecdGains; + int i, j; - // get data from all connected clients - GetBlockAllConC ( vecChanID, vecvecsData, vecvecdGains ); + CVector vecChanID; + CVector > vecvecdGains; + CVector > vecvecsData; + + + // get data from all connected clients ------------------------------------- + bool bChannelIsNowDisconnected = false; + + // make put and get calls thread safe. Do not forget to unlock mutex + // afterwards! + Mutex.lock(); + { + // first, get number and IDs of connected channels + vecChanID.Init ( 0 ); + for ( i = 0; i < USED_NUM_CHANNELS; i++ ) + { + if ( vecChannels[i].IsConnected() ) + { + // add ID and data + vecChanID.Add ( i ); + } + } + + // process connected channels + const int iNumCurConnChan = vecChanID.Size(); + + // init temporary vectors + vecvecdGains.Init ( iNumCurConnChan ); + vecvecsData.Init ( iNumCurConnChan ); + + for ( i = 0; i < iNumCurConnChan; i++ ) + { + // init vectors storing information of all channels + vecvecdGains[i].Init ( iNumCurConnChan ); + vecvecsData[i].Init ( SYSTEM_FRAME_SIZE_SAMPLES ); + + // get gains of all connected channels + for ( j = 0; j < iNumCurConnChan; j++ ) + { + // The second index of "vecvecdGains" does not represent + // the channel ID! Therefore we have to use "vecChanID" to + // query the IDs of the currently connected channels + vecvecdGains[i][j] = + vecChannels[vecChanID[i]].GetGain( vecChanID[j] ); + } + + // get current number of CELT coded bytes + const int iCeltNumCodedBytes = + vecChannels[i].GetNetwFrameSize(); + + // init temporal data vector and clear input buffers + CVector vecbyData ( iCeltNumCodedBytes ); + + // get data + const EGetDataStat eGetStat = vecChannels[i].GetData ( vecbyData ); + + // if channel was just disconnected, set flag that connected + // client list is sent to all other clients + if ( eGetStat == GS_CHAN_NOW_DISCONNECTED ) + { + bChannelIsNowDisconnected = true; + } + + // CELT decode received data stream + CVector vecsAudioMono ( SYSTEM_FRAME_SIZE_SAMPLES ); + + if ( eGetStat == GS_BUFFER_OK ) + { + celt_decode ( CeltDecoder[i], + &vecbyData[0], + iCeltNumCodedBytes, + &vecvecsData[i][0] ); + } + else + { + // lost packet + celt_decode ( CeltDecoder[i], + NULL, + iCeltNumCodedBytes, + &vecvecsData[i][0] ); + } + + // send message for get status (for GUI) + if ( eGetStat == GS_BUFFER_OK ) + { + PostWinMessage ( MS_JIT_BUF_GET, MUL_COL_LED_GREEN, i ); + } + else + { + PostWinMessage ( MS_JIT_BUF_GET, MUL_COL_LED_RED, i ); + } + } + + // a channel is now disconnected, take action on it + if ( bChannelIsNowDisconnected ) + { + // update channel list for all currently connected clients + CreateAndSendChanListForAllConChannels(); + } + } + Mutex.unlock(); // release mutex + + + // Process data ------------------------------------------------------------ const int iNumClients = vecChanID.Size(); // Check if at least one client is connected. If not, stop server until @@ -307,8 +408,7 @@ void CServer::OnTimer() // get current number of CELT coded bytes const int iCeltNumCodedBytes = - vecChannels[vecChanID[i]].GetNetwFrameSize() / - vecChannels[vecChanID[i]].GetNetwFrameSizeFact(); + vecChannels[vecChanID[i]].GetNetwFrameSize(); // CELT encoding CVector vecCeltData ( iCeltNumCodedBytes ); @@ -342,7 +442,7 @@ CVector CServer::ProcessData ( CVector >& vecvecsData, int i; // init return vector with zeros since we mix all channels on that vector - CVector vecsOutData ( SYSTEM_BLOCK_FRAME_SAMPLES, 0 ); + CVector vecsOutData ( SYSTEM_FRAME_SIZE_SAMPLES, 0 ); const int iNumClients = vecvecsData.Size(); @@ -352,7 +452,7 @@ CVector CServer::ProcessData ( CVector >& vecvecsData, // if channel gain is 1, avoid multiplication for speed optimization if ( vecdGains[j] == static_cast ( 1.0 ) ) { - for ( i = 0; i < SYSTEM_BLOCK_FRAME_SAMPLES; i++ ) + for ( i = 0; i < SYSTEM_FRAME_SIZE_SAMPLES; i++ ) { vecsOutData[i] = Double2Short ( vecsOutData[i] + vecvecsData[j][i] ); @@ -360,7 +460,7 @@ CVector CServer::ProcessData ( CVector >& vecvecsData, } else { - for ( i = 0; i < SYSTEM_BLOCK_FRAME_SAMPLES; i++ ) + for ( i = 0; i < SYSTEM_FRAME_SIZE_SAMPLES; i++ ) { vecsOutData[i] = Double2Short ( vecsOutData[i] + @@ -372,112 +472,6 @@ CVector CServer::ProcessData ( CVector >& vecvecsData, return vecsOutData; } -void CServer::GetBlockAllConC ( CVector& vecChanID, - CVector >& vecvecsData, - CVector >& vecvecdGains ) -{ - int i, j; - bool bChannelIsNowDisconnected = false; - - vecChanID.Init ( 0 ); - vecvecsData.Init ( 0 ); - vecvecdGains.Init ( 0 ); - - // make put and get calls thread safe. Do not forget to unlock mutex - // afterwards! - Mutex.lock(); - { - // check all possible channels - for ( i = 0; i < USED_NUM_CHANNELS; i++ ) - { - // get current number of CELT coded bytes - const int iCeltNumCodedBytes = - vecChannels[i].GetNetwFrameSize() / - vecChannels[i].GetNetwFrameSizeFact(); - - // init temporal data vector and clear input buffers - CVector vecbyData ( iCeltNumCodedBytes ); - - // read out all input buffers to decrease timeout counter on - // disconnected channels - const EGetDataStat eGetStat = vecChannels[i].GetData ( vecbyData ); - - // if channel was just disconnected, set flag that connected - // client list is sent to all other clients - if ( eGetStat == GS_CHAN_NOW_DISCONNECTED ) - { - bChannelIsNowDisconnected = true; - } - - if ( vecChannels[i].IsConnected() ) - { - // CELT decode received data stream - CVector vecsAudioMono ( SYSTEM_BLOCK_FRAME_SAMPLES ); - - if ( eGetStat == GS_BUFFER_OK ) - { - celt_decode ( CeltDecoder[i], - &vecbyData[0], - iCeltNumCodedBytes, - &vecsAudioMono[0] ); - } - else - { - // lost packet - celt_decode ( CeltDecoder[i], - NULL, - iCeltNumCodedBytes, - &vecsAudioMono[0] ); - } - - // add ID and data - vecChanID.Add ( i ); - - const int iOldSize = vecvecsData.Size(); - vecvecsData.Enlarge ( 1 ); - vecvecsData[iOldSize].Init ( vecsAudioMono.Size() ); - vecvecsData[iOldSize] = vecsAudioMono; - - // send message for get status (for GUI) - if ( eGetStat == GS_BUFFER_OK ) - { - PostWinMessage ( MS_JIT_BUF_GET, MUL_COL_LED_GREEN, i ); - } - else - { - PostWinMessage ( MS_JIT_BUF_GET, MUL_COL_LED_RED, i ); - } - } - } - - // now that we know the IDs of the connected clients, get gains - const int iNumCurConnChan = vecChanID.Size(); - vecvecdGains.Init ( iNumCurConnChan ); - - for ( i = 0; i < iNumCurConnChan; i++ ) - { - vecvecdGains[i].Init ( iNumCurConnChan ); - - for ( j = 0; j < iNumCurConnChan; j++ ) - { - // The second index of "vecvecdGains" does not represent - // the channel ID! Therefore we have to use "vecChanID" to - // query the IDs of the currently connected channels - vecvecdGains[i][j] = - vecChannels[vecChanID[i]].GetGain( vecChanID[j] ); - } - } - - // a channel is now disconnected, take action on it - if ( bChannelIsNowDisconnected ) - { - // update channel list for all currently connected clients - CreateAndSendChanListForAllConChannels(); - } - } - Mutex.unlock(); // release mutex -} - CVector CServer::CreateChannelList() { CVector vecChanInfo ( 0 ); diff --git a/src/server.h b/src/server.h index 12d7b513..61c5c622 100755 --- a/src/server.h +++ b/src/server.h @@ -105,10 +105,6 @@ protected: void StartStatusHTMLFileWriting ( const QString& strNewFileName, const QString& strNewServerNameWithPort ); - void GetBlockAllConC ( CVector& vecChanID, - CVector >& vecvecsData, - CVector >& vecvecdGains ); - int CheckAddr ( const CHostAddress& Addr ); int GetFreeChan(); CVector CreateChannelList(); diff --git a/src/socket.h b/src/socket.h index d2c4f7f7..9385f30c 100755 --- a/src/socket.h +++ b/src/socket.h @@ -40,12 +40,6 @@ class CServer; // forward declaration of CServer -/* Definitions ****************************************************************/ -// 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 ********************************************************************/ class CSocket : public QObject {