• Main Page
  • Related Pages
  • Data Structures
  • Files
  • File List
  • Globals

src/libsphinxad/ad_oss_bsd.c

00001 /* -*- c-basic-offset: 4; indent-tabs-mode: nil -*- */
00002 /* ====================================================================
00003  * Copyright (c) 1999-2001 Carnegie Mellon University.  All rights
00004  * reserved.
00005  *
00006  * Redistribution and use in source and binary forms, with or without
00007  * modification, are permitted provided that the following conditions
00008  * are met:
00009  *
00010  * 1. Redistributions of source code must retain the above copyright
00011  *    notice, this list of conditions and the following disclaimer. 
00012  *
00013  * 2. Redistributions in binary form must reproduce the above copyright
00014  *    notice, this list of conditions and the following disclaimer in
00015  *    the documentation and/or other materials provided with the
00016  *    distribution.
00017  *
00018  * This work was supported in part by funding from the Defense Advanced 
00019  * Research Projects Agency and the National Science Foundation of the 
00020  * United States of America, and the CMU Sphinx Speech Consortium.
00021  *
00022  * THIS SOFTWARE IS PROVIDED BY CARNEGIE MELLON UNIVERSITY ``AS IS'' AND 
00023  * ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 
00024  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
00025  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY
00026  * NOR ITS EMPLOYEES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
00027  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
00028  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
00029  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
00030  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
00031  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
00032  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00033  *
00034  * ====================================================================
00035  *
00036  */
00037 
00038 /* Sphinx II libad (FreeBSD)
00039  * ^^^^^^^^^^^^^^^^^^^^^^^
00040  * $Id: ad_oss_bsd.c 5509 2006-03-28 02:25:10Z dhdfu $
00041  *
00042  * John G. Dorsey (jd5q+@andrew.cmu.edu)
00043  * Engineering Design Research Center
00044  * Carnegie Mellon University
00045  * ********************************************************************
00046  * 
00047  * REVISION HISTORY
00048  *
00049  * 28-Jan-2000  Alan W Black (awb@cs.cmu.edu. added FreeBSD support (by
00050                 simply cloning the linux support).
00051  * 09-Aug-1999  Kevin Lenzo (lenzo@cs.cmu.edu) at Cernegie Mellon University.
00052  *              Incorporated nickr@cs.cmu.edu's changes (marked below) and
00053  *              SPS_EPSILON to allow for sample rates that are "close enough".
00054  * 
00055  * 15-Jun-1999  M. K. Ravishankar (rkm@cs.cmu.edu) Consolidated all ad functions into
00056  *              this one file.  Added ad_open_sps().
00057  *              Other cosmetic changes for consistency (e.g., use of err.h).
00058  * 
00059  * 18-May-1999  Kevin Lenzo (lenzo@cs.cmu.edu) added <errno.h>.
00060  */
00061 
00062 
00063 #include <fcntl.h>
00064 #include <stdio.h>
00065 #include <stdlib.h>
00066 #include <string.h>
00067 #include <sys/soundcard.h>
00068 #include <sys/ioctl.h>
00069 #include <errno.h>
00070 #include <unistd.h>
00071 #include <config.h>
00072 
00073 #include "prim_type.h"
00074 #include "ad.h"
00075 
00076 #define AUDIO_FORMAT AFMT_S16_LE        /* 16-bit signed, little endian */
00077 #define INPUT_GAIN   (80)
00078 
00079 #define SPS_EPSILON   200
00080 
00081 #ifndef SNDCTL_DSP_SETDUPLEX
00082 #define SNDCTL_DSP_SETDUPLEX -1
00083 #endif
00084 
00085 ad_rec_t *
00086 ad_open_dev(const char *dev, int32 sps)
00087 {
00088     ad_rec_t *handle;
00089     int32 dspFD, mixerFD;
00090     int32 nonBlocking = 1, sourceMic = 1, inputGain = INPUT_GAIN;
00091     int32 audioFormat = AUDIO_FORMAT;
00092     int32 dspCaps = 0;
00093     int32 sampleRate;
00094 
00095     sampleRate = sps;
00096 
00097     if (dev == NULL)
00098         dev = DEFAULT_DEVICE;
00099 
00100     /* Used to have O_NDELAY. */
00101     if ((dspFD = open(dev, O_RDONLY)) < 0) {
00102         if (errno == EBUSY)
00103             fprintf(stderr, "%s(%d): Audio device(%s) busy\n",
00104                     __FILE__, __LINE__, dev);
00105         else
00106             fprintf(stderr,
00107                     "%s(%d): Failed to open audio device(%s): %s\n",
00108                     __FILE__, __LINE__, dev, strerror(errno));
00109         return NULL;
00110     }
00111 
00112     if (ioctl(dspFD, SNDCTL_DSP_SYNC, 0) < 0) {
00113         fprintf(stderr, "Audio ioctl(SYNC) failed: %s\n", strerror(errno));
00114         close(dspFD);
00115         return NULL;
00116     }
00117 
00118     if (ioctl(dspFD, SNDCTL_DSP_RESET, 0) < 0) {
00119         fprintf(stderr, "Audio ioctl(RESET) failed: %s\n",
00120                 strerror(errno));
00121         close(dspFD);
00122         return NULL;
00123     }
00124 
00125     if (ioctl(dspFD, SNDCTL_DSP_SETFMT, &audioFormat) < 0) {
00126         fprintf(stderr, "Audio ioctl(SETFMT 0x%x) failed: %s\n",
00127                 audioFormat, strerror(errno));
00128         close(dspFD);
00129         return NULL;
00130     }
00131     if (audioFormat != AUDIO_FORMAT) {
00132         fprintf(stderr,
00133                 "Audio ioctl(SETFMT): 0x%x, expected: 0x%x\n",
00134                 audioFormat, AUDIO_FORMAT);
00135         close(dspFD);
00136         return NULL;
00137     }
00138 
00139     if (ioctl(dspFD, SNDCTL_DSP_SPEED, &sampleRate) < 0) {
00140         fprintf(stderr, "Audio ioctl(SPEED %d) failed %s\n",
00141                 sampleRate, strerror(errno));
00142         close(dspFD);
00143         return NULL;
00144     }
00145     if (sampleRate != sps) {
00146         fprintf(stderr, "Audio ioctl(SPEED): %d, expected: %d\n",
00147                 sampleRate, sps);
00148         close(dspFD);
00149         return NULL;
00150     }
00151 
00152     if (ioctl(dspFD, SNDCTL_DSP_NONBLOCK, &nonBlocking) < 0) {
00153         fprintf(stderr, "ioctl(NONBLOCK) failed: %s\n", strerror(errno));
00154         close(dspFD);
00155         return NULL;
00156     }
00157 
00158     if (ioctl(dspFD, SNDCTL_DSP_GETCAPS, &dspCaps) < 0) {
00159         fprintf(stderr, "ioctl(GETCAPS) failed: %s\n", strerror(errno));
00160         close(dspFD);
00161         return NULL;
00162     }
00163 #if 0
00164     printf("DSP Revision %d:\n", dspCaps & DSP_CAP_REVISION);
00165     printf("DSP %s duplex capability.\n",
00166            (dspCaps & DSP_CAP_DUPLEX) ? "has" : "does not have");
00167     printf("DSP %s real time capability.\n",
00168            (dspCaps & DSP_CAP_REALTIME) ? "has" : "does not have");
00169     printf("DSP %s batch capability.\n",
00170            (dspCaps & DSP_CAP_BATCH) ? "has" : "does not have");
00171     printf("DSP %s coprocessor capability.\n",
00172            (dspCaps & DSP_CAP_COPROC) ? "has" : "does not have");
00173     printf("DSP %s trigger capability.\n",
00174            (dspCaps & DSP_CAP_TRIGGER) ? "has" : "does not have");
00175     printf("DSP %s memory map capability.\n",
00176            (dspCaps & DSP_CAP_MMAP) ? "has" : "does not have");
00177 #endif
00178 
00179     if ((dspCaps & DSP_CAP_DUPLEX)
00180         && (ioctl(dspFD, SNDCTL_DSP_SETDUPLEX, 0) < 0))
00181         fprintf(stderr, "ioctl(SETDUPLEX) failed: %s\n", strerror(errno));
00182 
00183     /* Patched by N. Roy (nickr@ri.cmu.edu), 99/7/23. 
00184        Previously, mixer was set through dspFD. This is incorrect. Should
00185        be set through mixerFD, /dev/mixer. 
00186        Also, only the left channel volume was being set.
00187      */
00188 
00189     if ((mixerFD = open("/dev/mixer", O_RDONLY)) < 0) {
00190         if (errno == EBUSY) {
00191             fprintf(stderr, "%s %d: mixer device busy.\n",
00192                     __FILE__, __LINE__);
00193             fprintf(stderr, "%s %d: Using current setting.\n",
00194                     __FILE__, __LINE__);
00195         }
00196         else {
00197             fprintf(stderr, "%s %d: %s\n", __FILE__, __LINE__,
00198                     strerror(errno));
00199             exit(1);
00200         }
00201     }
00202 
00203     if (mixerFD >= 0) {
00204         if (ioctl(mixerFD, SOUND_MIXER_WRITE_RECSRC, &sourceMic) < 0) {
00205             if (errno == ENXIO)
00206                 fprintf(stderr,
00207                         "%s %d: can't set mic source for this device.\n",
00208                         __FILE__, __LINE__);
00209             else {
00210                 fprintf(stderr,
00211                         "%s %d: mixer set to mic: %s\n",
00212                         __FILE__, __LINE__, strerror(errno));
00213                 exit(1);
00214             }
00215         }
00216 
00217         /* Set the same gain for left and right channels. */
00218         inputGain = inputGain << 8 | inputGain;
00219         if (ioctl(mixerFD, SOUND_MIXER_WRITE_MIC, &inputGain) < 0) {
00220             fprintf(stderr,
00221                     "%s %d: mixer input gain to %d: %s\n",
00222                     __FILE__, __LINE__, strerror(errno));
00223             exit(1);
00224         }
00225 
00226         close(mixerFD);
00227     }
00228 
00229     if ((handle = (ad_rec_t *) calloc(1, sizeof(ad_rec_t))) == NULL) {
00230         fprintf(stderr, "calloc(%ld) failed\n", sizeof(ad_rec_t));
00231         abort();
00232     }
00233 
00234     handle->dspFD = dspFD;
00235     handle->recording = 0;
00236     handle->sps = sps;
00237     handle->bps = sizeof(int16);
00238 
00239     return (handle);
00240 }
00241 
00242 ad_rec_t *
00243 ad_open_sps(int32 sps)
00244 {
00245     return ad_open_dev(DEFAULT_DEVICE, sps);
00246 }
00247 
00248 ad_rec_t *
00249 ad_open(void)
00250 {
00251     return ad_open_sps(DEFAULT_SAMPLES_PER_SEC);
00252 }
00253 
00254 int32
00255 ad_close(ad_rec_t * handle)
00256 {
00257     if (handle->dspFD < 0)
00258         return AD_ERR_NOT_OPEN;
00259 
00260     if (handle->recording) {
00261         if (ad_stop_rec(handle) < 0)
00262             return AD_ERR_GEN;
00263     }
00264 
00265     close(handle->dspFD);
00266     free(handle);
00267 
00268     return (0);
00269 }
00270 
00271 int32
00272 ad_start_rec(ad_rec_t * handle)
00273 {
00274     if (handle->dspFD < 0)
00275         return AD_ERR_NOT_OPEN;
00276 
00277     if (handle->recording)
00278         return AD_ERR_GEN;
00279 
00280     /* Sample rate, format, input mix settings, &c. are configured
00281      * with ioctl(2) calls under Linux. It makes more sense to handle
00282      * these at device open time and consider the state of the device
00283      * to be fixed until closed.
00284      */
00285 
00286     handle->recording = 1;
00287 
00288     /* rkm@cs: This doesn't actually do anything.  How do we turn recording on/off? */
00289 
00290     return (0);
00291 }
00292 
00293 int32
00294 ad_stop_rec(ad_rec_t * handle)
00295 {
00296     if (handle->dspFD < 0)
00297         return AD_ERR_NOT_OPEN;
00298 
00299     if (!handle->recording)
00300         return AD_ERR_GEN;
00301 
00302     if (ioctl(handle->dspFD, SNDCTL_DSP_SYNC, 0) < 0) {
00303         fprintf(stderr, "Audio ioctl(SYNC) failed: %s\n", strerror(errno));
00304         return AD_ERR_GEN;
00305     }
00306 
00307     handle->recording = 0;
00308 
00309     return (0);
00310 }
00311 
00312 int32
00313 ad_read(ad_rec_t * handle, int16 * buf, int32 max)
00314 {
00315     int32 length;
00316 
00317     length = max * handle->bps; /* #samples -> #bytes */
00318 
00319     if ((length = read(handle->dspFD, buf, length)) > 0) {
00320 #if 0
00321         if ((length % handle->bps) != 0)
00322             fprintf(stderr,
00323                     "Audio read returned non-integral #sample bytes (%d)\n",
00324                     length);
00325 #endif
00326         length /= handle->bps;
00327     }
00328 
00329     if (length < 0) {
00330         if (errno != EAGAIN) {
00331             fprintf(stderr, "Audio read error");
00332             return AD_ERR_GEN;
00333         }
00334         else {
00335             length = 0;
00336         }
00337     }
00338 
00339     if ((length == 0) && (!handle->recording))
00340         return AD_EOF;
00341 
00342     return length;
00343 }

Generated on Thu Jan 6 2011 for SphinxBase by  doxygen 1.7.1