00001 
00057 
00058 
00059 
00060 
00061 
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 
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; 
00112   int samplerate;       
00113   char *defaultdev = DEFAULT_DEVICE; 
00114   char *devname;
00115   int frag;
00116   int frag_msec;
00117   char *env;
00118 
00119   
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   
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   
00134   
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;               
00144   fmt2 = AFMT_S16_BE;               
00145 #endif 
00146   
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   
00168   
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   
00175   
00176   
00177   {
00178     int arg;
00179     int f, f2;
00180 
00181     
00182 
00183     if ((env = getenv("LATENCY_MSEC")) == NULL) {
00184       frag_msec = MAX_FRAGMENT_MSEC;
00185     } else {
00186       frag_msec = atoi(env);
00187     }
00188       
00189     
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     
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   
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     
00219     int channels;
00220     int stereo;
00221     boolean ok_p = FALSE;
00222 
00223     stereo = 0;                 
00224     if (ioctl(audio_fd, SNDCTL_DSP_STEREO, &stereo) == -1) {
00225       
00226       jlog("Stat: adin_oss: sndctl_dsp_stereo not supported, going to try another...\n");
00227     } else {
00228       if (stereo != 0) {
00229         
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         
00234         
00235         stereo_rec = FALSE;
00236         ok_p = TRUE;
00237       }
00238     }
00239     if (! ok_p) {               
00240       
00241       channels = 1;
00242       if (ioctl(audio_fd, SNDCTL_DSP_CHANNELS, &channels) == -1) {
00243         
00244         jlog("Stat: adin_oss: sndctl_dsp_channels not supported, try another...\n");
00245       } else {
00246         if (channels != 1) {
00247           
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           
00252           
00253           stereo_rec = FALSE;
00254           ok_p = TRUE;
00255         }
00256       }
00257     }
00258     if (! ok_p) {
00259       
00260       jlog("Warning: adin_oss: failed to setup monaural recording, trying to use the left channel of stereo input\n");
00261       stereo = 1;                       
00262       if (ioctl(audio_fd, SNDCTL_DSP_STEREO, &stereo) == -1) {
00263         
00264         jlog("Stat: adin_oss: failed to set stereo input using sndctl_dsp_stereo\n");
00265       } else {
00266         if (stereo != 1) {
00267           
00268           jlog("Stat: adin_oss: failed to set stereo input using sndctl_dsp_stereo\n");
00269         } else {
00270           
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) {               
00278       
00279       channels = 2;
00280       if (ioctl(audio_fd, SNDCTL_DSP_CHANNELS, &channels) == -1) {
00281         
00282         jlog("Stat: adin_oss: failed to set stereo input using sndctl_dsp_channels\n");
00283       } else {
00284         if (channels != 2) {
00285           
00286           jlog("Stat: adin_oss: failed to set stereo input using sndctl_dsp_channels\n");
00287         } else {
00288           
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) {               
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   
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   
00340 
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 
00359 
00360 
00361 
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   
00393   
00394   
00395   
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     
00403     jlog("Error: adin_oss: failed to poll device\n");
00404     return(-2);                 
00405   }
00406   if (FD_ISSET(audio_fd, &rfds)) { 
00407     
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     
00413     size = sampnum * sizeof(SP16);
00414     if (size > info.bytes) size = info.bytes;
00415     if (size < frag_size) size = frag_size;
00416     size &= ~ 1;                
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       
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 {                      
00432     jlog("Warning: adin_oss: no data fragment after %d msec?\n", MAXPOLLINTERVAL);
00433     cnt = 0;
00434   }
00435 
00436   return(cnt);
00437 }