From 50eba66c0cc30b8192f70eb13d6d093980ba16da Mon Sep 17 00:00:00 2001 From: Volker Fischer Date: Tue, 3 Oct 2006 21:16:23 +0000 Subject: [PATCH] some cleanup --- linux/sound.cpp | 299 ++++++++++++++++++++++++----------------- linux/sound.h | 7 +- src/client.cpp | 12 +- src/llconclientdlg.cpp | 34 ++--- 4 files changed, 204 insertions(+), 148 deletions(-) diff --git a/linux/sound.cpp b/linux/sound.cpp index 5f149bd6..11cede0b 100755 --- a/linux/sound.cpp +++ b/linux/sound.cpp @@ -21,8 +21,10 @@ void CSound::InitRecording(int iNewBufferSize, bool bNewBlocking) iBufferSizeIn = iNewBufferSize / NUM_IN_OUT_CHANNELS; /* mono size */ /* if recording device was already open, close it first */ - if (rhandle != NULL) - snd_pcm_close(rhandle); + if ( rhandle != NULL ) + { + snd_pcm_close ( rhandle ); + } /* record device: The most important ALSA interfaces to the PCM devices are 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 your hardware supports the configuration you would like to use */ /* 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)); -// throw CGenErr("alsa CSound::Init_HW record"); + qDebug ( "open error: %s", snd_strerror ( err ) ); } /* 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)); -// throw CGenErr("alsa CSound::Init_HW record"); + qDebug ( "cannot set blocking: %s", snd_strerror ( err ) ); } /* set hardware parameters */ - SetHWParams(rhandle, true, iBufferSizeIn, iCurPeriodSizeIn); + SetHWParams ( rhandle, iBufferSizeIn, iCurPeriodSizeIn ); /* sw parameters --------------------------------------------------------- */ 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)); -// return NULL ; + qDebug ( "snd_pcm_sw_params_malloc: %s", snd_strerror ( err ) ); } - /* Get the current swparams */ - if (err = snd_pcm_sw_params_current(rhandle, swparams) < 0) + // get the current swparams + if ( err = snd_pcm_sw_params_current ( rhandle, swparams ) < 0 ) { - qDebug("Unable to determine current swparams : %s", snd_strerror(err)); -// throw CGenErr("alsa CSound::Init_HW "); + qDebug ( "Unable to determine current swparams : %s", snd_strerror ( err ) ); } - /* Start the transfer when the buffer immediately */ - err = snd_pcm_sw_params_set_start_threshold(rhandle, swparams, 0); - if (err < 0) { - qDebug("Unable to set start threshold mode : %s", snd_strerror(err)); -// throw CGenErr("alsa CSound::Init_HW "); + // start the transfer when the buffer immediately -> no threshold, val: 0 + err = snd_pcm_sw_params_set_start_threshold ( rhandle, swparams, 0 ); + if ( err < 0 ) + { + qDebug ( "Unable to set start threshold mode : %s", snd_strerror ( err ) ); } - /* Align all transfers to 1 sample */ - err = snd_pcm_sw_params_set_xfer_align(rhandle, swparams, 1); - if (err < 0) { - qDebug("Unable to set transfer align : %s", snd_strerror(err)); -// throw CGenErr("alsa CSound::Init_HW "); + // align all transfers to 1 sample + err = snd_pcm_sw_params_set_xfer_align ( rhandle, swparams, 1 ); + if ( err < 0 ) + { + 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 - /* Allow the transfer when at least period_size samples can be processed */ -// /* round up to closest transfer boundary */ -// start_threshold = (buffer_size / xfer_align) * xfer_align ; -// 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 "); + 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 ) ); } - - - /* Write the parameters to the record/playback device */ - err = snd_pcm_sw_params(rhandle, swparams); - if (err < 0) { - qDebug("Unable to set sw params : %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 ); + if ( err < 0 ) + { + qDebug ( "Unable to set sw params : %s", snd_strerror ( err ) ); } - /* clean-up */ - snd_pcm_sw_params_free(swparams); + // clean-up + snd_pcm_sw_params_free ( swparams ); + + + // start record + snd_pcm_reset ( rhandle ); + snd_pcm_start ( rhandle ); - snd_pcm_reset(rhandle); - snd_pcm_start(rhandle); - - qDebug("alsa init record done"); + qDebug ( "alsa init record done" ); } bool CSound::Read(CVector& psData) @@ -210,34 +207,88 @@ void CSound::InitPlayback ( int iNewBufferSize, bool bNewBlocking ) { int err; - /* Save buffer size */ - iBufferSizeOut = iNewBufferSize / NUM_IN_OUT_CHANNELS; /* mono size */ + // save buffer 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 ) { snd_pcm_close ( phandle ); } - /* playback device */ - /* either "hw:0,0" or "plughw:0,0" */ - if ( err = snd_pcm_open ( &phandle, "hw:0,0", SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK ) != 0) + // playback device (either "hw:0,0" or "plughw:0,0") + if ( err = snd_pcm_open ( &phandle, "hw:0,0", + SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK ) != 0) { 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 ) { qDebug ( "cannot set blocking: %s", snd_strerror ( err ) ); -// throw CGenErr("alsa CSound::Init_HW record"); } - /* set hardware parameters */ - SetHWParams ( phandle, false, iBufferSizeOut, iCurPeriodSizeOut ); + // set hardware parameters + 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" ); } @@ -263,29 +314,29 @@ bool CSound::Write ( CVector& psData ) if ( ret < 0 ) { - if ( ret == -EAGAIN ) - { - if ( ( ret = snd_pcm_wait ( phandle, 1 ) ) < 0 ) - { - qDebug ( "poll failed (%s)", snd_strerror ( ret ) ); - break; - } - - continue; - } - else if ( ret == -EPIPE ) + if ( ret == -EPIPE ) { /* under-run */ qDebug ( "wunderrun" ); ret = snd_pcm_prepare ( phandle ); - + if ( ret < 0 ) { 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; + } else if ( ret == -ESTRPIPE ) { qDebug("wstrpipe"); @@ -310,12 +361,11 @@ bool CSound::Write ( CVector& psData ) else { 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; } @@ -340,60 +390,59 @@ void CSound::SetOutNumBuf(int iNewNum) /* common **********************************************************************/ -bool CSound::SetHWParams(snd_pcm_t* handle, const bool bIsRecord, - const int iBufferSizeIn, const int iNumPeriodBlocks) +bool CSound::SetHWParams(snd_pcm_t* handle, const int iBufferSizeIn, + const int iNumPeriodBlocks) { int err; 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; } - - 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; } - /* get configuration */ - if (err = snd_pcm_hw_params_any(handle, hwparams) < 0) + // restrict a configuration space to contain only one access type: + // 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)); - 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)); + qDebug ( "Access type not available : %s", snd_strerror ( err ) ); return true; } - /* Set the sample format */ - if (err = snd_pcm_hw_params_set_format(handle, hwparams, SND_PCM_FORMAT_S16) < 0) + // 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 ) { - qDebug("Sample format not available : %s", snd_strerror(err)); + qDebug ( "Sample format not available : %s", snd_strerror ( err ) ); return true; } - /* Set the count of channels */ - if (err = snd_pcm_hw_params_set_channels(handle, hwparams, NUM_IN_OUT_CHANNELS) < 0) + // 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 ) { - 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; } - /* 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; 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; } - 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 ); return true; @@ -432,47 +481,47 @@ snd_pcm_uframes_t PeriodSize = iBufferSizeIn; qDebug("Unable to set hw params : %s", snd_strerror(err)); return true; } + + /* check period and buffer size */ -qDebug("desired block size: %d / desired buffer size: %d", iBufferSizeIn, iBufferSizeIn * iNumPeriodBlocks); - -// TEST snd_pcm_uframes_t buffer_size; 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)); -// 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; err = snd_pcm_hw_params_get_period_size(hwparams, &period_size, 0); if (err < 0) { 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 */ - snd_pcm_hw_params_free(hwparams); + snd_pcm_hw_params_free ( hwparams ); return false; } -void CSound::Close() +void CSound::Close () { /* read */ - if (rhandle != NULL) - snd_pcm_close(rhandle); + if ( rhandle != NULL ) + { + snd_pcm_close ( rhandle ); + } rhandle = NULL; /* playback */ - if (phandle != NULL) - snd_pcm_close(phandle); + if ( phandle != NULL ) + { + snd_pcm_close ( phandle ); + } phandle = NULL; } diff --git a/linux/sound.h b/linux/sound.h index 78a25e1b..98512009 100755 --- a/linux/sound.h +++ b/linux/sound.h @@ -47,7 +47,8 @@ public: CSound() #if WITH_SOUND : rhandle(NULL), phandle(NULL), iCurPeriodSizeIn(NUM_PERIOD_BLOCKS_IN), - iCurPeriodSizeOut(NUM_PERIOD_BLOCKS_OUT) + iCurPeriodSizeOut(NUM_PERIOD_BLOCKS_OUT), bChangParamIn(true), + bChangParamOut(true) #endif {} virtual ~CSound() {Close();} @@ -78,8 +79,8 @@ protected: snd_pcm_t* rhandle; snd_pcm_t* phandle; - bool SetHWParams(snd_pcm_t* handle, const bool bIsRecord, - const int iBufferSizeIn, const int iNumPeriodBlocks); + bool SetHWParams(snd_pcm_t* handle, const int iBufferSizeIn, + const int iNumPeriodBlocks); int iBufferSizeOut; int iBufferSizeIn; diff --git a/src/client.cpp b/src/client.cpp index 8d813cb7..c5091806 100755 --- a/src/client.cpp +++ b/src/client.cpp @@ -130,13 +130,15 @@ void CClient::run() /* Set thread priority (The working thread should have a higher priority than the GUI) */ #ifdef _WIN32 - SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL); + SetThreadPriority ( GetCurrentThread (), THREAD_PRIORITY_ABOVE_NORMAL ); #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; - memset(&schp, 0, sizeof(schp)); - schp.sched_priority = sched_get_priority_max(SCHED_FIFO); - sched_setscheduler(0, SCHED_FIFO, &schp); + memset ( &schp, 0, sizeof ( schp ) ); + schp.sched_priority = sched_get_priority_max ( SCHED_FIFO ); + sched_setscheduler ( 0, SCHED_FIFO, &schp ); #endif /* init object */ diff --git a/src/llconclientdlg.cpp b/src/llconclientdlg.cpp index 8071fd04..8bd75ce6 100755 --- a/src/llconclientdlg.cpp +++ b/src/llconclientdlg.cpp @@ -205,41 +205,45 @@ void CLlconClientDlg::closeEvent ( QCloseEvent * Event ) Event->accept(); } -void CLlconClientDlg::OnConnectDisconBut() +void CLlconClientDlg::OnConnectDisconBut () { /* start/stop client, set button text */ - if (pClient->IsRunning()) + if ( pClient->IsRunning () ) { - pClient->Stop(); - PushButtonConnect->setText(CON_BUT_CONNECTTEXT); + pClient->Stop (); + PushButtonConnect->setText ( CON_BUT_CONNECTTEXT ); /* stop timer for level meter bars and reset them */ - TimerSigMet.stop(); - ProgressBarInputLevelL->setProgress(0); - ProgressBarInputLevelR->setProgress(0); + TimerSigMet.stop (); + ProgressBarInputLevelL->setProgress ( 0 ); + ProgressBarInputLevelR->setProgress ( 0 ); /* immediately update status bar */ - OnTimerStatus(); + OnTimerStatus (); } else { /* set address and check if address is valid */ - if (pClient->SetServerAddr(LineEditServerAddr->text())) - { - pClient->start(); - PushButtonConnect->setText(CON_BUT_DISCONNECTTEXT); + if ( pClient->SetServerAddr ( LineEditServerAddr->text () ) ) + { +#if ( QT_VERSION > 300 ) + pClient->start ( QThread::TimeCriticalPriority ); +#else + pClient->start (); +#endif + PushButtonConnect->setText ( CON_BUT_DISCONNECTTEXT ); /* start timer for level meter bar */ - TimerSigMet.start(LEVELMETER_UPDATE_TIME); + TimerSigMet.start ( LEVELMETER_UPDATE_TIME ); } else { /* Restart timer to ensure that the text is visible at least the time for one complete interval */ - TimerStatus.changeInterval(STATUSBAR_UPDATE_TIME); + TimerStatus.changeInterval ( STATUSBAR_UPDATE_TIME ); /* show the error in the status bar */ - TextLabelStatus->setText(tr("invalid address")); + TextLabelStatus->setText ( tr ( "invalid address" ) ); } } }