big changes on software structure, intermediate backup checkin -> NOT WORKING correctly right now

This commit is contained in:
Volker Fischer 2009-03-01 11:17:35 +00:00
parent 8843e94822
commit 91071384d2
26 changed files with 557 additions and 1236 deletions

View File

@ -48,12 +48,12 @@ class CSound : public CSoundBase
public:
CSound ( void (*fpNewCallback) ( CVector<short>& 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(); }

View File

@ -134,13 +134,6 @@ protected:
class CAudioCompression
{
public:
enum EAudComprType
{
CT_NONE = 0,
CT_IMAADPCM = 1,
CT_MSADPCM = 2
};
CAudioCompression() {}
virtual ~CAudioCompression() {}

View File

@ -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<CChannelShortInfo>& 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;

View File

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

View File

@ -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<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() ) );
@ -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<CChannelShortInfo> CChannelSet::CreateChannelList()
@ -104,7 +127,7 @@ CVector<CChannelShortInfo> CChannelSet::CreateChannelList()
CVector<CChannelShortInfo> 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<CChannelShortInfo> 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<unsigned char>& 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<unsigned char>& 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<unsigned char>& 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<unsigned char>& 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<unsigned char>& vecbyRecBuf,
}
Mutex.unlock();
return bRet;
return bAudioOK;
}
void CChannelSet::GetBlockAllConC ( CVector<int>& vecChanID,
@ -347,7 +375,7 @@ void CChannelSet::GetBlockAllConC ( CVector<int>& vecChanID,
bool bCreateChanList = false;
// init temporal data vector and clear input buffers
CVector<double> vecdData ( MIN_BLOCK_SIZE_SAMPLES );
CVector<double> vecdData ( MIN_SERVER_BLOCK_SIZE_SAMPLES );
vecChanID.Init ( 0 );
vecvecdData.Init ( 0 );
@ -358,7 +386,7 @@ void CChannelSet::GetBlockAllConC ( CVector<int>& 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<int>& vecChanID,
void CChannelSet::GetConCliParam ( CVector<CHostAddress>& vecHostAddresses,
CVector<QString>& vecsName,
CVector<int>& veciJitBufSize,
CVector<int>& veciNetwOutBlSiFact,
CVector<int>& veciNetwInBlSiFact )
CVector<int>& 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<CHostAddress>& 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<uint8_t> 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<uint8_t> 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<unsigned char>& 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<unsigned char>& 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<unsigned char>& 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<short> vecsDecomprAudio ( AudioCompressionIn.Decode ( vecbyData ) );
// convert received data from short to double
CVector<double> vecdDecomprAudio ( iCurNetwInBlSiFact * MIN_BLOCK_SIZE_SAMPLES );
for ( int i = 0; i < iCurNetwInBlSiFact * MIN_BLOCK_SIZE_SAMPLES; i++ )
const int iAudioSize = vecsDecomprAudio.Size();
CVector<double> vecdDecomprAudio ( iAudioSize );
for ( int i = 0; i < iAudioSize; i++ )
{
vecdDecomprAudio[i] = static_cast<double> ( vecsDecomprAudio[i] );
}
@ -938,21 +1014,28 @@ EPutDataStat CChannel::PutData ( const CVector<unsigned char>& 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<unsigned char> CChannel::PrepSendPacket ( const CVector<short>& vecsNPac
// 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 ) )
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;

View File

@ -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<unsigned char>& 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<sNetwBufferInProps> vecNetwBufferInProps;
CAudioCompression::EAudComprType eAudComprTypeOut;
EAudComprType eAudComprTypeOut;
public slots:
void OnSendProtMessage ( CVector<uint8_t> 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<uint8_t> vecMessage );
@ -237,8 +241,7 @@ public:
void GetConCliParam ( CVector<CHostAddress>& vecHostAddresses,
CVector<QString>& vecsName,
CVector<int>& veciJitBufSize,
CVector<int>& veciNetwOutBlSiFact,
CVector<int>& veciNetwInBlSiFact );
CVector<int>& veciNetwOutBlSiFact );
// access functions for actual channels
bool IsConnected ( const int iChanNum )
@ -284,6 +287,10 @@ public slots:
void OnSendProtMessCh3 ( CVector<uint8_t> mess ) { emit MessReadyForSending ( 3, mess ); }
void OnSendProtMessCh4 ( CVector<uint8_t> mess ) { emit MessReadyForSending ( 4, mess ); }
void OnSendProtMessCh5 ( CVector<uint8_t> mess ) { emit MessReadyForSending ( 5, mess ); }
void OnSendProtMessCh6 ( CVector<uint8_t> mess ) { emit MessReadyForSending ( 6, mess ); }
void OnSendProtMessCh7 ( CVector<uint8_t> mess ) { emit MessReadyForSending ( 7, mess ); }
void OnSendProtMessCh8 ( CVector<uint8_t> mess ) { emit MessReadyForSending ( 8, mess ); }
void OnSendProtMessCh9 ( CVector<uint8_t> 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<uint8_t> vecMessage );

View File

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

View File

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

View File

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

View File

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

View File

@ -5,8 +5,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>544</width>
<height>306</height>
<width>421</width>
<height>313</height>
</rect>
</property>
<property name="windowTitle" >
@ -286,426 +286,6 @@
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="TextNetBufSiFactOut" >
<property name="text" >
<string>Size</string>
</property>
<property name="alignment" >
<set>Qt::AlignCenter</set>
</property>
<property name="wordWrap" >
<bool>false</bool>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" >
<property name="spacing" >
<number>6</number>
</property>
<property name="leftMargin" >
<number>0</number>
</property>
<property name="topMargin" >
<number>0</number>
</property>
<property name="rightMargin" >
<number>0</number>
</property>
<property name="bottomMargin" >
<number>0</number>
</property>
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" >
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QSlider" name="SliderNetBufSiFactOut" >
<property name="pageStep" >
<number>1</number>
</property>
<property name="orientation" >
<enum>Qt::Vertical</enum>
</property>
<property name="tickPosition" >
<enum>QSlider::TicksBothSides</enum>
</property>
</widget>
</item>
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" >
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="TextLabel2_2" >
<property name="text" >
<string>Check Ping</string>
</property>
<property name="alignment" >
<set>Qt::AlignCenter</set>
</property>
<property name="wordWrap" >
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="TextLabel2_3" >
<property name="text" >
<string>Time!</string>
</property>
<property name="alignment" >
<set>Qt::AlignCenter</set>
</property>
<property name="wordWrap" >
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="GroupBoxSoundCardBuffers" >
<property name="title" >
<string>Soundcard Buffers</string>
</property>
<layout class="QVBoxLayout" >
<property name="spacing" >
<number>6</number>
</property>
<property name="leftMargin" >
<number>9</number>
</property>
<property name="topMargin" >
<number>9</number>
</property>
<property name="rightMargin" >
<number>9</number>
</property>
<property name="bottomMargin" >
<number>9</number>
</property>
<item>
<layout class="QHBoxLayout" >
<property name="spacing" >
<number>6</number>
</property>
<property name="leftMargin" >
<number>0</number>
</property>
<property name="topMargin" >
<number>0</number>
</property>
<property name="rightMargin" >
<number>0</number>
</property>
<property name="bottomMargin" >
<number>0</number>
</property>
<item>
<layout class="QVBoxLayout" >
<property name="spacing" >
<number>6</number>
</property>
<property name="leftMargin" >
<number>0</number>
</property>
<property name="topMargin" >
<number>0</number>
</property>
<property name="rightMargin" >
<number>0</number>
</property>
<property name="bottomMargin" >
<number>0</number>
</property>
<item>
<widget class="QLabel" name="TextSndBufOut" >
<property name="sizePolicy" >
<sizepolicy vsizetype="Minimum" hsizetype="MinimumExpanding" >
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize" >
<size>
<width>30</width>
<height>0</height>
</size>
</property>
<property name="text" >
<string>Out</string>
</property>
<property name="alignment" >
<set>Qt::AlignCenter</set>
</property>
<property name="wordWrap" >
<bool>false</bool>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" >
<property name="spacing" >
<number>6</number>
</property>
<property name="leftMargin" >
<number>0</number>
</property>
<property name="topMargin" >
<number>0</number>
</property>
<property name="rightMargin" >
<number>0</number>
</property>
<property name="bottomMargin" >
<number>0</number>
</property>
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" >
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QSlider" name="SliderSndBufOut" >
<property name="pageStep" >
<number>1</number>
</property>
<property name="orientation" >
<enum>Qt::Vertical</enum>
</property>
<property name="tickPosition" >
<enum>QSlider::TicksBothSides</enum>
</property>
</widget>
</item>
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" >
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" >
<property name="spacing" >
<number>6</number>
</property>
<property name="leftMargin" >
<number>0</number>
</property>
<property name="topMargin" >
<number>0</number>
</property>
<property name="rightMargin" >
<number>0</number>
</property>
<property name="bottomMargin" >
<number>0</number>
</property>
<item>
<widget class="QLabel" name="TextSndBufIn" >
<property name="sizePolicy" >
<sizepolicy vsizetype="Minimum" hsizetype="MinimumExpanding" >
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize" >
<size>
<width>30</width>
<height>0</height>
</size>
</property>
<property name="text" >
<string>In</string>
</property>
<property name="alignment" >
<set>Qt::AlignCenter</set>
</property>
<property name="wordWrap" >
<bool>false</bool>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" >
<property name="spacing" >
<number>6</number>
</property>
<property name="leftMargin" >
<number>0</number>
</property>
<property name="topMargin" >
<number>0</number>
</property>
<property name="rightMargin" >
<number>0</number>
</property>
<property name="bottomMargin" >
<number>0</number>
</property>
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" >
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QSlider" name="SliderSndBufIn" >
<property name="pageStep" >
<number>1</number>
</property>
<property name="orientation" >
<enum>Qt::Vertical</enum>
</property>
<property name="tickPosition" >
<enum>QSlider::TicksBothSides</enum>
</property>
</widget>
</item>
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" >
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="TextLabel1" >
<property name="text" >
<string>Out / In:</string>
</property>
<property name="alignment" >
<set>Qt::AlignCenter</set>
</property>
<property name="wordWrap" >
<bool>false</bool>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" >
<property name="spacing" >
<number>6</number>
</property>
<property name="leftMargin" >
<number>0</number>
</property>
<property name="topMargin" >
<number>0</number>
</property>
<property name="rightMargin" >
<number>0</number>
</property>
<property name="bottomMargin" >
<number>0</number>
</property>
<item>
<widget class="CMultiColorLED" native="1" name="CLEDSoundOut" >
<property name="sizePolicy" >
<sizepolicy vsizetype="Fixed" hsizetype="Fixed" >
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize" >
<size>
<width>13</width>
<height>13</height>
</size>
</property>
<property name="maximumSize" >
<size>
<width>13</width>
<height>13</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="CMultiColorLED" native="1" name="CLEDSoundIn" >
<property name="sizePolicy" >
<sizepolicy vsizetype="Fixed" hsizetype="Fixed" >
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize" >
<size>
<width>13</width>
<height>13</height>
</size>
</property>
<property name="maximumSize" >
<size>
<width>13</width>
<height>13</height>
</size>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>

View File

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

View File

@ -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<QString> vecsName;
CVector<int> veciJitBufSize;
CVector<int> veciNetwOutBlSiFact;
CVector<int> 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 );
}

View File

@ -5,8 +5,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>699</width>
<height>291</height>
<width>767</width>
<height>280</height>
</rect>
</property>
<property name="windowTitle" >
@ -19,12 +19,21 @@
<bool>true</bool>
</property>
<layout class="QVBoxLayout" >
<property name="margin" >
<number>9</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<property name="leftMargin" >
<number>9</number>
</property>
<property name="topMargin" >
<number>9</number>
</property>
<property name="rightMargin" >
<number>9</number>
</property>
<property name="bottomMargin" >
<number>9</number>
</property>
<item>
<widget class="QTreeWidget" name="ListViewClients" >
<property name="rootIsDecorated" >
@ -55,11 +64,6 @@
<string>Jitter buffer size</string>
</property>
</column>
<column>
<property name="text" >
<string>Block Size In</string>
</property>
</column>
<column>
<property name="text" >
<string>Block Size Out</string>
@ -69,12 +73,21 @@
</item>
<item>
<layout class="QHBoxLayout" >
<property name="margin" >
<number>0</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<property name="leftMargin" >
<number>0</number>
</property>
<property name="topMargin" >
<number>0</number>
</property>
<property name="rightMargin" >
<number>0</number>
</property>
<property name="bottomMargin" >
<number>0</number>
</property>
<item>
<widget class="QLabel" name="TextLabelNameVersion" >
<property name="text" >

View File

@ -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<quint16> ( 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();
}
}

View File

@ -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<uint8_t>& 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<unsigned char>& 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<uint8_t>& vecData )
const int iRecCodingType =
static_cast<unsigned short> ( 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;
}

