00001
00057
00058
00059
00060
00061
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
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;
00122 int samplerate;
00123 char *defaultdev = DEFAULT_DEVICE;
00124 char *devname;
00125 int frag;
00126 int frag_msec;
00127 char *env;
00128
00129
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
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
00144
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;
00154 fmt2 = AFMT_S16_BE;
00155 #endif
00156
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
00178
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
00185
00186
00187 {
00188 int arg;
00189 int f, f2;
00190
00191
00192
00193 if ((env = getenv("LATENCY_MSEC")) == NULL) {
00194 frag_msec = MAX_FRAGMENT_MSEC;
00195 } else {
00196 frag_msec = atoi(env);
00197 }
00198
00199
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
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
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
00229 int channels;
00230 int stereo;
00231 boolean ok_p = FALSE;
00232
00233 stereo = 0;
00234 if (ioctl(audio_fd, SNDCTL_DSP_STEREO, &stereo) == -1) {
00235
00236 jlog("Stat: adin_oss: sndctl_dsp_stereo not supported, going to try another...\n");
00237 } else {
00238 if (stereo != 0) {
00239
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
00244
00245 stereo_rec = FALSE;
00246 ok_p = TRUE;
00247 }
00248 }
00249 if (! ok_p) {
00250
00251 channels = 1;
00252 if (ioctl(audio_fd, SNDCTL_DSP_CHANNELS, &channels) == -1) {
00253
00254 jlog("Stat: adin_oss: sndctl_dsp_channels not supported, try another...\n");
00255 } else {
00256 if (channels != 1) {
00257
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
00262
00263 stereo_rec = FALSE;
00264 ok_p = TRUE;
00265 }
00266 }
00267 }
00268 if (! ok_p) {
00269
00270 jlog("Warning: adin_oss: failed to setup monaural recording, trying to use the left channel of stereo input\n");
00271 stereo = 1;
00272 if (ioctl(audio_fd, SNDCTL_DSP_STEREO, &stereo) == -1) {
00273
00274 jlog("Stat: adin_oss: failed to set stereo input using sndctl_dsp_stereo\n");
00275 } else {
00276 if (stereo != 1) {
00277
00278 jlog("Stat: adin_oss: failed to set stereo input using sndctl_dsp_stereo\n");
00279 } else {
00280
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) {
00288
00289 channels = 2;
00290 if (ioctl(audio_fd, SNDCTL_DSP_CHANNELS, &channels) == -1) {
00291
00292 jlog("Stat: adin_oss: failed to set stereo input using sndctl_dsp_channels\n");
00293 } else {
00294 if (channels != 2) {
00295
00296 jlog("Stat: adin_oss: failed to set stereo input using sndctl_dsp_channels\n");
00297 } else {
00298
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) {
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
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
00340 }
00341
00347 boolean
00348 adin_oss_begin()
00349 {
00350 char buf[4];
00351
00352
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
00371
00372
00373
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
00408
00409
00410
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
00418 jlog("Error: adin_oss: failed to poll device\n");
00419 return(-2);
00420 }
00421 if (FD_ISSET(audio_fd, &rfds)) {
00422
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
00428 size = sampnum * sizeof(SP16);
00429 if (size > info.bytes) size = info.bytes;
00430 if (size < frag_size) size = frag_size;
00431 size &= ~ 1;
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
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 {
00447 jlog("Warning: adin_oss: no data fragment after %d msec?\n", MAXPOLLINTERVAL);
00448 cnt = 0;
00449 }
00450
00451 return(cnt);
00452 #endif
00453 }
00454