some work for HQ audio

This commit is contained in:
Volker Fischer 2008-08-05 18:55:40 +00:00
parent 0b7c401c9a
commit 91f7ef489a
5 changed files with 88 additions and 158 deletions

View File

@ -421,30 +421,43 @@ void CChannelSet::GetConCliParam ( CVector<CHostAddress>& 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<unsigned char>& 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<unsigned char>& 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<unsigned char>& 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<short> vecsDecomprAudio ( AudioCompressionIn.Decode ( vecbyData ) );
CVector<short> 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<unsigned char> CChannel::PrepSendPacket ( const CVector<short>& 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);
*/
}

View File

@ -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<uint8_t> 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<long int> veciTimeElapsed;
CVector<long int> veciTiStIdx;
int iInitCnt;
};
#endif /* !defined ( CHANNEL_HOIH9345KJH98_3_4344_BB23945IUHF1912__INCLUDED_ ) */

View File

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

View File

@ -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<int> vecChanID;
CVector<CVector<double> > vecvecdData ( MIN_BLOCK_SIZE_SAMPLES );
CVector<CVector<double> > vecvecdData ( MIN_SERVER_BLOCK_SIZE_SAMPLES );
CVector<CVector<double> > vecvecdGains;
// get data from all connected clients
@ -150,7 +150,7 @@ void CServer::OnTimer()
CVector<short> CServer::ProcessData ( CVector<CVector<double> >& vecvecdData,
CVector<double>& vecdGains )
{
CVector<short> vecsOutData ( MIN_BLOCK_SIZE_SAMPLES );
CVector<short> vecsOutData ( MIN_SERVER_BLOCK_SIZE_SAMPLES );
const int iNumClients = vecvecdData.Size();
@ -158,7 +158,7 @@ CVector<short> CServer::ProcessData ( CVector<CVector<double> >& 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;

View File

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