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 #include <fcntl.h>
00060 #include <stdio.h>
00061 #include <stdlib.h>
00062 #include <string.h>
00063 #include <sys/soundcard.h>
00064 #include <sys/ioctl.h>
00065 #include <errno.h>
00066 #include <unistd.h>
00067 #include <config.h>
00068
00069 #include "prim_type.h"
00070 #include "ad.h"
00071
00072 #define AUDIO_FORMAT AFMT_S16_LE
00073 #define INPUT_GAIN (80)
00074
00075 #define SPS_EPSILON 200
00076 #define SAMPLERATE_TOLERANCE 0.01
00077
00078 ad_rec_t *
00079 ad_open_dev(const char *dev, int32 sps)
00080 {
00081 ad_rec_t *handle;
00082 int32 dspFD, mixerFD;
00083 int32 nonBlocking = 1, sourceMic = SOUND_MASK_MIC, inputGain =
00084 INPUT_GAIN, devMask = 0;
00085 int32 audioFormat = AUDIO_FORMAT;
00086 int32 dspCaps = 0;
00087 int32 sampleRate;
00088 int32 numberChannels = 1;
00089
00090 sampleRate = sps;
00091
00092 if (dev == NULL)
00093 dev = DEFAULT_DEVICE;
00094
00095
00096 if ((dspFD = open(dev, O_RDONLY)) < 0) {
00097 if (errno == EBUSY)
00098 fprintf(stderr, "%s(%d): Audio device(%s) busy\n",
00099 __FILE__, __LINE__, dev);
00100 else
00101 fprintf(stderr,
00102 "%s(%d): Failed to open audio device(%s): %s\n",
00103 __FILE__, __LINE__, dev, strerror(errno));
00104 return NULL;
00105 }
00106
00107 if (ioctl(dspFD, SNDCTL_DSP_SYNC, 0) < 0) {
00108 fprintf(stderr, "Audio ioctl(SYNC) failed: %s\n", strerror(errno));
00109 close(dspFD);
00110 return NULL;
00111 }
00112
00113 if (ioctl(dspFD, SNDCTL_DSP_RESET, 0) < 0) {
00114 fprintf(stderr, "Audio ioctl(RESET) failed: %s\n",
00115 strerror(errno));
00116 close(dspFD);
00117 return NULL;
00118 }
00119
00120 if (ioctl(dspFD, SNDCTL_DSP_SETFMT, &audioFormat) < 0) {
00121 fprintf(stderr, "Audio ioctl(SETFMT 0x%x) failed: %s\n",
00122 audioFormat, strerror(errno));
00123 close(dspFD);
00124 return NULL;
00125 }
00126 if (audioFormat != AUDIO_FORMAT) {
00127 fprintf(stderr,
00128 "Audio ioctl(SETFMT): 0x%x, expected: 0x%x\n",
00129 audioFormat, AUDIO_FORMAT);
00130 close(dspFD);
00131 return NULL;
00132 }
00133
00134 if (ioctl(dspFD, SNDCTL_DSP_SPEED, &sampleRate) < 0) {
00135 fprintf(stderr, "Audio ioctl(SPEED %d) failed %s\n",
00136 sampleRate, strerror(errno));
00137 close(dspFD);
00138 return NULL;
00139 }
00140 if (sampleRate != sps) {
00141 if (abs(sampleRate - sps) <= (sampleRate * SAMPLERATE_TOLERANCE)) {
00142 fprintf(stderr,
00143 "Audio ioctl(SPEED) not perfect, but is acceptable. "
00144 "(Wanted %d, but got %d)\n", sampleRate, sps);
00145 }
00146 else {
00147 fprintf(stderr,
00148 "Audio ioctl(SPEED): %d, expected: %d\n",
00149 sampleRate, sps);
00150 close(dspFD);
00151 return NULL;
00152 }
00153 }
00154
00155 if (ioctl(dspFD, SNDCTL_DSP_CHANNELS, &numberChannels) < 0) {
00156 fprintf(stderr, "Audio ioctl(CHANNELS %d) failed %s\n",
00157 numberChannels, strerror(errno));
00158 close(dspFD);
00159 return NULL;
00160 }
00161
00162 if (ioctl(dspFD, SNDCTL_DSP_NONBLOCK, &nonBlocking) < 0) {
00163 fprintf(stderr, "ioctl(NONBLOCK) failed: %s\n", strerror(errno));
00164 close(dspFD);
00165 return NULL;
00166 }
00167
00168 if (ioctl(dspFD, SNDCTL_DSP_GETCAPS, &dspCaps) < 0) {
00169 fprintf(stderr, "ioctl(GETCAPS) failed: %s\n", strerror(errno));
00170 close(dspFD);
00171 return NULL;
00172 }
00173 #if 0
00174 printf("DSP Revision %d:\n", dspCaps & DSP_CAP_REVISION);
00175 printf("DSP %s duplex capability.\n",
00176 (dspCaps & DSP_CAP_DUPLEX) ? "has" : "does not have");
00177 printf("DSP %s real time capability.\n",
00178 (dspCaps & DSP_CAP_REALTIME) ? "has" : "does not have");
00179 printf("DSP %s batch capability.\n",
00180 (dspCaps & DSP_CAP_BATCH) ? "has" : "does not have");
00181 printf("DSP %s coprocessor capability.\n",
00182 (dspCaps & DSP_CAP_COPROC) ? "has" : "does not have");
00183 printf("DSP %s trigger capability.\n",
00184 (dspCaps & DSP_CAP_TRIGGER) ? "has" : "does not have");
00185 printf("DSP %s memory map capability.\n",
00186 (dspCaps & DSP_CAP_MMAP) ? "has" : "does not have");
00187 #endif
00188
00189 if ((dspCaps & DSP_CAP_DUPLEX)
00190 && (ioctl(dspFD, SNDCTL_DSP_SETDUPLEX, 0) < 0))
00191 fprintf(stderr, "ioctl(SETDUPLEX) failed: %s\n", strerror(errno));
00192
00193
00194
00195
00196
00197
00198
00199 if ((mixerFD = open("/dev/mixer", O_RDONLY)) < 0) {
00200 if (errno == EBUSY) {
00201 fprintf(stderr, "%s %d: mixer device busy.\n",
00202 __FILE__, __LINE__);
00203 fprintf(stderr, "%s %d: Using current setting.\n",
00204 __FILE__, __LINE__);
00205 }
00206 else {
00207 fprintf(stderr, "%s %d: %s\n", __FILE__, __LINE__,
00208 strerror(errno));
00209 exit(1);
00210 }
00211 }
00212
00213 if (mixerFD >= 0) {
00214 if (ioctl(mixerFD, SOUND_MIXER_WRITE_RECSRC, &sourceMic) < 0) {
00215 if (errno == ENXIO)
00216 fprintf(stderr,
00217 "%s %d: can't set mic source for this device.\n",
00218 __FILE__, __LINE__);
00219 else {
00220 fprintf(stderr,
00221 "%s %d: mixer set to mic: %s\n",
00222 __FILE__, __LINE__, strerror(errno));
00223 exit(1);
00224 }
00225 }
00226
00227
00228 inputGain = inputGain << 8 | inputGain;
00229
00230
00231
00232
00233 if (ioctl(mixerFD, SOUND_MIXER_READ_DEVMASK, &devMask) < 0) {
00234 fprintf(stderr,
00235 "%s %d: failed to read device mask: %s\n",
00236 __FILE__, __LINE__, strerror(errno));
00237 exit(1);
00238 }
00239 if (devMask & SOUND_MASK_IGAIN) {
00240 if (ioctl(mixerFD, SOUND_MIXER_WRITE_IGAIN, &inputGain) < 0) {
00241 fprintf(stderr,
00242 "%s %d: mixer input gain to %d: %s\n",
00243 __FILE__, __LINE__, inputGain, strerror(errno));
00244 exit(1);
00245 }
00246 }
00247 else if (devMask & SOUND_MASK_RECLEV) {
00248 if (ioctl(mixerFD, SOUND_MIXER_WRITE_RECLEV, &inputGain) < 0) {
00249 fprintf(stderr,
00250 "%s %d: mixer record level to %d: %s\n",
00251 __FILE__, __LINE__, inputGain, strerror(errno));
00252 exit(1);
00253 }
00254 }
00255 else {
00256 fprintf(stderr,
00257 "%s %d: can't set input gain/recording level for this device.\n",
00258 __FILE__, __LINE__);
00259 }
00260
00261 close(mixerFD);
00262 }
00263
00264 if ((handle = (ad_rec_t *) calloc(1, sizeof(ad_rec_t))) == NULL) {
00265 fprintf(stderr, "calloc(%ld) failed\n", sizeof(ad_rec_t));
00266 abort();
00267 }
00268
00269 handle->dspFD = dspFD;
00270 handle->recording = 0;
00271 handle->sps = sps;
00272 handle->bps = sizeof(int16);
00273
00274 return (handle);
00275 }
00276
00277 ad_rec_t *
00278 ad_open_sps(int32 sps)
00279 {
00280 return ad_open_dev(DEFAULT_DEVICE, sps);
00281 }
00282
00283 ad_rec_t *
00284 ad_open(void)
00285 {
00286 return ad_open_sps(DEFAULT_SAMPLES_PER_SEC);
00287 }
00288
00289 int32
00290 ad_close(ad_rec_t * handle)
00291 {
00292 if (handle->dspFD < 0)
00293 return AD_ERR_NOT_OPEN;
00294
00295 if (handle->recording) {
00296 if (ad_stop_rec(handle) < 0)
00297 return AD_ERR_GEN;
00298 }
00299
00300 close(handle->dspFD);
00301 free(handle);
00302
00303 return (0);
00304 }
00305
00306 int32
00307 ad_start_rec(ad_rec_t * handle)
00308 {
00309 if (handle->dspFD < 0)
00310 return AD_ERR_NOT_OPEN;
00311
00312 if (handle->recording)
00313 return AD_ERR_GEN;
00314
00315
00316
00317
00318
00319
00320
00321 handle->recording = 1;
00322
00323
00324
00325 return (0);
00326 }
00327
00328 int32
00329 ad_stop_rec(ad_rec_t * handle)
00330 {
00331 if (handle->dspFD < 0)
00332 return AD_ERR_NOT_OPEN;
00333
00334 if (!handle->recording)
00335 return AD_ERR_GEN;
00336
00337 if (ioctl(handle->dspFD, SNDCTL_DSP_SYNC, 0) < 0) {
00338 fprintf(stderr, "Audio ioctl(SYNC) failed: %s\n", strerror(errno));
00339 return AD_ERR_GEN;
00340 }
00341
00342 handle->recording = 0;
00343
00344 return (0);
00345 }
00346
00347 int32
00348 ad_read(ad_rec_t * handle, int16 * buf, int32 max)
00349 {
00350 int32 length;
00351
00352 length = max * handle->bps;
00353
00354 if ((length = read(handle->dspFD, buf, length)) > 0) {
00355 #if 0
00356 if ((length % handle->bps) != 0)
00357 fprintf(stderr,
00358 "Audio read returned non-integral #sample bytes (%d)\n",
00359 length);
00360 #endif
00361 length /= handle->bps;
00362 }
00363
00364 if (length < 0) {
00365 if (errno != EAGAIN) {
00366 fprintf(stderr, "Audio read error");
00367 return AD_ERR_GEN;
00368 }
00369 else {
00370 length = 0;
00371 }
00372 }
00373
00374 if ((length == 0) && (!handle->recording))
00375 return AD_EOF;
00376
00377 return length;
00378 }