diff --git a/src/channel.cpp b/src/channel.cpp index 247cf899..7029e449 100755 --- a/src/channel.cpp +++ b/src/channel.cpp @@ -421,30 +421,43 @@ void CChannelSet::GetConCliParam ( CVector& vecHostAddresses, } + /******************************************************************************\ * CChannel * \******************************************************************************/ CChannel::CChannel() : sName ( "" ), - vecdGains ( MAX_NUM_CHANNELS, (double) 1.0 ) + vecdGains ( MAX_NUM_CHANNELS, (double) 1.0 ), + // 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 ) { // query all possible network in buffer sizes for determining if an - // audio packet was received + // audio packet was received, consider all possible sample rates (audio + // quality types: low quality, high quality) for ( int i = 0; i < MAX_NET_BLOCK_SIZE_FACTOR; i++ ) { // network block size factor must start from 1 -> ( i + 1 ) - vecNetwInBufSizes[i] = AudioCompressionIn.Init ( + // low quality audio + vecNetwInBufSizesAudLQ[i] = AudioCompressionInLowQSampRate.Init ( ( i + 1 ) * MIN_BLOCK_SIZE_SAMPLES, CAudioCompression::CT_IMAADPCM ); + + // high quality audio + vecNetwInBufSizesAudHQ[i] = AudioCompressionInHighQSampRate.Init ( + ( i + 1 ) * MIN_SERVER_BLOCK_SIZE_SAMPLES, + CAudioCompression::CT_IMAADPCM ); } - iCurNetwInBlSiFact = DEF_NET_BLOCK_SIZE_FACTOR; + // set initial minimum block size value (default) + SetMinBlockSize ( MIN_BLOCK_SIZE_SAMPLES ); // init the socket buffer SetSockBufSize ( DEF_NET_BUF_SIZE_NUM_BL ); // set initial input and output block size factors - SetNetwBufSizeFactOut ( iCurNetwInBlSiFact ); - SetNetwInBlSiFact ( iCurNetwInBlSiFact ); + SetNetwInBlSiFact ( DEF_NET_BLOCK_SIZE_FACTOR ); + SetNetwBufSizeFactOut ( DEF_NET_BLOCK_SIZE_FACTOR ); // init time-out for the buffer with zero -> no connection iConTimeOut = 0; @@ -488,6 +501,20 @@ CChannel::CChannel() : sName ( "" ), this, SIGNAL ( PingReceived ( QTime ) ) ); } +void CChannel::SetMinBlockSize ( const int iNewMinBlockSize ) +{ + // store new parameter + iCurMinBlockSize = iNewMinBlockSize; + + + +// TODO init dependencies on minimum block size here!!! + + +} + + + void CChannel::SetEnable ( const bool bNEnStat ) { // set internal parameter @@ -505,11 +532,15 @@ void CChannel::SetNetwInBlSiFact ( const int iNewBlockSizeFactor ) // store new value iCurNetwInBlSiFact = iNewBlockSizeFactor; - // init audio compression unit - iAudComprSizeIn = AudioCompressionIn.Init ( + // init audio compression units + AudioCompressionInLowQSampRate.Init ( iNewBlockSizeFactor * MIN_BLOCK_SIZE_SAMPLES, CAudioCompression::CT_IMAADPCM ); + AudioCompressionInHighQSampRate.Init ( + iNewBlockSizeFactor * MIN_SERVER_BLOCK_SIZE_SAMPLES, + CAudioCompression::CT_IMAADPCM ); + // initial value for connection time out counter iConTimeOutStartVal = ( CON_TIME_OUT_SEC_MAX * 1000 ) / ( iNewBlockSizeFactor * MIN_BLOCK_DURATION_MS ); @@ -624,7 +655,9 @@ EPutDataStat CChannel::PutData ( const CVector& vecbyData, // init flags bool bIsProtocolPacket = false; bool bIsAudioPacket = false; + bool bIsHQAudioPacket = false; // is high quality audio packet (high sample rate) bool bNewConnection = false; + int iInputBlockSizeFactor; if ( bIsEnabled ) { @@ -632,7 +665,7 @@ EPutDataStat CChannel::PutData ( const CVector& vecbyData, // only use protocol data if channel is connected if ( IsConnected() ) { - // this seems not to be an audio block, parse the message + // parse the message assuming this is a protocol message if ( Protocol.ParseMessage ( vecbyData, iNumBytes ) ) { // set status flags @@ -650,27 +683,41 @@ EPutDataStat CChannel::PutData ( const CVector& vecbyData, // check if this is an audio packet by checking all possible lengths for ( int i = 0; i < MAX_NET_BLOCK_SIZE_FACTOR; i++ ) { - if ( iNumBytes == vecNetwInBufSizes[i] ) + // check for low/high quality audio packets and set flags + if ( iNumBytes == vecNetwInBufSizesAudLQ[i] ) { - bIsAudioPacket = true; + bIsAudioPacket = true; + bIsHQAudioPacket = false; + iInputBlockSizeFactor = i + 1; + } - // check if we are correctly initialized - const int iNewNetwInBlSiFact = i + 1; - if ( iNewNetwInBlSiFact != iCurNetwInBlSiFact ) - { - // re-initialize to new value - SetNetwInBlSiFact ( iNewNetwInBlSiFact ); - } + if ( iNumBytes == vecNetwInBufSizesAudHQ[i] ) + { + bIsAudioPacket = true; + bIsHQAudioPacket = true; + iInputBlockSizeFactor = i + 1; } } // only process if packet has correct size if ( bIsAudioPacket ) { + // check if we are correctly initialized + if ( iInputBlockSizeFactor != iCurNetwInBlSiFact ) + { + // re-initialize to new value + SetNetwInBlSiFact ( iInputBlockSizeFactor ); + } + Mutex.lock(); { + + +// TODO use bIsHQAudioPacket + + // decompress audio - CVector vecsDecomprAudio ( AudioCompressionIn.Decode ( vecbyData ) ); + CVector vecsDecomprAudio ( AudioCompressionInHighQSampRate.Decode ( vecbyData ) ); // do resampling to compensate for sample rate offsets in the // different sound cards of the clients @@ -783,110 +830,3 @@ CVector CChannel::PrepSendPacket ( const CVector& vecsNPac return vecbySendBuf; } - - - - - - - - - -/******************************************************************************\ -* CSampleOffsetEst * -\******************************************************************************/ -void CSampleOffsetEst::Init() -{ - /* init sample rate estimation */ - dSamRateEst = SERVER_SAMPLE_RATE; - - /* init vectors storing the data */ - veciTimeElapsed.Init(VEC_LEN_SAM_OFFS_EST); - veciTiStIdx.Init(VEC_LEN_SAM_OFFS_EST); - - /* start reference time (the counter wraps to zero 24 hours after the last - call to start() or restart, but this should not concern us since this - software will most probably not be used that long) */ - RefTime.start(); - - /* init accumulated time stamp variable */ - iAccTiStVal = 0; - - /* init count (do not ship any result in init phase) */ - iInitCnt = VEC_LEN_SAM_OFFS_EST + 1; -} - -void CSampleOffsetEst::AddTimeStampIdx(const int iTimeStampIdx) -{ - int i; - - const int iLastIdx = VEC_LEN_SAM_OFFS_EST - 1; - - /* take care of wrap of the time stamp index (byte wrap) */ - if (iTimeStampIdx < veciTiStIdx[iLastIdx] - iAccTiStVal) - iAccTiStVal += _MAXBYTE + 1; - - /* add new data pair to the FIFO */ - for (i = 1; i < VEC_LEN_SAM_OFFS_EST; i++) - { - /* move old data */ - veciTimeElapsed[i - 1] = veciTimeElapsed[i]; - veciTiStIdx[i - 1] = veciTiStIdx[i]; - } - - /* add new data */ - veciTimeElapsed[iLastIdx] = RefTime.elapsed(); - veciTiStIdx[iLastIdx] = iAccTiStVal + iTimeStampIdx; - -/* -static FILE* pFile = fopen("v.dat", "w"); -for (i = 0; i < VEC_LEN_SAM_OFFS_EST; i++) - fprintf(pFile, "%d\n", veciTimeElapsed[i]); -fflush(pFile); -*/ - - - /* calculate linear regression for sample rate estimation */ - /* first, calculate averages */ - double dTimeAv = 0; - double dTiStAv = 0; - for (i = 0; i < VEC_LEN_SAM_OFFS_EST; i++) - { - dTimeAv += veciTimeElapsed[i]; - dTiStAv += veciTiStIdx[i]; - } - dTimeAv /= VEC_LEN_SAM_OFFS_EST; - dTiStAv /= VEC_LEN_SAM_OFFS_EST; - - /* calculate gradient */ - double dNom = 0; - double dDenom = 0; - for (i = 0; i < VEC_LEN_SAM_OFFS_EST; i++) - { - const double dCurTimeNoAv = veciTimeElapsed[i] - dTimeAv; - dNom += dCurTimeNoAv * (veciTiStIdx[i] - dTiStAv); - dDenom += dCurTimeNoAv * dCurTimeNoAv; - } - - /* final sample rate offset estimation calculation */ - if (iInitCnt > 0) - iInitCnt--; - else - { - dSamRateEst = dNom / dDenom * NUM_BL_TIME_STAMPS * MIN_BLOCK_SIZE_SAMPLES * 1000; - -/* -static FILE* pFile = fopen("v.dat", "w"); -for (i = 0; i < VEC_LEN_SAM_OFFS_EST; i++) - fprintf(pFile, "%d %d\n", veciTimeElapsed[i], veciTiStIdx[i]); -fflush(pFile); -*/ - } - -/* -static FILE* pFile = fopen("v.dat", "w"); -fprintf(pFile, "%e\n", dSamRateEst); -fflush(pFile); -*/ - -} diff --git a/src/channel.h b/src/channel.h index 1d634957..0e6841aa 100755 --- a/src/channel.h +++ b/src/channel.h @@ -99,6 +99,9 @@ public: void SetRemoteChanGain ( const int iId, const double dGain ) { Protocol.CreateChanGainMes ( iId, dGain ); } + void SetMinBlockSize ( const int iNewMinBlockSize ); + int GetMinBlockSize() { return iCurMinBlockSize; } + void SetSockBufSize ( const int iNumBlocks ); int GetSockBufSize() { return iCurSockBufSize; } @@ -137,8 +140,8 @@ protected: void SetNetwInBlSiFact ( const int iNewBlockSizeFactor ); // audio compression - CAudioCompression AudioCompressionIn; - int iAudComprSizeIn; + CAudioCompression AudioCompressionInLowQSampRate; + CAudioCompression AudioCompressionInHighQSampRate; CAudioCompression AudioCompressionOut; int iAudComprSizeOut; @@ -172,7 +175,10 @@ protected: bool bIsEnabled; - int vecNetwInBufSizes[MAX_NET_BLOCK_SIZE_FACTOR]; + int vecNetwInBufSizesAudLQ[MAX_NET_BLOCK_SIZE_FACTOR]; + int vecNetwInBufSizesAudHQ[MAX_NET_BLOCK_SIZE_FACTOR]; + + int iCurMinBlockSize; int iCurNetwInBlSiFact; int iCurNetwOutBlSiFact; @@ -298,26 +304,4 @@ signals: void MessReadyForSending ( int iChID, CVector vecMessage ); }; - -/* Sample rate offset estimation -------------------------------------------- */ -class CSampleOffsetEst -{ -public: - CSampleOffsetEst() { Init(); } - virtual ~CSampleOffsetEst() {} - - void Init(); - void AddTimeStampIdx ( const int iTimeStampIdx ); - double GetSamRate() { return dSamRateEst; } - -protected: - QTime RefTime; - int iAccTiStVal; - double dSamRateEst; - CVector veciTimeElapsed; - CVector veciTiStIdx; - int iInitCnt; -}; - - #endif /* !defined ( CHANNEL_HOIH9345KJH98_3_4344_BB23945IUHF1912__INCLUDED_ ) */ diff --git a/src/global.h b/src/global.h index 7b6aec94..3dac97de 100755 --- a/src/global.h +++ b/src/global.h @@ -53,7 +53,11 @@ #define LLCON_PORT_NUMBER 22122 // server sample rate -#define SERVER_SAMPLE_RATE 24000 +#define SERVER_SAMPLE_RATE 24000 // TODO: 32000 + +// client low quality audio sample rate (high quality is the same as the server +// sample rate) +#define CLIENT_LOWQUALITY_SAMPLE_RATE 24000 // sound card sample rate. Should be always 48 kHz to avoid sound card driver // internal sample rate conversion which might be buggy @@ -63,7 +67,9 @@ // of this duration #define MIN_BLOCK_DURATION_MS 2 // ms -#define MIN_BLOCK_SIZE_SAMPLES ( MIN_BLOCK_DURATION_MS * SERVER_SAMPLE_RATE / 1000 ) +// TODO rename MIN_BLOCK_SIZE_SAMPLES -> MIN_CLIENT_LQ_BLOCK_SIZE_SAMPLES +#define MIN_BLOCK_SIZE_SAMPLES ( MIN_BLOCK_DURATION_MS * CLIENT_LOWQUALITY_SAMPLE_RATE / 1000 ) +#define MIN_SERVER_BLOCK_SIZE_SAMPLES ( MIN_BLOCK_DURATION_MS * SERVER_SAMPLE_RATE / 1000 ) #define MIN_SND_CRD_BLOCK_SIZE_SAMPLES ( MIN_BLOCK_DURATION_MS * SND_CRD_SAMPLE_RATE / 1000 ) // maximum value of factor for network block size diff --git a/src/server.cpp b/src/server.cpp index dd3813ca..17e0a798 100755 --- a/src/server.cpp +++ b/src/server.cpp @@ -29,7 +29,7 @@ CServer::CServer ( const bool bUseLogging, const quint16 iPortNumber ) : Socket ( &ChannelSet, this, iPortNumber ) { - 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 ); @@ -97,7 +97,7 @@ void CServer::Stop() 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 @@ -150,7 +150,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(); @@ -158,7 +158,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/socket.h b/src/socket.h index 02c2c64e..524af52f 100755 --- a/src/socket.h +++ b/src/socket.h @@ -36,7 +36,7 @@ /* Definitions ****************************************************************/ -// maximum block size for network input buffer. Consider two bytes per sample +// 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 )