foo.cxx

Go to the documentation of this file.
00001 /*
00002 DON'T EDIT THIS FILE BY HAND, IT IS GENERATED 
00003 BY THE SCRIPT SndPcmGen.pl FROM
00004 alsa-lib/test/latency.c
00005 SndPcm.cxx.in.head
00006 SndPcm.cxx.in.tail
00007 SndPcm.hxx.in.head
00008 SndPcm.hxx.in.tail
00009 */
00010 
00011 /*
00012  * Copyright (c) 2001-2004 MUSIC TECHNOLOGY GROUP (MTG)
00013  *                         UNIVERSITAT POMPEU FABRA
00014  *
00015  *
00016  * This program is free software; you can redistribute it and/or modify
00017  * it under the terms of the GNU General Public License as published by
00018  * the Free Software Foundation; either version 2 of the License, or
00019  * (at your option) any later version.
00020  *
00021  * This program is distributed in the hope that it will be useful,
00022  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00023  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00024  * GNU General Public License for more details.
00025  *
00026  * You should have received a copy of the GNU General Public License
00027  * along with this program; if not, write to the Free Software
00028  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00029  *
00030  */
00031 
00032 #include "SndPcm.hxx"
00033 #include <stdarg.h>
00034 
00035 #include <stdarg.h>
00036 
00037 void SndPcm::cat_error(const char* fmt,...)
00038 {
00039         int len = strlen(error_str);
00040         int rem = 1024 - len;
00041         if (rem>0) {
00042                 va_list ap;
00043                 va_start(ap,fmt);
00044                 vsnprintf(error_str+len,rem,fmt,ap);
00045                 va_end(ap);
00046         }
00047 }
00048 
00049         
00050 SndPcm::SndPcm(int irate,int ichannels,int ilatency,
00051         const char* pdevice,const char* cdevice)
00052 {
00053         format = SND_PCM_FORMAT_S16_LE;
00054         rate = irate;
00055         channels = ichannels;
00056         latency_min = ilatency;
00057         latency_max = ilatency*2;
00058         block = 0;
00059         tick_time = 0;
00060         tick_time_ok = 0;
00061         error_str[0]=0;
00062         int err;
00063 
00064         if ((err = snd_pcm_open(&phandle, pdevice, SND_PCM_STREAM_PLAYBACK, block ? 0 : SND_PCM_NONBLOCK)) < 0) {
00065                 cat_error("SndPcm::SndPcm(...): Playback open error: %s\n", snd_strerror(err));
00066                 throw SndPcmError(error_str);
00067         }
00068         if ((err = snd_pcm_open(&chandle, cdevice, SND_PCM_STREAM_CAPTURE, block ? 0 : SND_PCM_NONBLOCK)) < 0) {
00069                 cat_error("SndPcm::SndPcm(...): Record open error: %s\n", snd_strerror(err));
00070                 throw SndPcmError(error_str);
00071         }
00072 
00073         latency = latency_min - 4;
00074         if (setparams(phandle, chandle, &latency) < 0)
00075                 throw SndPcmError(error_str);
00076 }                       
00077 
00078 SndPcm::~SndPcm()
00079 {
00080         snd_pcm_hw_free(phandle);
00081         snd_pcm_hw_free(chandle);
00082         snd_pcm_close(phandle);
00083         snd_pcm_close(chandle);
00084 }
00085 
00086 void SndPcm::Start(void)
00087 {
00088         int err;
00089         char buffer[1024];
00090         
00091         int nSilentBlockSamples = snd_pcm_bytes_to_samples(chandle,1024);
00092         int nSilentBlockFrames = snd_pcm_bytes_to_frames(chandle,1024);
00093         
00094         if ((err = snd_pcm_link(chandle, phandle)) < 0) {
00095                 cat_error("Streams link error: %s\n", snd_strerror(err));
00096                 throw SndPcmError(error_str);
00097         }
00098         if (snd_pcm_format_set_silence(format, buffer, nSilentBlockSamples) < 0) {
00099                 cat_error("silence error\n");
00100                 throw SndPcmError(error_str);
00101         }
00102         int n = latency*2; /* write two silent buffers */
00103         while (n)
00104         {
00105                 int m = n;
00106                 if (m>nSilentBlockFrames) m = nSilentBlockFrames;
00107                 if (writebuf(phandle, buffer, m) < 0) {
00108                         cat_error("write error\n");
00109                         throw SndPcmError(error_str);
00110                 }
00111                 n -= m;
00112         }
00113 
00114         if ((err = snd_pcm_start(chandle)) < 0) {
00115                 cat_error("Go error: %s\n", snd_strerror(err));
00116                 throw SndPcmError(error_str);
00117         }
00118 }
00119 
00120 void SndPcm::Stop(void)
00121 {
00122         snd_pcm_drop(chandle);
00123         snd_pcm_nonblock(phandle, 0);
00124         snd_pcm_drain(phandle);
00125         snd_pcm_nonblock(phandle, !block ? 1 : 0);
00126         snd_pcm_unlink(chandle);
00127 }
00128 
00129 void SndPcm::RecoverXRun(short* data)
00130 {
00131         int err;
00132         
00133         snd_pcm_drop(chandle);
00134         snd_pcm_drop(phandle);
00135 
00136         putchar('.');
00137 
00138         latency = latency_min - 4;
00139         if (setparams(phandle, chandle, &latency) < 0)
00140                 throw SndPcmError(error_str);
00141 
00142         if (writebuf(phandle,(char*) data, latency) < 0) {
00143                 cat_error("write error\n");
00144                 throw SndPcmError(error_str);
00145         }
00146         if (writebuf(phandle,(char*) data, latency) < 0) {
00147                 cat_error("write error\n");
00148                 throw SndPcmError(error_str);
00149         }
00150 
00151         if ((err = snd_pcm_start(chandle)) < 0) {
00152                 cat_error("Go error: %s\n", snd_strerror(err));
00153                 throw SndPcmError(error_str);
00154         }
00155 
00156 }
00157 
00158 
00159 void SndPcm::Poll(void)
00160 {
00161         snd_pcm_wait(chandle, 1000);
00162 }
00163 /*
00164  * The functions which follow are taken from the latency test included
00165  * in the ALSA source distribution, with the following copyright note:
00166  *
00167  *  Latency test program
00168  *
00169  *     Author: Jaroslav Kysela <perex@suse.cz>
00170  *
00171  *     Author of bandpass filter sweep effect:
00172  *             Maarten de Boer <mdeboer@iua.upf.es>
00173  *
00174  *  This small demo program can be used for measuring latency between
00175  *  capture and playback. This latency is measured from driver (diff when
00176  *  playback and capture was started). Scheduler is set to SCHED_RR.
00177  *
00178  *
00179  *   This program is free software; you can redistribute it and/or modify
00180  *   it under the terms of the GNU General Public License as published by
00181  *   the Free Software Foundation; either version 2 of the License, or
00182  *   (at your option) any later version.
00183  *
00184  *   This program is distributed in the hope that it will be useful,
00185  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
00186  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00187  *   GNU General Public License for more details.
00188  *
00189  *   You should have received a copy of the GNU General Public License
00190  *   along with this program; if not, write to the Free Software
00191  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
00192  *
00193  */
00194 int SndPcm::setparams_stream(snd_pcm_t *handle,
00195                      snd_pcm_hw_params_t *params,
00196                      const char *id)
00197 {
00198         int err;
00199 
00200         err = snd_pcm_hw_params_any(handle, params);
00201         if (err < 0) {
00202                 cat_error("Broken configuration for %s PCM: no configurations available: %s\n", snd_strerror(err), id);
00203                 return err;
00204         }
00205         err = snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
00206         if (err < 0) {
00207                 cat_error("Access type not available for %s: %s\n", id, snd_strerror(err));
00208                 return err;
00209         }
00210         err = snd_pcm_hw_params_set_format(handle, params, format);
00211         if (err < 0) {
00212                 cat_error("Sample format not available for %s: %s\n", id, snd_strerror(err));
00213                 return err;
00214         }
00215         err = snd_pcm_hw_params_set_channels(handle, params, channels);
00216         if (err < 0) {
00217                 cat_error("Channels count (%i) not available for %s: %s\n", channels, id, snd_strerror(err));
00218                 return err;
00219         }
00220         err = snd_pcm_hw_params_set_rate_near(handle, params, rate, 0);
00221         if (err < 0) {
00222                 cat_error("Rate %iHz not available for %s: %s\n", rate, id, snd_strerror(err));
00223                 return err;
00224         }
00225         if (err != rate) {
00226                 cat_error("Rate doesn't match (requested %iHz, get %iHz)\n", rate, err);
00227                 return -EINVAL;
00228         }
00229         return 0;
00230 }
00231 
00232 int SndPcm::setparams_bufsize(snd_pcm_t *handle,
00233                       snd_pcm_hw_params_t *params,
00234                       snd_pcm_hw_params_t *tparams,
00235                       snd_pcm_uframes_t bufsize,
00236                       const char *id)
00237 {
00238         int err;
00239         snd_pcm_uframes_t periodsize;
00240 
00241         snd_pcm_hw_params_copy(params, tparams);
00242         err = snd_pcm_hw_params_set_buffer_size_near(handle, params, bufsize * 2);
00243         if (err < 0) {
00244                 cat_error("Unable to set buffer size %li for %s: %s\n", bufsize * 2, id, snd_strerror(err));
00245                 return err;
00246         }
00247         periodsize = snd_pcm_hw_params_get_buffer_size(params) / 2;
00248         err = snd_pcm_hw_params_set_period_size_near(handle, params, periodsize, 0);
00249         if (err < 0) {
00250                 cat_error("Unable to set period size %li for %s: %s\n", periodsize, id, snd_strerror(err));
00251                 return err;
00252         }
00253         return 0;
00254 }
00255 
00256 int SndPcm::setparams_set(snd_pcm_t *handle,
00257                   snd_pcm_hw_params_t *params,
00258                   snd_pcm_sw_params_t *swparams,
00259                   const char *id)
00260 {
00261         int err, val, sleep_min = 0;
00262 
00263         err = snd_pcm_hw_params(handle, params);
00264         if (err < 0) {
00265                 cat_error("Unable to set hw params for %s: %s\n", id, snd_strerror(err));
00266                 return err;
00267         }
00268         err = snd_pcm_sw_params_current(handle, swparams);
00269         if (err < 0) {
00270                 cat_error("Unable to determine current swparams for %s: %s\n", id, snd_strerror(err));
00271                 return err;
00272         }
00273         err = snd_pcm_sw_params_set_start_threshold(handle, swparams, 0x7fffffff);
00274         if (err < 0) {
00275                 cat_error("Unable to set start threshold mode for %s: %s\n", id, snd_strerror(err));
00276                 return err;
00277         }
00278         tick_time_ok = 0;
00279         if (tick_time > 0) {
00280                 int time, ttime;
00281                 time = snd_pcm_hw_params_get_period_time(params, NULL);
00282                 ttime = snd_pcm_hw_params_get_tick_time(params, NULL);
00283                 if (time < ttime) {
00284                         cat_error("Skipping to set minimal sleep: period time < tick time\n");
00285                 } else if (ttime <= 0) {
00286                         cat_error("Skipping to set minimal sleep: tick time <= 0 (%i)\n", ttime);
00287                 } else {
00288                         sleep_min = tick_time / ttime;
00289                         if (sleep_min <= 0)
00290                                 sleep_min = 1;
00291                         err = snd_pcm_sw_params_set_sleep_min(handle, swparams, sleep_min);
00292                         if (err < 0) {
00293                                 cat_error("Unable to set minimal sleep %i for %s: %s\n", sleep_min, id, snd_strerror(err));
00294                                 return err;
00295                         }
00296                         tick_time_ok = sleep_min * ttime;
00297                 }
00298         }
00299         val = !block ? 4 : snd_pcm_hw_params_get_period_size(params, NULL);
00300         if (tick_time_ok > 0)
00301                 val = 16;
00302         val = snd_pcm_hw_params_get_period_size(params, NULL);
00303         err = snd_pcm_sw_params_set_avail_min(handle, swparams, val);
00304         if (err < 0) {
00305                 cat_error("Unable to set avail min for %s: %s\n", id, snd_strerror(err));
00306                 return err;
00307         }
00308         val = !block ? 4 : 1;
00309         err = snd_pcm_sw_params_set_xfer_align(handle, swparams, val);
00310         if (err < 0) {
00311                 cat_error("Unable to set transfer align for %s: %s\n", id, snd_strerror(err));
00312                 return err;
00313         }
00314         err = snd_pcm_sw_params(handle, swparams);
00315         if (err < 0) {
00316                 cat_error("Unable to set sw params for %s: %s\n", id, snd_strerror(err));
00317                 return err;
00318         }
00319         return 0;
00320 }
00321 
00322 int SndPcm::setparams(snd_pcm_t *phandle, snd_pcm_t *chandle, int *bufsize)
00323 {
00324         int err, last_bufsize = *bufsize;
00325         snd_pcm_hw_params_t *pt_params, *ct_params;     /* templates with rate, format and channels */
00326         snd_pcm_hw_params_t *p_params, *c_params;
00327         snd_pcm_sw_params_t *p_swparams, *c_swparams;
00328         snd_pcm_sframes_t size;
00329 
00330         snd_pcm_hw_params_alloca(&p_params);
00331         snd_pcm_hw_params_alloca(&c_params);
00332         snd_pcm_hw_params_alloca(&pt_params);
00333         snd_pcm_hw_params_alloca(&ct_params);
00334         snd_pcm_sw_params_alloca(&p_swparams);
00335         snd_pcm_sw_params_alloca(&c_swparams);
00336         if ((err = setparams_stream(phandle, pt_params, "playback")) < 0) {
00337                 cat_error("Unable to set parameters for playback stream: %s\n", snd_strerror(err));
00338                 return -1;;
00339         }
00340         if ((err = setparams_stream(chandle, ct_params, "capture")) < 0) {
00341                 cat_error("Unable to set parameters for playback stream: %s\n", snd_strerror(err));
00342                 return -1;;
00343         }
00344 
00345       __again:
00346         if (last_bufsize == *bufsize)
00347                 *bufsize += 4;
00348         last_bufsize = *bufsize;
00349         if (*bufsize > latency_max)
00350                 return -1;
00351         if ((err = setparams_bufsize(phandle, p_params, pt_params, *bufsize, "playback")) < 0) {
00352                 cat_error("Unable to set sw parameters for playback stream: %s\n", snd_strerror(err));
00353                 return -1;;
00354         }
00355         if ((err = setparams_bufsize(chandle, c_params, ct_params, *bufsize, "capture")) < 0) {
00356                 cat_error("Unable to set sw parameters for playback stream: %s\n", snd_strerror(err));
00357                 return -1;;
00358         }
00359 
00360         size = snd_pcm_hw_params_get_period_size(p_params, NULL);
00361         if (size > *bufsize)
00362                 *bufsize = size;
00363         size = snd_pcm_hw_params_get_period_size(c_params, NULL);
00364         if (size > *bufsize)
00365                 *bufsize = size;
00366         if (snd_pcm_hw_params_get_period_time(p_params, NULL) !=
00367             snd_pcm_hw_params_get_period_time(c_params, NULL))
00368                 goto __again;
00369         if (snd_pcm_hw_params_get_period_size(p_params, NULL) * 2 < snd_pcm_hw_params_get_buffer_size(p_params))
00370                 goto __again;
00371         if (snd_pcm_hw_params_get_period_size(c_params, NULL) * 2 < snd_pcm_hw_params_get_buffer_size(c_params))
00372                 goto __again;
00373 
00374         if ((err = setparams_set(phandle, p_params, p_swparams, "playback")) < 0) {
00375                 cat_error("Unable to set sw parameters for playback stream: %s\n", snd_strerror(err));
00376                 return -1;;
00377         }
00378         if ((err = setparams_set(chandle, c_params, c_swparams, "capture")) < 0) {
00379                 cat_error("Unable to set sw parameters for playback stream: %s\n", snd_strerror(err));
00380                 return -1;;
00381         }
00382 
00383         if ((err = snd_pcm_prepare(phandle)) < 0) {
00384                 cat_error("Prepare error: %s\n", snd_strerror(err));
00385                 return -1;;
00386         }
00387 
00388 
00389 
00390         fflush(stdout);
00391         return 0;
00392 }
00393 
00394 long SndPcm::readbuf(snd_pcm_t *handle, char *buf, long len)
00395 {
00396         long r;
00397 
00398         if (!block) {
00399                 do {
00400                         r = snd_pcm_readi(handle, buf, len);
00401                 } while (r == -EAGAIN);
00402                 if (r > 0) {
00403 
00404 
00405 
00406                 }
00407                 // cat_error("read = %li\n", r);
00408         } else {
00409                 int frame_bytes = (snd_pcm_format_width(format) / 8) * channels;
00410                 do {
00411                         r = snd_pcm_readi(handle, buf, len);
00412                         if (r > 0) {
00413                                 buf += r * frame_bytes;
00414                                 len -= r;
00415 
00416 
00417 
00418                         }
00419                         // cat_error("r = %li, len = %li\n", r, len);
00420                 } while (r >= 1 && len > 0);
00421         }
00422         // showstat(handle, 0);
00423         return r;
00424 }
00425 
00426 long SndPcm::writebuf(snd_pcm_t *handle, char *buf, long len)
00427 {
00428         long r;
00429 
00430         while (len > 0) {
00431                 r = snd_pcm_writei(handle, buf, len);
00432                 if (r == -EAGAIN)
00433                         continue;
00434                 // cat_error("write = %li\n", r);
00435                 if (r < 0)
00436                         return r;
00437                 // showstat(handle, 0);
00438                 buf += r * 4;
00439                 len -= r;
00440 
00441         }
00442         return 0;
00443 }
00444 
00445 /*
00446  * Copyright (c) 2001-2002 MUSIC TECHNOLOGY GROUP (MTG)
00447  *                         UNIVERSITAT POMPEU FABRA
00448  *
00449  *
00450  * This program is free software; you can redistribute it and/or modify
00451  * it under the terms of the GNU General Public License as published by
00452  * the Free Software Foundation; either version 2 of the License, or
00453  * (at your option) any later version.
00454  *
00455  * This program is distributed in the hope that it will be useful,
00456  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00457  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00458  * GNU General Public License for more details.
00459  *
00460  * You should have received a copy of the GNU General Public License
00461  * along with this program; if not, write to the Free Software
00462  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00463  *
00464  */
00465 
00466 #ifdef TESTSNDPCM
00467 
00468 #include <sched.h>
00469 
00470 void setscheduler(void)
00471 {
00472         struct sched_param sched_param;
00473 
00474         if (sched_getparam(0, &sched_param) < 0) {
00475                 printf("Scheduler getparam failed...\n");
00476                 return;
00477         }
00478         sched_param.sched_priority = sched_get_priority_max(SCHED_RR);
00479         if (!sched_setscheduler(0, SCHED_RR, &sched_param)) {
00480                 printf("Scheduler set to Round Robin with priority %i...\n", sched_param.sched_priority);
00481                 fflush(stdout);
00482                 return;
00483         }
00484         printf("!!!Scheduler set to Round Robin with priority %i FAILED!!!\n", sched_param.sched_priority);
00485 }
00486 
00487 main()
00488 {
00489         short buf[1024];
00490         try
00491         {
00492                 SndPcm sndpcm(44099,2,"plughw:0,0","plughw:0,0");
00493                 
00494                 setscheduler();
00495 
00496                 sndpcm.Start();
00497                 
00498                 for (int i=0;i<1000;i++)
00499                 {
00500                         sndpcm.Poll();
00501                         sndpcm.ReadBuf(buf);
00502                         sndpcm.WriteBuf(buf);
00503                 }
00504         }
00505         catch (SndPcmError e)
00506         {
00507                 printf(e.str);
00508         }
00509 }
00510 
00511 #endif
00512 

Generated on Tue Aug 12 22:33:42 2008 for CLAM by  doxygen 1.5.5