2006-12-18 15:39:33 +01:00
|
|
|
/******************************************************************************\
|
2008-01-02 23:16:38 +01:00
|
|
|
* Copyright (c) 2004-2008
|
2006-12-18 15:39:33 +01:00
|
|
|
*
|
|
|
|
* Author(s):
|
|
|
|
* Volker Fischer
|
|
|
|
*
|
|
|
|
******************************************************************************
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify it under
|
|
|
|
* the terms of the GNU General Public License as published by the Free Software
|
|
|
|
* Foundation; either version 2 of the License, or (at your option) any later
|
|
|
|
* version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
|
|
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
|
|
* details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License along with
|
|
|
|
* this program; if not, write to the Free Software Foundation, Inc.,
|
|
|
|
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
*
|
|
|
|
\******************************************************************************/
|
|
|
|
|
|
|
|
#include "client.h"
|
|
|
|
|
|
|
|
|
2006-02-26 11:50:47 +01:00
|
|
|
/* Implementation *************************************************************/
|
2008-08-13 21:08:45 +02:00
|
|
|
CClient::CClient ( const quint16 iPortNumber ) : bRun ( false ),
|
2009-02-14 01:46:58 +01:00
|
|
|
iSndCrdMonoBlockSizeSam ( MIN_SND_CRD_BLOCK_SIZE_SAMPLES ),
|
|
|
|
iSndCrdStereoBlockSizeSam ( 2 * MIN_SND_CRD_BLOCK_SIZE_SAMPLES ),
|
2008-10-31 21:27:55 +01:00
|
|
|
Sound ( MIN_SND_CRD_BLOCK_SIZE_SAMPLES * 2 /* stereo */ ),
|
2008-08-13 21:08:45 +02:00
|
|
|
Socket ( &Channel, iPortNumber ),
|
2009-02-17 13:32:50 +01:00
|
|
|
iAudioInFader ( AUD_FADER_IN_MIDDLE ),
|
2009-02-12 18:15:17 +01:00
|
|
|
iReverbLevel ( 0 ),
|
2008-03-29 08:14:35 +01:00
|
|
|
bReverbOnLeftChan ( false ),
|
|
|
|
iNetwBufSizeFactIn ( DEF_NET_BLOCK_SIZE_FACTOR ),
|
2008-07-24 18:20:25 +02:00
|
|
|
strIPAddress ( "" ), strName ( "" ),
|
2009-02-11 19:37:26 +01:00
|
|
|
bOpenChatOnNewMessage ( true ),
|
2009-02-12 15:48:35 +01:00
|
|
|
bDoAutoSockBufSize ( true )
|
2006-02-26 11:50:47 +01:00
|
|
|
{
|
2006-11-25 15:46:57 +01:00
|
|
|
// connection for protocol
|
2006-12-07 19:57:26 +01:00
|
|
|
QObject::connect ( &Channel,
|
|
|
|
SIGNAL ( MessReadyForSending ( CVector<uint8_t> ) ),
|
2006-11-25 15:46:57 +01:00
|
|
|
this, SLOT ( OnSendProtMessage ( CVector<uint8_t> ) ) );
|
2006-03-07 22:26:40 +01:00
|
|
|
|
2006-11-25 15:46:57 +01:00
|
|
|
QObject::connect ( &Channel, SIGNAL ( ReqJittBufSize() ),
|
|
|
|
this, SLOT ( OnReqJittBufSize() ) );
|
2006-11-05 11:09:32 +01:00
|
|
|
|
2006-11-25 15:46:57 +01:00
|
|
|
QObject::connect ( &Channel, SIGNAL ( ProtocolStatus ( bool ) ),
|
|
|
|
this, SLOT ( OnProtocolStatus ( bool ) ) );
|
2006-11-26 22:25:56 +01:00
|
|
|
|
2006-12-07 19:57:26 +01:00
|
|
|
QObject::connect ( &Channel,
|
|
|
|
SIGNAL ( ConClientListMesReceived ( CVector<CChannelShortInfo> ) ),
|
2006-11-26 22:25:56 +01:00
|
|
|
SIGNAL ( ConClientListMesReceived ( CVector<CChannelShortInfo> ) ) );
|
2006-12-09 11:04:27 +01:00
|
|
|
|
|
|
|
QObject::connect ( &Channel, SIGNAL ( NewConnection() ),
|
|
|
|
this, SLOT ( OnNewConnection() ) );
|
2008-07-24 18:20:25 +02:00
|
|
|
|
|
|
|
QObject::connect ( &Channel, SIGNAL ( ChatTextReceived ( QString ) ),
|
|
|
|
this, SIGNAL ( ChatTextReceived ( QString ) ) );
|
2008-08-02 15:42:24 +02:00
|
|
|
|
2008-08-10 23:56:03 +02:00
|
|
|
QObject::connect ( &Channel, SIGNAL ( PingReceived ( int ) ),
|
|
|
|
this, SLOT ( OnReceivePingMessage ( int ) ) );
|
2006-02-26 11:50:47 +01:00
|
|
|
}
|
|
|
|
|
2006-03-01 20:46:44 +01:00
|
|
|
void CClient::OnSendProtMessage ( CVector<uint8_t> vecMessage )
|
2006-02-26 11:50:47 +01:00
|
|
|
{
|
2006-03-01 20:46:44 +01:00
|
|
|
|
|
|
|
// convert unsigned uint8_t in char, TODO convert all buffers in uint8_t
|
2006-12-07 19:57:26 +01:00
|
|
|
CVector<unsigned char> vecbyDataConv ( vecMessage.Size() );
|
|
|
|
for ( int i = 0; i < vecMessage.Size(); i++ ) {
|
2006-11-25 15:46:57 +01:00
|
|
|
vecbyDataConv[i] = static_cast<unsigned char> ( vecMessage[i] );
|
2006-03-01 20:46:44 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-11-25 15:46:57 +01:00
|
|
|
// the protocol queries me to call the function to send the message
|
|
|
|
// send it through the network
|
2006-12-07 19:57:26 +01:00
|
|
|
Socket.SendPacket ( vecbyDataConv, Channel.GetAddress() );
|
2006-02-26 11:50:47 +01:00
|
|
|
}
|
2006-03-12 13:24:42 +01:00
|
|
|
|
|
|
|
void CClient::OnReqJittBufSize()
|
|
|
|
{
|
2006-11-25 15:46:57 +01:00
|
|
|
Channel.CreateJitBufMes ( Channel.GetSockBufSize() );
|
2006-03-13 21:23:05 +01:00
|
|
|
|
|
|
|
// FIXME: we set the network buffer size factor here, too -> in the
|
|
|
|
// future a separate request function for this parameter should be created
|
2006-11-25 15:46:57 +01:00
|
|
|
Channel.CreateNetwBlSiFactMes ( iNetwBufSizeFactIn );
|
2006-03-12 13:24:42 +01:00
|
|
|
}
|
2006-12-10 12:06:14 +01:00
|
|
|
|
|
|
|
void CClient::OnNewConnection()
|
|
|
|
{
|
|
|
|
// a new connection was successfully initiated, send name and request
|
|
|
|
// connected clients list
|
|
|
|
Channel.SetRemoteName ( strName );
|
2008-08-09 09:57:44 +02:00
|
|
|
|
|
|
|
// We have to send a connected clients list request since it can happen
|
|
|
|
// that we just had connected to the server and then disconnected but
|
|
|
|
// the server still thinks that we are connected (the server is still
|
|
|
|
// waiting for the channel time-out). If we now connect again, we would
|
|
|
|
// not get the list because the server does not know about a new connection.
|
2006-12-10 12:06:14 +01:00
|
|
|
Channel.CreateReqConnClientsList();
|
|
|
|
}
|
2006-12-18 15:39:33 +01:00
|
|
|
|
2008-08-10 23:56:03 +02:00
|
|
|
void CClient::OnReceivePingMessage ( int iMs )
|
2008-08-02 09:28:21 +02:00
|
|
|
{
|
2008-08-11 19:21:09 +02:00
|
|
|
// calculate difference between received time in ms and current time in ms,
|
|
|
|
// take care of wrap arounds (if wrapping, do not use result)
|
|
|
|
const int iCurDiff = PreciseTime.elapsed() - iMs;
|
|
|
|
if ( iCurDiff >= 0 )
|
|
|
|
{
|
|
|
|
emit PingTimeReceived ( iCurDiff );
|
|
|
|
}
|
2008-08-02 09:28:21 +02:00
|
|
|
}
|
|
|
|
|
2006-12-18 15:39:33 +01:00
|
|
|
bool CClient::SetServerAddr ( QString strNAddr )
|
|
|
|
{
|
|
|
|
QHostAddress InetAddr;
|
2008-07-22 17:35:58 +02:00
|
|
|
quint16 iNetPort = LLCON_PORT_NUMBER;
|
|
|
|
|
|
|
|
// parse input address for the type [IP address]:[port number]
|
|
|
|
QString strPort = strNAddr.section ( ":", 1, 1 );
|
|
|
|
if ( !strPort.isEmpty() )
|
|
|
|
{
|
|
|
|
// a colon is present in the address string, try to extract port number
|
|
|
|
iNetPort = strPort.toInt();
|
|
|
|
|
|
|
|
// extract address port before colon (should be actual internet address)
|
|
|
|
strNAddr = strNAddr.section ( ":", 0, 0 );
|
|
|
|
}
|
2006-12-18 15:39:33 +01:00
|
|
|
|
2007-02-24 10:49:52 +01:00
|
|
|
// first try if this is an IP number an can directly applied to QHostAddress
|
|
|
|
if ( !InetAddr.setAddress ( strNAddr ) )
|
2006-12-18 15:39:33 +01:00
|
|
|
{
|
2007-02-24 10:49:52 +01:00
|
|
|
// it was no vaild IP address, try to get host by name, assuming
|
|
|
|
// that the string contains a valid host name string
|
2008-01-17 19:56:43 +01:00
|
|
|
QHostInfo HostInfo = QHostInfo::fromName ( strNAddr );
|
2007-02-24 10:49:52 +01:00
|
|
|
|
2008-01-17 19:56:43 +01:00
|
|
|
if ( HostInfo.error() == QHostInfo::NoError )
|
2007-02-24 10:49:52 +01:00
|
|
|
{
|
2008-01-17 19:56:43 +01:00
|
|
|
// apply IP address to QT object
|
|
|
|
if ( !HostInfo.addresses().isEmpty() )
|
|
|
|
{
|
|
|
|
// use the first IP address
|
|
|
|
InetAddr = HostInfo.addresses().first();
|
|
|
|
}
|
2007-02-24 10:49:52 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return false; // invalid address
|
|
|
|
}
|
2006-12-18 15:39:33 +01:00
|
|
|
}
|
2007-02-24 10:49:52 +01:00
|
|
|
|
|
|
|
// apply address (the server port is fixed and always the same)
|
2008-07-22 17:35:58 +02:00
|
|
|
Channel.SetAddress ( CHostAddress ( InetAddr, iNetPort ) );
|
2007-02-24 10:49:52 +01:00
|
|
|
|
|
|
|
return true;
|
2006-11-05 11:09:32 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void CClient::OnProtocolStatus ( bool bOk )
|
|
|
|
{
|
2006-11-25 15:46:57 +01:00
|
|
|
// show protocol status in GUI
|
|
|
|
if ( bOk )
|
|
|
|
{
|
|
|
|
PostWinMessage ( MS_PROTOCOL, MUL_COL_LED_RED );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
PostWinMessage ( MS_PROTOCOL, MUL_COL_LED_GREEN );
|
|
|
|
}
|
2006-11-05 11:09:32 +01:00
|
|
|
}
|
2006-01-28 12:29:22 +01:00
|
|
|
|
|
|
|
void CClient::Init()
|
|
|
|
{
|
2008-10-31 21:27:55 +01:00
|
|
|
// set block size (in samples)
|
2009-02-14 01:46:58 +01:00
|
|
|
iMonoBlockSizeSam = MIN_BLOCK_SIZE_SAMPLES;
|
|
|
|
iStereoBlockSizeSam = 2 * MIN_BLOCK_SIZE_SAMPLES;
|
2006-01-28 12:29:22 +01:00
|
|
|
|
2009-02-17 12:58:27 +01:00
|
|
|
vecsAudioSndCrdStereo.Init ( iSndCrdStereoBlockSizeSam );
|
|
|
|
vecdAudioSndCrdMono.Init ( iSndCrdMonoBlockSizeSam );
|
|
|
|
vecdAudioSndCrdStereo.Init ( iSndCrdStereoBlockSizeSam );
|
2006-01-28 12:29:22 +01:00
|
|
|
|
2009-02-17 12:58:27 +01:00
|
|
|
vecdAudioStereo.Init ( iStereoBlockSizeSam );
|
2006-01-28 12:29:22 +01:00
|
|
|
|
2008-10-31 21:27:55 +01:00
|
|
|
Sound.InitRecording();
|
|
|
|
Sound.InitPlayback();
|
2006-01-28 12:29:22 +01:00
|
|
|
|
2006-12-07 19:57:26 +01:00
|
|
|
// resample objects are always initialized with the input block size
|
|
|
|
// record
|
2009-02-14 01:46:58 +01:00
|
|
|
ResampleObjDown.Init ( iSndCrdMonoBlockSizeSam, SND_CRD_SAMPLE_RATE, SYSTEM_SAMPLE_RATE );
|
2006-01-28 12:29:22 +01:00
|
|
|
|
2006-12-07 19:57:26 +01:00
|
|
|
// playback
|
2009-02-14 01:46:58 +01:00
|
|
|
ResampleObjUp.Init ( iMonoBlockSizeSam, SYSTEM_SAMPLE_RATE, SND_CRD_SAMPLE_RATE );
|
2006-01-28 12:29:22 +01:00
|
|
|
|
2006-12-07 19:57:26 +01:00
|
|
|
// init network buffers
|
2009-02-14 01:46:58 +01:00
|
|
|
vecsNetwork.Init ( iMonoBlockSizeSam );
|
|
|
|
vecdNetwData.Init ( iMonoBlockSizeSam );
|
2006-01-28 12:29:22 +01:00
|
|
|
|
2006-12-07 19:57:26 +01:00
|
|
|
// init moving average buffer for response time evaluation
|
|
|
|
RespTimeMoAvBuf.Init ( LEN_MOV_AV_RESPONSE );
|
2006-01-28 12:29:22 +01:00
|
|
|
|
2006-12-07 19:57:26 +01:00
|
|
|
// init time for response time evaluation
|
2009-02-08 23:44:18 +01:00
|
|
|
TimeLastBlock = PreciseTime.elapsed();
|
2006-01-28 12:29:22 +01:00
|
|
|
|
2006-11-25 15:46:57 +01:00
|
|
|
AudioReverb.Clear();
|
2006-01-28 12:29:22 +01:00
|
|
|
}
|
2006-12-18 15:39:33 +01:00
|
|
|
|
|
|
|
void CClient::run()
|
|
|
|
{
|
2009-02-14 01:46:58 +01:00
|
|
|
int i, j;
|
2006-12-18 15:39:33 +01:00
|
|
|
|
|
|
|
// Set thread priority (The working thread should have a higher
|
|
|
|
// priority than the GUI)
|
|
|
|
#ifdef _WIN32
|
2009-02-14 12:15:53 +01:00
|
|
|
SetThreadPriority ( GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL );
|
2006-01-28 12:29:22 +01:00
|
|
|
#else
|
2008-02-02 10:35:58 +01:00
|
|
|
/*
|
2006-12-07 19:57:26 +01:00
|
|
|
// set the process to realtime privs, taken from
|
|
|
|
// "http://www.gardena.net/benno/linux/audio" but does not seem to work,
|
|
|
|
// maybe a problem with user rights
|
2006-11-25 15:46:57 +01:00
|
|
|
struct sched_param schp;
|
|
|
|
memset ( &schp, 0, sizeof ( schp ) );
|
|
|
|
schp.sched_priority = sched_get_priority_max ( SCHED_FIFO );
|
|
|
|
sched_setscheduler ( 0, SCHED_FIFO, &schp );
|
2008-02-02 10:35:58 +01:00
|
|
|
*/
|
2006-12-18 15:39:33 +01:00
|
|
|
#endif
|
|
|
|
|
2006-12-07 19:57:26 +01:00
|
|
|
// init object
|
2008-07-15 22:33:41 +02:00
|
|
|
try
|
|
|
|
{
|
|
|
|
Init();
|
|
|
|
}
|
|
|
|
catch ( CGenErr generr )
|
|
|
|
{
|
|
|
|
// TODO better error management -> should be catched in main thread
|
|
|
|
// problem: how to catch errors in a different thread...?
|
|
|
|
|
|
|
|
// quick hack solution
|
2008-07-22 17:17:19 +02:00
|
|
|
QMessageBox::critical ( 0, APP_NAME, generr.GetErrorText(), "Quit", 0 );
|
2008-07-15 22:33:41 +02:00
|
|
|
exit ( 0 );
|
|
|
|
}
|
2006-12-18 15:39:33 +01:00
|
|
|
|
|
|
|
|
2009-02-14 01:46:58 +01:00
|
|
|
// runtime phase -----------------------------------------------------------
|
2006-12-09 11:04:27 +01:00
|
|
|
// enable channel
|
|
|
|
Channel.SetEnable ( true );
|
2006-12-18 15:39:33 +01:00
|
|
|
|
2006-11-25 15:46:57 +01:00
|
|
|
bRun = true;
|
|
|
|
|
2006-12-18 15:39:33 +01:00
|
|
|
// main loop of working thread
|
|
|
|
while ( bRun )
|
|
|
|
{
|
|
|
|
// get audio from sound card (blocking function)
|
2009-02-17 12:58:27 +01:00
|
|
|
if ( Sound.Read ( vecsAudioSndCrdStereo ) )
|
2006-12-18 15:39:33 +01:00
|
|
|
{
|
2006-12-07 19:57:26 +01:00
|
|
|
PostWinMessage ( MS_SOUND_IN, MUL_COL_LED_RED );
|
2006-12-18 15:39:33 +01:00
|
|
|
}
|
2006-11-25 15:46:57 +01:00
|
|
|
else
|
2006-12-18 15:39:33 +01:00
|
|
|
{
|
2006-12-07 19:57:26 +01:00
|
|
|
PostWinMessage ( MS_SOUND_IN, MUL_COL_LED_GREEN );
|
2006-12-18 15:39:33 +01:00
|
|
|
}
|
|
|
|
|
2009-02-14 01:46:58 +01:00
|
|
|
// convert data from short to double
|
|
|
|
for ( i = 0; i < iSndCrdStereoBlockSizeSam; i++ )
|
2006-12-18 15:39:33 +01:00
|
|
|
{
|
2009-02-17 12:58:27 +01:00
|
|
|
vecdAudioSndCrdStereo[i] = (double) vecsAudioSndCrdStereo[i];
|
2006-12-18 15:39:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// resample data for each channel seaparately
|
2009-02-17 12:58:27 +01:00
|
|
|
ResampleObjDown.ResampleStereo ( vecdAudioSndCrdStereo, vecdAudioStereo );
|
2006-12-18 15:39:33 +01:00
|
|
|
|
2009-02-14 01:46:58 +01:00
|
|
|
// update stereo signal level meter
|
2009-02-17 12:58:27 +01:00
|
|
|
SignalLevelMeter.Update ( vecdAudioStereo );
|
2006-11-25 15:46:57 +01:00
|
|
|
|
2006-12-07 19:57:26 +01:00
|
|
|
// add reverberation effect if activated
|
|
|
|
if ( iReverbLevel != 0 )
|
2006-11-25 15:46:57 +01:00
|
|
|
{
|
2008-08-03 23:38:24 +02:00
|
|
|
// calculate attenuation amplification factor
|
2006-11-25 15:46:57 +01:00
|
|
|
const double dRevLev = (double) iReverbLevel / AUD_REVERB_MAX / 2;
|
|
|
|
|
2006-12-07 19:57:26 +01:00
|
|
|
if ( bReverbOnLeftChan )
|
2006-11-25 15:46:57 +01:00
|
|
|
{
|
2009-02-14 01:46:58 +01:00
|
|
|
for ( i = 0; i < iStereoBlockSizeSam; i += 2 )
|
2006-11-25 15:46:57 +01:00
|
|
|
{
|
2006-12-07 19:57:26 +01:00
|
|
|
// left channel
|
2009-02-17 12:58:27 +01:00
|
|
|
vecdAudioStereo[i] +=
|
|
|
|
dRevLev * AudioReverb.ProcessSample ( vecdAudioStereo[i] );
|
2006-11-25 15:46:57 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2009-02-14 01:46:58 +01:00
|
|
|
for ( i = 1; i < iStereoBlockSizeSam; i += 2 )
|
2006-11-25 15:46:57 +01:00
|
|
|
{
|
2006-12-07 19:57:26 +01:00
|
|
|
// right channel
|
2009-02-17 12:58:27 +01:00
|
|
|
vecdAudioStereo[i] +=
|
|
|
|
dRevLev * AudioReverb.ProcessSample ( vecdAudioStereo[i] );
|
2006-11-25 15:46:57 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2006-12-18 15:39:33 +01:00
|
|
|
|
2009-02-17 13:32:50 +01:00
|
|
|
// mix both signals depending on the fading setting, convert
|
|
|
|
// from double to short
|
|
|
|
if ( iAudioInFader == AUD_FADER_IN_MIDDLE )
|
2006-11-25 15:46:57 +01:00
|
|
|
{
|
2009-02-17 13:32:50 +01:00
|
|
|
// just mix channels together
|
2009-02-14 01:46:58 +01:00
|
|
|
for ( i = 0, j = 0; i < iMonoBlockSizeSam; i++, j += 2 )
|
2006-12-07 19:57:26 +01:00
|
|
|
{
|
2009-02-14 01:46:58 +01:00
|
|
|
vecsNetwork[i] =
|
2009-02-17 13:32:50 +01:00
|
|
|
Double2Short ( vecdAudioStereo[j] + vecdAudioStereo[j + 1] );
|
2006-12-07 19:57:26 +01:00
|
|
|
}
|
2009-02-14 01:46:58 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2009-02-17 13:32:50 +01:00
|
|
|
const double dAttFact =
|
|
|
|
(double) ( AUD_FADER_IN_MIDDLE - abs ( AUD_FADER_IN_MIDDLE - iAudioInFader ) ) /
|
|
|
|
AUD_FADER_IN_MIDDLE;
|
|
|
|
|
|
|
|
if ( iAudioInFader > AUD_FADER_IN_MIDDLE )
|
2006-12-07 19:57:26 +01:00
|
|
|
{
|
2009-02-17 13:32:50 +01:00
|
|
|
for ( i = 0, j = 0; i < iMonoBlockSizeSam; i++, j += 2 )
|
|
|
|
{
|
|
|
|
// attenuation on right channel
|
|
|
|
vecsNetwork[i] =
|
|
|
|
Double2Short ( vecdAudioStereo[j] + dAttFact * vecdAudioStereo[j + 1] );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for ( i = 0, j = 0; i < iMonoBlockSizeSam; i++, j += 2 )
|
|
|
|
{
|
|
|
|
// attenuation on left channel
|
|
|
|
vecsNetwork[i] =
|
|
|
|
Double2Short ( vecdAudioStereo[j + 1] + dAttFact * vecdAudioStereo[j] );
|
|
|
|
}
|
2006-12-07 19:57:26 +01:00
|
|
|
}
|
2006-12-18 15:39:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// send it through the network
|
|
|
|
Socket.SendPacket ( Channel.PrepSendPacket ( vecsNetwork ),
|
2008-10-31 21:27:55 +01:00
|
|
|
Channel.GetAddress() );
|
2006-01-28 12:29:22 +01:00
|
|
|
|
2006-12-09 11:40:18 +01:00
|
|
|
// receive a new block
|
|
|
|
if ( Channel.GetData ( vecdNetwData ) == GS_BUFFER_OK )
|
2006-12-18 15:39:33 +01:00
|
|
|
{
|
2006-12-07 19:57:26 +01:00
|
|
|
PostWinMessage ( MS_JIT_BUF_GET, MUL_COL_LED_GREEN );
|
2006-12-18 15:39:33 +01:00
|
|
|
}
|
2006-11-25 15:46:57 +01:00
|
|
|
else
|
2006-12-18 15:39:33 +01:00
|
|
|
{
|
2006-12-07 19:57:26 +01:00
|
|
|
PostWinMessage ( MS_JIT_BUF_GET, MUL_COL_LED_RED );
|
2006-12-18 15:39:33 +01:00
|
|
|
}
|
|
|
|
|
2006-01-28 12:29:22 +01:00
|
|
|
/*
|
2009-02-08 23:44:18 +01:00
|
|
|
// TEST
|
2006-01-28 12:29:22 +01:00
|
|
|
// fid=fopen('v.dat','r');x=fread(fid,'int16');fclose(fid);
|
|
|
|
static FILE* pFileDelay = fopen("v.dat", "wb");
|
|
|
|
short sData[2];
|
2009-02-14 01:46:58 +01:00
|
|
|
for (i = 0; i < iMonoBlockSizeSam; i++)
|
2006-01-28 12:29:22 +01:00
|
|
|
{
|
2006-11-25 15:46:57 +01:00
|
|
|
sData[0] = (short) vecdNetwData[i];
|
|
|
|
fwrite(&sData, size_t(2), size_t(1), pFileDelay);
|
2006-01-28 12:29:22 +01:00
|
|
|
}
|
|
|
|
fflush(pFileDelay);
|
|
|
|
*/
|
|
|
|
|
2006-12-18 15:39:33 +01:00
|
|
|
// check if channel is connected
|
|
|
|
if ( Channel.IsConnected() )
|
|
|
|
{
|
2009-02-17 12:58:27 +01:00
|
|
|
// resample data
|
|
|
|
ResampleObjUp.ResampleMono ( vecdNetwData, vecdAudioSndCrdMono );
|
|
|
|
|
|
|
|
// convert data from double to short type and copy mono
|
|
|
|
// received data in both sound card channels
|
|
|
|
for ( i = 0, j = 0; i < iSndCrdMonoBlockSizeSam; i++, j += 2 )
|
2006-12-18 15:39:33 +01:00
|
|
|
{
|
2009-02-17 12:58:27 +01:00
|
|
|
vecsAudioSndCrdStereo[j] = vecsAudioSndCrdStereo[j + 1] =
|
|
|
|
Double2Short ( vecdAudioSndCrdMono[i] );
|
2006-12-18 15:39:33 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// if not connected, clear data
|
2009-02-17 12:58:27 +01:00
|
|
|
vecsAudioSndCrdStereo.Reset ( 0 );
|
2006-12-18 15:39:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// play the new block
|
2009-02-17 12:58:27 +01:00
|
|
|
if ( Sound.Write ( vecsAudioSndCrdStereo ) )
|
2006-12-18 15:39:33 +01:00
|
|
|
{
|
2006-12-07 19:57:26 +01:00
|
|
|
PostWinMessage ( MS_SOUND_OUT, MUL_COL_LED_RED );
|
2006-12-18 15:39:33 +01:00
|
|
|
}
|
2006-11-25 15:46:57 +01:00
|
|
|
else
|
2006-12-18 15:39:33 +01:00
|
|
|
{
|
2006-12-07 19:57:26 +01:00
|
|
|
PostWinMessage ( MS_SOUND_OUT, MUL_COL_LED_GREEN );
|
2006-11-25 15:46:57 +01:00
|
|
|
}
|
|
|
|
|
2009-02-11 19:37:26 +01:00
|
|
|
// update response time measurement and socket buffer size
|
|
|
|
UpdateTimeResponseMeasurement();
|
|
|
|
UpdateSocketBufferSize();
|
2006-12-18 15:39:33 +01:00
|
|
|
}
|
2006-12-09 11:04:27 +01:00
|
|
|
|
|
|
|
// disable channel
|
|
|
|
Channel.SetEnable ( false );
|
2006-12-18 15:39:33 +01:00
|
|
|
|
2008-07-14 00:57:31 +02:00
|
|
|
// disable sound interface
|
|
|
|
Sound.Close();
|
|
|
|
|
2006-12-18 15:39:33 +01:00
|
|
|
// reset current signal level and LEDs
|
2009-02-14 01:46:58 +01:00
|
|
|
SignalLevelMeter.Reset();
|
2006-12-18 15:39:33 +01:00
|
|
|
PostWinMessage ( MS_RESET_ALL, 0 );
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CClient::Stop()
|
|
|
|
{
|
|
|
|
// set flag so that thread can leave the main loop
|
2006-12-09 11:04:27 +01:00
|
|
|
bRun = false;
|
2006-12-18 15:39:33 +01:00
|
|
|
|
|
|
|
// give thread some time to terminate, return status
|
|
|
|
return wait ( 5000 );
|
2006-02-26 11:50:47 +01:00
|
|
|
}
|
2009-02-11 19:37:26 +01:00
|
|
|
|
|
|
|
void CClient::UpdateTimeResponseMeasurement()
|
|
|
|
{
|
|
|
|
// add time difference
|
|
|
|
const int CurTime = PreciseTime.elapsed();
|
|
|
|
|
|
|
|
// 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 );
|
|
|
|
|
|
|
|
RespTimeMoAvBuf.Add ( dCurAddVal * dCurAddVal ); // add squared value
|
|
|
|
|
|
|
|
// store old time value
|
|
|
|
TimeLastBlock = CurTime;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CClient::UpdateSocketBufferSize()
|
2009-02-12 15:48:35 +01:00
|
|
|
{
|
2009-02-11 19:37:26 +01:00
|
|
|
// just update the socket buffer size if auto setting is enabled, otherwise
|
2009-02-11 19:45:22 +01:00
|
|
|
// do nothing
|
|
|
|
if ( bDoAutoSockBufSize )
|
2009-02-11 19:37:26 +01:00
|
|
|
{
|
|
|
|
// we use the time response measurement for the automatic setting
|
|
|
|
// Assumptions:
|
|
|
|
// - the network jitter can be neglected compared to the audio
|
|
|
|
// interface jitter
|
|
|
|
// - the audio interface jitter is assumed to be Gaussian
|
|
|
|
// - the buffer size is set to two times the standard deviation of
|
|
|
|
// the audio interface jitter (~95% of the jitter should be fit in the
|
|
|
|
// buffer)
|
|
|
|
// - introduce a hysteresis to avoid switching the buffer sizes all the
|
|
|
|
// time in case the time response measurement is close to a bound
|
|
|
|
// - only use time response measurement results if averaging buffer is
|
|
|
|
// completely filled
|
|
|
|
const double dHysteresis = 0.3;
|
|
|
|
|
2009-02-11 19:45:22 +01:00
|
|
|
if ( RespTimeMoAvBuf.IsInitialized() )
|
2009-02-11 19:37:26 +01:00
|
|
|
{
|
|
|
|
// calculate current buffer setting
|
|
|
|
// TODO 2* seems not give optimal results, maybe use 3*?
|
2009-02-11 19:45:22 +01:00
|
|
|
// TEST add 2 buffers
|
2009-02-16 17:06:14 +01:00
|
|
|
// add .5 to "round up" -> ceil
|
|
|
|
const double dEstCurBufSet = 2 * ( GetTimingStdDev() + 0.5 ) + 2;
|
2009-02-11 19:37:26 +01:00
|
|
|
|
|
|
|
// upper/lower hysteresis decision
|
|
|
|
const int iUpperHystDec = LlconMath().round ( dEstCurBufSet - dHysteresis );
|
|
|
|
const int iLowerHystDec = LlconMath().round ( dEstCurBufSet + dHysteresis );
|
|
|
|
|
|
|
|
// if both decisions are equal than use the result
|
|
|
|
if ( iUpperHystDec == iLowerHystDec )
|
2009-02-11 19:45:22 +01:00
|
|
|
{
|
2009-02-13 00:06:41 +01:00
|
|
|
// set the socket buffer via the main window thread since somehow
|
|
|
|
// it gives a protocol deadlock if we call the SetSocketBufSize()
|
|
|
|
// function directly
|
|
|
|
PostWinMessage ( MS_SET_JIT_BUF_SIZE, iUpperHystDec );
|
2009-02-11 19:37:26 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// we are in the middle of the decision region, use
|
|
|
|
// previous setting for determing the new decision
|
|
|
|
if ( !( ( GetSockBufSize() == iUpperHystDec ) ||
|
|
|
|
( GetSockBufSize() == iLowerHystDec ) ) )
|
|
|
|
{
|
2009-02-13 00:06:41 +01:00
|
|
|
// The old result is not near the new decision,
|
|
|
|
// use per definition the upper decision.
|
|
|
|
// Set the socket buffer via the main window thread since somehow
|
|
|
|
// it gives a protocol deadlock if we call the SetSocketBufSize()
|
|
|
|
// function directly.
|
|
|
|
PostWinMessage ( MS_SET_JIT_BUF_SIZE, iUpperHystDec );
|
2009-02-11 19:37:26 +01:00
|
|
|
}
|
|
|
|
}
|
2009-02-11 19:45:22 +01:00
|
|
|
}
|
2009-02-11 19:37:26 +01:00
|
|
|
}
|
|
|
|
}
|