View File

@ -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<unsigned char>& vecbyData,
const int iNumBytes );
void DeleteSendMessQueue();
protected:
class CSendMessage
{

View File

@ -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<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
@ -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<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();
@ -197,7 +197,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

@ -54,11 +54,10 @@ public:
void GetConCliParam ( CVector<CHostAddress>& vecHostAddresses,
CVector<QString>& vecsName,
CVector<int>& veciJitBufSize, CVector<int>& veciNetwOutBlSiFact,
CVector<int>& veciNetwInBlSiFact )
CVector<int>& veciJitBufSize, CVector<int>& veciNetwOutBlSiFact )
{
ChannelSet.GetConCliParam ( vecHostAddresses, vecsName,
veciJitBufSize, veciNetwOutBlSiFact, veciNetwInBlSiFact );
veciJitBufSize, veciNetwOutBlSiFact );
}
bool GetTimingStdDev ( double& dCurTiStdDev );

View File

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

View File

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

View File

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

View File

@ -34,9 +34,11 @@
class CSoundBase : public QThread
{
public:
CSoundBase ( void (*fpNewCallback) ( CVector<short>& psData, void* arg ),
CSoundBase ( const bool bNewIsCallbackAudioInterface,
void (*fpNewCallback) ( CVector<short>& 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<short>& psData, void* arg );
void* pCallbackArg;
// callback function call for derived classes
void Callback ( CVector<short>& psData )
{
(*fpCallback) ( psData, pCallbackArg );
}
// these functions should be overwritten by derived class for
// non callback based audio interfaces
virtual bool Read ( CVector<short>& psData ) { printf ( "no sound!" ); return false; }
@ -57,6 +65,7 @@ protected:
void run();
bool bRun;
bool bIsCallbackAudioInterface;
CVector<short> vecsAudioSndCrdStereo;
};

View File

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

View File

@ -29,15 +29,10 @@
/* Implementation *************************************************************/
#include <qmutex.h>
// 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<short> 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<short>& 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<short>& 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<int> (
ceil ( static_cast<double> ( 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<short>& 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<short>& 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<short> ( 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<short> ( 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<int> ( 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<int> ( 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<int> ( 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<int> ( 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();
}

View File

@ -28,6 +28,7 @@
#include <windows.h>
#include <string>
#include <qmutex.h>
#include <qmessagebox.h>
#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<short>& psData );
virtual bool Write ( CVector<short>& 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_ )