00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
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
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
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
00184
00185
00186
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
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
00281
00282
00283
00284
00285
00286 handle->recording = 1;
00287
00288
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;
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 }