Julius 4.2
|
00001 00057 /* 00058 * Copyright (c) 1991-2011 Kawahara Lab., Kyoto University 00059 * Copyright (c) 2000-2005 Shikano Lab., Nara Institute of Science and Technology 00060 * Copyright (c) 2005-2011 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 ///< Acceptable width of sampling frequency 00086 #define MAXPOLLINTERVAL 300 ///< Read timeout in msec. 00087 00094 #define MAX_FRAGMENT_MSEC 50 00095 00099 #define MIN_FRAGMENT_SIZE 256 00100 00101 static int srate; 00102 static int audio_fd; 00103 static boolean need_swap; 00104 static int frag_size; 00105 static boolean stereo_rec; 00106 static char *defaultdev = DEFAULT_DEVICE; 00107 static char devname[MAXPATHLEN]; 00108 00117 boolean 00118 adin_oss_standby(int sfreq, void *dummy) 00119 { 00120 #ifndef HAS_OSS 00121 jlog("Error: OSS not compiled in\n"); 00122 return FALSE; 00123 #else 00124 /* store required sampling rate for checking after opening device */ 00125 srate = sfreq; 00126 return TRUE; 00127 } 00128 00136 static boolean 00137 adin_oss_open(char *devstr) 00138 { 00139 int fmt, fmt_can, fmt1, fmt2, rfmt; /* sampling format */ 00140 int samplerate; /* 16kHz */ 00141 int frag; 00142 int frag_msec; 00143 char *env, *p; 00144 00145 /* open device */ 00146 if ((audio_fd = open(devstr, O_RDONLY|O_NONBLOCK)) == -1) { 00147 jlog("Error: adin_oss: failed to open %s\n", devstr); 00148 return(FALSE); 00149 } 00150 00151 /* check whether soundcard can record 16bit data */ 00152 /* and set fmt */ 00153 if (ioctl(audio_fd, SNDCTL_DSP_GETFMTS, &fmt_can) == -1) { 00154 jlog("Error: adin_oss: failed to get formats from audio device\n"); 00155 return(FALSE); 00156 } 00157 #ifdef WORDS_BIGENDIAN 00158 fmt1 = AFMT_S16_BE; 00159 fmt2 = AFMT_S16_LE; 00160 #else 00161 fmt1 = AFMT_S16_LE; /* 16bit signed (little endian) */ 00162 fmt2 = AFMT_S16_BE; /* (big endian) */ 00163 #endif /* WORDS_BIGENDIAN */ 00164 /* fmt2 needs byte swap */ 00165 if (fmt_can & fmt1) { 00166 fmt = fmt1; 00167 need_swap = FALSE; 00168 } else if (fmt_can & fmt2) { 00169 fmt = fmt2; 00170 need_swap = TRUE; 00171 } else { 00172 jlog("Error: adin_oss: 16bit recording not supported on this device\n"); 00173 return FALSE; 00174 } 00175 #ifdef DEBUG 00176 if (need_swap) { 00177 jlog("Stat: adin_oss: samples need swap\n"); 00178 } else { 00179 jlog("Stat: adin_oss: samples need not swap\n"); 00180 } 00181 #endif 00182 00183 if (close(audio_fd) != 0) return FALSE; 00184 00185 /* re-open for recording */ 00186 /* open device */ 00187 if ((audio_fd = open(devstr, O_RDONLY)) == -1) { 00188 jlog("Error: adin_oss: failed to open %s", devstr); 00189 return(FALSE); 00190 } 00191 00192 /* try to set a small fragment size to minimize delay, */ 00193 /* although many devices use static fragment size... */ 00194 /* (and smaller fragment causes busy buffering) */ 00195 { 00196 int arg; 00197 int f, f2; 00198 00199 /* if environment variable "LATENCY_MSEC" is defined, try to set it 00200 as a minimum latency in msec (will be rouneded to 2^x). */ 00201 if ((env = getenv("LATENCY_MSEC")) == NULL) { 00202 frag_msec = MAX_FRAGMENT_MSEC; 00203 } else { 00204 frag_msec = atoi(env); 00205 } 00206 00207 /* get fragment size from MAX_FRAGMENT_MSEC and MIN_FRAGMENT_SIZE */ 00208 f = 0; 00209 f2 = 1; 00210 while (f2 * 1000 / (srate * sizeof(SP16)) <= frag_msec 00211 || f2 < MIN_FRAGMENT_SIZE) { 00212 f++; 00213 f2 *= 2; 00214 } 00215 frag = f - 1; 00216 00217 /* set to device */ 00218 arg = 0x7fff0000 | frag; 00219 if (ioctl(audio_fd, SNDCTL_DSP_SETFRAGMENT, &arg)) { 00220 jlog("Stat: adin_oss: set fragment size to 2^%d=%d bytes (%d msec)\n", frag, 2 << (frag-1), (2 << (frag-1)) * 1000 / (srate * sizeof(SP16))); 00221 } 00222 } 00223 00224 /* set format, samplerate, channels */ 00225 rfmt = fmt; 00226 if (ioctl(audio_fd, SNDCTL_DSP_SETFMT, &rfmt) == -1) { 00227 jlog("Error: adin_oss: failed to get available formats from device\n"); 00228 return(FALSE); 00229 } 00230 if (rfmt != fmt) { 00231 jlog("Error: adin_oss: 16bit recording is not supported on this device\n"); 00232 return FALSE; 00233 } 00234 00235 { 00236 /* try SNDCTL_DSP_STEREO, SNDCTL_DSP_CHANNELS, monaural, stereo */ 00237 int channels; 00238 int stereo; 00239 boolean ok_p = FALSE; 00240 00241 stereo = 0; /* mono */ 00242 if (ioctl(audio_fd, SNDCTL_DSP_STEREO, &stereo) == -1) { 00243 /* failed: SNDCTL_DSP_STEREO not supported */ 00244 jlog("Stat: adin_oss: sndctl_dsp_stereo not supported, going to try another...\n"); 00245 } else { 00246 if (stereo != 0) { 00247 /* failed to set monaural recording by SNDCTL_DSP_STEREO */ 00248 jlog("Stat: adin_oss: failed to set monaural recording by sndctl_dsp_stereo\n"); 00249 jlog("Stat: adin_oss: going to try another...\n"); 00250 } else { 00251 /* succeeded to set monaural recording by SNDCTL_DSP_STEREO */ 00252 //jlog("Stat: adin_oss: recording now set to mono\n"); 00253 stereo_rec = FALSE; 00254 ok_p = TRUE; 00255 } 00256 } 00257 if (! ok_p) { /* not setup yet */ 00258 /* try using sndctl_dsp_channels */ 00259 channels = 1; 00260 if (ioctl(audio_fd, SNDCTL_DSP_CHANNELS, &channels) == -1) { 00261 /* failed: SNDCTL_DSP_CHANNELS not supported */ 00262 jlog("Stat: adin_oss: sndctl_dsp_channels not supported, try another...\n"); 00263 } else { 00264 if (channels != 1) { 00265 /* failed to set monaural recording by SNDCTL_DSP_CHANNELS */ 00266 jlog("Stat: adin_oss: failed to set monaural recording by sndctl_dsp_channels\n"); 00267 jlog("Stat: adin_oss: going to try another...\n"); 00268 } else { 00269 /* succeeded to set monaural recording by SNDCTL_DSP_CHANNELS */ 00270 //jlog("Stat: adin_oss: recording now set to mono\n"); 00271 stereo_rec = FALSE; 00272 ok_p = TRUE; 00273 } 00274 } 00275 } 00276 if (! ok_p) { 00277 /* try using stereo input */ 00278 jlog("Warning: adin_oss: failed to setup monaural recording, trying to use the left channel of stereo input\n"); 00279 stereo = 1; /* stereo */ 00280 if (ioctl(audio_fd, SNDCTL_DSP_STEREO, &stereo) == -1) { 00281 /* failed: SNDCTL_DSP_STEREO not supported */ 00282 jlog("Stat: adin_oss: failed to set stereo input using sndctl_dsp_stereo\n"); 00283 } else { 00284 if (stereo != 1) { 00285 /* failed to set stereo recording by SNDCTL_DSP_STEREO */ 00286 jlog("Stat: adin_oss: failed to set stereo input using sndctl_dsp_stereo\n"); 00287 } else { 00288 /* succeeded to set stereo recording by SNDCTL_DSP_STEREO */ 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) { /* not setup yet */ 00296 /* try using stereo input with sndctl_dsp_channels */ 00297 channels = 2; 00298 if (ioctl(audio_fd, SNDCTL_DSP_CHANNELS, &channels) == -1) { 00299 /* failed: SNDCTL_DSP_CHANNELS not supported */ 00300 jlog("Stat: adin_oss: failed to set stereo input using sndctl_dsp_channels\n"); 00301 } else { 00302 if (channels != 2) { 00303 /* failed to set stereo recording by SNDCTL_DSP_CHANNELS */ 00304 jlog("Stat: adin_oss: failed to set stereo input using sndctl_dsp_channels\n"); 00305 } else { 00306 /* succeeded to set stereo recording by SNDCTL_DSP_CHANNELS */ 00307 jlog("Stat: adin_oss: recording now set to stereo, using left channel\n"); 00308 stereo_rec = TRUE; 00309 ok_p = TRUE; 00310 } 00311 } 00312 } 00313 if (! ok_p) { /* all failed */ 00314 jlog("Error: adin_oss: failed to setup recording channels\n"); 00315 return FALSE; 00316 } 00317 } 00318 00319 samplerate = srate; 00320 if (ioctl(audio_fd, SNDCTL_DSP_SPEED, &samplerate) == -1) { 00321 jlog("Erorr: adin_oss: failed to set sample rate to %dHz\n", srate); 00322 return(FALSE); 00323 } 00324 if (samplerate < srate - FREQALLOWRANGE || samplerate > srate + FREQALLOWRANGE) { 00325 jlog("Error: adin_oss: failed to set sampling rate to near %dHz. (%d)\n", srate, samplerate); 00326 return FALSE; 00327 } 00328 if (samplerate != srate) { 00329 jlog("Warning: adin_oss: specified sampling rate was %dHz but set to %dHz, \n", srate, samplerate); 00330 } 00331 jlog("Stat: adin_oss: sampling rate = %dHz\n", samplerate); 00332 00333 /* get actual fragment size */ 00334 if (ioctl(audio_fd, SNDCTL_DSP_GETBLKSIZE, &frag_size) == -1) { 00335 jlog("Error: adin_oss: failed to get fragment size\n"); 00336 return(FALSE); 00337 } 00338 if (env == NULL) { 00339 jlog("Stat: adin_oss: going to set latency to %d msec\n", frag_msec); 00340 } else { 00341 jlog("Stat: adin_oss: going to set latency to %d msec (from env LATENCY_MSEC)\n", frag_msec); 00342 } 00343 jlog("Stat: adin_oss: audio I/O Latency = %d msec (fragment size = %d samples)\n", frag_size * 1000/ (srate * sizeof(SP16)), frag_size / sizeof(SP16)); 00344 00345 return TRUE; 00346 00347 #endif /* HAS_OSS */ 00348 } 00349 00357 boolean 00358 adin_oss_begin(char *pathname) 00359 { 00360 char buf[4]; 00361 char *p; 00362 00363 /* set device name */ 00364 if (pathname != NULL) { 00365 strncpy(devname, pathname, MAXPATHLEN); 00366 jlog("Stat: adin_oss: device name = %s (from argument)\n", devname); 00367 } else if ((p = getenv("AUDIODEV")) != NULL) { 00368 strncpy(devname, p, MAXPATHLEN); 00369 jlog("Stat: adin_oss: device name = %s (from AUDIODEV)\n", devname); 00370 } else { 00371 strncpy(devname, defaultdev, MAXPATHLEN); 00372 jlog("Stat: adin_oss: device name = %s (application default)\n", devname); 00373 } 00374 00375 /* open the device */ 00376 if (adin_oss_open(devname) == FALSE) return FALSE; 00377 00378 /* Read 1 sample (and ignore it) to tell the audio device start recording. 00379 (If you knows better way, teach me...) */ 00380 if (stereo_rec) { 00381 read(audio_fd, buf, 4); 00382 } else { 00383 read(audio_fd, buf, 2); 00384 } 00385 return(TRUE); 00386 } 00387 00393 boolean 00394 adin_oss_end() 00395 { 00396 if (close(audio_fd) != 0) return FALSE; 00397 return TRUE; 00398 } 00399 00417 int 00418 adin_oss_read(SP16 *buf, int sampnum) 00419 { 00420 #ifndef HAS_OSS 00421 return -2; 00422 #else 00423 int size,cnt,i; 00424 audio_buf_info info; 00425 fd_set rfds; 00426 struct timeval tv; 00427 int status; 00428 00429 /* check for incoming samples in device buffer */ 00430 /* if there is at least one sample fragment, go next */ 00431 /* if not exist, wait for the data to come for at most MAXPOLLINTERVAL msec */ 00432 /* if no sample fragment has come in the MAXPOLLINTERVAL period, go next */ 00433 FD_ZERO(&rfds); 00434 FD_SET(audio_fd, &rfds); 00435 tv.tv_sec = 0; 00436 tv.tv_usec = MAXPOLLINTERVAL * 1000; 00437 status = select(audio_fd+1, &rfds, NULL, NULL, &tv); 00438 if (status < 0) { 00439 /* select() failed */ 00440 jlog("Error: adin_oss: failed to poll device\n"); 00441 return(-2); /* error */ 00442 } 00443 if (FD_ISSET(audio_fd, &rfds)) { /* has some data */ 00444 /* get sample num that can be read without blocking */ 00445 if (ioctl(audio_fd, SNDCTL_DSP_GETISPACE, &info) == -1) { 00446 jlog("Error: adin_oss: failed to get number of samples in the buffer\n"); 00447 return(-2); 00448 } 00449 /* get them as much as possible */ 00450 size = sampnum * sizeof(SP16); 00451 if (size > info.bytes) size = info.bytes; 00452 if (size < frag_size) size = frag_size; 00453 size &= ~ 1; /* Force 16bit alignment */ 00454 cnt = read(audio_fd, buf, size); 00455 if ( cnt < 0 ) { 00456 jlog("Error: adin_oss: failed to read samples\n"); 00457 return ( -2 ); 00458 } 00459 cnt /= sizeof(short); 00460 00461 if (stereo_rec) { 00462 /* remove R channel */ 00463 for(i=1;i<cnt;i+=2) buf[(i-1)/2]=buf[i]; 00464 cnt/=2; 00465 } 00466 00467 if (need_swap) swap_sample_bytes(buf, cnt); 00468 } else { /* no data after waiting */ 00469 jlog("Warning: adin_oss: no data fragment after %d msec?\n", MAXPOLLINTERVAL); 00470 cnt = 0; 00471 } 00472 00473 return(cnt); 00474 #endif /* HAS_OSS */ 00475 } 00476 00484 char * 00485 adin_oss_input_name() 00486 { 00487 #ifndef HAS_OSS 00488 return NULL; 00489 #else 00490 return(devname); 00491 #endif 00492 }