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

@ -21,8 +21,10 @@ void CSound::InitRecording(int iNewBufferSize, bool bNewBlocking)
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,
@ -32,87 +34,82 @@ void CSound::InitRecording(int iNewBufferSize, bool bNewBlocking)
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 ) );
// 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;
if (err = snd_pcm_sw_params_malloc (&swparams) != 0) // 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)); 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)); {
// throw CGenErr("alsa CSound::Init_HW "); 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)); {
// throw CGenErr("alsa CSound::Init_HW "); qDebug ( "Unable to set transfer align : %s", snd_strerror ( err ) );
} }
// set avail min inside a software configuration container
/* 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
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
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
timing source is used */
snd_pcm_uframes_t period_size = iBufferSizeIn;
// TEST err = snd_pcm_sw_params_set_avail_min ( rhandle, swparams, period_size );
/* Allow the transfer when at least period_size samples can be processed */ if ( err < 0 )
// /* round up to closest transfer boundary */ {
// start_threshold = (buffer_size / xfer_align) * xfer_align ; qDebug ( "Unable to set avail min : %s", snd_strerror ( err ) );
// if (start_threshold < 1)
// start_threshold = 1 ;
// TEST
snd_pcm_uframes_t period_size = iBufferSizeIn;
err = snd_pcm_sw_params_set_avail_min(rhandle, swparams, period_size);
if (err < 0) {
qDebug("Unable to set avail min : %s", snd_strerror(err));
// throw CGenErr("alsa CSound::Init_HW ");
} }
// write the parameters to the record/playback device
err = snd_pcm_sw_params ( rhandle, swparams );
/* Write the parameters to the record/playback device */ if ( err < 0 )
err = snd_pcm_sw_params(rhandle, swparams); {
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 );
snd_pcm_reset(rhandle);
snd_pcm_start(rhandle);
qDebug("alsa init record done"); // start record
snd_pcm_reset ( rhandle );
snd_pcm_start ( rhandle );
qDebug ( "alsa init record done" );
} }
bool CSound::Read(CVector<short>& psData) bool CSound::Read(CVector<short>& psData)
@ -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,12 +361,11 @@ 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;
start += ret; start += 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;
if (err = snd_pcm_hw_params_malloc(&hwparams) < 0) // allocate an invalid snd_pcm_hw_params_t using standard malloc
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;
} }
if (err = snd_pcm_hw_params_any(handle, hwparams) < 0) // fill params with a full configuration space for a PCM
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
if ( err = snd_pcm_hw_params_set_access ( handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED ) < 0 )
{ {
qDebug("Broken configuration : no configurations available: %s", snd_strerror(err)); qDebug ( "Access type not 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)
{
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:
if (err = snd_pcm_hw_params_set_format(handle, hwparams, SND_PCM_FORMAT_S16) < 0) // set the sample format PCM, 16 bit
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:
if (err = snd_pcm_hw_params_set_channels(handle, hwparams, NUM_IN_OUT_CHANNELS) < 0) // set the count of channels (usually stereo, 2 channels)
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,46 +482,46 @@ 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);
/* 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;
} }

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

@ -130,13 +130,15 @@ void CClient::run()
/* 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 */ /* 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 );
sched_setscheduler(0, SCHED_FIFO, &schp); sched_setscheduler ( 0, SCHED_FIFO, &schp );
#endif #endif
/* init object */ /* init object */

View file

@ -205,41 +205,45 @@ void CLlconClientDlg::closeEvent ( QCloseEvent * Event )
Event->accept(); Event->accept();
} }
void CLlconClientDlg::OnConnectDisconBut() void CLlconClientDlg::OnConnectDisconBut ()
{ {
/* start/stop client, set button text */ /* start/stop client, set button text */
if (pClient->IsRunning()) if ( pClient->IsRunning () )
{ {
pClient->Stop(); pClient->Stop ();
PushButtonConnect->setText(CON_BUT_CONNECTTEXT); PushButtonConnect->setText ( CON_BUT_CONNECTTEXT );
/* stop timer for level meter bars and reset them */ /* stop timer for level meter bars and reset them */
TimerSigMet.stop(); TimerSigMet.stop ();
ProgressBarInputLevelL->setProgress(0); ProgressBarInputLevelL->setProgress ( 0 );
ProgressBarInputLevelR->setProgress(0); ProgressBarInputLevelR->setProgress ( 0 );
/* immediately update status bar */ /* immediately update status bar */
OnTimerStatus(); OnTimerStatus ();
} }
else else
{ {
/* 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 () ) )
{ {
pClient->start(); #if ( QT_VERSION > 300 )
PushButtonConnect->setText(CON_BUT_DISCONNECTTEXT); pClient->start ( QThread::TimeCriticalPriority );
#else
pClient->start ();
#endif
PushButtonConnect->setText ( CON_BUT_DISCONNECTTEXT );
/* start timer for level meter bar */ /* start timer for level meter bar */
TimerSigMet.start(LEVELMETER_UPDATE_TIME); TimerSigMet.start ( LEVELMETER_UPDATE_TIME );
} }
else else
{ {
/* Restart timer to ensure that the text is visible at /* Restart timer to ensure that the text is visible at
least the time for one complete interval */ least the time for one complete interval */
TimerStatus.changeInterval(STATUSBAR_UPDATE_TIME); TimerStatus.changeInterval ( STATUSBAR_UPDATE_TIME );
/* show the error in the status bar */ /* show the error in the status bar */
TextLabelStatus->setText(tr("invalid address")); TextLabelStatus->setText ( tr ( "invalid address" ) );
} }
} }
} }