libsent/src/adin/adin_mic_linux_oss.c

Go to the documentation of this file.
00001 
00057 /*
00058  * Copyright (c) 1991-2007 Kawahara Lab., Kyoto University
00059  * Copyright (c) 2000-2005 Shikano Lab., Nara Institute of Science and Technology
00060  * Copyright (c) 2005-2007 Julius project team, Nagoya Institute of Technology
00061  * All rights reserved
00062  */
00063 
00064 #include <sent/stddefs.h>
00065 #include <sent/adin.h>
00066 
00067 #include <sys/ioctl.h>
00068 #include <sys/types.h>
00069 #include <sys/stat.h>
00070 #include <sys/time.h>
00071 #include <fcntl.h>
00072 
00073 /* sound header */
00074 #include <sys/soundcard.h>
00075 
00077 #define DEFAULT_DEVICE "/dev/dsp"
00078 
00079 #define FREQALLOWRANGE 200      
00080 #define MAXPOLLINTERVAL 300     
00081 
00088 #define MAX_FRAGMENT_MSEC 50
00089 
00093 #define MIN_FRAGMENT_SIZE 256
00094 
00095 static int audio_fd;            
00096 static boolean need_swap;       
00097 static int frag_size;           
00098 static boolean stereo_rec;      
00099 
00108 boolean
00109 adin_mic_standby(int sfreq, void *dummy)
00110 {
00111   int fmt, fmt_can, fmt1, fmt2, rfmt; /* sampling format */
00112   int samplerate;       /* 16kHz */
00113   char *defaultdev = DEFAULT_DEVICE; /* default device */
00114   char *devname;
00115   int frag;
00116   int frag_msec;
00117   char *env;
00118 
00119   /* set device name */
00120   if ((devname = getenv("AUDIODEV")) == NULL) {
00121     devname = defaultdev;
00122     jlog("Stat: adin_oss: device name = %s\n", devname);
00123   } else {
00124     jlog("Stat: adin_oss: device name obtained from AUDIODEV: %s\n", devname);
00125   }
00126 
00127   /* open device */
00128   if ((audio_fd = open(devname, O_RDONLY|O_NONBLOCK)) == -1) {
00129     jlog("Error: adin_oss: failed to open %s\n", devname);
00130     return(FALSE);
00131   }
00132 
00133   /* check whether soundcard can record 16bit data */
00134   /* and set fmt */
00135   if (ioctl(audio_fd, SNDCTL_DSP_GETFMTS, &fmt_can) == -1) {
00136     jlog("Error: adin_oss: failed to get formats from audio device\n");
00137     return(FALSE);
00138   }
00139 #ifdef WORDS_BIGENDIAN
00140   fmt1 = AFMT_S16_BE;
00141   fmt2 = AFMT_S16_LE;
00142 #else
00143   fmt1 = AFMT_S16_LE;               /* 16bit signed (little endian) */
00144   fmt2 = AFMT_S16_BE;               /* (big endian) */
00145 #endif /* WORDS_BIGENDIAN */
00146   /* fmt2 needs byte swap */
00147   if (fmt_can & fmt1) {
00148     fmt = fmt1;
00149     need_swap = FALSE;
00150   } else if (fmt_can & fmt2) {
00151     fmt = fmt2;
00152     need_swap = TRUE;
00153   } else {
00154     jlog("Error: adin_oss: 16bit recording not supported on this device\n");
00155     return FALSE;
00156   }
00157 #ifdef DEBUG
00158   if (need_swap) {
00159     jlog("Stat: adin_oss: samples need swap\n");
00160   } else {
00161     jlog("Stat: adin_oss: samples need not swap\n");
00162   }
00163 #endif
00164   
00165   if (close(audio_fd) != 0) return FALSE;
00166 
00167   /* re-open for recording */
00168   /* open device */
00169   if ((audio_fd = open(devname, O_RDONLY)) == -1) {
00170     jlog("Error: adin_oss: failed to open %s", devname);
00171     return(FALSE);
00172   }
00173 
00174   /* try to set a small fragment size to minimize delay, */
00175   /* although many devices use static fragment size... */
00176   /* (and smaller fragment causes busy buffering) */
00177   {
00178     int arg;
00179     int f, f2;
00180 
00181     /* if environment variable "LATENCY_MSEC" is defined, try to set it
00182        as a minimum latency in msec (will be rouneded to 2^x). */
00183     if ((env = getenv("LATENCY_MSEC")) == NULL) {
00184       frag_msec = MAX_FRAGMENT_MSEC;
00185     } else {
00186       frag_msec = atoi(env);
00187     }
00188       
00189     /* get fragment size from MAX_FRAGMENT_MSEC and MIN_FRAGMENT_SIZE */
00190     f = 0;
00191     f2 = 1;
00192     while (f2 * 1000 / (sfreq * sizeof(SP16)) <= frag_msec
00193            || f2 < MIN_FRAGMENT_SIZE) {
00194       f++;
00195       f2 *= 2;
00196     }
00197     frag = f - 1;
00198 
00199     /* set to device */
00200     arg = 0x7fff0000 | frag;
00201     if (ioctl(audio_fd, SNDCTL_DSP_SETFRAGMENT, &arg)) {
00202       jlog("Stat: adin_oss: set fragment size to 2^%d=%d bytes (%d msec)\n", frag, 2 << (frag-1), (2 << (frag-1)) * 1000 / (sfreq * sizeof(SP16)));
00203     }
00204   }
00205   
00206   /* set format, samplerate, channels */
00207   rfmt = fmt;
00208   if (ioctl(audio_fd, SNDCTL_DSP_SETFMT, &rfmt) == -1) {
00209     jlog("Error: adin_oss: failed to get available formats from device\n");
00210     return(FALSE);
00211   }
00212   if (rfmt != fmt) {
00213     jlog("Error: adin_oss: 16bit recording is not supported on this device\n");
00214     return FALSE;
00215   }
00216 
00217   {
00218     /* try SNDCTL_DSP_STEREO, SNDCTL_DSP_CHANNELS, monaural, stereo */
00219     int channels;
00220     int stereo;
00221     boolean ok_p = FALSE;
00222 
00223     stereo = 0;                 /* mono */
00224     if (ioctl(audio_fd, SNDCTL_DSP_STEREO, &stereo) == -1) {
00225       /* failed: SNDCTL_DSP_STEREO not supported */
00226       jlog("Stat: adin_oss: sndctl_dsp_stereo not supported, going to try another...\n");
00227     } else {
00228       if (stereo != 0) {
00229         /* failed to set monaural recording by SNDCTL_DSP_STEREO */
00230         jlog("Stat: adin_oss: failed to set monaural recording by sndctl_dsp_stereo\n");
00231         jlog("Stat: adin_oss: going to try another...\n");
00232       } else {
00233         /* succeeded to set monaural recording by SNDCTL_DSP_STEREO */
00234         //jlog("Stat: adin_oss: recording now set to mono\n");
00235         stereo_rec = FALSE;
00236         ok_p = TRUE;
00237       }
00238     }
00239     if (! ok_p) {               /* not setup yet */
00240       /* try using sndctl_dsp_channels */
00241       channels = 1;
00242       if (ioctl(audio_fd, SNDCTL_DSP_CHANNELS, &channels) == -1) {
00243         /* failed: SNDCTL_DSP_CHANNELS not supported */
00244         jlog("Stat: adin_oss: sndctl_dsp_channels not supported, try another...\n");
00245       } else {
00246         if (channels != 1) {
00247           /* failed to set monaural recording by SNDCTL_DSP_CHANNELS */
00248           jlog("Stat: adin_oss: failed to set monaural recording by sndctl_dsp_channels\n");
00249           jlog("Stat: adin_oss: going to try another...\n");
00250         } else {
00251           /* succeeded to set monaural recording by SNDCTL_DSP_CHANNELS */
00252           //jlog("Stat: adin_oss: recording now set to mono\n");
00253           stereo_rec = FALSE;
00254           ok_p = TRUE;
00255         }
00256       }
00257     }
00258     if (! ok_p) {
00259       /* try using stereo input */
00260       jlog("Warning: adin_oss: failed to setup monaural recording, trying to use the left channel of stereo input\n");
00261       stereo = 1;                       /* stereo */
00262       if (ioctl(audio_fd, SNDCTL_DSP_STEREO, &stereo) == -1) {
00263         /* failed: SNDCTL_DSP_STEREO not supported */
00264         jlog("Stat: adin_oss: failed to set stereo input using sndctl_dsp_stereo\n");
00265       } else {
00266         if (stereo != 1) {
00267           /* failed to set stereo recording by SNDCTL_DSP_STEREO */
00268           jlog("Stat: adin_oss: failed to set stereo input using sndctl_dsp_stereo\n");
00269         } else {
00270           /* succeeded to set stereo recording by SNDCTL_DSP_STEREO */
00271           jlog("Stat: adin_oss: recording now set to stereo, using left channel\n");
00272           stereo_rec = TRUE;
00273           ok_p = TRUE;
00274         }
00275       }
00276     }
00277     if (! ok_p) {               /* not setup yet */
00278       /* try using stereo input with sndctl_dsp_channels */
00279       channels = 2;
00280       if (ioctl(audio_fd, SNDCTL_DSP_CHANNELS, &channels) == -1) {
00281         /* failed: SNDCTL_DSP_CHANNELS not supported */
00282         jlog("Stat: adin_oss: failed to set stereo input using sndctl_dsp_channels\n");
00283       } else {
00284         if (channels != 2) {
00285           /* failed to set stereo recording by SNDCTL_DSP_CHANNELS */
00286           jlog("Stat: adin_oss: failed to set stereo input using sndctl_dsp_channels\n");
00287         } else {
00288           /* succeeded to set stereo recording by SNDCTL_DSP_CHANNELS */
00289           jlog("Stat: adin_oss: recording now set to stereo, using left channel\n");
00290           stereo_rec = TRUE;
00291           ok_p = TRUE;
00292         }
00293       }
00294     }
00295     if (! ok_p) {               /* all failed */
00296       jlog("Error: adin_oss: failed to setup recording channels\n");
00297       return FALSE;
00298     }
00299   }
00300 
00301   samplerate = sfreq;
00302   if (ioctl(audio_fd, SNDCTL_DSP_SPEED, &samplerate) == -1) {
00303     jlog("Erorr: adin_oss: failed to set sample rate to %dHz\n", sfreq);
00304     return(FALSE);
00305   }
00306   if (samplerate < sfreq - FREQALLOWRANGE || samplerate > sfreq + FREQALLOWRANGE) {
00307     jlog("Error: adin_oss: failed to set sampling rate to near %dHz. (%d)\n", sfreq, samplerate);
00308     return FALSE;
00309   }
00310   if (samplerate != sfreq) {
00311     jlog("Warning: adin_oss: specified sampling rate was %dHz but set to %dHz, \n", sfreq, samplerate);
00312   }
00313   jlog("Stat: adin_oss: sampling rate = %dHz\n", samplerate);
00314 
00315   /* get actual fragment size */
00316   if (ioctl(audio_fd, SNDCTL_DSP_GETBLKSIZE, &frag_size) == -1) {
00317     jlog("Error: adin_oss: failed to get fragment size\n");
00318     return(FALSE);
00319   }
00320   if (env == NULL) {
00321     jlog("Stat: adin_oss: going to set latency to %d msec\n", frag_msec);
00322   } else {
00323     jlog("Stat: adin_oss: going to set latency to %d msec (from env LATENCY_MSEC)\n", frag_msec);
00324   }
00325   jlog("Stat: adin_oss: audio I/O Latency = %d msec (fragment size = %d samples)\n", frag_size * 1000/ (sfreq * sizeof(SP16)), frag_size / sizeof(SP16));
00326 
00327   return TRUE;
00328 }
00329  
00335 boolean
00336 adin_mic_begin()
00337 {
00338   char buf[4];
00339   /* Read 1 sample (and ignore it) to tell the audio device start recording.
00340      (If you knows better way, teach me...) */
00341   if (stereo_rec) {
00342     read(audio_fd, buf, 4);
00343   } else {
00344     read(audio_fd, buf, 2);
00345   }
00346   return(TRUE);
00347 }
00348 
00354 boolean
00355 adin_mic_end()
00356 {
00357   /*
00358    * Not reset device on each end of speech, just let the buffer overrun...
00359    * Resetting and restarting of recording device sometimes causes
00360    * hawling noises at the next recording.
00361    * I don't now why, so take the easy way... :-(
00362    */
00363   return TRUE;
00364 }
00365 
00383 int
00384 adin_mic_read(SP16 *buf, int sampnum)
00385 {
00386   int size,cnt,i;
00387   audio_buf_info info;
00388   fd_set rfds;
00389   struct timeval tv;
00390   int status;
00391 
00392   /* check for incoming samples in device buffer */
00393   /* if there is at least one sample fragment, go next */
00394   /* if not exist, wait for the data to come for at most MAXPOLLINTERVAL msec */
00395   /* if no sample fragment has come in the MAXPOLLINTERVAL period, go next */
00396   FD_ZERO(&rfds);
00397   FD_SET(audio_fd, &rfds);
00398   tv.tv_sec = 0;
00399   tv.tv_usec = MAXPOLLINTERVAL * 1000;
00400   status = select(audio_fd+1, &rfds, NULL, NULL, &tv);
00401   if (status < 0) {
00402     /* select() failed */
00403     jlog("Error: adin_oss: failed to poll device\n");
00404     return(-2);                 /* error */
00405   }
00406   if (FD_ISSET(audio_fd, &rfds)) { /* has some data */
00407     /* get sample num that can be read without blocking */
00408     if (ioctl(audio_fd, SNDCTL_DSP_GETISPACE, &info) == -1) {
00409       jlog("Error: adin_oss: failed to get number of samples in the buffer\n");
00410       return(-2);
00411     }
00412     /* get them as much as possible */
00413     size = sampnum * sizeof(SP16);
00414     if (size > info.bytes) size = info.bytes;
00415     if (size < frag_size) size = frag_size;
00416     size &= ~ 1;                /* Force 16bit alignment */
00417     cnt = read(audio_fd, buf, size);
00418     if ( cnt < 0 ) {
00419       jlog("Error: adin_oss: failed to read samples\n");
00420       return ( -2 );
00421     }
00422     cnt /= sizeof(short);
00423 
00424     if (stereo_rec) {
00425       /* remove R channel */
00426       for(i=1;i<cnt;i+=2) buf[(i-1)/2]=buf[i];
00427       cnt/=2;
00428     }
00429     
00430     if (need_swap) swap_sample_bytes(buf, cnt);
00431   } else {                      /* no data after waiting */
00432     jlog("Warning: adin_oss: no data fragment after %d msec?\n", MAXPOLLINTERVAL);
00433     cnt = 0;
00434   }
00435 
00436   return(cnt);
00437 }

Generated on Tue Dec 18 15:59:54 2007 for Julius by  doxygen 1.5.4