2006-01-28 12:29:22 +01:00
|
|
|
/******************************************************************************\
|
|
|
|
* Copyright (c) 2004-2006
|
|
|
|
*
|
|
|
|
* Author(s):
|
2006-11-25 15:46:57 +01:00
|
|
|
* Volker Fischer
|
2006-01-28 12:29:22 +01:00
|
|
|
*
|
|
|
|
******************************************************************************
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify it under
|
|
|
|
* the terms of the GNU General Public License as published by the Free Software
|
|
|
|
* Foundation; either version 2 of the License, or (at your option) any later
|
|
|
|
* version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
|
|
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
|
|
* details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License along with
|
|
|
|
* this program; if not, write to the Free Software Foundation, Inc.,
|
|
|
|
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
*
|
|
|
|
\******************************************************************************/
|
|
|
|
|
|
|
|
#include "channel.h"
|
|
|
|
|
|
|
|
|
|
|
|
/******************************************************************************\
|
|
|
|
* CChannelSet *
|
2006-03-04 12:11:26 +01:00
|
|
|
\******************************************************************************/
|
|
|
|
CChannelSet::CChannelSet()
|
|
|
|
{
|
2006-11-25 15:46:57 +01:00
|
|
|
// make sure we have MAX_NUM_CHANNELS connections!!!
|
|
|
|
// send message
|
|
|
|
QObject::connect(&vecChannels[0],SIGNAL(MessReadyForSending(CVector<uint8_t>)),this,SLOT(OnSendProtMessCh0(CVector<uint8_t>)));
|
|
|
|
QObject::connect(&vecChannels[1],SIGNAL(MessReadyForSending(CVector<uint8_t>)),this,SLOT(OnSendProtMessCh1(CVector<uint8_t>)));
|
|
|
|
QObject::connect(&vecChannels[2],SIGNAL(MessReadyForSending(CVector<uint8_t>)),this,SLOT(OnSendProtMessCh2(CVector<uint8_t>)));
|
|
|
|
QObject::connect(&vecChannels[3],SIGNAL(MessReadyForSending(CVector<uint8_t>)),this,SLOT(OnSendProtMessCh3(CVector<uint8_t>)));
|
|
|
|
QObject::connect(&vecChannels[4],SIGNAL(MessReadyForSending(CVector<uint8_t>)),this,SLOT(OnSendProtMessCh4(CVector<uint8_t>)));
|
|
|
|
// QObject::connect(&vecChannels[5],SIGNAL(MessReadyForSending(CVector<uint8_t>)),this,SLOT(OnSendProtMessCh5(CVector<uint8_t>)));
|
|
|
|
// QObject::connect(&vecChannels[6],SIGNAL(MessReadyForSending(CVector<uint8_t>)),this,SLOT(OnSendProtMessCh6(CVector<uint8_t>)));
|
|
|
|
// QObject::connect(&vecChannels[7],SIGNAL(MessReadyForSending(CVector<uint8_t>)),this,SLOT(OnSendProtMessCh7(CVector<uint8_t>)));
|
|
|
|
// QObject::connect(&vecChannels[8],SIGNAL(MessReadyForSending(CVector<uint8_t>)),this,SLOT(OnSendProtMessCh8(CVector<uint8_t>)));
|
|
|
|
// QObject::connect(&vecChannels[9],SIGNAL(MessReadyForSending(CVector<uint8_t>)),this,SLOT(OnSendProtMessCh9(CVector<uint8_t>)));
|
|
|
|
|
|
|
|
// request jitter buffer size
|
|
|
|
QObject::connect(&vecChannels[0],SIGNAL(NewConnection()),this,SLOT(OnNewConnectionCh0()));
|
|
|
|
QObject::connect(&vecChannels[1],SIGNAL(NewConnection()),this,SLOT(OnNewConnectionCh1()));
|
|
|
|
QObject::connect(&vecChannels[2],SIGNAL(NewConnection()),this,SLOT(OnNewConnectionCh2()));
|
|
|
|
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()));
|
2006-03-04 12:12:47 +01:00
|
|
|
}
|
2006-11-04 14:09:42 +01:00
|
|
|
|
|
|
|
void CChannelSet::CreateAndSendChanListForAllConClients()
|
|
|
|
{
|
2006-11-25 15:46:57 +01:00
|
|
|
int i;
|
|
|
|
CVector<int> veciChanIDs ( 0 );
|
|
|
|
CVector<uint32_t> veciIpAddrs ( 0 );
|
|
|
|
CVector<std::string> vecstrNames ( 0 );
|
|
|
|
|
|
|
|
// the channel ID is defined as the order of the channels in the channel
|
|
|
|
// set where we do not care about not-connected channels
|
|
|
|
int iCurChanID = 0;
|
|
|
|
|
|
|
|
// look for free channels
|
|
|
|
for ( i = 0; i < MAX_NUM_CHANNELS; i++ )
|
|
|
|
{
|
|
|
|
if ( vecChannels[i].IsConnected() )
|
|
|
|
{
|
|
|
|
// append channel ID, IP address and channel name to storing vectors
|
|
|
|
veciChanIDs.Add ( i );
|
|
|
|
veciIpAddrs.Add ( vecChannels[i].GetAddress().InetAddr.ip4Addr() );
|
|
|
|
vecstrNames.Add ( vecChannels[i].GetName() );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// now send connected channels list to all connected clients
|
|
|
|
for ( i = 0; i < MAX_NUM_CHANNELS; i++ )
|
|
|
|
{
|
|
|
|
if ( vecChannels[i].IsConnected() )
|
|
|
|
{
|
|
|
|
// send message
|
|
|
|
vecChannels[i].CreateConClientListMes ( veciChanIDs, veciIpAddrs, vecstrNames );
|
|
|
|
}
|
|
|
|
}
|
2006-11-04 14:09:42 +01:00
|
|
|
}
|
2006-03-04 12:11:26 +01:00
|
|
|
|
2006-01-28 12:29:22 +01:00
|
|
|
int CChannelSet::GetFreeChan()
|
|
|
|
{
|
2006-11-25 15:46:57 +01:00
|
|
|
/* look for a free channel */
|
|
|
|
for ( int i = 0; i < MAX_NUM_CHANNELS; i++ )
|
|
|
|
{
|
|
|
|
if ( !vecChannels[i].IsConnected() )
|
|
|
|
{
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* no free channel found, return invalid ID */
|
|
|
|
return INVALID_CHANNEL_ID;
|
2006-01-28 12:29:22 +01:00
|
|
|
}
|
|
|
|
|
2006-02-17 22:08:05 +01:00
|
|
|
int CChannelSet::CheckAddr ( const CHostAddress& Addr )
|
2006-01-28 12:29:22 +01:00
|
|
|
{
|
2006-11-25 15:46:57 +01:00
|
|
|
CHostAddress InetAddr;
|
2006-01-28 12:29:22 +01:00
|
|
|
|
2006-11-25 15:46:57 +01:00
|
|
|
/* Check for all possible channels if IP is already in use */
|
|
|
|
for ( int i = 0; i < MAX_NUM_CHANNELS; i++ )
|
2006-01-28 12:29:22 +01:00
|
|
|
{
|
2006-11-25 15:46:57 +01:00
|
|
|
if ( vecChannels[i].GetAddress ( InetAddr ) )
|
|
|
|
{
|
|
|
|
/* IP found, return channel number */
|
|
|
|
if ( InetAddr == Addr )
|
|
|
|
{
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* IP not found, return invalid ID */
|
|
|
|
return INVALID_CHANNEL_ID;
|
2006-01-28 12:29:22 +01:00
|
|
|
}
|
|
|
|
|
2006-02-17 22:08:05 +01:00
|
|
|
bool CChannelSet::PutData ( const CVector<unsigned char>& vecbyRecBuf,
|
2006-11-25 15:46:57 +01:00
|
|
|
const int iNumBytesRead,
|
|
|
|
const CHostAddress& HostAdr )
|
2006-01-28 12:29:22 +01:00
|
|
|
{
|
2006-11-25 15:46:57 +01:00
|
|
|
bool bRet = false;
|
|
|
|
bool bCreateChanList = false;
|
|
|
|
|
|
|
|
Mutex.lock();
|
|
|
|
{
|
|
|
|
bool bChanOK = true;
|
|
|
|
|
|
|
|
/* get channel ID --------------------------------------------------- */
|
|
|
|
/* check address */
|
|
|
|
int iCurChanID = CheckAddr ( HostAdr );
|
|
|
|
|
|
|
|
if ( iCurChanID == INVALID_CHANNEL_ID )
|
|
|
|
{
|
|
|
|
/* a new client is calling, look for free channel */
|
|
|
|
iCurChanID = GetFreeChan();
|
|
|
|
|
|
|
|
if ( iCurChanID != INVALID_CHANNEL_ID )
|
|
|
|
{
|
|
|
|
vecChannels[iCurChanID].SetAddress ( HostAdr );
|
|
|
|
|
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* no free channel available */
|
|
|
|
bChanOK = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* put received data in jitter buffer ------------------------------- */
|
|
|
|
if ( bChanOK )
|
|
|
|
{
|
|
|
|
/* put packet in socket buffer */
|
|
|
|
switch ( vecChannels[iCurChanID].PutData ( vecbyRecBuf, iNumBytesRead ) )
|
|
|
|
{
|
|
|
|
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
|
|
|
|
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
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PS_PROT_ERR:
|
|
|
|
PostWinMessage ( MS_JIT_BUF_PUT, MUL_COL_LED_YELLOW, iCurChanID );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// after data is put in channel buffer, create channel list message if
|
|
|
|
// requested
|
|
|
|
if ( bCreateChanList )
|
|
|
|
{
|
|
|
|
CreateAndSendChanListForAllConClients();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Mutex.unlock();
|
|
|
|
|
|
|
|
return bRet;
|
2006-01-28 12:29:22 +01:00
|
|
|
}
|
|
|
|
|
2006-02-17 22:08:05 +01:00
|
|
|
void CChannelSet::GetBlockAllConC ( CVector<int>& vecChanID,
|
2006-11-25 15:46:57 +01:00
|
|
|
CVector<CVector<double> >& vecvecdData,
|
|
|
|
CVector<double>& vecdGains )
|
2006-01-28 12:29:22 +01:00
|
|
|
{
|
2006-11-25 15:46:57 +01:00
|
|
|
/* init temporal data vector and clear input buffers */
|
|
|
|
CVector<double> vecdData ( MIN_BLOCK_SIZE_SAMPLES );
|
|
|
|
|
|
|
|
vecChanID.Init ( 0 );
|
|
|
|
vecvecdData.Init ( 0 );
|
|
|
|
vecdGains.Init ( 0 );
|
|
|
|
|
|
|
|
/* make put and get calls thread safe. Do not forget to unlock mutex
|
|
|
|
afterwards! */
|
|
|
|
Mutex.lock();
|
|
|
|
{
|
|
|
|
/* Check all possible channels */
|
|
|
|
for ( int i = 0; i < MAX_NUM_CHANNELS; i++ )
|
|
|
|
{
|
|
|
|
/* read out all input buffers to decrease timeout counter on
|
|
|
|
disconnected channels */
|
|
|
|
const bool bGetOK = vecChannels[i].GetData ( vecdData );
|
|
|
|
|
|
|
|
if ( vecChannels[i].IsConnected() )
|
|
|
|
{
|
|
|
|
/* add ID, gain and data */
|
|
|
|
vecChanID.Add ( i );
|
|
|
|
vecdGains.Add ( vecChannels[i].GetGain() );
|
|
|
|
|
|
|
|
const int iOldSize = vecvecdData.Size();
|
|
|
|
vecvecdData.Enlarge ( 1 );
|
|
|
|
vecvecdData[iOldSize].Init ( vecdData.Size() );
|
|
|
|
vecvecdData[iOldSize] = vecdData;
|
|
|
|
|
|
|
|
/* send message for get status (for GUI) */
|
|
|
|
if ( bGetOK )
|
|
|
|
{
|
|
|
|
PostWinMessage ( MS_JIT_BUF_GET, MUL_COL_LED_GREEN, i );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
PostWinMessage ( MS_JIT_BUF_GET, MUL_COL_LED_RED, i );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Mutex.unlock(); /* release mutex */
|
2006-01-28 12:29:22 +01:00
|
|
|
}
|
|
|
|
|
2006-02-17 22:08:05 +01:00
|
|
|
void CChannelSet::GetConCliParam ( CVector<CHostAddress>& vecHostAddresses,
|
2006-11-25 15:46:57 +01:00
|
|
|
CVector<int>& veciJitBufSize,
|
|
|
|
CVector<int>& veciNetwOutBlSiFact,
|
|
|
|
CVector<int>& veciNetwInBlSiFact )
|
2006-01-28 12:29:22 +01:00
|
|
|
{
|
2006-11-25 15:46:57 +01:00
|
|
|
CHostAddress InetAddr;
|
|
|
|
|
|
|
|
/* init return values */
|
|
|
|
vecHostAddresses.Init ( MAX_NUM_CHANNELS );
|
|
|
|
veciJitBufSize.Init ( MAX_NUM_CHANNELS );
|
|
|
|
veciNetwOutBlSiFact.Init ( MAX_NUM_CHANNELS );
|
|
|
|
veciNetwInBlSiFact.Init ( MAX_NUM_CHANNELS );
|
|
|
|
|
|
|
|
/* Check all possible channels */
|
|
|
|
for ( int i = 0; i < MAX_NUM_CHANNELS; i++ )
|
|
|
|
{
|
|
|
|
if ( vecChannels[i].GetAddress ( InetAddr ) )
|
|
|
|
{
|
|
|
|
/* get requested data */
|
|
|
|
vecHostAddresses[i] = InetAddr;
|
|
|
|
veciJitBufSize[i] = vecChannels[i].GetSockBufSize ();
|
|
|
|
veciNetwOutBlSiFact[i] = vecChannels[i].GetNetwBufSizeFactOut ();
|
|
|
|
veciNetwInBlSiFact[i] = vecChannels[i].GetNetwBufSizeFactIn ();
|
|
|
|
}
|
|
|
|
}
|
2006-01-28 12:29:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/******************************************************************************\
|
|
|
|
* CChannel *
|
|
|
|
\******************************************************************************/
|
2006-11-04 10:57:59 +01:00
|
|
|
CChannel::CChannel() : sName ( "" ), dGain ( (double) 1.0 )
|
2006-03-13 20:32:23 +01:00
|
|
|
{
|
2006-11-25 15:46:57 +01:00
|
|
|
// query all possible network in buffer sizes for determining if an
|
|
|
|
// audio packet was received
|
|
|
|
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 (
|
|
|
|
( i + 1 ) * MIN_BLOCK_SIZE_SAMPLES,
|
|
|
|
CAudioCompression::CT_IMAADPCM );
|
|
|
|
}
|
2006-03-13 20:32:23 +01:00
|
|
|
|
2006-11-25 15:46:57 +01:00
|
|
|
iCurNetwInBlSiFact = DEF_NET_BLOCK_SIZE_FACTOR;
|
2006-03-13 20:32:23 +01:00
|
|
|
|
2006-11-25 15:46:57 +01:00
|
|
|
/* init the socket buffer */
|
|
|
|
SetSockBufSize ( DEF_NET_BUF_SIZE_NUM_BL );
|
2006-01-28 12:29:22 +01:00
|
|
|
|
2006-11-25 15:46:57 +01:00
|
|
|
// set initial input and output block size factors
|
|
|
|
SetNetwBufSizeFactOut ( iCurNetwInBlSiFact );
|
|
|
|
SetNetwInBlSiFact ( iCurNetwInBlSiFact );
|
2006-03-13 20:32:23 +01:00
|
|
|
|
2006-11-25 15:46:57 +01:00
|
|
|
/* init time-out for the buffer with zero -> no connection */
|
|
|
|
iConTimeOut = 0;
|
2006-02-26 11:50:47 +01:00
|
|
|
|
|
|
|
|
2006-11-25 15:46:57 +01:00
|
|
|
/* connections ---------------------------------------------------------- */
|
|
|
|
QObject::connect ( &Protocol,
|
|
|
|
SIGNAL ( MessReadyForSending ( CVector<uint8_t> ) ),
|
|
|
|
this, SLOT ( OnSendProtMessage ( CVector<uint8_t> ) ) );
|
2006-02-27 20:45:27 +01:00
|
|
|
|
2006-11-25 15:46:57 +01:00
|
|
|
QObject::connect ( &Protocol, SIGNAL ( ChangeJittBufSize ( int ) ),
|
|
|
|
this, SLOT ( OnJittBufSizeChange ( int ) ) );
|
2006-03-07 22:26:40 +01:00
|
|
|
|
2006-11-25 15:46:57 +01:00
|
|
|
QObject::connect ( &Protocol, SIGNAL ( ReqJittBufSize() ),
|
|
|
|
SIGNAL ( ReqJittBufSize() ) );
|
2006-03-12 12:50:35 +01:00
|
|
|
|
2006-11-25 15:46:57 +01:00
|
|
|
QObject::connect ( &Protocol, SIGNAL ( ChangeNetwBlSiFact ( int ) ),
|
|
|
|
this, SLOT ( OnNetwBlSiFactChange ( int ) ) );
|
2006-02-26 11:50:47 +01:00
|
|
|
}
|
2006-03-04 11:24:40 +01:00
|
|
|
|
2006-03-11 21:35:38 +01:00
|
|
|
void CChannel::SetNetwInBlSiFact ( const int iNewBlockSizeFactor )
|
|
|
|
{
|
2006-11-25 15:46:57 +01:00
|
|
|
// store new value
|
|
|
|
iCurNetwInBlSiFact = iNewBlockSizeFactor;
|
2006-03-11 21:35:38 +01:00
|
|
|
|
2006-11-25 15:46:57 +01:00
|
|
|
/* init audio compression unit */
|
|
|
|
iAudComprSizeIn = AudioCompressionIn.Init (
|
|
|
|
iNewBlockSizeFactor * MIN_BLOCK_SIZE_SAMPLES,
|
|
|
|
CAudioCompression::CT_IMAADPCM );
|
2006-03-11 21:35:38 +01:00
|
|
|
|
2006-11-25 15:46:57 +01:00
|
|
|
// initial value for connection time out counter
|
|
|
|
iConTimeOutStartVal = ( CON_TIME_OUT_SEC_MAX * 1000 ) /
|
|
|
|
( iNewBlockSizeFactor * MIN_BLOCK_DURATION_MS );
|
2006-03-12 13:24:42 +01:00
|
|
|
|
2006-11-25 15:46:57 +01:00
|
|
|
// socket buffer must be adjusted
|
|
|
|
SetSockBufSize ( GetSockBufSize() );
|
2006-03-11 21:35:38 +01:00
|
|
|
}
|
|
|
|
|
2006-03-13 21:23:05 +01:00
|
|
|
void CChannel::SetNetwBufSizeFactOut ( const int iNewNetwBlSiFactOut )
|
2006-03-11 21:35:38 +01:00
|
|
|
{
|
2006-11-25 15:46:57 +01:00
|
|
|
// store new value
|
|
|
|
iCurNetwOutBlSiFact = iNewNetwBlSiFactOut;
|
2006-03-13 21:23:05 +01:00
|
|
|
|
2006-11-25 15:46:57 +01:00
|
|
|
/* init audio compression unit */
|
|
|
|
iAudComprSizeOut = AudioCompressionOut.Init (
|
|
|
|
iNewNetwBlSiFactOut * MIN_BLOCK_SIZE_SAMPLES,
|
|
|
|
CAudioCompression::CT_IMAADPCM );
|
2006-03-11 21:35:38 +01:00
|
|
|
|
2006-11-25 15:46:57 +01:00
|
|
|
/* init conversion buffer */
|
|
|
|
ConvBuf.Init ( iNewNetwBlSiFactOut * MIN_BLOCK_SIZE_SAMPLES );
|
2006-03-13 21:23:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void CChannel::OnNetwBlSiFactChange ( int iNewNetwBlSiFact )
|
|
|
|
{
|
|
|
|
// TEST
|
2006-09-03 11:49:15 +02:00
|
|
|
//qDebug ( "new network block size factor: %d", iNewNetwBlSiFact );
|
2006-03-13 21:23:05 +01:00
|
|
|
|
2006-11-25 15:46:57 +01:00
|
|
|
SetNetwBufSizeFactOut ( iNewNetwBlSiFact );
|
2006-03-11 21:35:38 +01:00
|
|
|
}
|
|
|
|
|
2006-03-04 11:24:40 +01:00
|
|
|
void CChannel::OnSendProtMessage ( CVector<uint8_t> vecMessage )
|
|
|
|
{
|
2006-11-25 15:46:57 +01:00
|
|
|
// only send messages if we are connected, otherwise delete complete queue
|
|
|
|
if ( IsConnected() )
|
|
|
|
{
|
|
|
|
// emit message to actually send the data
|
|
|
|
emit MessReadyForSending ( vecMessage );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// delete send message queue
|
|
|
|
Protocol.DeleteSendMessQueue();
|
|
|
|
}
|
2006-03-04 11:24:40 +01:00
|
|
|
}
|
2006-03-12 12:50:35 +01:00
|
|
|
|
2006-03-12 11:02:01 +01:00
|
|
|
void CChannel::SetSockBufSize ( const int iNumBlocks )
|
2006-01-28 12:29:22 +01:00
|
|
|
{
|
2006-11-25 15:46:57 +01:00
|
|
|
/* this opperation must be done with mutex */
|
|
|
|
Mutex.lock();
|
|
|
|
{
|
|
|
|
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 );
|
|
|
|
}
|
|
|
|
Mutex.unlock();
|
2006-01-28 12:29:22 +01:00
|
|
|
}
|
2006-02-27 20:45:27 +01:00
|
|
|
|
|
|
|
void CChannel::OnJittBufSizeChange ( int iNewJitBufSize )
|
|
|
|
{
|
2006-03-01 20:46:44 +01:00
|
|
|
// TEST
|
2006-09-03 11:49:15 +02:00
|
|
|
//qDebug ( "new jitter buffer size: %d", iNewJitBufSize );
|
2006-03-01 20:46:44 +01:00
|
|
|
|
2006-11-25 15:46:57 +01:00
|
|
|
SetSockBufSize ( iNewJitBufSize );
|
2006-02-27 20:45:27 +01:00
|
|
|
}
|
2006-03-12 12:50:35 +01:00
|
|
|
|
2006-01-28 12:29:22 +01:00
|
|
|
bool CChannel::GetAddress(CHostAddress& RetAddr)
|
|
|
|
{
|
2006-11-25 15:46:57 +01:00
|
|
|
if ( IsConnected() )
|
|
|
|
{
|
|
|
|
RetAddr = InetAddr;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
RetAddr = CHostAddress();
|
|
|
|
return false;
|
|
|
|
}
|
2006-01-28 12:29:22 +01:00
|
|
|
}
|
|
|
|
|
2006-03-06 18:04:07 +01:00
|
|
|
EPutDataStat CChannel::PutData ( const CVector<unsigned char>& vecbyData,
|
2006-11-25 15:46:57 +01:00
|
|
|
int iNumBytes )
|
2006-01-28 12:29:22 +01:00
|
|
|
{
|
2006-11-25 15:46:57 +01:00
|
|
|
EPutDataStat eRet = PS_GEN_ERROR;
|
|
|
|
bool bNewConnection = false;
|
|
|
|
bool bIsAudioPacket = false;
|
|
|
|
|
|
|
|
// 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] )
|
|
|
|
{
|
|
|
|
bIsAudioPacket = true;
|
|
|
|
|
|
|
|
// check if we are correctly initialized
|
|
|
|
const int iNewNetwInBlSiFact = i + 1;
|
|
|
|
if ( iNewNetwInBlSiFact != iCurNetwInBlSiFact )
|
|
|
|
{
|
|
|
|
// re-initialize to new value
|
|
|
|
SetNetwInBlSiFact ( iNewNetwInBlSiFact );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* only process if packet has correct size */
|
|
|
|
if ( bIsAudioPacket )
|
|
|
|
{
|
|
|
|
Mutex.lock();
|
|
|
|
{
|
|
|
|
/* decompress audio */
|
|
|
|
CVector<short> vecsDecomprAudio ( AudioCompressionIn.Decode ( vecbyData ) );
|
|
|
|
|
|
|
|
/* do resampling to compensate for sample rate offsets in the
|
|
|
|
different sound cards of the clients */
|
2006-01-28 12:29:22 +01:00
|
|
|
/*
|
|
|
|
for (int i = 0; i < BLOCK_SIZE_SAMPLES; i++)
|
2006-11-25 15:46:57 +01:00
|
|
|
vecdResInData[i] = (double) vecsData[i];
|
2006-01-28 12:29:22 +01:00
|
|
|
|
|
|
|
const int iInSize = ResampleObj.Resample(vecdResInData, vecdResOutData,
|
2006-11-25 15:46:57 +01:00
|
|
|
(double) SAMPLE_RATE / (SAMPLE_RATE - dSamRateOffset));
|
2006-01-28 12:29:22 +01:00
|
|
|
*/
|
|
|
|
|
2006-03-11 21:35:38 +01:00
|
|
|
vecdResOutData.Init ( iCurNetwInBlSiFact * MIN_BLOCK_SIZE_SAMPLES );
|
|
|
|
for ( int i = 0; i < iCurNetwInBlSiFact * MIN_BLOCK_SIZE_SAMPLES; i++ ) {
|
2006-11-25 15:46:57 +01:00
|
|
|
vecdResOutData[i] = (double) vecsDecomprAudio[i];
|
2006-03-11 21:35:38 +01:00
|
|
|
}
|
2006-01-28 12:29:22 +01:00
|
|
|
|
2006-11-25 15:46:57 +01:00
|
|
|
if ( SockBuf.Put ( vecdResOutData ) )
|
|
|
|
{
|
|
|
|
eRet = PS_AUDIO_OK;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
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
|
|
|
|
{
|
|
|
|
// only use protocol data if channel is connected
|
|
|
|
if ( IsConnected() )
|
|
|
|
{
|
|
|
|
// this seems not to be an audio block, parse the message
|
|
|
|
if ( Protocol.ParseMessage ( vecbyData, iNumBytes ) )
|
|
|
|
{
|
|
|
|
eRet = PS_PROT_OK;
|
|
|
|
|
|
|
|
// create message for protocol status
|
|
|
|
emit ProtocolStatus ( true );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
eRet = PS_PROT_ERR;
|
|
|
|
|
|
|
|
// create message for protocol status
|
|
|
|
emit ProtocolStatus ( false );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// inform other objects that new connection was established
|
|
|
|
if ( bNewConnection )
|
|
|
|
{
|
|
|
|
// log new connection
|
|
|
|
CHostAddress address ( GetAddress() );
|
|
|
|
qDebug ( CLogTimeDate::toString() + "Connected with IP %s",
|
|
|
|
address.InetAddr.toString().latin1() );
|
|
|
|
|
|
|
|
emit NewConnection();
|
|
|
|
}
|
|
|
|
|
|
|
|
return eRet;
|
2006-01-28 12:29:22 +01:00
|
|
|
}
|
|
|
|
|
2006-02-26 11:50:47 +01:00
|
|
|
bool CChannel::GetData ( CVector<double>& vecdData )
|
2006-03-06 18:04:07 +01:00
|
|
|
{
|
2006-11-25 15:46:57 +01:00
|
|
|
bool bGetOK = false;
|
|
|
|
|
|
|
|
Mutex.lock(); /* get mutex lock */
|
|
|
|
{
|
|
|
|
bGetOK = SockBuf.Get ( vecdData );
|
|
|
|
|
|
|
|
if ( !bGetOK )
|
|
|
|
{
|
|
|
|
/* decrease time-out counter */
|
|
|
|
if ( iConTimeOut > 0 )
|
|
|
|
{
|
|
|
|
iConTimeOut--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Mutex.unlock(); /* get mutex unlock */
|
|
|
|
|
|
|
|
return bGetOK;
|
2006-01-28 12:29:22 +01:00
|
|
|
}
|
|
|
|
|
2006-03-12 14:19:41 +01:00
|
|
|
CVector<unsigned char> CChannel::PrepSendPacket ( const CVector<short>& vecsNPacket )
|
2006-01-28 12:29:22 +01:00
|
|
|
{
|
2006-11-25 15:46:57 +01:00
|
|
|
/* if the block is not ready we have to initialize with zero length to
|
|
|
|
tell the following network send routine that nothing should be sent */
|
|
|
|
CVector<unsigned char> vecbySendBuf ( 0 );
|
|
|
|
|
|
|
|
/* 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() );
|
|
|
|
}
|
|
|
|
|
|
|
|
return vecbySendBuf;
|
2006-01-28 12:29:22 +01:00
|
|
|
}
|
2006-02-12 15:26:46 +01:00
|
|
|
|
2006-03-04 11:24:40 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2006-01-28 12:29:22 +01:00
|
|
|
|
|
|
|
/******************************************************************************\
|
|
|
|
* CSampleOffsetEst *
|
|
|
|
\******************************************************************************/
|
|
|
|
void CSampleOffsetEst::Init()
|
|
|
|
{
|
2006-11-25 15:46:57 +01:00
|
|
|
/* init sample rate estimation */
|
|
|
|
dSamRateEst = SAMPLE_RATE;
|
2006-01-28 12:29:22 +01:00
|
|
|
|
2006-11-25 15:46:57 +01:00
|
|
|
/* init vectors storing the data */
|
|
|
|
veciTimeElapsed.Init(VEC_LEN_SAM_OFFS_EST);
|
|
|
|
veciTiStIdx.Init(VEC_LEN_SAM_OFFS_EST);
|
2006-01-28 12:29:22 +01:00
|
|
|
|
2006-11-25 15:46:57 +01:00
|
|
|
/* 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();
|
2006-01-28 12:29:22 +01:00
|
|
|
|
2006-11-25 15:46:57 +01:00
|
|
|
/* init accumulated time stamp variable */
|
|
|
|
iAccTiStVal = 0;
|
2006-01-28 12:29:22 +01:00
|
|
|
|
2006-11-25 15:46:57 +01:00
|
|
|
/* init count (do not ship any result in init phase) */
|
|
|
|
iInitCnt = VEC_LEN_SAM_OFFS_EST + 1;
|
2006-01-28 12:29:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void CSampleOffsetEst::AddTimeStampIdx(const int iTimeStampIdx)
|
|
|
|
{
|
2006-11-25 15:46:57 +01:00
|
|
|
int i;
|
2006-01-28 12:29:22 +01:00
|
|
|
|
2006-11-25 15:46:57 +01:00
|
|
|
const int iLastIdx = VEC_LEN_SAM_OFFS_EST - 1;
|
2006-01-28 12:29:22 +01:00
|
|
|
|
2006-11-25 15:46:57 +01:00
|
|
|
/* take care of wrap of the time stamp index (byte wrap) */
|
|
|
|
if (iTimeStampIdx < veciTiStIdx[iLastIdx] - iAccTiStVal)
|
|
|
|
iAccTiStVal += _MAXBYTE + 1;
|
2006-01-28 12:29:22 +01:00
|
|
|
|
2006-11-25 15:46:57 +01:00
|
|
|
/* 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];
|
|
|
|
}
|
2006-01-28 12:29:22 +01:00
|
|
|
|
2006-11-25 15:46:57 +01:00
|
|
|
/* add new data */
|
|
|
|
veciTimeElapsed[iLastIdx] = RefTime.elapsed();
|
|
|
|
veciTiStIdx[iLastIdx] = iAccTiStVal + iTimeStampIdx;
|
2006-01-28 12:29:22 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
static FILE* pFile = fopen("v.dat", "w");
|
|
|
|
for (i = 0; i < VEC_LEN_SAM_OFFS_EST; i++)
|
2006-11-25 15:46:57 +01:00
|
|
|
fprintf(pFile, "%d\n", veciTimeElapsed[i]);
|
2006-01-28 12:29:22 +01:00
|
|
|
fflush(pFile);
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
2006-11-25 15:46:57 +01:00
|
|
|
/* 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;
|
2006-01-28 12:29:22 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
static FILE* pFile = fopen("v.dat", "w");
|
|
|
|
for (i = 0; i < VEC_LEN_SAM_OFFS_EST; i++)
|
2006-11-25 15:46:57 +01:00
|
|
|
fprintf(pFile, "%d %d\n", veciTimeElapsed[i], veciTiStIdx[i]);
|
2006-01-28 12:29:22 +01:00
|
|
|
fflush(pFile);
|
|
|
|
*/
|
2006-11-25 15:46:57 +01:00
|
|
|
}
|
2006-01-28 12:29:22 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
static FILE* pFile = fopen("v.dat", "w");
|
|
|
|
fprintf(pFile, "%e\n", dSamRateEst);
|
|
|
|
fflush(pFile);
|
|
|
|
*/
|
|
|
|
|
|
|
|
}
|