libsent/src/adin/adin_mic_linux_oss.c

説明を見る。
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 
00066 #include <sent/adin.h>
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 #ifdef HAS_OSS
00075 #if defined(HAVE_SYS_SOUNDCARD_H)
00076 #include <sys/soundcard.h>
00077 #elif defined(HAVE_MACHINE_SOUNDCARD_H)
00078 #include <machine/soundcard.h>
00079 #endif
00080 #endif
00081 
00083 #define DEFAULT_DEVICE "/dev/dsp"
00084 
00085 #define FREQALLOWRANGE 200      
00086 #define MAXPOLLINTERVAL 300     
00087 
00094 #define MAX_FRAGMENT_MSEC 50
00095 
00099 #define MIN_FRAGMENT_SIZE 256
00100 
00101 static int audio_fd;            
00102 static boolean need_swap;       
00103 static int frag_size;           
00104 static boolean stereo_rec;      
00105 
00114 boolean
00115 adin_oss_standby(int sfreq, void *dummy)
00116 {
00117 #ifndef HAS_OSS
00118   jlog("Error: OSS not compiled in\n");
00119   return FALSE;
00120 #else
00121   int fmt, fmt_can, fmt1, fmt2, rfmt; /* sampling format */
00122   int samplerate;       /* 16kHz */
00123   char *defaultdev = DEFAULT_DEVICE; /* default device */
00124   char *devname;
00125   int frag;
00126   int frag_msec;
00127   char *env;
00128 
00129   /* set device name */
00130   if ((devname = getenv("AUDIODEV")) == NULL) {
00131     devname = defaultdev;
00132     jlog("Stat: adin_oss: device name = %s\n", devname);
00133   } else {
00134     jlog("Stat: adin_oss: device name obtained from AUDIODEV: %s\n", devname);
00135   }
00136 
00137   /* open device */
00138   if ((audio_fd = open(devname, O_RDONLY|O_NONBLOCK)) == -1) {
00139     jlog("Error: adin_oss: failed to open %s\n", devname);
00140     return(FALSE);
00141   }
00142 
00143   /* check whether soundcard can record 16bit data */
00144   /* and set fmt */
00145   if (ioctl(audio_fd, SNDCTL_DSP_GETFMTS, &fmt_can) == -1) {
00146     jlog("Error: adin_oss: failed to get formats from audio device\n");
00147     return(FALSE);
00148   }
00149 #ifdef WORDS_BIGENDIAN
00150   fmt1 = AFMT_S16_BE;
00151   fmt2 = AFMT_S16_LE;
00152 #else
00153   fmt1 = AFMT_S16_LE;               /* 16bit signed (little endian) */
00154   fmt2 = AFMT_S16_BE;               /* (big endian) */
00155 #endif /* WORDS_BIGENDIAN */
00156   /* fmt2 needs byte swap */
00157   if (fmt_can & fmt1) {
00158     fmt = fmt1;
00159     need_swap = FALSE;
00160   } else if (fmt_can & fmt2) {
00161     fmt = fmt2;
00162     need_swap = TRUE;
00163   } else {
00164     jlog("Error: adin_oss: 16bit recording not supported on this device\n");
00165     return FALSE;
00166   }
00167 #ifdef DEBUG
00168   if (need_swap) {
00169     jlog("Stat: adin_oss: samples need swap\n");
00170   } else {
00171     jlog("Stat: adin_oss: samples need not swap\n");
00172   }
00173 #endif
00174   
00175   if (close(audio_fd) != 0) return FALSE;
00176 
00177   /* re-open for recording */
00178   /* open device */
00179   if ((audio_fd = open(devname, O_RDONLY)) == -1) {
00180     jlog("Error: adin_oss: failed to open %s", devname);
00181     return(FALSE);
00182   }
00183 
00184   /* try to set a small fragment size to minimize delay, */
00185   /* although many devices use static fragment size... */
00186   /* (and smaller fragment causes busy buffering) */
00187   {
00188     int arg;
00189     int f, f2;
00190 
00191     /* if environment variable "LATENCY_MSEC" is defined, try to set it
00192        as a minimum latency in msec (will be rouneded to 2^x). */
00193     if ((env = getenv("LATENCY_MSEC")) == NULL) {
00194       frag_msec = MAX_FRAGMENT_MSEC;
00195     } else {
00196       frag_msec = atoi(env);
00197     }
00198       
00199     /* get fragment size from MAX_FRAGMENT_MSEC and MIN_FRAGMENT_SIZE */
00200     f = 0;
00201     f2 = 1;
00202     while (f2 * 1000 / (sfreq * sizeof(SP16)) <= frag_msec
00203            || f2 < MIN_FRAGMENT_SIZE) {
00204       f++;
00205       f2 *= 2;
00206     }
00207     frag = f - 1;
00208 
00209     /* set to device */
00210     arg = 0x7fff0000 | frag;
00211     if (ioctl(audio_fd, SNDCTL_DSP_SETFRAGMENT, &arg)) {
00212       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)));
00213     }
00214   }
00215   
00216   /* set format, samplerate, channels */
00217   rfmt = fmt;
00218   if (ioctl(audio_fd, SNDCTL_DSP_SETFMT, &rfmt) == -1) {
00219     jlog("Error: adin_oss: failed to get available formats from device\n");
00220     return(FALSE);
00221   }
00222   if (rfmt != fmt) {
00223     jlog("Error: adin_oss: 16bit recording is not supported on this device\n");
00224     return FALSE;
00225   }
00226 
00227   {
00228     /* try SNDCTL_DSP_STEREO, SNDCTL_DSP_CHANNELS, monaural, stereo */
00229     int channels;
00230     int stereo;
00231     boolean ok_p = FALSE;
00232 
00233     stereo = 0;                 /* mono */
00234     if (ioctl(audio_fd, SNDCTL_DSP_STEREO, &stereo) == -1) {
00235       /* failed: SNDCTL_DSP_STEREO not supported */
00236       jlog("Stat: adin_oss: sndctl_dsp_stereo not supported, going to try another...\n");
00237     } else {
00238       if (stereo != 0) {
00239         /* failed to set monaural recording by SNDCTL_DSP_STEREO */
00240         jlog("Stat: adin_oss: failed to set monaural recording by sndctl_dsp_stereo\n");
00241         jlog("Stat: adin_oss: going to try another...\n");
00242       } else {
00243         /* succeeded to set monaural recording by SNDCTL_DSP_STEREO */
00244         //jlog("Stat: adin_oss: recording now set to mono\n");
00245         stereo_rec = FALSE;
00246         ok_p = TRUE;
00247       }
00248     }
00249     if (! ok_p) {               /* not setup yet */
00250       /* try using sndctl_dsp_channels */
00251       channels = 1;
00252       if (ioctl(audio_fd, SNDCTL_DSP_CHANNELS, &channels) == -1) {
00253         /* failed: SNDCTL_DSP_CHANNELS not supported */
00254         jlog("Stat: adin_oss: sndctl_dsp_channels not supported, try another...\n");
00255       } else {
00256         if (channels != 1) {
00257           /* failed to set monaural recording by SNDCTL_DSP_CHANNELS */
00258           jlog("Stat: adin_oss: failed to set monaural recording by sndctl_dsp_channels\n");
00259           jlog("Stat: adin_oss: going to try another...\n");
00260         } else {
00261           /* succeeded to set monaural recording by SNDCTL_DSP_CHANNELS */
00262           //jlog("Stat: adin_oss: recording now set to mono\n");
00263           stereo_rec = FALSE;
00264           ok_p = TRUE;
00265         }
00266       }
00267     }
00268     if (! ok_p) {
00269       /* try using stereo input */
00270       jlog("Warning: adin_oss: failed to setup monaural recording, trying to use the left channel of stereo input\n");
00271       stereo = 1;                       /* stereo */
00272       if (ioctl(audio_fd, SNDCTL_DSP_STEREO, &stereo) == -1) {
00273         /* failed: SNDCTL_DSP_STEREO not supported */
00274         jlog("Stat: adin_oss: failed to set stereo input using sndctl_dsp_stereo\n");
00275       } else {
00276         if (stereo != 1) {
00277           /* failed to set stereo recording by SNDCTL_DSP_STEREO */
00278           jlog("Stat: adin_oss: failed to set stereo input using sndctl_dsp_stereo\n");
00279         } else {
00280           /* succeeded to set stereo recording by SNDCTL_DSP_STEREO */
00281           jlog("Stat: adin_oss: recording now set to stereo, using left channel\n");
00282           stereo_rec = TRUE;
00283           ok_p = TRUE;
00284         }
00285       }
00286     }
00287     if (! ok_p) {               /* not setup yet */
00288       /* try using stereo input with sndctl_dsp_channels */
00289       channels = 2;
00290       if (ioctl(audio_fd, SNDCTL_DSP_CHANNELS, &channels) == -1) {
00291         /* failed: SNDCTL_DSP_CHANNELS not supported */
00292         jlog("Stat: adin_oss: failed to set stereo input using sndctl_dsp_channels\n");
00293       } else {
00294         if (channels != 2) {
00295           /* failed to set stereo recording by SNDCTL_DSP_CHANNELS */
00296           jlog("Stat: adin_oss: failed to set stereo input using sndctl_dsp_channels\n");
00297         } else {
00298           /* succeeded to set stereo recording by SNDCTL_DSP_CHANNELS */
00299           jlog("Stat: adin_oss: recording now set to stereo, using left channel\n");
00300           stereo_rec = TRUE;
00301           ok_p = TRUE;
00302         }
00303       }
00304     }
00305     if (! ok_p) {               /* all failed */
00306       jlog("Error: adin_oss: failed to setup recording channels\n");
00307       return FALSE;
00308     }
00309   }
00310 
00311   samplerate = sfreq;
00312   if (ioctl(audio_fd, SNDCTL_DSP_SPEED, &samplerate) == -1) {
00313     jlog("Erorr: adin_oss: failed to set sample rate to %dHz\n", sfreq);
00314     return(FALSE);
00315   }
00316   if (samplerate < sfreq - FREQALLOWRANGE || samplerate > sfreq + FREQALLOWRANGE) {
00317     jlog("Error: adin_oss: failed to set sampling rate to near %dHz. (%d)\n", sfreq, samplerate);
00318     return FALSE;
00319   }
00320   if (samplerate != sfreq) {
00321     jlog("Warning: adin_oss: specified sampling rate was %dHz but set to %dHz, \n", sfreq, samplerate);
00322   }
00323   jlog("Stat: adin_oss: sampling rate = %dHz\n", samplerate);
00324 
00325   /* get actual fragment size */
00326   if (ioctl(audio_fd, SNDCTL_DSP_GETBLKSIZE, &frag_size) == -1) {
00327     jlog("Error: adin_oss: failed to get fragment size\n");
00328     return(FALSE);
00329   }
00330   if (env == NULL) {
00331     jlog("Stat: adin_oss: going to set latency to %d msec\n", frag_msec);
00332   } else {
00333     jlog("Stat: adin_oss: going to set latency to %d msec (from env LATENCY_MSEC)\n", frag_msec);
00334   }
00335   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));
00336 
00337   return TRUE;
00338 
00339 #endif /* HAS_OSS */
00340 }
00341  
00347 boolean
00348 adin_oss_begin()
00349 {
00350   char buf[4];
00351   /* Read 1 sample (and ignore it) to tell the audio device start recording.
00352      (If you knows better way, teach me...) */
00353   if (stereo_rec) {
00354     read(audio_fd, buf, 4);
00355   } else {
00356     read(audio_fd, buf, 2);
00357   }
00358   return(TRUE);
00359 }
00360 
00366 boolean
00367 adin_oss_end()
00368 {
00369   /*
00370    * Not reset device on each end of speech, just let the buffer overrun...
00371    * Resetting and restarting of recording device sometimes causes
00372    * hawling noises at the next recording.
00373    * I don't now why, so take the easy way... :-(
00374    */
00375   return TRUE;
00376 }
00377 
00395 int
00396 adin_oss_read(SP16 *buf, int sampnum)
00397 {
00398 #ifndef HAS_OSS
00399   return -2;
00400 #else
00401   int size,cnt,i;
00402   audio_buf_info info;
00403   fd_set rfds;
00404   struct timeval tv;
00405   int status;
00406 
00407   /* check for incoming samples in device buffer */
00408   /* if there is at least one sample fragment, go next */
00409   /* if not exist, wait for the data to come for at most MAXPOLLINTERVAL msec */
00410   /* if no sample fragment has come in the MAXPOLLINTERVAL period, go next */
00411   FD_ZERO(&rfds);
00412   FD_SET(audio_fd, &rfds);
00413   tv.tv_sec = 0;
00414   tv.tv_usec = MAXPOLLINTERVAL * 1000;
00415   status = select(audio_fd+1, &rfds, NULL, NULL, &tv);
00416   if (status < 0) {
00417     /* select() failed */
00418     jlog("Error: adin_oss: failed to poll device\n");
00419     return(-2);                 /* error */
00420   }
00421   if (FD_ISSET(audio_fd, &rfds)) { /* has some data */
00422     /* get sample num that can be read without blocking */
00423     if (ioctl(audio_fd, SNDCTL_DSP_GETISPACE, &info) == -1) {
00424       jlog("Error: adin_oss: failed to get number of samples in the buffer\n");
00425       return(-2);
00426     }
00427     /* get them as much as possible */
00428     size = sampnum * sizeof(SP16);
00429     if (size > info.bytes) size = info.bytes;
00430     if (size < frag_size) size = frag_size;
00431     size &= ~ 1;                /* Force 16bit alignment */
00432     cnt = read(audio_fd, buf, size);
00433     if ( cnt < 0 ) {
00434       jlog("Error: adin_oss: failed to read samples\n");
00435       return ( -2 );
00436     }
00437     cnt /= sizeof(short);
00438 
00439     if (stereo_rec) {
00440       /* remove R channel */
00441       for(i=1;i<cnt;i+=2) buf[(i-1)/2]=buf[i];
00442       cnt/=2;
00443     }
00444     
00445     if (need_swap) swap_sample_bytes(buf, cnt);
00446   } else {                      /* no data after waiting */
00447     jlog("Warning: adin_oss: no data fragment after %d msec?\n", MAXPOLLINTERVAL);
00448     cnt = 0;
00449   }
00450 
00451   return(cnt);
00452 #endif /* HAS_OSS */
00453 }
00454 

Juliusに対してThu Jul 23 12:16:23 2009に生成されました。  doxygen 1.5.1