some code style changes, added first implementation of mixer in client window
This commit is contained in:
parent
63adf15507
commit
7f4bea94eb
5 changed files with 531 additions and 490 deletions
658
linux/sound.cpp
658
linux/sound.cpp
|
@ -2,7 +2,7 @@
|
||||||
* Copyright (c) 2004-2005
|
* Copyright (c) 2004-2005
|
||||||
*
|
*
|
||||||
* Author(s):
|
* Author(s):
|
||||||
* Volker Fischer, Alexander Kurpiers
|
* Volker Fischer, Alexander Kurpiers
|
||||||
*
|
*
|
||||||
* This code is based on the Open-Source sound interface implementation of
|
* This code is based on the Open-Source sound interface implementation of
|
||||||
* the Dream DRM Receiver project.
|
* the Dream DRM Receiver project.
|
||||||
|
@ -15,412 +15,412 @@
|
||||||
/* Wave in ********************************************************************/
|
/* Wave in ********************************************************************/
|
||||||
void CSound::InitRecording(int iNewBufferSize, bool bNewBlocking)
|
void CSound::InitRecording(int iNewBufferSize, bool bNewBlocking)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
/* set internal buffer size for read */
|
/* set internal buffer size for read */
|
||||||
iBufferSizeIn = iNewBufferSize / NUM_IN_OUT_CHANNELS; /* mono size */
|
iBufferSizeIn = iNewBufferSize / NUM_IN_OUT_CHANNELS; /* mono size */
|
||||||
|
|
||||||
/* if recording device was already open, close it first */
|
/* if recording device was already open, close it first */
|
||||||
if ( rhandle != NULL )
|
if ( rhandle != NULL )
|
||||||
{
|
{
|
||||||
snd_pcm_close ( rhandle );
|
snd_pcm_close ( rhandle );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* record device: The most important ALSA interfaces to the PCM devices are
|
/* record device: The most important ALSA interfaces to the PCM devices are
|
||||||
the "plughw" and the "hw" interface. If you use the "plughw" interface,
|
the "plughw" and the "hw" interface. If you use the "plughw" interface,
|
||||||
you need not care much about the sound hardware. If your soundcard does
|
you need not care much about the sound hardware. If your soundcard does
|
||||||
not support the sample rate or sample format you specify, your data will
|
not support the sample rate or sample format you specify, your data will
|
||||||
be automatically converted. This also applies to the access type and the
|
be automatically converted. This also applies to the access type and the
|
||||||
number of channels. With the "hw" interface, you have to check whether
|
number of channels. With the "hw" interface, you have to check whether
|
||||||
your hardware supports the configuration you would like to use */
|
your hardware supports the configuration you would like to use */
|
||||||
/* either "hw:0,0" or "plughw:0,0" */
|
/* either "hw:0,0" or "plughw:0,0" */
|
||||||
if ( err = snd_pcm_open ( &rhandle, "hw:0,0", SND_PCM_STREAM_CAPTURE, 0 ) != 0 )
|
if ( err = snd_pcm_open ( &rhandle, "hw:0,0", SND_PCM_STREAM_CAPTURE, 0 ) != 0 )
|
||||||
{
|
{
|
||||||
qDebug ( "open error: %s", snd_strerror ( err ) );
|
qDebug ( "open error: %s", snd_strerror ( err ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* recording should be blocking */
|
/* recording should be blocking */
|
||||||
if ( err = snd_pcm_nonblock ( rhandle, FALSE ) != 0 )
|
if ( err = snd_pcm_nonblock ( rhandle, FALSE ) != 0 )
|
||||||
{
|
{
|
||||||
qDebug ( "cannot set blocking: %s", snd_strerror ( err ) );
|
qDebug ( "cannot set blocking: %s", snd_strerror ( err ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* set hardware parameters */
|
/* set hardware parameters */
|
||||||
SetHWParams ( rhandle, iBufferSizeIn, iCurPeriodSizeIn );
|
SetHWParams ( rhandle, iBufferSizeIn, iCurPeriodSizeIn );
|
||||||
|
|
||||||
|
|
||||||
/* sw parameters --------------------------------------------------------- */
|
/* sw parameters --------------------------------------------------------- */
|
||||||
snd_pcm_sw_params_t* swparams;
|
snd_pcm_sw_params_t* swparams;
|
||||||
|
|
||||||
// allocate an invalid snd_pcm_sw_params_t using standard malloc
|
// allocate an invalid snd_pcm_sw_params_t using standard malloc
|
||||||
if ( err = snd_pcm_sw_params_malloc ( &swparams ) != 0 )
|
if ( err = snd_pcm_sw_params_malloc ( &swparams ) != 0 )
|
||||||
{
|
{
|
||||||
qDebug ( "snd_pcm_sw_params_malloc: %s", snd_strerror ( err ) );
|
qDebug ( "snd_pcm_sw_params_malloc: %s", snd_strerror ( err ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the current swparams
|
// get the current swparams
|
||||||
if ( err = snd_pcm_sw_params_current ( rhandle, swparams ) < 0 )
|
if ( err = snd_pcm_sw_params_current ( rhandle, swparams ) < 0 )
|
||||||
{
|
{
|
||||||
qDebug ( "Unable to determine current swparams : %s", snd_strerror ( err ) );
|
qDebug ( "Unable to determine current swparams : %s", snd_strerror ( err ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
// start the transfer when the buffer immediately -> no threshold, val: 0
|
// start the transfer when the buffer immediately -> no threshold, val: 0
|
||||||
err = snd_pcm_sw_params_set_start_threshold ( rhandle, swparams, 0 );
|
err = snd_pcm_sw_params_set_start_threshold ( rhandle, swparams, 0 );
|
||||||
if ( err < 0 )
|
if ( err < 0 )
|
||||||
{
|
{
|
||||||
qDebug ( "Unable to set start threshold mode : %s", snd_strerror ( err ) );
|
qDebug ( "Unable to set start threshold mode : %s", snd_strerror ( err ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
// align all transfers to 1 sample
|
// align all transfers to 1 sample
|
||||||
err = snd_pcm_sw_params_set_xfer_align ( rhandle, swparams, 1 );
|
err = snd_pcm_sw_params_set_xfer_align ( rhandle, swparams, 1 );
|
||||||
if ( err < 0 )
|
if ( err < 0 )
|
||||||
{
|
{
|
||||||
qDebug ( "Unable to set transfer align : %s", snd_strerror ( err ) );
|
qDebug ( "Unable to set transfer align : %s", snd_strerror ( err ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
// set avail min inside a software configuration container
|
// set avail min inside a software configuration container
|
||||||
/* Note: This is similar to setting an OSS wakeup point. The valid values
|
/* Note: This is similar to setting an OSS wakeup point. The valid values
|
||||||
for 'val' are determined by the specific hardware. Most PC sound cards
|
for 'val' are determined by the specific hardware. Most PC sound cards
|
||||||
can only accept power of 2 frame counts (i.e. 512, 1024, 2048). You
|
can only accept power of 2 frame counts (i.e. 512, 1024, 2048). You
|
||||||
cannot use this as a high resolution timer - it is limited to how often
|
cannot use this as a high resolution timer - it is limited to how often
|
||||||
the sound card hardware raises an interrupt. Note that you can greatly
|
the sound card hardware raises an interrupt. Note that you can greatly
|
||||||
improve the reponses using snd_pcm_sw_params_set_sleep_min where another
|
improve the reponses using snd_pcm_sw_params_set_sleep_min where another
|
||||||
timing source is used */
|
timing source is used */
|
||||||
snd_pcm_uframes_t period_size = iBufferSizeIn;
|
snd_pcm_uframes_t period_size = iBufferSizeIn;
|
||||||
|
|
||||||
err = snd_pcm_sw_params_set_avail_min ( rhandle, swparams, period_size );
|
err = snd_pcm_sw_params_set_avail_min ( rhandle, swparams, period_size );
|
||||||
if ( err < 0 )
|
if ( err < 0 )
|
||||||
{
|
{
|
||||||
qDebug ( "Unable to set avail min : %s", snd_strerror ( err ) );
|
qDebug ( "Unable to set avail min : %s", snd_strerror ( err ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
// write the parameters to the record/playback device
|
// write the parameters to the record/playback device
|
||||||
err = snd_pcm_sw_params ( rhandle, swparams );
|
err = snd_pcm_sw_params ( rhandle, swparams );
|
||||||
if ( err < 0 )
|
if ( err < 0 )
|
||||||
{
|
{
|
||||||
qDebug ( "Unable to set sw params : %s", snd_strerror ( err ) );
|
qDebug ( "Unable to set sw params : %s", snd_strerror ( err ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
// clean-up
|
// clean-up
|
||||||
snd_pcm_sw_params_free ( swparams );
|
snd_pcm_sw_params_free ( swparams );
|
||||||
|
|
||||||
|
|
||||||
// start record
|
// start record
|
||||||
snd_pcm_reset ( rhandle );
|
snd_pcm_reset ( rhandle );
|
||||||
snd_pcm_start ( rhandle );
|
snd_pcm_start ( rhandle );
|
||||||
|
|
||||||
qDebug ( "alsa init record done" );
|
qDebug ( "alsa init record done" );
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CSound::Read(CVector<short>& psData)
|
bool CSound::Read(CVector<short>& psData)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* Check if device must be opened or reinitialized */
|
/* Check if device must be opened or reinitialized */
|
||||||
if (bChangParamIn == true)
|
if (bChangParamIn == true)
|
||||||
{
|
{
|
||||||
InitRecording ( iBufferSizeIn * NUM_IN_OUT_CHANNELS );
|
InitRecording ( iBufferSizeIn * NUM_IN_OUT_CHANNELS );
|
||||||
|
|
||||||
/* Reset flag */
|
/* Reset flag */
|
||||||
bChangParamIn = false;
|
bChangParamIn = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = snd_pcm_readi(rhandle, &psData[0], iBufferSizeIn);
|
ret = snd_pcm_readi(rhandle, &psData[0], iBufferSizeIn);
|
||||||
|
|
||||||
if ( ret < 0 )
|
if ( ret < 0 )
|
||||||
{
|
{
|
||||||
if ( ret == -EPIPE )
|
if ( ret == -EPIPE )
|
||||||
{
|
{
|
||||||
// under-run
|
// under-run
|
||||||
qDebug ( "rprepare" );
|
qDebug ( "rprepare" );
|
||||||
|
|
||||||
ret = snd_pcm_prepare ( rhandle );
|
ret = snd_pcm_prepare ( rhandle );
|
||||||
|
|
||||||
if ( ret < 0 )
|
if ( ret < 0 )
|
||||||
{
|
{
|
||||||
qDebug ( "Can't recover from underrun, prepare failed: %s", snd_strerror ( ret ) );
|
qDebug ( "Can't recover from underrun, prepare failed: %s", snd_strerror ( ret ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = snd_pcm_start ( rhandle );
|
ret = snd_pcm_start ( rhandle );
|
||||||
|
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
{
|
{
|
||||||
qDebug ( "Can't recover from underrun, start failed: %s", snd_strerror ( ret ) );
|
qDebug ( "Can't recover from underrun, start failed: %s", snd_strerror ( ret ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
else if ( ret == -ESTRPIPE )
|
else if ( ret == -ESTRPIPE )
|
||||||
{
|
{
|
||||||
qDebug ( "strpipe" );
|
qDebug ( "strpipe" );
|
||||||
|
|
||||||
// wait until the suspend flag is released
|
// wait until the suspend flag is released
|
||||||
while ( ( ret = snd_pcm_resume ( rhandle ) ) == -EAGAIN )
|
while ( ( ret = snd_pcm_resume ( rhandle ) ) == -EAGAIN )
|
||||||
{
|
{
|
||||||
sleep ( 1 );
|
sleep ( 1 );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( ret < 0 )
|
if ( ret < 0 )
|
||||||
{
|
{
|
||||||
ret = snd_pcm_prepare ( rhandle );
|
ret = snd_pcm_prepare ( rhandle );
|
||||||
|
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
{
|
{
|
||||||
qDebug ( "Can't recover from suspend, prepare failed: %s", snd_strerror ( ret ) );
|
qDebug ( "Can't recover from suspend, prepare failed: %s", snd_strerror ( ret ) );
|
||||||
}
|
}
|
||||||
throw CGenErr ( "CSound:Read" );
|
throw CGenErr ( "CSound:Read" );
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
qDebug ( "CSound::Read: %s", snd_strerror ( ret ) );
|
qDebug ( "CSound::Read: %s", snd_strerror ( ret ) );
|
||||||
throw CGenErr ( "CSound:Read" );
|
throw CGenErr ( "CSound:Read" );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSound::SetInNumBuf ( int iNewNum )
|
void CSound::SetInNumBuf ( int iNewNum )
|
||||||
{
|
{
|
||||||
/* check new parameter */
|
/* check new parameter */
|
||||||
if ( ( iNewNum >= MAX_SND_BUF_IN ) || ( iNewNum < 1 ) )
|
if ( ( iNewNum >= MAX_SND_BUF_IN ) || ( iNewNum < 1 ) )
|
||||||
{
|
{
|
||||||
iNewNum = NUM_PERIOD_BLOCKS_IN;
|
iNewNum = NUM_PERIOD_BLOCKS_IN;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Change only if parameter is different */
|
/* Change only if parameter is different */
|
||||||
if ( iNewNum != iCurPeriodSizeIn )
|
if ( iNewNum != iCurPeriodSizeIn )
|
||||||
{
|
{
|
||||||
iCurPeriodSizeIn = iNewNum;
|
iCurPeriodSizeIn = iNewNum;
|
||||||
bChangParamIn = true;
|
bChangParamIn = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Wave out *******************************************************************/
|
/* Wave out *******************************************************************/
|
||||||
void CSound::InitPlayback ( int iNewBufferSize, bool bNewBlocking )
|
void CSound::InitPlayback ( int iNewBufferSize, bool bNewBlocking )
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
// save buffer size
|
// save buffer size
|
||||||
iBufferSizeOut = iNewBufferSize / NUM_IN_OUT_CHANNELS; // mono size
|
iBufferSizeOut = iNewBufferSize / NUM_IN_OUT_CHANNELS; // mono size
|
||||||
|
|
||||||
// if playback device was already open, close it first
|
// if playback device was already open, close it first
|
||||||
if ( phandle != NULL )
|
if ( phandle != NULL )
|
||||||
{
|
{
|
||||||
snd_pcm_close ( phandle );
|
snd_pcm_close ( phandle );
|
||||||
}
|
}
|
||||||
|
|
||||||
// playback device (either "hw:0,0" or "plughw:0,0")
|
// playback device (either "hw:0,0" or "plughw:0,0")
|
||||||
if ( err = snd_pcm_open ( &phandle, "hw:0,0",
|
if ( err = snd_pcm_open ( &phandle, "hw:0,0",
|
||||||
SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK ) != 0)
|
SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK ) != 0)
|
||||||
{
|
{
|
||||||
qDebug ( "open error: %s", snd_strerror ( err ) );
|
qDebug ( "open error: %s", snd_strerror ( err ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
// non-blocking playback
|
// non-blocking playback
|
||||||
if ( err = snd_pcm_nonblock ( phandle, TRUE ) != 0 )
|
if ( err = snd_pcm_nonblock ( phandle, TRUE ) != 0 )
|
||||||
{
|
{
|
||||||
qDebug ( "cannot set blocking: %s", snd_strerror ( err ) );
|
qDebug ( "cannot set blocking: %s", snd_strerror ( err ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
// set hardware parameters
|
// set hardware parameters
|
||||||
SetHWParams ( phandle, iBufferSizeOut, iCurPeriodSizeOut );
|
SetHWParams ( phandle, iBufferSizeOut, iCurPeriodSizeOut );
|
||||||
|
|
||||||
// start playback
|
// start playback
|
||||||
snd_pcm_start ( phandle );
|
snd_pcm_start ( phandle );
|
||||||
|
|
||||||
qDebug ( "alsa init playback done" );
|
qDebug ( "alsa init playback done" );
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CSound::Write ( CVector<short>& psData )
|
bool CSound::Write ( CVector<short>& psData )
|
||||||
{
|
{
|
||||||
int size = iBufferSizeIn;
|
int size = iBufferSizeIn;
|
||||||
int start = 0;
|
int start = 0;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* Check if device must be opened or reinitialized */
|
/* Check if device must be opened or reinitialized */
|
||||||
if ( bChangParamOut == true )
|
if ( bChangParamOut == true )
|
||||||
{
|
{
|
||||||
InitPlayback ( iBufferSizeOut * NUM_IN_OUT_CHANNELS );
|
InitPlayback ( iBufferSizeOut * NUM_IN_OUT_CHANNELS );
|
||||||
|
|
||||||
/* Reset flag */
|
/* Reset flag */
|
||||||
bChangParamOut = false;
|
bChangParamOut = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
while ( size )
|
while ( size )
|
||||||
{
|
{
|
||||||
ret = snd_pcm_writei ( phandle, &psData[start], size );
|
ret = snd_pcm_writei ( phandle, &psData[start], size );
|
||||||
|
|
||||||
if ( ret < 0 )
|
if ( ret < 0 )
|
||||||
{
|
{
|
||||||
if ( ret == -EPIPE )
|
if ( ret == -EPIPE )
|
||||||
{
|
{
|
||||||
/* under-run */
|
/* under-run */
|
||||||
qDebug ( "wunderrun" );
|
qDebug ( "wunderrun" );
|
||||||
|
|
||||||
ret = snd_pcm_prepare ( phandle );
|
ret = snd_pcm_prepare ( phandle );
|
||||||
|
|
||||||
if ( ret < 0 )
|
if ( ret < 0 )
|
||||||
{
|
{
|
||||||
qDebug ( "Can't recover from underrun, prepare failed: %s", snd_strerror ( ret ) );
|
qDebug ( "Can't recover from underrun, prepare failed: %s", snd_strerror ( ret ) );
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else if ( ret == -EAGAIN )
|
else if ( ret == -EAGAIN )
|
||||||
{
|
{
|
||||||
if ( ( ret = snd_pcm_wait ( phandle, 1 ) ) < 0 )
|
if ( ( ret = snd_pcm_wait ( phandle, 1 ) ) < 0 )
|
||||||
{
|
{
|
||||||
qDebug ( "poll failed (%s)", snd_strerror ( ret ) );
|
qDebug ( "poll failed (%s)", snd_strerror ( ret ) );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else if ( ret == -ESTRPIPE )
|
else if ( ret == -ESTRPIPE )
|
||||||
{
|
{
|
||||||
qDebug("wstrpipe");
|
qDebug("wstrpipe");
|
||||||
|
|
||||||
/* wait until the suspend flag is released */
|
/* wait until the suspend flag is released */
|
||||||
while ( (ret = snd_pcm_resume ( phandle ) ) == -EAGAIN )
|
while ( (ret = snd_pcm_resume ( phandle ) ) == -EAGAIN )
|
||||||
{
|
{
|
||||||
sleep(1);
|
sleep(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( ret < 0 )
|
if ( ret < 0 )
|
||||||
{
|
{
|
||||||
ret = snd_pcm_prepare ( phandle );
|
ret = snd_pcm_prepare ( phandle );
|
||||||
|
|
||||||
if ( ret < 0 )
|
if ( ret < 0 )
|
||||||
{
|
{
|
||||||
qDebug ( "Can't recover from suspend, prepare failed: %s", snd_strerror ( ret ) );
|
qDebug ( "Can't recover from suspend, prepare failed: %s", snd_strerror ( ret ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
qDebug ( "Write error: %s", snd_strerror ( ret ) );
|
qDebug ( "Write error: %s", snd_strerror ( ret ) );
|
||||||
}
|
}
|
||||||
break; // skip one period
|
break; // skip one period
|
||||||
}
|
}
|
||||||
|
|
||||||
size -= ret;
|
size -= ret;
|
||||||
start += ret;
|
start += ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSound::SetOutNumBuf(int iNewNum)
|
void CSound::SetOutNumBuf(int iNewNum)
|
||||||
{
|
{
|
||||||
/* check new parameter */
|
/* check new parameter */
|
||||||
if ( ( iNewNum >= MAX_SND_BUF_OUT ) || ( iNewNum < 1 ) )
|
if ( ( iNewNum >= MAX_SND_BUF_OUT ) || ( iNewNum < 1 ) )
|
||||||
{
|
{
|
||||||
iNewNum = NUM_PERIOD_BLOCKS_OUT;
|
iNewNum = NUM_PERIOD_BLOCKS_OUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Change only if parameter is different */
|
/* Change only if parameter is different */
|
||||||
if ( iNewNum != iCurPeriodSizeOut )
|
if ( iNewNum != iCurPeriodSizeOut )
|
||||||
{
|
{
|
||||||
iCurPeriodSizeOut = iNewNum;
|
iCurPeriodSizeOut = iNewNum;
|
||||||
bChangParamOut = true;
|
bChangParamOut = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* common **********************************************************************/
|
/* common **********************************************************************/
|
||||||
bool CSound::SetHWParams(snd_pcm_t* handle, const int iBufferSizeIn,
|
bool CSound::SetHWParams(snd_pcm_t* handle, const int iBufferSizeIn,
|
||||||
const int iNumPeriodBlocks)
|
const int iNumPeriodBlocks)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
snd_pcm_hw_params_t* hwparams;
|
snd_pcm_hw_params_t* hwparams;
|
||||||
|
|
||||||
// allocate an invalid snd_pcm_hw_params_t using standard malloc
|
// allocate an invalid snd_pcm_hw_params_t using standard malloc
|
||||||
if ( err = snd_pcm_hw_params_malloc ( &hwparams ) < 0 )
|
if ( err = snd_pcm_hw_params_malloc ( &hwparams ) < 0 )
|
||||||
{
|
{
|
||||||
qDebug ( "cannot allocate hardware parameter structure (%s)\n", snd_strerror ( err ) );
|
qDebug ( "cannot allocate hardware parameter structure (%s)\n", snd_strerror ( err ) );
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// fill params with a full configuration space for a PCM
|
// fill params with a full configuration space for a PCM
|
||||||
if ( err = snd_pcm_hw_params_any ( handle, hwparams ) < 0 )
|
if ( err = snd_pcm_hw_params_any ( handle, hwparams ) < 0 )
|
||||||
{
|
{
|
||||||
qDebug ( "cannot initialize hardware parameter structure (%s)\n", snd_strerror ( err ) );
|
qDebug ( "cannot initialize hardware parameter structure (%s)\n", snd_strerror ( err ) );
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// restrict a configuration space to contain only one access type:
|
// restrict a configuration space to contain only one access type:
|
||||||
// set the interleaved read/write format
|
// set the interleaved read/write format
|
||||||
if ( err = snd_pcm_hw_params_set_access ( handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED ) < 0 )
|
if ( err = snd_pcm_hw_params_set_access ( handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED ) < 0 )
|
||||||
{
|
{
|
||||||
qDebug ( "Access type not available : %s", snd_strerror ( err ) );
|
qDebug ( "Access type not available : %s", snd_strerror ( err ) );
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// restrict a configuration space to contain only one format:
|
// restrict a configuration space to contain only one format:
|
||||||
// set the sample format PCM, 16 bit
|
// set the sample format PCM, 16 bit
|
||||||
if ( err = snd_pcm_hw_params_set_format ( handle, hwparams, SND_PCM_FORMAT_S16 ) < 0 )
|
if ( err = snd_pcm_hw_params_set_format ( handle, hwparams, SND_PCM_FORMAT_S16 ) < 0 )
|
||||||
{
|
{
|
||||||
qDebug ( "Sample format not available : %s", snd_strerror ( err ) );
|
qDebug ( "Sample format not available : %s", snd_strerror ( err ) );
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// restrict a configuration space to contain only one channels count:
|
// restrict a configuration space to contain only one channels count:
|
||||||
// set the count of channels (usually stereo, 2 channels)
|
// set the count of channels (usually stereo, 2 channels)
|
||||||
if ( err = snd_pcm_hw_params_set_channels(handle, hwparams, NUM_IN_OUT_CHANNELS ) < 0 )
|
if ( err = snd_pcm_hw_params_set_channels(handle, hwparams, NUM_IN_OUT_CHANNELS ) < 0 )
|
||||||
{
|
{
|
||||||
qDebug ( "Channels count (%i) not available s: %s", NUM_IN_OUT_CHANNELS, snd_strerror ( err ) );
|
qDebug ( "Channels count (%i) not available s: %s", NUM_IN_OUT_CHANNELS, snd_strerror ( err ) );
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// restrict a configuration space to have rate nearest to a target:
|
// restrict a configuration space to have rate nearest to a target:
|
||||||
// set the sample-rate
|
// set the sample-rate
|
||||||
unsigned int rrate = SND_CRD_SAMPLE_RATE;
|
unsigned int rrate = SND_CRD_SAMPLE_RATE;
|
||||||
if ( err = snd_pcm_hw_params_set_rate_near ( handle, hwparams, &rrate, 0 ) < 0 )
|
if ( err = snd_pcm_hw_params_set_rate_near ( handle, hwparams, &rrate, 0 ) < 0 )
|
||||||
{
|
{
|
||||||
qDebug ( "Rate %iHz not available : %s", rrate, snd_strerror ( err ) );
|
qDebug ( "Rate %iHz not available : %s", rrate, snd_strerror ( err ) );
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if ( rrate != SND_CRD_SAMPLE_RATE ) // check if rate is possible
|
if ( rrate != SND_CRD_SAMPLE_RATE ) // check if rate is possible
|
||||||
{
|
{
|
||||||
qDebug ( "Rate doesn't match (requested %iHz, get %iHz)", rrate, err );
|
qDebug ( "Rate doesn't match (requested %iHz, get %iHz)", rrate, err );
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// set the buffer size and period size
|
// set the buffer size and period size
|
||||||
snd_pcm_uframes_t BufferFrames = iBufferSizeIn * iNumPeriodBlocks;
|
snd_pcm_uframes_t BufferFrames = iBufferSizeIn * iNumPeriodBlocks;
|
||||||
if ( err = snd_pcm_hw_params_set_buffer_size_near ( handle, hwparams, &BufferFrames ) < 0 )
|
if ( err = snd_pcm_hw_params_set_buffer_size_near ( handle, hwparams, &BufferFrames ) < 0 )
|
||||||
{
|
{
|
||||||
qDebug ( "cannot set buffer size (%s)\n", snd_strerror ( err ) );
|
qDebug ( "cannot set buffer size (%s)\n", snd_strerror ( err ) );
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// set the period size
|
// set the period size
|
||||||
snd_pcm_uframes_t PeriodSize = iBufferSizeIn;
|
snd_pcm_uframes_t PeriodSize = iBufferSizeIn;
|
||||||
if ( err = snd_pcm_hw_params_set_period_size_near ( handle, hwparams, &PeriodSize, 0 ) < 0 )
|
if ( err = snd_pcm_hw_params_set_period_size_near ( handle, hwparams, &PeriodSize, 0 ) < 0 )
|
||||||
{
|
{
|
||||||
qDebug ( "cannot set period size (%s)\n", snd_strerror ( err ) );
|
qDebug ( "cannot set period size (%s)\n", snd_strerror ( err ) );
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// write the parameters to device
|
// write the parameters to device
|
||||||
if ( err = snd_pcm_hw_params ( handle, hwparams ) < 0 )
|
if ( err = snd_pcm_hw_params ( handle, hwparams ) < 0 )
|
||||||
{
|
{
|
||||||
qDebug("Unable to set hw params : %s", snd_strerror(err));
|
qDebug("Unable to set hw params : %s", snd_strerror(err));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* check period and buffer size */
|
/* check period and buffer size */
|
||||||
snd_pcm_uframes_t buffer_size;
|
snd_pcm_uframes_t buffer_size;
|
||||||
if (err = snd_pcm_hw_params_get_buffer_size(hwparams, &buffer_size) < 0) {
|
if (err = snd_pcm_hw_params_get_buffer_size(hwparams, &buffer_size) < 0) {
|
||||||
qDebug("Unable to get buffer size for playback: %s\n", snd_strerror(err));
|
qDebug("Unable to get buffer size for playback: %s\n", snd_strerror(err));
|
||||||
}
|
}
|
||||||
qDebug("buffer size: %d (desired: %d)", buffer_size, iBufferSizeIn * iNumPeriodBlocks);
|
qDebug("buffer size: %d (desired: %d)", buffer_size, iBufferSizeIn * iNumPeriodBlocks);
|
||||||
|
|
||||||
|
@ -428,34 +428,34 @@ snd_pcm_uframes_t period_size;
|
||||||
err = snd_pcm_hw_params_get_period_size(hwparams, &period_size, 0);
|
err = snd_pcm_hw_params_get_period_size(hwparams, &period_size, 0);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
{
|
{
|
||||||
qDebug("Unable to get period size for playback: %s\n", snd_strerror(err));
|
qDebug("Unable to get period size for playback: %s\n", snd_strerror(err));
|
||||||
}
|
}
|
||||||
qDebug("frame size: %d (desired: %d)", period_size, iBufferSizeIn);
|
qDebug("frame size: %d (desired: %d)", period_size, iBufferSizeIn);
|
||||||
|
|
||||||
|
|
||||||
/* clean-up */
|
/* clean-up */
|
||||||
snd_pcm_hw_params_free ( hwparams );
|
snd_pcm_hw_params_free ( hwparams );
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSound::Close ()
|
void CSound::Close ()
|
||||||
{
|
{
|
||||||
/* read */
|
/* read */
|
||||||
if ( rhandle != NULL )
|
if ( rhandle != NULL )
|
||||||
{
|
{
|
||||||
snd_pcm_close ( rhandle );
|
snd_pcm_close ( rhandle );
|
||||||
}
|
}
|
||||||
|
|
||||||
rhandle = NULL;
|
rhandle = NULL;
|
||||||
|
|
||||||
/* playback */
|
/* playback */
|
||||||
if ( phandle != NULL )
|
if ( phandle != NULL )
|
||||||
{
|
{
|
||||||
snd_pcm_close ( phandle );
|
snd_pcm_close ( phandle );
|
||||||
}
|
}
|
||||||
|
|
||||||
phandle = NULL;
|
phandle = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* WITH_SOUND */
|
#endif /* WITH_SOUND */
|
||||||
|
|
100
linux/sound.h
100
linux/sound.h
|
@ -2,7 +2,7 @@
|
||||||
* Copyright (c) 2004-2005
|
* Copyright (c) 2004-2005
|
||||||
*
|
*
|
||||||
* Author(s):
|
* Author(s):
|
||||||
* Volker Fischer, Alexander Kurpiers
|
* Volker Fischer, Alexander Kurpiers
|
||||||
*
|
*
|
||||||
* This code is based on the Open-Source sound interface implementation of
|
* This code is based on the Open-Source sound interface implementation of
|
||||||
* the Dream DRM Receiver project.
|
* the Dream DRM Receiver project.
|
||||||
|
@ -31,74 +31,74 @@
|
||||||
|
|
||||||
|
|
||||||
/* Definitions ****************************************************************/
|
/* Definitions ****************************************************************/
|
||||||
#define NUM_IN_OUT_CHANNELS 2 /* always stereo */
|
#define NUM_IN_OUT_CHANNELS 2 /* always stereo */
|
||||||
|
|
||||||
/* the number of periods is critical for latency */
|
/* the number of periods is critical for latency */
|
||||||
#define NUM_PERIOD_BLOCKS_IN 2
|
#define NUM_PERIOD_BLOCKS_IN 2
|
||||||
#define NUM_PERIOD_BLOCKS_OUT 2
|
#define NUM_PERIOD_BLOCKS_OUT 2
|
||||||
|
|
||||||
#define MAX_SND_BUF_IN 200
|
#define MAX_SND_BUF_IN 200
|
||||||
#define MAX_SND_BUF_OUT 200
|
#define MAX_SND_BUF_OUT 200
|
||||||
|
|
||||||
/* Classes ********************************************************************/
|
/* Classes ********************************************************************/
|
||||||
class CSound
|
class CSound
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CSound()
|
CSound()
|
||||||
#if WITH_SOUND
|
#if WITH_SOUND
|
||||||
: rhandle(NULL), phandle(NULL), iCurPeriodSizeIn(NUM_PERIOD_BLOCKS_IN),
|
: rhandle(NULL), phandle(NULL), iCurPeriodSizeIn(NUM_PERIOD_BLOCKS_IN),
|
||||||
iCurPeriodSizeOut(NUM_PERIOD_BLOCKS_OUT), bChangParamIn(true),
|
iCurPeriodSizeOut(NUM_PERIOD_BLOCKS_OUT), bChangParamIn(true),
|
||||||
bChangParamOut(true)
|
bChangParamOut(true)
|
||||||
#endif
|
#endif
|
||||||
{}
|
{}
|
||||||
virtual ~CSound() {Close();}
|
virtual ~CSound() {Close();}
|
||||||
|
|
||||||
/* Not implemented yet, always return one device and default string */
|
/* Not implemented yet, always return one device and default string */
|
||||||
int GetNumDev() {return 1;}
|
int GetNumDev() {return 1;}
|
||||||
void SetOutDev(int iNewDev) {}
|
void SetOutDev(int iNewDev) {}
|
||||||
void SetInDev(int iNewDev) {}
|
void SetInDev(int iNewDev) {}
|
||||||
|
|
||||||
/* Return invalid device ID which is the same as using "wave mapper" which
|
/* Return invalid device ID which is the same as using "wave mapper" which
|
||||||
we assume here to be used */
|
we assume here to be used */
|
||||||
int GetOutDev() {return 1;}
|
int GetOutDev() {return 1;}
|
||||||
int GetInDev() {return 1;}
|
int GetInDev() {return 1;}
|
||||||
|
|
||||||
#if WITH_SOUND
|
#if WITH_SOUND
|
||||||
void SetInNumBuf(int iNewNum);
|
void SetInNumBuf(int iNewNum);
|
||||||
int GetInNumBuf() {return iCurPeriodSizeIn;}
|
int GetInNumBuf() {return iCurPeriodSizeIn;}
|
||||||
void SetOutNumBuf(int iNewNum);
|
void SetOutNumBuf(int iNewNum);
|
||||||
int GetOutNumBuf() {return iCurPeriodSizeOut;}
|
int GetOutNumBuf() {return iCurPeriodSizeOut;}
|
||||||
void InitRecording(int iNewBufferSize, bool bNewBlocking = true);
|
void InitRecording(int iNewBufferSize, bool bNewBlocking = true);
|
||||||
void InitPlayback(int iNewBufferSize, bool bNewBlocking = false);
|
void InitPlayback(int iNewBufferSize, bool bNewBlocking = false);
|
||||||
bool Read(CVector<short>& psData);
|
bool Read(CVector<short>& psData);
|
||||||
bool Write(CVector<short>& psData);
|
bool Write(CVector<short>& psData);
|
||||||
|
|
||||||
void Close();
|
void Close();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
snd_pcm_t* rhandle;
|
snd_pcm_t* rhandle;
|
||||||
snd_pcm_t* phandle;
|
snd_pcm_t* phandle;
|
||||||
|
|
||||||
bool SetHWParams(snd_pcm_t* handle, const int iBufferSizeIn,
|
bool SetHWParams(snd_pcm_t* handle, const int iBufferSizeIn,
|
||||||
const int iNumPeriodBlocks);
|
const int iNumPeriodBlocks);
|
||||||
|
|
||||||
int iBufferSizeOut;
|
int iBufferSizeOut;
|
||||||
int iBufferSizeIn;
|
int iBufferSizeIn;
|
||||||
bool bChangParamIn;
|
bool bChangParamIn;
|
||||||
int iCurPeriodSizeIn;
|
int iCurPeriodSizeIn;
|
||||||
bool bChangParamOut;
|
bool bChangParamOut;
|
||||||
int iCurPeriodSizeOut;
|
int iCurPeriodSizeOut;
|
||||||
#else
|
#else
|
||||||
/* Dummy definitions */
|
/* Dummy definitions */
|
||||||
void SetInNumBuf(int iNewNum) {}
|
void SetInNumBuf(int iNewNum) {}
|
||||||
int GetInNumBuf() {return 1;}
|
int GetInNumBuf() {return 1;}
|
||||||
void SetOutNumBuf(int iNewNum) {}
|
void SetOutNumBuf(int iNewNum) {}
|
||||||
int GetOutNumBuf() {return 1;}
|
int GetOutNumBuf() {return 1;}
|
||||||
void InitRecording(int iNewBufferSize, bool bNewBlocking = true) {printf("no sound!");}
|
void InitRecording(int iNewBufferSize, bool bNewBlocking = true) {printf("no sound!");}
|
||||||
void InitPlayback(int iNewBufferSize, bool bNewBlocking = false) {printf("no sound!");}
|
void InitPlayback(int iNewBufferSize, bool bNewBlocking = false) {printf("no sound!");}
|
||||||
bool Read(CVector<short>& psData) {printf("no sound!"); return false;}
|
bool Read(CVector<short>& psData) {printf("no sound!"); return false;}
|
||||||
bool Write(CVector<short>& psData) {printf("no sound!"); return false;}
|
bool Write(CVector<short>& psData) {printf("no sound!"); return false;}
|
||||||
void Close() {}
|
void Close() {}
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
199
src/client.cpp
199
src/client.cpp
|
@ -26,14 +26,15 @@
|
||||||
|
|
||||||
|
|
||||||
/* Implementation *************************************************************/
|
/* Implementation *************************************************************/
|
||||||
CClient::CClient () : bRun ( false ), Socket ( &Channel ),
|
CClient::CClient() : bRun ( false ), Socket ( &Channel ),
|
||||||
iAudioInFader ( AUD_FADER_IN_MAX / 2 ),
|
iAudioInFader ( AUD_FADER_IN_MAX / 2 ),
|
||||||
iReverbLevel ( AUD_REVERB_MAX / 6 ),
|
iReverbLevel ( AUD_REVERB_MAX / 6 ),
|
||||||
bReverbOnLeftChan ( false ),
|
bReverbOnLeftChan ( false ),
|
||||||
iNetwBufSizeFactIn ( DEF_NET_BLOCK_SIZE_FACTOR )
|
iNetwBufSizeFactIn ( DEF_NET_BLOCK_SIZE_FACTOR )
|
||||||
{
|
{
|
||||||
// connection for protocol
|
// connection for protocol
|
||||||
QObject::connect ( &Channel, SIGNAL ( MessReadyForSending ( CVector<uint8_t> ) ),
|
QObject::connect ( &Channel,
|
||||||
|
SIGNAL ( MessReadyForSending ( CVector<uint8_t> ) ),
|
||||||
this, SLOT ( OnSendProtMessage ( CVector<uint8_t> ) ) );
|
this, SLOT ( OnSendProtMessage ( CVector<uint8_t> ) ) );
|
||||||
|
|
||||||
QObject::connect ( &Channel, SIGNAL ( ReqJittBufSize() ),
|
QObject::connect ( &Channel, SIGNAL ( ReqJittBufSize() ),
|
||||||
|
@ -42,7 +43,8 @@ CClient::CClient () : bRun ( false ), Socket ( &Channel ),
|
||||||
QObject::connect ( &Channel, SIGNAL ( ProtocolStatus ( bool ) ),
|
QObject::connect ( &Channel, SIGNAL ( ProtocolStatus ( bool ) ),
|
||||||
this, SLOT ( OnProtocolStatus ( bool ) ) );
|
this, SLOT ( OnProtocolStatus ( bool ) ) );
|
||||||
|
|
||||||
QObject::connect ( &Channel, SIGNAL ( ConClientListMesReceived ( CVector<CChannelShortInfo> ) ),
|
QObject::connect ( &Channel,
|
||||||
|
SIGNAL ( ConClientListMesReceived ( CVector<CChannelShortInfo> ) ),
|
||||||
SIGNAL ( ConClientListMesReceived ( CVector<CChannelShortInfo> ) ) );
|
SIGNAL ( ConClientListMesReceived ( CVector<CChannelShortInfo> ) ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,15 +52,15 @@ void CClient::OnSendProtMessage ( CVector<uint8_t> vecMessage )
|
||||||
{
|
{
|
||||||
|
|
||||||
// convert unsigned uint8_t in char, TODO convert all buffers in uint8_t
|
// convert unsigned uint8_t in char, TODO convert all buffers in uint8_t
|
||||||
CVector<unsigned char> vecbyDataConv ( vecMessage.Size () );
|
CVector<unsigned char> vecbyDataConv ( vecMessage.Size() );
|
||||||
for ( int i = 0; i < vecMessage.Size (); i++ ) {
|
for ( int i = 0; i < vecMessage.Size(); i++ ) {
|
||||||
vecbyDataConv[i] = static_cast<unsigned char> ( vecMessage[i] );
|
vecbyDataConv[i] = static_cast<unsigned char> ( vecMessage[i] );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// the protocol queries me to call the function to send the message
|
// the protocol queries me to call the function to send the message
|
||||||
// send it through the network
|
// send it through the network
|
||||||
Socket.SendPacket ( vecbyDataConv, Channel.GetAddress () );
|
Socket.SendPacket ( vecbyDataConv, Channel.GetAddress() );
|
||||||
}
|
}
|
||||||
|
|
||||||
void CClient::OnReqJittBufSize()
|
void CClient::OnReqJittBufSize()
|
||||||
|
@ -102,37 +104,37 @@ void CClient::OnProtocolStatus ( bool bOk )
|
||||||
|
|
||||||
void CClient::Init()
|
void CClient::Init()
|
||||||
{
|
{
|
||||||
/* set block sizes (in samples) */
|
// set block sizes (in samples)
|
||||||
iBlockSizeSam = MIN_BLOCK_SIZE_SAMPLES;
|
iBlockSizeSam = MIN_BLOCK_SIZE_SAMPLES;
|
||||||
iSndCrdBlockSizeSam = MIN_SND_CRD_BLOCK_SIZE_SAMPLES;
|
iSndCrdBlockSizeSam = MIN_SND_CRD_BLOCK_SIZE_SAMPLES;
|
||||||
|
|
||||||
vecsAudioSndCrd.Init(iSndCrdBlockSizeSam * 2); /* stereo */
|
vecsAudioSndCrd.Init ( iSndCrdBlockSizeSam * 2 ); // stereo
|
||||||
vecdAudioSndCrdL.Init(iSndCrdBlockSizeSam);
|
vecdAudioSndCrdL.Init ( iSndCrdBlockSizeSam );
|
||||||
vecdAudioSndCrdR.Init(iSndCrdBlockSizeSam);
|
vecdAudioSndCrdR.Init ( iSndCrdBlockSizeSam );
|
||||||
|
|
||||||
vecdAudioL.Init(iBlockSizeSam);
|
vecdAudioL.Init ( iBlockSizeSam );
|
||||||
vecdAudioR.Init(iBlockSizeSam);
|
vecdAudioR.Init ( iBlockSizeSam );
|
||||||
|
|
||||||
Sound.InitRecording(iSndCrdBlockSizeSam * 2 /* stereo */);
|
Sound.InitRecording ( iSndCrdBlockSizeSam * 2 ); // stereo
|
||||||
Sound.InitPlayback(iSndCrdBlockSizeSam * 2 /* stereo */);
|
Sound.InitPlayback ( iSndCrdBlockSizeSam * 2 ); // stereo
|
||||||
|
|
||||||
/* resample objects are always initialized with the input block size */
|
// resample objects are always initialized with the input block size
|
||||||
/* record */
|
// record
|
||||||
ResampleObjDownL.Init(iSndCrdBlockSizeSam, SND_CRD_SAMPLE_RATE, SAMPLE_RATE);
|
ResampleObjDownL.Init ( iSndCrdBlockSizeSam, SND_CRD_SAMPLE_RATE, SAMPLE_RATE );
|
||||||
ResampleObjDownR.Init(iSndCrdBlockSizeSam, SND_CRD_SAMPLE_RATE, SAMPLE_RATE);
|
ResampleObjDownR.Init ( iSndCrdBlockSizeSam, SND_CRD_SAMPLE_RATE, SAMPLE_RATE );
|
||||||
|
|
||||||
/* playback */
|
// playback
|
||||||
ResampleObjUpL.Init(iBlockSizeSam, SAMPLE_RATE, SND_CRD_SAMPLE_RATE);
|
ResampleObjUpL.Init ( iBlockSizeSam, SAMPLE_RATE, SND_CRD_SAMPLE_RATE );
|
||||||
ResampleObjUpR.Init(iBlockSizeSam, SAMPLE_RATE, SND_CRD_SAMPLE_RATE);
|
ResampleObjUpR.Init ( iBlockSizeSam, SAMPLE_RATE, SND_CRD_SAMPLE_RATE );
|
||||||
|
|
||||||
/* init network buffers */
|
// init network buffers
|
||||||
vecsNetwork.Init(iBlockSizeSam);
|
vecsNetwork.Init ( iBlockSizeSam );
|
||||||
vecdNetwData.Init(iBlockSizeSam);
|
vecdNetwData.Init ( iBlockSizeSam );
|
||||||
|
|
||||||
/* init moving average buffer for response time evaluation */
|
// init moving average buffer for response time evaluation
|
||||||
RespTimeMoAvBuf.Init(LEN_MOV_AV_RESPONSE);
|
RespTimeMoAvBuf.Init ( LEN_MOV_AV_RESPONSE );
|
||||||
|
|
||||||
/* init time for response time evaluation */
|
// init time for response time evaluation
|
||||||
TimeLastBlock = QTime::currentTime();
|
TimeLastBlock = QTime::currentTime();
|
||||||
|
|
||||||
AudioReverb.Clear();
|
AudioReverb.Clear();
|
||||||
|
@ -142,111 +144,116 @@ void CClient::run()
|
||||||
{
|
{
|
||||||
int i, iInCnt;
|
int i, iInCnt;
|
||||||
|
|
||||||
/* Set thread priority (The working thread should have a higher
|
// Set thread priority (The working thread should have a higher
|
||||||
priority than the GUI) */
|
// priority than the GUI)
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
SetThreadPriority ( GetCurrentThread (), THREAD_PRIORITY_ABOVE_NORMAL );
|
SetThreadPriority ( GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL );
|
||||||
#else
|
#else
|
||||||
/* set the process to realtime privs, taken from
|
// set the process to realtime privs, taken from
|
||||||
"http://www.gardena.net/benno/linux/audio" but does not seem to work,
|
// "http://www.gardena.net/benno/linux/audio" but does not seem to work,
|
||||||
maybe a problem with user rights */
|
// maybe a problem with user rights
|
||||||
struct sched_param schp;
|
struct sched_param schp;
|
||||||
memset ( &schp, 0, sizeof ( schp ) );
|
memset ( &schp, 0, sizeof ( schp ) );
|
||||||
schp.sched_priority = sched_get_priority_max ( SCHED_FIFO );
|
schp.sched_priority = sched_get_priority_max ( SCHED_FIFO );
|
||||||
sched_setscheduler ( 0, SCHED_FIFO, &schp );
|
sched_setscheduler ( 0, SCHED_FIFO, &schp );
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* init object */
|
// init object
|
||||||
Init();
|
Init();
|
||||||
|
|
||||||
|
|
||||||
/* runtime phase --------------------------------------------------------- */
|
// runtime phase ------------------------------------------------------------
|
||||||
bRun = true;
|
bRun = true;
|
||||||
|
|
||||||
/* main loop of working thread */
|
// main loop of working thread
|
||||||
while (bRun)
|
while ( bRun )
|
||||||
{
|
{
|
||||||
/* get audio from sound card (blocking function) */
|
// get audio from sound card (blocking function)
|
||||||
if (Sound.Read(vecsAudioSndCrd))
|
if ( Sound.Read ( vecsAudioSndCrd ) )
|
||||||
{
|
{
|
||||||
PostWinMessage(MS_SOUND_IN, MUL_COL_LED_RED);
|
PostWinMessage ( MS_SOUND_IN, MUL_COL_LED_RED );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
PostWinMessage(MS_SOUND_IN, MUL_COL_LED_GREEN);
|
PostWinMessage ( MS_SOUND_IN, MUL_COL_LED_GREEN );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* copy data from one stereo buffer in two separate buffers */
|
// copy data from one stereo buffer in two separate buffers
|
||||||
iInCnt = 0;
|
iInCnt = 0;
|
||||||
for (i = 0; i < iSndCrdBlockSizeSam; i++)
|
for ( i = 0; i < iSndCrdBlockSizeSam; i++ )
|
||||||
{
|
{
|
||||||
vecdAudioSndCrdL[i] = (double) vecsAudioSndCrd[iInCnt++];
|
vecdAudioSndCrdL[i] = (double) vecsAudioSndCrd[iInCnt++];
|
||||||
vecdAudioSndCrdR[i] = (double) vecsAudioSndCrd[iInCnt++];
|
vecdAudioSndCrdR[i] = (double) vecsAudioSndCrd[iInCnt++];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* resample data for each channel seaparately */
|
// resample data for each channel seaparately
|
||||||
ResampleObjDownL.Resample(vecdAudioSndCrdL, vecdAudioL);
|
ResampleObjDownL.Resample ( vecdAudioSndCrdL, vecdAudioL );
|
||||||
ResampleObjDownR.Resample(vecdAudioSndCrdR, vecdAudioR);
|
ResampleObjDownR.Resample ( vecdAudioSndCrdR, vecdAudioR );
|
||||||
|
|
||||||
/* update signal level meters */
|
// update signal level meters
|
||||||
SignalLevelMeterL.Update(vecdAudioL);
|
SignalLevelMeterL.Update ( vecdAudioL );
|
||||||
SignalLevelMeterR.Update(vecdAudioR);
|
SignalLevelMeterR.Update ( vecdAudioR );
|
||||||
|
|
||||||
/* add reverberation effect if activated */
|
// add reverberation effect if activated
|
||||||
if (iReverbLevel != 0)
|
if ( iReverbLevel != 0 )
|
||||||
{
|
{
|
||||||
/* first attenuation amplification factor */
|
// first attenuation amplification factor
|
||||||
const double dRevLev = (double) iReverbLevel / AUD_REVERB_MAX / 2;
|
const double dRevLev = (double) iReverbLevel / AUD_REVERB_MAX / 2;
|
||||||
|
|
||||||
if (bReverbOnLeftChan)
|
if ( bReverbOnLeftChan )
|
||||||
{
|
{
|
||||||
for (i = 0; i < iBlockSizeSam; i++)
|
for (i = 0; i < iBlockSizeSam; i++)
|
||||||
{
|
{
|
||||||
/* left channel */
|
// left channel
|
||||||
vecdAudioL[i] +=
|
vecdAudioL[i] +=
|
||||||
dRevLev * AudioReverb.ProcessSample(vecdAudioL[i]);
|
dRevLev * AudioReverb.ProcessSample ( vecdAudioL[i] );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (i = 0; i < iBlockSizeSam; i++)
|
for ( i = 0; i < iBlockSizeSam; i++ )
|
||||||
{
|
{
|
||||||
/* right channel */
|
// right channel
|
||||||
vecdAudioR[i] +=
|
vecdAudioR[i] +=
|
||||||
dRevLev * AudioReverb.ProcessSample(vecdAudioR[i]);
|
dRevLev * AudioReverb.ProcessSample ( vecdAudioR[i] );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* mix both signals depending on the fading setting */
|
// mix both signals depending on the fading setting
|
||||||
const int iMiddleOfFader = AUD_FADER_IN_MAX / 2;
|
const int iMiddleOfFader = AUD_FADER_IN_MAX / 2;
|
||||||
const double dAttFact =
|
const double dAttFact =
|
||||||
(double) (iMiddleOfFader - abs(iMiddleOfFader - iAudioInFader)) /
|
(double) ( iMiddleOfFader - abs ( iMiddleOfFader - iAudioInFader ) ) /
|
||||||
iMiddleOfFader;
|
iMiddleOfFader;
|
||||||
for (i = 0; i < iBlockSizeSam; i++)
|
|
||||||
|
for ( i = 0; i < iBlockSizeSam; i++ )
|
||||||
{
|
{
|
||||||
double dMixedSignal;
|
double dMixedSignal;
|
||||||
|
|
||||||
if (iAudioInFader > iMiddleOfFader)
|
if ( iAudioInFader > iMiddleOfFader )
|
||||||
|
{
|
||||||
dMixedSignal = vecdAudioL[i] + dAttFact * vecdAudioR[i];
|
dMixedSignal = vecdAudioL[i] + dAttFact * vecdAudioR[i];
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
dMixedSignal = vecdAudioR[i] + dAttFact * vecdAudioL[i];
|
dMixedSignal = vecdAudioR[i] + dAttFact * vecdAudioL[i];
|
||||||
|
}
|
||||||
|
|
||||||
vecsNetwork[i] = Double2Short(dMixedSignal);
|
vecsNetwork[i] = Double2Short ( dMixedSignal );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* send it through the network */
|
// send it through the network
|
||||||
Socket.SendPacket ( Channel.PrepSendPacket ( vecsNetwork ),
|
Socket.SendPacket ( Channel.PrepSendPacket ( vecsNetwork ),
|
||||||
Channel.GetAddress () );
|
Channel.GetAddress () );
|
||||||
|
|
||||||
/* receive a new block */
|
// receive a new block
|
||||||
if (Channel.GetData(vecdNetwData))
|
if ( Channel.GetData ( vecdNetwData ) )
|
||||||
{
|
{
|
||||||
PostWinMessage(MS_JIT_BUF_GET, MUL_COL_LED_GREEN);
|
PostWinMessage ( MS_JIT_BUF_GET, MUL_COL_LED_GREEN );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
PostWinMessage(MS_JIT_BUF_GET, MUL_COL_LED_RED);
|
PostWinMessage ( MS_JIT_BUF_GET, MUL_COL_LED_RED );
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef _DEBUG_
|
#ifdef _DEBUG_
|
||||||
|
@ -311,53 +318,53 @@ fflush(pFileDelay);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
/* check if channel is connected */
|
// check if channel is connected
|
||||||
if (Channel.IsConnected())
|
if ( Channel.IsConnected() )
|
||||||
{
|
{
|
||||||
/* write mono input signal in both sound-card channels */
|
// write mono input signal in both sound-card channels
|
||||||
for (i = 0; i < iBlockSizeSam; i++)
|
for ( i = 0; i < iBlockSizeSam; i++ )
|
||||||
{
|
{
|
||||||
vecdAudioL[i] = vecdAudioR[i] = vecdNetwData[i];
|
vecdAudioL[i] = vecdAudioR[i] = vecdNetwData[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* if not connected, clear data */
|
// if not connected, clear data
|
||||||
for (i = 0; i < iBlockSizeSam; i++)
|
for ( i = 0; i < iBlockSizeSam; i++ )
|
||||||
{
|
{
|
||||||
vecdAudioL[i] = vecdAudioR[i] = 0.0;
|
vecdAudioL[i] = vecdAudioR[i] = 0.0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* resample data for each channel separately */
|
// resample data for each channel separately
|
||||||
ResampleObjUpL.Resample(vecdAudioL, vecdAudioSndCrdL);
|
ResampleObjUpL.Resample ( vecdAudioL, vecdAudioSndCrdL );
|
||||||
ResampleObjUpR.Resample(vecdAudioR, vecdAudioSndCrdR);
|
ResampleObjUpR.Resample ( vecdAudioR, vecdAudioSndCrdR );
|
||||||
|
|
||||||
/* copy data from one stereo buffer in two separate buffers */
|
// copy data from one stereo buffer in two separate buffers
|
||||||
iInCnt = 0;
|
iInCnt = 0;
|
||||||
for (i = 0; i < iSndCrdBlockSizeSam; i++)
|
for ( i = 0; i < iSndCrdBlockSizeSam; i++ )
|
||||||
{
|
{
|
||||||
vecsAudioSndCrd[iInCnt++] = Double2Short(vecdAudioSndCrdL[i]);
|
vecsAudioSndCrd[iInCnt++] = Double2Short ( vecdAudioSndCrdL[i] );
|
||||||
vecsAudioSndCrd[iInCnt++] = Double2Short(vecdAudioSndCrdR[i]);
|
vecsAudioSndCrd[iInCnt++] = Double2Short ( vecdAudioSndCrdR[i] );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* play the new block */
|
// play the new block
|
||||||
if (Sound.Write(vecsAudioSndCrd))
|
if ( Sound.Write ( vecsAudioSndCrd ) )
|
||||||
{
|
{
|
||||||
PostWinMessage(MS_SOUND_OUT, MUL_COL_LED_RED);
|
PostWinMessage ( MS_SOUND_OUT, MUL_COL_LED_RED );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
PostWinMessage(MS_SOUND_OUT, MUL_COL_LED_GREEN);
|
PostWinMessage ( MS_SOUND_OUT, MUL_COL_LED_GREEN );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* update response time measurement --------------------------------- */
|
// update response time measurement ------------------------------------
|
||||||
/* add time difference */
|
// add time difference
|
||||||
const QTime CurTime = QTime::currentTime();
|
const QTime CurTime = QTime::currentTime();
|
||||||
|
|
||||||
/* we want to calculate the standard deviation (we assume that the mean
|
// we want to calculate the standard deviation (we assume that the mean
|
||||||
is correct at the block period time) */
|
// is correct at the block period time)
|
||||||
const double dCurAddVal =
|
const double dCurAddVal =
|
||||||
( (double) TimeLastBlock.msecsTo ( CurTime ) - MIN_BLOCK_DURATION_MS );
|
( (double) TimeLastBlock.msecsTo ( CurTime ) - MIN_BLOCK_DURATION_MS );
|
||||||
|
|
||||||
|
@ -368,23 +375,23 @@ fprintf(pFileTest, "%e\n", dCurAddVal);
|
||||||
fflush(pFileTest);
|
fflush(pFileTest);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
RespTimeMoAvBuf.Add ( dCurAddVal * dCurAddVal ); /* add squared value */
|
RespTimeMoAvBuf.Add ( dCurAddVal * dCurAddVal ); // add squared value
|
||||||
|
|
||||||
/* store old time value */
|
// store old time value
|
||||||
TimeLastBlock = CurTime;
|
TimeLastBlock = CurTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* reset current signal level and LEDs */
|
// reset current signal level and LEDs
|
||||||
SignalLevelMeterL.Reset();
|
SignalLevelMeterL.Reset();
|
||||||
SignalLevelMeterR.Reset();
|
SignalLevelMeterR.Reset();
|
||||||
PostWinMessage(MS_RESET_ALL, 0);
|
PostWinMessage ( MS_RESET_ALL, 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CClient::Stop()
|
bool CClient::Stop()
|
||||||
{
|
{
|
||||||
/* set flag so that thread can leave the main loop */
|
// set flag so that thread can leave the main loop
|
||||||
bRun = false;
|
bRun = false;
|
||||||
|
|
||||||
/* give thread some time to terminate, return status */
|
// give thread some time to terminate, return status
|
||||||
return wait(5000);
|
return wait ( 5000 );
|
||||||
}
|
}
|
||||||
|
|
|
@ -114,9 +114,13 @@ CLlconClientDlg::CLlconClientDlg ( CClient* pNCliP, QWidget* parent,
|
||||||
/* set radio buttons --- */
|
/* set radio buttons --- */
|
||||||
// reverb channel
|
// reverb channel
|
||||||
if (pClient->IsReverbOnLeftChan())
|
if (pClient->IsReverbOnLeftChan())
|
||||||
|
{
|
||||||
RadioButtonRevSelL->setChecked(true);
|
RadioButtonRevSelL->setChecked(true);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
RadioButtonRevSelR->setChecked(true);
|
RadioButtonRevSelR->setChecked(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Settings menu ------------------------------------------------------- */
|
/* Settings menu ------------------------------------------------------- */
|
||||||
|
@ -138,6 +142,18 @@ CLlconClientDlg::CLlconClientDlg ( CClient* pNCliP, QWidget* parent,
|
||||||
/* Now tell the layout about the menu */
|
/* Now tell the layout about the menu */
|
||||||
CLlconClientDlgBaseLayout->setMenuBar ( pMenu );
|
CLlconClientDlgBaseLayout->setMenuBar ( pMenu );
|
||||||
|
|
||||||
|
|
||||||
|
// mixer board -------------------------------------------------------------
|
||||||
|
// create all mixer controls and make them invisible
|
||||||
|
vecpChanFader.Init ( MAX_NUM_CHANNELS );
|
||||||
|
for ( int i = 0; i < MAX_NUM_CHANNELS; i++ )
|
||||||
|
{
|
||||||
|
vecpChanFader[i] = new CLlconClientDlg::CChannelFader ( FrameAudioFaders,
|
||||||
|
FrameAudioFadersLayout, "test" );
|
||||||
|
|
||||||
|
vecpChanFader[i]->Hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* connections ---------------------------------------------------------- */
|
/* connections ---------------------------------------------------------- */
|
||||||
// push-buttons
|
// push-buttons
|
||||||
|
@ -221,7 +237,20 @@ void CLlconClientDlg::OnConnectDisconBut ()
|
||||||
ProgressBarInputLevelR->setProgress ( 0 );
|
ProgressBarInputLevelR->setProgress ( 0 );
|
||||||
|
|
||||||
/* immediately update status bar */
|
/* immediately update status bar */
|
||||||
OnTimerStatus ();
|
OnTimerStatus ();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// TEST
|
||||||
|
/*
|
||||||
|
// make old controls invisible
|
||||||
|
for ( int i = 0; i < MAX_NUM_CHANNELS; i++ )
|
||||||
|
{
|
||||||
|
vecpChanFader[i]->Hide();
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -294,32 +323,28 @@ void CLlconClientDlg::OnConClientListMesReceived ( CVector<CChannelShortInfo> ve
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//FrameAudioFadersLayout->addWidget(new QLabel ( "test", FrameAudioFaders ));
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
|
|
||||||
// remove old controls
|
// make old controls invisible
|
||||||
for ( i = 0; i < vecpChanFader.Size(); i++ )
|
for ( i = 0; i < MAX_NUM_CHANNELS; i++ )
|
||||||
{
|
{
|
||||||
delete vecpChanFader[i];
|
vecpChanFader[i]->Hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// TEST add current faders
|
// TEST add current faders
|
||||||
vecpChanFader.Init ( vecChanInfo.Size() );
|
|
||||||
for ( i = 0; i < vecChanInfo.Size(); i++ )
|
for ( i = 0; i < vecChanInfo.Size(); i++ )
|
||||||
{
|
{
|
||||||
QHostAddress addrTest ( vecChanInfo[i].veciIpAddr );
|
QHostAddress addrTest ( vecChanInfo[i].veciIpAddr );
|
||||||
|
|
||||||
vecpChanFader[i] = new CLlconClientDlg::CChannelFader ( FrameAudioFaders,
|
vecpChanFader[i]->Show();
|
||||||
FrameAudioFadersLayout, addrTest.toString() );
|
vecpChanFader[i]->SetText ( addrTest.toString().latin1() );
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// vecpChanFader[i] = new CLlconClientDlg::CChannelFader ( FrameAudioFaders,
|
||||||
|
// FrameAudioFadersLayout, addrTest.toString() );
|
||||||
}
|
}
|
||||||
//FrameAudioFadersLayout->addWidget(new QLabel ( "test", FrameAudioFaders ));
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -399,3 +424,8 @@ pFader->setEnabled ( FALSE );
|
||||||
|
|
||||||
pParentLayout->insertLayout ( 0, pMainGrid );
|
pParentLayout->insertLayout ( 0, pMainGrid );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CLlconClientDlg::CChannelFader::SetText ( const std::string sText )
|
||||||
|
{
|
||||||
|
pLabel->setText ( sText.c_str() );
|
||||||
|
}
|
||||||
|
|
|
@ -85,6 +85,10 @@ protected:
|
||||||
// TODO get rid of pMainGrid
|
// TODO get rid of pMainGrid
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SetText ( const std::string sText );
|
||||||
|
void Show() { pLabel->show(); pFader->show(); }
|
||||||
|
void Hide() { pLabel->hide(); pFader->hide(); }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
QGridLayout* pMainGrid;
|
QGridLayout* pMainGrid;
|
||||||
QSlider* pFader;
|
QSlider* pFader;
|
||||||
|
|
Loading…
Reference in a new issue