"Fossies" - the Fresh Open Source Software Archive

Member "speech_tools/audio/linux_sound.cc" (4 Sep 2017, 25446 Bytes) of package /linux/misc/speech_tools-2.5.0-release.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "linux_sound.cc" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 2.4-release_vs_2.5.0-release.

    1 /*************************************************************************/
    2 /*                                                                       */
    3 /*                Centre for Speech Technology Research                  */
    4 /*                     University of Edinburgh, UK                       */
    5 /*                      Copyright (c) 1997,1998                          */
    6 /*                        All Rights Reserved.                           */
    7 /*                                                                       */
    8 /*  Permission is hereby granted, free of charge, to use and distribute  */
    9 /*  this software and its documentation without restriction, including   */
   10 /*  without limitation the rights to use, copy, modify, merge, publish,  */
   11 /*  distribute, sublicense, and/or sell copies of this work, and to      */
   12 /*  permit persons to whom this work is furnished to do so, subject to   */
   13 /*  the following conditions:                                            */
   14 /*   1. The code must retain the above copyright notice, this list of    */
   15 /*      conditions and the following disclaimer.                         */
   16 /*   2. Any modifications must be clearly marked as such.                */
   17 /*   3. Original authors' names are not deleted.                         */
   18 /*   4. The authors' names are not used to endorse or promote products   */
   19 /*      derived from this software without specific prior written        */
   20 /*      permission.                                                      */
   21 /*                                                                       */
   22 /*  THE UNIVERSITY OF EDINBURGH AND THE CONTRIBUTORS TO THIS WORK        */
   23 /*  DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING      */
   24 /*  ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT   */
   25 /*  SHALL THE UNIVERSITY OF EDINBURGH NOR THE CONTRIBUTORS BE LIABLE     */
   26 /*  FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES    */
   27 /*  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN   */
   28 /*  AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,          */
   29 /*  ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF       */
   30 /*  THIS SOFTWARE.                                                       */
   31 /*                                                                       */
   32 /*************************************************************************/
   33 /*                Author :  Alan W Black                                 */
   34 /*                Date   :  July 1997                                    */
   35 /*-----------------------------------------------------------------------*/
   36 /*  Optional support for /dev/dsp under FreeBSD and Linux                */
   37 /*  These use the same underlying sound drivers (voxware).  This uses    */
   38 /*  16bit linear if the device supports it otherwise it uses 8bit.  The  */
   39 /*  8bit driver is still better than falling back to the "sunaudio" ulaw */
   40 /*  8K as this driver can cope with various sample rates (and saves on   */
   41 /*  resampling).                                                         */
   42 /*                                                                       */
   43 /*  Combined FreeBSD and Voxware code Feb 98                             */
   44 /*                                                                       */
   45 /*  This may work on NetBSD and OpenBSD but I haven't tried it           */
   46 /*                                                                       */
   47 /*=======================================================================*/
   48 
   49 #include <cstdio>
   50 #include <cstring>
   51 #include <cstdlib>
   52 #include <cctype>
   53 #include <sys/stat.h>
   54 #include "EST_cutils.h"
   55 #include "EST_walloc.h"
   56 #include "EST_Wave.h"
   57 #include "EST_wave_aux.h"
   58 #include "EST_Option.h"
   59 #include "audioP.h"
   60 #include "EST_io_aux.h"
   61 #include "EST_error.h"
   62 
   63 #ifdef SUPPORT_FREEBSD16
   64 #include <sys/soundcard.h>
   65 #include <fcntl.h>
   66 int freebsd16_supported = TRUE;
   67 int linux16_supported = FALSE;
   68 static char *aud_sys_name = "FreeBSD";
   69 #endif /*SUPPORT_FREEBSD16 */
   70 
   71 #ifdef SUPPORT_VOXWARE
   72 
   73 #include <sys/ioctl.h>
   74 #include <sys/soundcard.h>
   75 #include <sys/types.h>
   76 #include <sys/stat.h>
   77 #include <fcntl.h>
   78 int linux16_supported = TRUE;
   79 int freebsd16_supported = FALSE;
   80 static const char *aud_sys_name = "Linux";
   81 static int stereo_only = 0;
   82 
   83 // Code to block signals while sound is playing.
   84 // Needed inside Java on (at least some) linux systems
   85 // as scheduling interrupts seem to break the writes. 
   86 
   87 #if defined(SUPPORT_LINUX16) || defined(SUPPORT_FREEBSD16)
   88 
   89 #include <csignal>
   90 #include <pthread.h>
   91 
   92 #define THREAD_DECS() \
   93     sigset_t  oldmask \
   94 
   95 #define THREAD_PROTECT() do { \
   96     sigset_t  newmask; \
   97     \
   98     sigfillset(&newmask); \
   99     \
  100     pthread_sigmask(SIG_BLOCK, &newmask, &oldmask); \
  101     } while(0)
  102 
  103 #define THREAD_UNPROTECT() do { \
  104      pthread_sigmask(SIG_SETMASK, &oldmask, NULL); \
  105      } while (0)
  106 
  107 #else
  108 #define  THREAD_DECS() //empty
  109 #define  THREAD_PROTECT() //empty
  110 #define  THREAD_UNPROTECT() //empty
  111 #endif /* LINUX_16/FREEBSD16 */
  112 
  113 static int sb_set_sample_rate(int sbdevice, int samp_rate)
  114 {
  115     int fmt;
  116     int sfmts;
  117     int stereo=0;
  118     int sstereo;
  119     int channels=1;
  120 
  121     ioctl(sbdevice,SNDCTL_DSP_RESET,0);
  122     ioctl(sbdevice,SNDCTL_DSP_SPEED,&samp_rate);
  123     sstereo = stereo;
  124     ioctl(sbdevice,SNDCTL_DSP_STEREO,&sstereo);
  125     /* Some devices don't do mono even when you ask them nicely */
  126     if (sstereo != stereo)
  127         stereo_only = 1;
  128     ioctl(sbdevice,SNDCTL_DSP_CHANNELS,&channels);
  129     ioctl(sbdevice,SNDCTL_DSP_GETFMTS,&sfmts);
  130 
  131     if (sfmts == AFMT_U8)
  132     fmt = AFMT_U8;         // its really an 8 bit only device
  133     else if (EST_LITTLE_ENDIAN)
  134     fmt = AFMT_S16_LE;  
  135     else
  136     fmt = AFMT_S16_BE;  
  137     
  138     ioctl(sbdevice,SNDCTL_DSP_SETFMT,&fmt);
  139     
  140     return fmt;
  141 }
  142 
  143 #define AUDIOBUFFSIZE 256
  144 // #define AUDIOBUFFSIZE 20480
  145 
  146 int play_linux_wave(EST_Wave &inwave, EST_Option &al)
  147 {
  148     int sample_rate;
  149     short *waveform;
  150     short *waveform2 = 0;
  151     int num_samples;
  152     int audio,actual_fmt;
  153     int i,r,n;
  154     const char *audiodevice;
  155 
  156     if (al.present("-audiodevice"))
  157     audiodevice = al.val("-audiodevice");
  158     else
  159     audiodevice = "/dev/dsp";
  160 
  161     if ((audio = open(audiodevice,O_WRONLY)) == -1)
  162     {
  163     cerr << aud_sys_name << ": can't open " << audiodevice << endl;
  164     return -1;
  165     }
  166  
  167     // int tmp=open("/tmp/vox_play_wave",O_WRONLY|O_CREAT);
  168     
  169     waveform = inwave.values().memory();
  170     num_samples = inwave.num_samples();
  171     sample_rate = inwave.sample_rate();
  172 
  173     actual_fmt = sb_set_sample_rate(audio,sample_rate);
  174 
  175     if (stereo_only)
  176     {
  177     waveform2 = walloc(short,num_samples*2);
  178     for (i=0; i<num_samples; i++)
  179     {
  180         waveform2[i*2] = inwave.a(i);
  181         waveform2[(i*2)+1] = inwave.a(i);
  182     }
  183     waveform = waveform2;
  184     num_samples *= 2;
  185     }
  186 
  187     THREAD_DECS();
  188     THREAD_PROTECT();
  189     
  190     if (sb_set_sample_rate(audio,sample_rate) == AFMT_U8)
  191     {
  192     // Its actually 8bit unsigned so convert the buffer;
  193     unsigned char *uchars = walloc(unsigned char,num_samples);
  194     for (i=0; i < num_samples; i++)
  195         uchars[i] = waveform[i]/256+128;
  196     for (i=0; i < num_samples; i += r)
  197     {
  198         if (num_samples > i+AUDIOBUFFSIZE)
  199         n = AUDIOBUFFSIZE;
  200         else
  201         n = num_samples-i;
  202         // r = write(tmp,&uchars[i], n);
  203         r = write(audio,&uchars[i], n);
  204         if (r == 0)
  205         {
  206         THREAD_UNPROTECT();
  207         cerr << aud_sys_name << ": failed to write to buffer" <<
  208             sample_rate << endl;
  209         close(audio);
  210         return -1;
  211         }
  212     }
  213     wfree(uchars);
  214     }
  215     else if ((actual_fmt == AFMT_S16_LE) || 
  216          (actual_fmt == AFMT_S16_BE))
  217     {
  218       int blksize, nbuf, c;
  219       short *buf;
  220 
  221       ioctl (audio, SNDCTL_DSP_GETBLKSIZE, &blksize);
  222       nbuf=blksize;
  223       buf=new short[nbuf];
  224 
  225       for (i=0; i < num_samples; i += r/2)
  226     {
  227       if (num_samples > i+nbuf)
  228         n = nbuf;
  229       else
  230         n = num_samples-i;
  231 
  232       for(c=0; c<n;c++)
  233         buf[c]=waveform[c+i];
  234 
  235       for(; c<nbuf;c++)
  236         buf[c]=waveform[n-1];
  237 
  238       // r = write(tmp,&waveform[i], n*2);
  239       // r = write(audio,&waveform[i], n*2);
  240       r=write(audio, buf, nbuf*2);
  241       if (r <= 0)
  242         {
  243           THREAD_UNPROTECT();
  244           EST_warning("%s: failed to write to buffer (sr=%d)",aud_sys_name, sample_rate );
  245         close(audio);
  246         return -1;
  247         }
  248         // ioctl(audio, SNDCTL_DSP_SYNC, 0);
  249       // fprintf(stderr,"[%d]", r);
  250     }
  251       delete [] buf;
  252     }
  253     else
  254     {
  255       THREAD_UNPROTECT();
  256       cerr << aud_sys_name << ": unable to set sample rate " <<
  257     sample_rate << endl;
  258       close(audio);
  259       return -1;
  260     }
  261     
  262     // ioctl(audio, SNDCTL_DSP_SYNC, 0);
  263 //    fprintf(stderr, "End Play\n");
  264 
  265     // close(tmp);
  266     close(audio);
  267     if (waveform2)
  268     wfree(waveform2);
  269     THREAD_UNPROTECT();
  270     return 1;
  271 }
  272 
  273 int record_linux_wave(EST_Wave &inwave, EST_Option &al)
  274 {
  275     int sample_rate=16000;  // egcs needs the initialized for some reason
  276     short *waveform;
  277     short *waveform2=0;
  278     int num_samples;
  279     int audio=-1,actual_fmt;
  280     int i,r,n;
  281     const char *audiodevice;
  282 
  283     if (al.present("-audiodevice"))
  284     audiodevice = al.val("-audiodevice");
  285     else
  286     audiodevice = "/dev/dsp";
  287 
  288     sample_rate = al.ival("-sample_rate");
  289     
  290     if ((audio = open(audiodevice,O_RDONLY)) == -1)
  291     {
  292     cerr << aud_sys_name << ": can't open " << audiodevice
  293          << "for reading" << endl;
  294     return -1;
  295     }
  296     
  297     actual_fmt = sb_set_sample_rate(audio,sample_rate);
  298 
  299     if ((actual_fmt == AFMT_S16_LE) || 
  300     (actual_fmt == AFMT_S16_BE))
  301     {
  302     // We assume that the device returns audio in native byte order
  303     // by default
  304     inwave.resize((int)(sample_rate*al.fval("-time")));
  305     inwave.set_sample_rate(sample_rate);
  306     num_samples = inwave.num_samples();
  307     waveform = inwave.values().memory();
  308 
  309     if (stereo_only)
  310     {
  311         waveform2 = walloc(short,num_samples*2);
  312         num_samples *= 2;
  313     }
  314     else
  315         waveform2 = waveform;
  316 
  317     for (i=0; i < num_samples; i+= r)
  318     {
  319         if (num_samples > i+AUDIOBUFFSIZE)
  320         n = AUDIOBUFFSIZE;
  321         else
  322         n = num_samples-i;
  323         r = read(audio,&waveform2[i], n*2);
  324         r /= 2;
  325         if (r <= 0)
  326         {
  327         cerr << aud_sys_name << ": failed to read from audio device"
  328             << endl;
  329         close(audio);
  330         return -1;
  331         }
  332     }
  333 
  334     }
  335     else if (actual_fmt == AFMT_U8)
  336     {
  337     inwave.resize((int)(sample_rate*al.fval("-time")));
  338     inwave.set_sample_rate(sample_rate);
  339     num_samples = inwave.num_samples();
  340     waveform = inwave.values().memory();
  341     unsigned char *u8wave = walloc(unsigned char,num_samples);
  342 
  343     for (i=0; i < num_samples; i+= r)
  344     {
  345         if (num_samples > i+AUDIOBUFFSIZE)
  346         n = AUDIOBUFFSIZE;
  347         else
  348         n = num_samples-i;
  349         r = read(audio,&u8wave[i],n);
  350         if (r <= 0)
  351         {
  352         cerr << aud_sys_name << ": failed to read from audio device"
  353             << endl;
  354         close(audio);
  355         wfree(u8wave);
  356         return -1;
  357         }
  358         
  359     }
  360     uchar_to_short(u8wave,waveform,num_samples);
  361     wfree(u8wave);
  362     }
  363     else
  364     {
  365     cerr << aud_sys_name << ": unknown audio format from device: " << 
  366         actual_fmt << endl;
  367     close(audio);
  368     return -1;
  369     }
  370 
  371     if (stereo_only)
  372     {
  373     for (i=0; i<num_samples; i+=2)
  374         waveform[i/2] = waveform2[i];
  375     wfree(waveform2);
  376     }
  377 
  378     close(audio);
  379     return 0;
  380 }
  381 
  382 #else 
  383 
  384 /*-----------------------------------------------------------------------*/
  385 /*  Support for alsa, the voxware stuff just doesn't work on most        */
  386 /*  machines now.  This code is a modification of the vanilla voxware    */
  387 /*  support                                                              */
  388 /*                                                                       */
  389 /*  Based on the alsa support in Flite provided by Lukas Loehrer         */
  390 /*                                                                       */
  391 /*=======================================================================*/
  392 
  393 #ifdef SUPPORT_ALSALINUX
  394 #include <sys/ioctl.h>
  395 #include <alsa/asoundlib.h>
  396 #include <sys/types.h>
  397 #include <sys/stat.h>
  398 #include <fcntl.h>
  399 #define aud_sys_name "ALSALINUX"
  400 
  401 // Code to block signals while sound is playing.
  402 // Needed inside Java on (at least some) linux systems
  403 // as scheduling interrupts seem to break the writes. 
  404 
  405 int linux16_supported = TRUE;
  406 int freebsd16_supported = FALSE;
  407 
  408 #ifdef THREAD_SAFETY
  409 #include <csignal>
  410 #include <pthread.h>
  411 
  412 #define THREAD_DECS() \
  413     sigset_t  oldmask \
  414 
  415 #define THREAD_PROTECT() do { \
  416     sigset_t  newmask; \
  417     \
  418     sigfillset(&newmask); \
  419     \
  420     pthread_sigmask(SIG_BLOCK, &newmask, &oldmask); \
  421     } while(0)
  422 
  423 #define THREAD_UNPROTECT() do { \
  424      pthread_sigmask(SIG_SETMASK, &oldmask, NULL); \
  425      } while (0)
  426 
  427 #else
  428 #define  THREAD_DECS() //empty
  429 #define  THREAD_PROTECT() //empty
  430 #define  THREAD_UNPROTECT() //empty
  431 #endif /* THREAD_SAFETY */
  432 
  433 static const char *pcm_dev_name ="default";
  434 
  435 typedef enum {
  436     CST_AUDIO_LINEAR16 = 0,
  437     CST_AUDIO_LINEAR8,
  438     CST_AUDIO_MULAW
  439 } cst_audiofmt;
  440 
  441 typedef struct cst_audiodev_struct {
  442     int sps, real_sps;
  443     int channels, real_channels;
  444     cst_audiofmt fmt, real_fmt;
  445     int byteswap;
  446     /*    cst_rateconv *rateconv; */
  447     void *platform_data;
  448 } cst_audiodev;
  449 
  450 static int audio_bps(cst_audiofmt fmt)
  451 {
  452     switch (fmt)
  453     {
  454     case CST_AUDIO_LINEAR16:
  455     return 2;
  456     case CST_AUDIO_LINEAR8:
  457     case CST_AUDIO_MULAW:
  458     return 1;
  459     }
  460     return 0;
  461 }
  462 
  463 static inline void print_pcm_state(snd_pcm_t *handle, char *msg)
  464 {
  465   fprintf(stderr, "PCM state at %s = %s\n", msg,
  466           snd_pcm_state_name(snd_pcm_state(handle)));
  467 }
  468 
  469 cst_audiodev *audio_open_alsa(int sps, int channels, cst_audiofmt fmt)
  470 {
  471   cst_audiodev *ad;
  472   unsigned  int real_rate;
  473   int err;
  474 
  475   /* alsa specific stuff */
  476   snd_pcm_t *pcm_handle;          
  477   snd_pcm_stream_t stream = SND_PCM_STREAM_PLAYBACK;
  478   snd_pcm_hw_params_t *hwparams;
  479   snd_pcm_format_t format;
  480   snd_pcm_access_t access = SND_PCM_ACCESS_RW_INTERLEAVED;
  481 
  482   /* Allocate the snd_pcm_hw_params_t structure on the stack. */
  483   snd_pcm_hw_params_alloca(&hwparams);
  484 
  485   /* Open pcm device */
  486   err = snd_pcm_open(&pcm_handle, pcm_dev_name, stream, 0);
  487   if (err < 0) 
  488   {
  489       EST_warning("audio_open_alsa: failed to open audio device %s. %s\n",
  490                   pcm_dev_name, snd_strerror(err));
  491       return NULL;
  492   }
  493 
  494   /* Init hwparams with full configuration space */
  495   err = snd_pcm_hw_params_any(pcm_handle, hwparams);
  496   if (err < 0) 
  497   {
  498     snd_pcm_close(pcm_handle);
  499     EST_warning("audio_open_alsa: failed to get hardware parameters from audio device. %s\n", snd_strerror(err));
  500     return NULL;
  501   }
  502 
  503   /* Set access mode */
  504   err = snd_pcm_hw_params_set_access(pcm_handle, hwparams, access);
  505   if (err < 0) 
  506   {
  507     snd_pcm_close(pcm_handle);
  508     EST_warning("audio_open_alsa: failed to set access mode. %s.\n", snd_strerror(err));
  509     return NULL;
  510   }
  511 
  512   /* Determine matching alsa sample format */
  513   /* This could be implemented in a more */
  514   /* flexible way (byte order conversion). */
  515   switch (fmt)
  516   {
  517   case CST_AUDIO_LINEAR16:
  518     if (EST_LITTLE_ENDIAN)
  519       format = SND_PCM_FORMAT_S16_LE;
  520     else
  521       format = SND_PCM_FORMAT_S16_BE;
  522     break;
  523   case CST_AUDIO_LINEAR8:
  524     format = SND_PCM_FORMAT_U8;
  525     break;
  526   case CST_AUDIO_MULAW:
  527     format = SND_PCM_FORMAT_MU_LAW;
  528     break;
  529   default:
  530     snd_pcm_close(pcm_handle);
  531     EST_warning("audio_open_alsa: failed to find suitable format.\n");
  532     return NULL;
  533     break;
  534   }
  535 
  536   /* Set samble format */
  537   err = snd_pcm_hw_params_set_format(pcm_handle, hwparams, format);
  538   if (err <0) 
  539   {
  540     snd_pcm_close(pcm_handle);
  541     EST_warning("audio_open_alsa: failed to set format. %s.\n", snd_strerror(err));
  542     return NULL;
  543   }
  544 
  545   /* Set sample rate near the disired rate */
  546   real_rate = sps;
  547   err = snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &real_rate, 0);
  548   if (err < 0)   
  549   {
  550     snd_pcm_close(pcm_handle);
  551     EST_warning("audio_open_alsa: failed to set sample rate near %d. %s.\n", sps, snd_strerror(err));
  552     return NULL;
  553   }
  554 
  555   /* Set number of channels */
  556   assert(channels >0);
  557   err = snd_pcm_hw_params_set_channels(pcm_handle, hwparams, channels);
  558   if (err < 0) 
  559   {
  560     snd_pcm_close(pcm_handle);
  561     EST_warning("audio_open_alsa: failed to set number of channels to %d. %s.\n", channels, snd_strerror(err));
  562     return NULL;
  563   }
  564 
  565   /* Commit hardware parameters */
  566   err = snd_pcm_hw_params(pcm_handle, hwparams);
  567   if (err < 0) 
  568   {
  569     snd_pcm_close(pcm_handle);
  570     EST_warning("audio_open_alsa: failed to set hw parameters. %s.\n", snd_strerror(err));
  571     return NULL;
  572   }
  573 
  574     /* There doesn't seem to be another way to set the latency -- if done
  575        here, it works, if not, it looses the first 2s or so */
  576     snd_pcm_set_params(pcm_handle,
  577                        format,
  578                        SND_PCM_ACCESS_RW_INTERLEAVED,
  579                        1,
  580                        real_rate,
  581                        1,
  582                        50000);
  583 
  584     /* Make sure the device is ready to accept data */
  585   assert(snd_pcm_state(pcm_handle) == SND_PCM_STATE_PREPARED);
  586 
  587   /* Write hardware parameters to flite audio device data structure */
  588   ad = walloc(cst_audiodev, 1);
  589   assert(ad != NULL);
  590   ad->real_sps = ad->sps = sps;
  591   ad->real_channels = ad->channels = channels;
  592   ad->real_fmt = ad->fmt = fmt;
  593   ad->platform_data = (void *) pcm_handle;
  594 
  595   return ad;
  596 }
  597 
  598 int audio_close_alsa(cst_audiodev *ad)
  599 {
  600   int result;
  601   snd_pcm_t *pcm_handle;
  602 
  603   if (ad == NULL)
  604       return 0;
  605 
  606   pcm_handle = (snd_pcm_t *) ad->platform_data;
  607 
  608   snd_pcm_drain(pcm_handle); /* wait for current stuff in buffer to finish */
  609 
  610   result = snd_pcm_close(pcm_handle);
  611   if (result < 0)
  612   {
  613     EST_warning("audio_close_alsa: Error: %s.\n", snd_strerror(result));
  614   }
  615   wfree(ad);
  616   return result;
  617 }
  618 
  619 /* Returns zero if recovery was successful. */
  620 static int recover_from_error(snd_pcm_t *pcm_handle, ssize_t res)
  621 {
  622   if (res == -EPIPE) /* xrun */
  623   {
  624     res = snd_pcm_prepare(pcm_handle);
  625     if (res < 0) 
  626     {
  627       /* Failed to recover from xrun */
  628       EST_warning("recover_from_write_error: failed to recover from xrun. %s\n.", snd_strerror(res));
  629       return res;
  630     }
  631   } 
  632   else if (res == -ESTRPIPE) /* Suspend */
  633   {
  634     while ((res = snd_pcm_resume(pcm_handle)) == -EAGAIN) 
  635     {
  636       snd_pcm_wait(pcm_handle, 1000);
  637     }
  638     if (res < 0) 
  639     {
  640       res = snd_pcm_prepare(pcm_handle);
  641       if (res <0) 
  642       {
  643         /* Resume failed */
  644         EST_warning("audio_recover_from_write_error: failed to resume after suspend. %s\n.", snd_strerror(res));
  645         return res;
  646       }
  647     }
  648   } 
  649   else if (res < 0) 
  650   {
  651     /* Unknown failure */
  652     EST_warning("audio_recover_from_write_error: %s.\n", snd_strerror(res));
  653     return res;
  654   }
  655   return 0;
  656 }
  657 
  658 int audio_write_alsa(cst_audiodev *ad, void *samples, int num_bytes)
  659 {
  660     size_t frame_size;
  661     ssize_t num_frames, res;
  662     snd_pcm_t *pcm_handle;
  663     char *buf = (char *) samples;
  664 
  665     /* Determine frame size in bytes */
  666     frame_size  = audio_bps(ad->real_fmt) * ad->real_channels;
  667     /* Require that only complete frames are handed in */
  668     assert((num_bytes % frame_size) == 0);
  669     num_frames = num_bytes / frame_size;
  670     pcm_handle = (snd_pcm_t *) ad->platform_data;
  671 
  672     while (num_frames > 0) 
  673     {
  674     res = snd_pcm_writei(pcm_handle, buf, num_frames);
  675     if (res != num_frames) 
  676     {
  677             if (res == -EAGAIN || (res > 0 && res < num_frames)) 
  678             {
  679         snd_pcm_wait(pcm_handle, 100);
  680             }
  681             else if (recover_from_error(pcm_handle, res) < 0) 
  682             {
  683         return -1;
  684             }
  685     }
  686 
  687     if (res >0) 
  688     {
  689             num_frames -= res;
  690             buf += res * frame_size;
  691     }
  692     }
  693     return num_bytes;
  694 }
  695 
  696 int audio_flush_alsa(cst_audiodev *ad)
  697 {
  698     int result;
  699     result = snd_pcm_drain((snd_pcm_t *) ad->platform_data);
  700     if (result < 0)
  701     {
  702     EST_warning("audio_flush_alsa: Error: %s.\n", snd_strerror(result));
  703     }
  704     /* Prepare device for more data */
  705     result = snd_pcm_prepare((snd_pcm_t *) ad->platform_data);
  706     if (result < 0)
  707     {
  708     EST_warning("audio_flush_alsa: Error: %s.\n", snd_strerror(result));
  709     }
  710     return result;
  711 }
  712 
  713 int audio_drain_alsa(cst_audiodev *ad)
  714 {
  715     int result;
  716     result = snd_pcm_drop((snd_pcm_t *) ad->platform_data);
  717     if (result < 0)
  718     {
  719     EST_warning("audio_drain_alsa: Error: %s.\n", snd_strerror(result));
  720     }
  721     /* Prepare device for more data */
  722     result = snd_pcm_prepare((snd_pcm_t *) ad->platform_data);
  723     if (result < 0)
  724     {
  725     EST_warning("audio_drain_alsa: Error: %s.\n", snd_strerror(result));
  726     }
  727     return result;
  728 }
  729 
  730 #define AUDIOBUFFSIZE 256
  731 // #define AUDIOBUFFSIZE 20480
  732 
  733 int play_linux_wave(EST_Wave &inwave, EST_Option &al)
  734 {
  735     int sample_rate;
  736     short *waveform;
  737     int num_samples;
  738     cst_audiodev *ad;
  739 
  740 #if 0
  741     const char *audiodevice;
  742     if (al.present("-audiodevice"))
  743     audiodevice = al.val("-audiodevice");
  744     else
  745     audiodevice = "/dev/dsp";
  746 #endif
  747 
  748     waveform = inwave.values().memory();
  749     num_samples = inwave.num_samples();
  750     sample_rate = inwave.sample_rate();
  751 
  752     ad = audio_open_alsa(sample_rate,1,CST_AUDIO_LINEAR16);
  753  
  754     THREAD_DECS();
  755     THREAD_PROTECT();
  756 
  757     audio_write_alsa(ad,waveform,num_samples*sizeof(short));
  758     
  759     audio_close_alsa(ad);
  760 
  761     THREAD_UNPROTECT();
  762     return 1;
  763 }
  764 
  765 int record_linux_wave(EST_Wave &inwave, EST_Option &al)
  766 {
  767 #if 0
  768     int sample_rate=16000;  // egcs needs the initialized for some reason
  769     short *waveform;
  770     short *waveform2=0;
  771     int num_samples;
  772     int audio=-1,actual_fmt;
  773     int i,r,n;
  774     char *audiodevice;
  775 
  776     if (al.present("-audiodevice"))
  777     audiodevice = al.val("-audiodevice");
  778     else
  779     audiodevice = "/dev/dsp";
  780 
  781     sample_rate = al.ival("-sample_rate");
  782     
  783     if ((audio = open(audiodevice,O_RDONLY)) == -1)
  784     {
  785     cerr << aud_sys_name << ": can't open " << audiodevice
  786          << "for reading" << endl;
  787     return -1;
  788     }
  789     
  790     actual_fmt = sb_set_sample_rate(audio,sample_rate);
  791 
  792     if ((actual_fmt == AFMT_S16_LE) || 
  793     (actual_fmt == AFMT_S16_BE))
  794     {
  795     // We assume that the device returns audio in native byte order
  796     // by default
  797     inwave.resize((int)(sample_rate*al.fval("-time")));
  798     inwave.set_sample_rate(sample_rate);
  799     num_samples = inwave.num_samples();
  800     waveform = inwave.values().memory();
  801 
  802     if (stereo_only)
  803     {
  804         waveform2 = walloc(short,num_samples*2);
  805         num_samples *= 2;
  806     }
  807     else
  808         waveform2 = waveform;
  809 
  810     for (i=0; i < num_samples; i+= r)
  811     {
  812         if (num_samples > i+AUDIOBUFFSIZE)
  813         n = AUDIOBUFFSIZE;
  814         else
  815         n = num_samples-i;
  816         r = read(audio,&waveform2[i], n*2);
  817         r /= 2;
  818         if (r <= 0)
  819         {
  820         cerr << aud_sys_name << ": failed to read from audio device"
  821             << endl;
  822         close(audio);
  823         return -1;
  824         }
  825     }
  826 
  827     }
  828     else if (actual_fmt == AFMT_U8)
  829     {
  830     inwave.resize((int)(sample_rate*al.fval("-time")));
  831     inwave.set_sample_rate(sample_rate);
  832     num_samples = inwave.num_samples();
  833     waveform = inwave.values().memory();
  834     unsigned char *u8wave = walloc(unsigned char,num_samples);
  835 
  836     for (i=0; i < num_samples; i+= r)
  837     {
  838         if (num_samples > i+AUDIOBUFFSIZE)
  839         n = AUDIOBUFFSIZE;
  840         else
  841         n = num_samples-i;
  842         r = read(audio,&u8wave[i],n);
  843         if (r <= 0)
  844         {
  845         cerr << aud_sys_name << ": failed to read from audio device"
  846             << endl;
  847         close(audio);
  848         wfree(u8wave);
  849         return -1;
  850         }
  851         
  852     }
  853     uchar_to_short(u8wave,waveform,num_samples);
  854     wfree(u8wave);
  855     }
  856     else
  857     {
  858     cerr << aud_sys_name << ": unknown audio format from device: " << 
  859         actual_fmt << endl;
  860     close(audio);
  861     return -1;
  862     }
  863 
  864     if (stereo_only)
  865     {
  866     for (i=0; i<num_samples; i+=2)
  867         waveform[i/2] = waveform2[i];
  868     wfree(waveform2);
  869     }
  870 
  871     close(audio);
  872 #endif /* 0 */ 
  873     return 0;
  874 }
  875 
  876 #else
  877 
  878 #ifdef SUPPORT_PULSEAUDIO
  879 #include <pulse/simple.h>
  880 
  881 int freebsd16_supported = FALSE;
  882 int linux16_supported = TRUE;
  883 
  884 static const char *aud_sys_name = "PULSEAUDIO";
  885 
  886 #define AUDIOBUFFSIZE 256
  887 // #define AUDIOBUFFSIZE 20480
  888 
  889 int play_linux_wave(EST_Wave &inwave, EST_Option &al)
  890 {
  891     pa_sample_spec *ss;
  892     pa_simple *s;
  893     short *waveform;
  894     int num_samples;
  895     int err=0, i, r;
  896 
  897     ss = walloc(pa_sample_spec,1);
  898     ss->rate = inwave.sample_rate();
  899     ss->channels = inwave.num_channels();
  900 
  901     if (EST_BIG_ENDIAN)
  902         ss->format = PA_SAMPLE_S16BE;
  903     else
  904         ss->format = PA_SAMPLE_S16LE;
  905     
  906     s = pa_simple_new(
  907                     NULL,      /* use default server */
  908                     "festival",
  909                     PA_STREAM_PLAYBACK,
  910                     NULL,      /* use default device */
  911                     "Speech",
  912                     ss,
  913                     NULL,      /* default channel map */
  914                     NULL,      /* default buffering attributes */
  915                     &err);
  916     if (err < 0)
  917         return NULL;
  918 
  919     waveform = inwave.values().memory();
  920     num_samples = inwave.num_samples();
  921 
  922     for (i=0; i < num_samples; i += AUDIOBUFFSIZE/2)
  923     {
  924         if (i + AUDIOBUFFSIZE/2 < num_samples)
  925             pa_simple_write(s,&waveform[i],(size_t)AUDIOBUFFSIZE,&err);
  926         else
  927             pa_simple_write(s,&waveform[i],(size_t)(num_samples-i)*2,&err);
  928     }
  929 
  930     pa_simple_drain(s,&err);
  931     pa_simple_free(s);
  932     wfree(ss);
  933 
  934     return 1;
  935 }
  936 
  937 int record_linux_wave(EST_Wave &inwave, EST_Option &al)
  938 {
  939     return -1;
  940 }
  941 
  942 #else /* not supported */
  943 
  944 int freebsd16_supported = FALSE;
  945 int linux16_supported = FALSE;
  946 
  947 int play_linux_wave(EST_Wave &inwave, EST_Option &al)
  948 {
  949     (void)inwave;
  950     (void)al;
  951     cerr << "MacOS X audio support not compiled." << endl;
  952     return -1;
  953 }
  954 int record_linux_wave(EST_Wave &inwave, EST_Option &al)
  955 {
  956     (void)inwave;
  957     (void)al;
  958     cerr << "MacOS X audio support not compiled." << endl;
  959     return -1;
  960 }
  961 
  962 #endif /* ALSA */
  963 #endif /* PULSEAUDIO */
  964 #endif /* VOXWARE */
  965