some cleanup

This commit is contained in:
Volker Fischer 2006-10-03 21:16:23 +00:00
parent c5cf24f58e
commit 50eba66c0c
4 changed files with 204 additions and 148 deletions

View File

@ -22,7 +22,9 @@ void CSound::InitRecording(int iNewBufferSize, bool bNewBlocking)
/* 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,
@ -35,80 +37,75 @@ void CSound::InitRecording(int iNewBufferSize, bool bNewBlocking)
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 ) );
// throw CGenErr("alsa CSound::Init_HW record");
} }
/* 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 ) );
// throw CGenErr("alsa CSound::Init_HW record");
} }
/* set hardware parameters */ /* set hardware parameters */
SetHWParams(rhandle, true, 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
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 ) );
// return NULL ;
} }
/* 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 ) );
// throw CGenErr("alsa CSound::Init_HW ");
} }
/* Start the transfer when the buffer immediately */ // 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 ) );
// throw CGenErr("alsa CSound::Init_HW ");
} }
/* 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 ) );
// throw CGenErr("alsa CSound::Init_HW ");
} }
// set avail min inside a software configuration container
// TEST /* Note: This is similar to setting an OSS wakeup point. The valid values
/* Allow the transfer when at least period_size samples can be processed */ for 'val' are determined by the specific hardware. Most PC sound cards
// /* round up to closest transfer boundary */ can only accept power of 2 frame counts (i.e. 512, 1024, 2048). You
// start_threshold = (buffer_size / xfer_align) * xfer_align ; cannot use this as a high resolution timer - it is limited to how often
// if (start_threshold < 1) the sound card hardware raises an interrupt. Note that you can greatly
// start_threshold = 1 ; improve the reponses using snd_pcm_sw_params_set_sleep_min where another
timing source is used */
// TEST
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 ) );
// throw CGenErr("alsa CSound::Init_HW ");
} }
// 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 ) );
// throw CGenErr("alsa CSound::Init_HW ");
} }
/* clean-up */ // clean-up
snd_pcm_sw_params_free ( swparams ); snd_pcm_sw_params_free ( swparams );
// start record
snd_pcm_reset ( rhandle ); snd_pcm_reset ( rhandle );
snd_pcm_start ( rhandle ); snd_pcm_start ( rhandle );
@ -210,34 +207,88 @@ 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 */ // playback device (either "hw:0,0" or "plughw:0,0")
/* 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 ) );
// throw CGenErr("alsa CSound::Init_HW playback");
} }
/* 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 ) );
// throw CGenErr("alsa CSound::Init_HW record");
} }
/* set hardware parameters */ // set hardware parameters
SetHWParams ( phandle, false, iBufferSizeOut, iCurPeriodSizeOut ); SetHWParams ( phandle, iBufferSizeOut, iCurPeriodSizeOut );
#if 0
/* sw parameters --------------------------------------------------------- */
snd_pcm_sw_params_t* swparams;
// TEST
// allocate an invalid snd_pcm_sw_params_t using standard malloc
if ( err = snd_pcm_sw_params_malloc ( &swparams ) != 0 )
{
qDebug ( "snd_pcm_sw_params_malloc: %s", snd_strerror ( err ) );
}
/* get the current swparams */
err = snd_pcm_sw_params_current(phandle, swparams);
if (err < 0)
{
qDebug("Unable to determine current swparams for playback: %s\n", snd_strerror(err));
}
/* start the transfer when the buffer is almost full: */
/* (buffer_size / avail_min) * avail_min */
err = snd_pcm_sw_params_set_start_threshold(phandle, swparams, iCurPeriodSizeOut - 1);
if (err < 0) {
qDebug("Unable to set start threshold mode for playback: %s\n", snd_strerror(err));
}
/* allow the transfer when at least period_size samples can be processed */
err = snd_pcm_sw_params_set_avail_min(phandle, swparams, iBufferSizeOut);
if (err < 0) {
qDebug("Unable to set avail min for playback: %s\n", snd_strerror(err));
}
/* align all transfers to 1 sample */
err = snd_pcm_sw_params_set_xfer_align(phandle, swparams, 1);
if (err < 0) {
qDebug("Unable to set transfer align for playback: %s\n", snd_strerror(err));
}
/* write the parameters to the playback device */
err = snd_pcm_sw_params(phandle, swparams);
if (err < 0) {
qDebug("Unable to set sw params for playback: %s\n", snd_strerror(err));
}
// clean-up
snd_pcm_sw_params_free ( swparams );
#endif
// start playback
snd_pcm_start ( phandle ); snd_pcm_start ( phandle );
qDebug ( "alsa init playback done" ); qDebug ( "alsa init playback done" );
} }
@ -263,17 +314,7 @@ bool CSound::Write ( CVector<short>& psData )
if ( ret < 0 ) if ( ret < 0 )
{ {
if ( ret == -EAGAIN ) if ( ret == -EPIPE )
{
if ( ( ret = snd_pcm_wait ( phandle, 1 ) ) < 0 )
{
qDebug ( "poll failed (%s)", snd_strerror ( ret ) );
break;
}
continue;
}
else if ( ret == -EPIPE )
{ {
/* under-run */ /* under-run */
qDebug ( "wunderrun" ); qDebug ( "wunderrun" );
@ -284,6 +325,16 @@ bool CSound::Write ( CVector<short>& psData )
{ {
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;
}
else if ( ret == -EAGAIN )
{
if ( ( ret = snd_pcm_wait ( phandle, 1 ) ) < 0 )
{
qDebug ( "poll failed (%s)", snd_strerror ( ret ) );
break;
}
continue; continue;
} }
else if ( ret == -ESTRPIPE ) else if ( ret == -ESTRPIPE )
@ -310,9 +361,8 @@ bool CSound::Write ( CVector<short>& psData )
else else
{ {
qDebug ( "Write error: %s", snd_strerror ( ret ) ); qDebug ( "Write error: %s", snd_strerror ( ret ) );
// throw CGenErr ( "Write error" );
} }
break; /* skip one period */ break; // skip one period
} }
size -= ret; size -= ret;
@ -340,60 +390,59 @@ void CSound::SetOutNumBuf(int iNewNum)
/* common **********************************************************************/ /* common **********************************************************************/
bool CSound::SetHWParams(snd_pcm_t* handle, const bool bIsRecord, bool CSound::SetHWParams(snd_pcm_t* handle, const int iBufferSizeIn,
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
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
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;
} }
/* get configuration */ // restrict a configuration space to contain only one access type:
if (err = snd_pcm_hw_params_any(handle, hwparams) < 0) // set the interleaved read/write format
{
qDebug("Broken configuration : no configurations available: %s", snd_strerror(err));
return true;
}
/* 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;
} }
/* Set the sample format */ // restrict a configuration space to contain only one format:
// 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;
} }
/* Set the count of channels */ // restrict a configuration space to contain only one channels count:
// 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;
} }
/* Set the sample-rate */ // restrict a configuration space to have rate nearest to a target:
// 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 ) 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;
@ -433,26 +482,22 @@ snd_pcm_uframes_t PeriodSize = iBufferSizeIn;
return true; return true;
} }
/* check period and buffer size */
qDebug("desired block size: %d / desired buffer size: %d", iBufferSizeIn, iBufferSizeIn * iNumPeriodBlocks);
// TEST
/* 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));
// throw CGenErr("alsa CSound::Init_HW ");
} }
qDebug("buffer size %d", buffer_size); qDebug("buffer size: %d (desired: %d)", buffer_size, iBufferSizeIn * iNumPeriodBlocks);
snd_pcm_uframes_t period_size; 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));
// throw CGenErr("alsa CSound::Init_HW ");
} }
qDebug("period size %d", period_size); qDebug("frame size: %d (desired: %d)", period_size, iBufferSizeIn);
@ -466,13 +511,17 @@ 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;
} }

View File

@ -47,7 +47,8 @@ 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) iCurPeriodSizeOut(NUM_PERIOD_BLOCKS_OUT), bChangParamIn(true),
bChangParamOut(true)
#endif #endif
{} {}
virtual ~CSound() {Close();} virtual ~CSound() {Close();}
@ -78,8 +79,8 @@ protected:
snd_pcm_t* rhandle; snd_pcm_t* rhandle;
snd_pcm_t* phandle; snd_pcm_t* phandle;
bool SetHWParams(snd_pcm_t* handle, const bool bIsRecord, bool SetHWParams(snd_pcm_t* handle, const int iBufferSizeIn,
const int iBufferSizeIn, const int iNumPeriodBlocks); const int iNumPeriodBlocks);
int iBufferSizeOut; int iBufferSizeOut;
int iBufferSizeIn; int iBufferSizeIn;

View File

@ -132,7 +132,9 @@ void CClient::run()
#ifdef _WIN32 #ifdef _WIN32
SetThreadPriority ( GetCurrentThread (), THREAD_PRIORITY_ABOVE_NORMAL ); SetThreadPriority ( GetCurrentThread (), THREAD_PRIORITY_ABOVE_NORMAL );
#else #else
/* set the process to realtime privs */ /* 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 */
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 );

View File

@ -226,7 +226,11 @@ void CLlconClientDlg::OnConnectDisconBut()
/* set address and check if address is valid */ /* set address and check if address is valid */
if ( pClient->SetServerAddr ( LineEditServerAddr->text () ) ) if ( pClient->SetServerAddr ( LineEditServerAddr->text () ) )
{ {
#if ( QT_VERSION > 300 )
pClient->start ( QThread::TimeCriticalPriority );
#else
pClient->start (); pClient->start ();
#endif
PushButtonConnect->setText ( CON_BUT_DISCONNECTTEXT ); PushButtonConnect->setText ( CON_BUT_DISCONNECTTEXT );
/* start timer for level meter bar */ /* start timer for level meter bar */