Annotation of embedaddon/ntp/libntp/audio.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * audio.c - audio interface for reference clock audio drivers
                      3:  */
                      4: #ifdef HAVE_CONFIG_H
                      5: # include <config.h>
                      6: #endif
                      7: 
                      8: #if defined(HAVE_SYS_AUDIOIO_H) || defined(HAVE_SUN_AUDIOIO_H) || \
                      9:     defined(HAVE_SYS_SOUNDCARD_H) || defined(HAVE_MACHINE_SOUNDCARD_H)
                     10: 
                     11: #include "audio.h"
                     12: #include "ntp_stdlib.h"
                     13: #include "ntp_syslog.h"
                     14: #ifdef HAVE_UNISTD_H
                     15: # include <unistd.h>
                     16: #endif
                     17: #include <stdio.h>
                     18: #include "ntp_string.h"
                     19: 
                     20: #ifdef HAVE_SYS_AUDIOIO_H
                     21: # include <sys/audioio.h>
                     22: #endif /* HAVE_SYS_AUDIOIO_H */
                     23: 
                     24: #ifdef HAVE_SUN_AUDIOIO_H
                     25: # include <sys/ioccom.h>
                     26: # include <sun/audioio.h>
                     27: #endif /* HAVE_SUN_AUDIOIO_H */
                     28: 
                     29: #ifdef HAVE_SYS_IOCTL_H
                     30: # include <sys/ioctl.h>
                     31: #endif /* HAVE_SYS_IOCTL_H */
                     32: 
                     33: #include <fcntl.h>
                     34: 
                     35: #ifdef HAVE_MACHINE_SOUNDCARD_H
                     36: # include <machine/soundcard.h>
                     37: # define PCM_STYLE_SOUND
                     38: #else
                     39: # ifdef HAVE_SYS_SOUNDCARD_H
                     40: #  include <sys/soundcard.h>
                     41: #  define PCM_STYLE_SOUND
                     42: # endif
                     43: #endif
                     44: 
                     45: #ifdef PCM_STYLE_SOUND
                     46: # include <ctype.h>
                     47: #endif
                     48: 
                     49: /*
                     50:  * Global variables
                     51:  */
                     52: #ifdef HAVE_SYS_AUDIOIO_H
                     53: static struct audio_device device; /* audio device ident */
                     54: #endif /* HAVE_SYS_AUDIOIO_H */
                     55: #ifdef PCM_STYLE_SOUND
                     56: # define INIT_FILE "/etc/ntp.audio"
                     57: int agc =      SOUND_MIXER_WRITE_RECLEV; /* or IGAIN or LINE */
                     58: int monitor =  SOUND_MIXER_WRITE_VOLUME; /* or OGAIN */
                     59: int devmask = 0;
                     60: int recmask = 0;
                     61: char cf_c_dev[100], cf_i_dev[100], cf_agc[100], cf_monitor[100];
                     62: 
                     63: const char *m_names[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_NAMES;
                     64: #else /* not PCM_STYLE_SOUND */
                     65: static struct audio_info info; /* audio device info */
                     66: #endif /* not PCM_STYLE_SOUND */
                     67: static int ctl_fd;             /* audio control file descriptor */
                     68: 
                     69: #ifdef PCM_STYLE_SOUND
                     70: static void audio_config_read (int, char **, char **);
                     71: static int  mixer_name (const char *, int);
                     72: 
                     73: 
                     74: int
                     75: mixer_name(
                     76:        const char *m_name,
                     77:        int m_mask
                     78:        )
                     79: {
                     80:        int i;
                     81: 
                     82:        for (i = 0; i < SOUND_MIXER_NRDEVICES; ++i)
                     83:                if (((1 << i) & m_mask)
                     84:                    && !strcmp(m_names[i], m_name))
                     85:                        break;
                     86: 
                     87:        return (SOUND_MIXER_NRDEVICES == i)
                     88:            ? -1
                     89:            : i
                     90:            ;
                     91: }
                     92: 
                     93: 
                     94: /*
                     95:  * Check:
                     96:  *
                     97:  * /etc/ntp.audio#     where # is the unit number
                     98:  * /etc/ntp.audio.#    where # is the unit number
                     99:  * /etc/ntp.audio
                    100:  *
                    101:  * for contents of the form:
                    102:  *
                    103:  * idev /dev/input_device
                    104:  * cdev /dev/control_device
                    105:  * agc pcm_input_device {igain,line,line1,...}
                    106:  * monitor pcm_monitor_device {ogain,...}
                    107:  *
                    108:  * The device names for the "agc" and "monitor" keywords
                    109:  * can be found by running either the "mixer" program or the
                    110:  * util/audio-pcm program.
                    111:  *
                    112:  * Great hunks of this subroutine were swiped from refclock_oncore.c
                    113:  */
                    114: static void
                    115: audio_config_read(
                    116:        int unit,
                    117:        char **c_dev,   /* Control device */
                    118:        char **i_dev    /* input device */
                    119:        )
                    120: {
                    121:        FILE *fd;
                    122:        char device[20], line[100], ab[100];
                    123: 
                    124:        snprintf(device, sizeof(device), "%s%d", INIT_FILE, unit);
                    125:        if ((fd = fopen(device, "r")) == NULL) {
                    126:                printf("audio_config_read: <%s> NO\n", device);
                    127:                snprintf(device, sizeof(device), "%s.%d", INIT_FILE,
                    128:                         unit);
                    129:                if ((fd = fopen(device, "r")) == NULL) {
                    130:                        printf("audio_config_read: <%s> NO\n", device);
                    131:                        snprintf(device, sizeof(device), "%s",
                    132:                                 INIT_FILE);
                    133:                        if ((fd = fopen(device, "r")) == NULL) {
                    134:                                printf("audio_config_read: <%s> NO\n",
                    135:                                       device);
                    136:                                return;
                    137:                        }
                    138:                }
                    139:        }
                    140:        printf("audio_config_read: reading <%s>\n", device);
                    141:        while (fgets(line, sizeof line, fd)) {
                    142:                char *cp, *cc, *ca;
                    143:                int i;
                    144: 
                    145:                /* Remove comments */
                    146:                if ((cp = strchr(line, '#')))
                    147:                        *cp = '\0';
                    148: 
                    149:                /* Remove any trailing spaces */
                    150:                for (i = strlen(line);
                    151:                     i > 0 && isascii((int)line[i - 1]) && isspace((int)line[i - 1]);
                    152:                        )
                    153:                        line[--i] = '\0';
                    154: 
                    155:                /* Remove leading space */
                    156:                for (cc = line; *cc && isascii((int)*cc) && isspace((int)*cc); cc++)
                    157:                        continue;
                    158: 
                    159:                /* Stop if nothing left */
                    160:                if (!*cc)
                    161:                        continue;
                    162: 
                    163:                /* Uppercase the command and find the arg */
                    164:                for (ca = cc; *ca; ca++) {
                    165:                        if (isascii((int)*ca)) {
                    166:                                if (islower((int)*ca)) {
                    167:                                        *ca = toupper(*ca);
                    168:                                } else if (isspace((int)*ca) || (*ca == '='))
                    169:                                        break;
                    170:                        }
                    171:                }
                    172: 
                    173:                /* Remove space (and possible =) leading the arg */
                    174:                for (; *ca && isascii((int)*ca) && (isspace((int)*ca) || (*ca == '=')); ca++)
                    175:                        continue;
                    176: 
                    177:                if (!strncmp(cc, "IDEV", 4) &&
                    178:                    1 == sscanf(ca, "%99s", ab)) {
                    179:                        strncpy(cf_i_dev, ab, sizeof(cf_i_dev));
                    180:                        printf("idev <%s>\n", ab);
                    181:                } else if (!strncmp(cc, "CDEV", 4) &&
                    182:                           1 == sscanf(ca, "%99s", ab)) {
                    183:                        strncpy(cf_c_dev, ab, sizeof(cf_c_dev));
                    184:                        printf("cdev <%s>\n", ab);
                    185:                } else if (!strncmp(cc, "AGC", 3) &&
                    186:                           1 == sscanf(ca, "%99s", ab)) {
                    187:                        strncpy(cf_agc, ab, sizeof(cf_agc));
                    188:                        printf("agc <%s> %d\n", ab, i);
                    189:                } else if (!strncmp(cc, "MONITOR", 7) &&
                    190:                           1 == sscanf(ca, "%99s", ab)) {
                    191:                        strncpy(cf_monitor, ab, sizeof(cf_monitor));
                    192:                        printf("monitor <%s> %d\n", ab, mixer_name(ab, -1));
                    193:                }
                    194:        }
                    195:        fclose(fd);
                    196:        return;
                    197: }
                    198: #endif /* PCM_STYLE_SOUND */
                    199: 
                    200: /*
                    201:  * audio_init - open and initialize audio device
                    202:  *
                    203:  * This code works with SunOS 4.x, Solaris 2.x, and PCM; however, it is
                    204:  * believed generic and applicable to other systems with a minor twid
                    205:  * or two. All it does is open the device, set the buffer size (Solaris
                    206:  * only), preset the gain and set the input port. It assumes that the
                    207:  * codec sample rate (8000 Hz), precision (8 bits), number of channels
                    208:  * (1) and encoding (ITU-T G.711 mu-law companded) have been set by
                    209:  * default.
                    210:  */
                    211: int
                    212: audio_init(
                    213:        char    *dname,         /* device name */
                    214:        int     bufsiz,         /* buffer size */
                    215:        int     unit            /* device unit (0-3) */
                    216:        )
                    217: {
                    218: #ifdef PCM_STYLE_SOUND
                    219: # define ACTL_DEV      "/dev/mixer%d"
                    220:        char actl_dev[30];
                    221: # ifdef HAVE_STRUCT_SND_SIZE
                    222:        struct snd_size s_size;
                    223: # endif
                    224: # ifdef AIOGFMT
                    225:        snd_chan_param s_c_p;
                    226: # endif
                    227: #endif
                    228:        int fd;
                    229:        int rval;
                    230:        char *actl =
                    231: #ifdef PCM_STYLE_SOUND
                    232:                actl_dev
                    233: #else
                    234:                "/dev/audioctl"
                    235: #endif
                    236:                ;
                    237: 
                    238: #ifdef PCM_STYLE_SOUND
                    239:        snprintf(actl_dev, sizeof(actl_dev), ACTL_DEV, unit);
                    240: 
                    241:        audio_config_read(unit, &actl, &dname);
                    242:        /* If we have values for cf_c_dev or cf_i_dev, use them. */
                    243:        if (*cf_c_dev)
                    244:                actl = cf_c_dev;
                    245:        if (*cf_i_dev)
                    246:                dname = cf_i_dev;
                    247: #endif
                    248: 
                    249:        /*
                    250:         * Open audio device
                    251:         */
                    252:        fd = open(dname, O_RDWR | O_NONBLOCK, 0777);
                    253:        if (fd < 0) {
                    254:                msyslog(LOG_ERR, "audio_init: %s %m\n", dname);
                    255:                return (fd);
                    256:        }
                    257: 
                    258:        /*
                    259:         * Open audio control device.
                    260:         */
                    261:        ctl_fd = open(actl, O_RDWR);
                    262:        if (ctl_fd < 0) {
                    263:                msyslog(LOG_ERR, "audio_init: invalid control device <%s>\n",
                    264:                    actl);
                    265:                close(fd);
                    266:                return(ctl_fd);
                    267:        }
                    268: 
                    269:        /*
                    270:         * Set audio device parameters.
                    271:         */
                    272: #ifdef PCM_STYLE_SOUND
                    273:        printf("audio_init: <%s> bufsiz %d\n", dname, bufsiz);
                    274:        rval = fd;
                    275: 
                    276: # ifdef HAVE_STRUCT_SND_SIZE
                    277:        if (ioctl(fd, AIOGSIZE, &s_size) == -1)
                    278:            printf("audio_init: AIOGSIZE: %s\n", strerror(errno));
                    279:        else
                    280:            printf("audio_init: orig: play_size %d, rec_size %d\n",
                    281:                s_size.play_size, s_size.rec_size);
                    282: 
                    283:        s_size.play_size = s_size.rec_size = bufsiz;
                    284:        printf("audio_init: want: play_size %d, rec_size %d\n",
                    285:               s_size.play_size, s_size.rec_size);
                    286: 
                    287:        if (ioctl(fd, AIOSSIZE, &s_size) == -1)
                    288:            printf("audio_init: AIOSSIZE: %s\n", strerror(errno));
                    289:        else
                    290:            printf("audio_init: set:  play_size %d, rec_size %d\n",
                    291:                s_size.play_size, s_size.rec_size);
                    292: # endif /* HAVE_STRUCT_SND_SIZE */
                    293: 
                    294: # ifdef SNDCTL_DSP_SETFRAGMENT
                    295:        {
                    296:                int tmp = (16 << 16) + 6; /* 16 fragments, each 2^6 bytes */
                    297:                if (ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &tmp) == -1)
                    298:                    printf("audio_init: SNDCTL_DSP_SETFRAGMENT: %s\n",
                    299:                           strerror(errno));
                    300:        }
                    301: # endif /* SNDCTL_DSP_SETFRAGMENT */
                    302: 
                    303: # ifdef AIOGFMT
                    304:        if (ioctl(fd, AIOGFMT, &s_c_p) == -1)
                    305:            printf("audio_init: AIOGFMT: %s\n", strerror(errno));
                    306:        else
                    307:            printf("audio_init: play_rate %lu, rec_rate %lu, play_format %#lx, rec_format %#lx\n",
                    308:                s_c_p.play_rate, s_c_p.rec_rate, s_c_p.play_format, s_c_p.rec_format);
                    309: # endif
                    310: 
                    311:        /* Grab the device and record masks */
                    312: 
                    313:        if (ioctl(ctl_fd, SOUND_MIXER_READ_DEVMASK, &devmask) == -1)
                    314:            printf("SOUND_MIXER_READ_DEVMASK: %s\n", strerror(errno));
                    315:        if (ioctl(ctl_fd, SOUND_MIXER_READ_RECMASK, &recmask) == -1)
                    316:            printf("SOUND_MIXER_READ_RECMASK: %s\n", strerror(errno));
                    317: 
                    318:        /* validate and set any specified config file stuff */
                    319:        if (cf_agc[0] != '\0') {
                    320:                int i;
                    321: 
                    322:                i = mixer_name(cf_agc, devmask);
                    323:                if (i >= 0)
                    324:                        agc = MIXER_WRITE(i);
                    325:                else
                    326:                        printf("input %s not in recmask %#x\n",
                    327:                               cf_agc, recmask);
                    328:        }
                    329: 
                    330:        if (cf_monitor[0] != '\0') {
                    331:                int i;
                    332: 
                    333:                /* devmask */
                    334:                i = mixer_name(cf_monitor, devmask);
                    335:                if (i >= 0)
                    336:                        monitor = MIXER_WRITE(i);
                    337:                else
                    338:                        printf("monitor %s not in devmask %#x\n",
                    339:                               cf_monitor, devmask);
                    340:        }
                    341: 
                    342: #else /* not PCM_STYLE_SOUND */
                    343:        AUDIO_INITINFO(&info);
                    344:        info.play.gain = AUDIO_MAX_GAIN;
                    345:        info.play.port = AUDIO_SPEAKER;
                    346: # ifdef HAVE_SYS_AUDIOIO_H
                    347:        info.record.buffer_size = bufsiz;
                    348: # endif /* HAVE_SYS_AUDIOIO_H */
                    349:        rval = ioctl(ctl_fd, (int)AUDIO_SETINFO, (char *)&info);
                    350:        if (rval < 0) {
                    351:                msyslog(LOG_ERR, "audio: invalid control device parameters\n");
                    352:                close(ctl_fd);
                    353:                close(fd);
                    354:                return(rval);
                    355:        }
                    356:        rval = fd;
                    357: #endif /* not PCM_STYLE_SOUND */
                    358:        return (rval);
                    359: }
                    360: 
                    361: 
                    362: /*
                    363:  * audio_gain - adjust codec gains and port
                    364:  */
                    365: int
                    366: audio_gain(
                    367:        int gain,               /* volume level (gain) 0-255 */
                    368:        int mongain,            /* input to output mix (monitor gain) 0-255 */
                    369:        int port                /* selected I/O port: 1 mic/2 line in */
                    370:        )
                    371: {
                    372:        int rval;
                    373:        static int o_mongain = -1;
                    374:        static int o_port = -1;
                    375: 
                    376: #ifdef PCM_STYLE_SOUND
                    377:        int l, r;
                    378: 
                    379:        rval = 0;
                    380: 
                    381:        r = l = 100 * gain / 255;       /* Normalize to 0-100 */
                    382: # ifdef DEBUG
                    383:        if (debug > 1)
                    384:                printf("audio_gain: gain %d/%d\n", gain, l);
                    385: # endif
                    386: #if 0  /* not a good idea to do this; connector wiring dependency */
                    387:        /* figure out what channel(s) to use. just nuke right for now. */
                    388:        r = 0 ; /* setting to zero nicely mutes the channel */
                    389: #endif
                    390:        l |= r << 8;
                    391:        if (cf_agc[0] != '\0')
                    392:                rval = ioctl(ctl_fd, agc, &l);
                    393:        else
                    394:                if (2 == port)
                    395:                        rval = ioctl(ctl_fd, SOUND_MIXER_WRITE_LINE, &l);
                    396:                else
                    397:                        rval = ioctl(ctl_fd, SOUND_MIXER_WRITE_MIC, &l);
                    398:        if (-1 == rval) {
                    399:                printf("audio_gain: agc write: %s\n", strerror(errno));
                    400:                return rval;
                    401:        }
                    402: 
                    403:        if (o_mongain != mongain) {
                    404:                r = l = 100 * mongain / 255;    /* Normalize to 0-100 */
                    405: # ifdef DEBUG
                    406:                if (debug > 1)
                    407:                        printf("audio_gain: mongain %d/%d\n", mongain, l);
                    408: # endif
                    409:                l |= r << 8;
                    410:                if (cf_monitor[0] != '\0')
                    411:                        rval = ioctl(ctl_fd, monitor, &l );
                    412:                else 
                    413:                        rval = ioctl(ctl_fd, SOUND_MIXER_WRITE_VOLUME,
                    414:                                     &l);
                    415:                if (-1 == rval) {
                    416:                        printf("audio_gain: mongain write: %s\n",
                    417:                               strerror(errno));
                    418:                        return (rval);
                    419:                }
                    420:                o_mongain = mongain;
                    421:        }
                    422: 
                    423:        if (o_port != port) {
                    424: # ifdef DEBUG
                    425:                if (debug > 1)
                    426:                        printf("audio_gain: port %d\n", port);
                    427: # endif
                    428:                l = (1 << ((port == 2) ? SOUND_MIXER_LINE : SOUND_MIXER_MIC));
                    429:                rval = ioctl(ctl_fd, SOUND_MIXER_WRITE_RECSRC, &l);
                    430:                if (rval == -1) {
                    431:                        printf("SOUND_MIXER_WRITE_RECSRC: %s\n",
                    432:                               strerror(errno));
                    433:                        return (rval);
                    434:                }
                    435: # ifdef DEBUG
                    436:                if (debug > 1) {
                    437:                        if (ioctl(ctl_fd, SOUND_MIXER_READ_RECSRC, &l) == -1)
                    438:                                printf("SOUND_MIXER_WRITE_RECSRC: %s\n",
                    439:                                       strerror(errno));
                    440:                        else
                    441:                                printf("audio_gain: recsrc is %d\n", l);
                    442:                }
                    443: # endif
                    444:                o_port = port;
                    445:        }
                    446: #else /* not PCM_STYLE_SOUND */
                    447:        ioctl(ctl_fd, (int)AUDIO_GETINFO, (char *)&info);
                    448:        info.record.encoding = AUDIO_ENCODING_ULAW;
                    449:        info.record.error = 0;
                    450:        info.record.gain = gain;
                    451:        if (o_mongain != mongain)
                    452:                o_mongain = info.monitor_gain = mongain;
                    453:        if (o_port != port)
                    454:                o_port = info.record.port = port;
                    455:        rval = ioctl(ctl_fd, (int)AUDIO_SETINFO, (char *)&info);
                    456:        if (rval < 0) {
                    457:                msyslog(LOG_ERR, "audio_gain: %m");
                    458:                return (rval);
                    459:        }
                    460:        rval = info.record.error;
                    461: #endif /* not PCM_STYLE_SOUND */
                    462:        return (rval);
                    463: }
                    464: 
                    465: 
                    466: /*
                    467:  * audio_show - display audio parameters
                    468:  *
                    469:  * This code doesn't really do anything, except satisfy curiousity and
                    470:  * verify the ioctl's work.
                    471:  */
                    472: void
                    473: audio_show(void)
                    474: {
                    475: #ifdef PCM_STYLE_SOUND
                    476:        int recsrc = 0;
                    477: 
                    478:        printf("audio_show: ctl_fd %d\n", ctl_fd);
                    479:        if (ioctl(ctl_fd, SOUND_MIXER_READ_RECSRC, &recsrc) == -1)
                    480:            printf("SOUND_MIXER_READ_RECSRC: %s\n", strerror(errno));
                    481: 
                    482: #else /* not PCM_STYLE_SOUND */
                    483: # ifdef HAVE_SYS_AUDIOIO_H
                    484:        ioctl(ctl_fd, (int)AUDIO_GETDEV, &device);
                    485:        printf("audio: name %s, version %s, config %s\n",
                    486:            device.name, device.version, device.config);
                    487: # endif /* HAVE_SYS_AUDIOIO_H */
                    488:        ioctl(ctl_fd, (int)AUDIO_GETINFO, (char *)&info);
                    489:        printf(
                    490:            "audio: rate %d, chan %d, prec %d, code %d, gain %d, mon %d, port %d\n",
                    491:            info.record.sample_rate, info.record.channels,
                    492:            info.record.precision, info.record.encoding,
                    493:            info.record.gain, info.monitor_gain, info.record.port);
                    494:        printf(
                    495:            "audio: samples %d, eof %d, pause %d, error %d, waiting %d, balance %d\n",
                    496:            info.record.samples, info.record.eof,
                    497:            info.record.pause, info.record.error,
                    498:            info.record.waiting, info.record.balance);
                    499: #endif /* not PCM_STYLE_SOUND */
                    500: }
                    501: #else
                    502: int audio_bs;
                    503: #endif /* HAVE_{SYS_AUDIOIO,SUN_AUDIOIO,MACHINE_SOUNDCARD,SYS_SOUNDCARD}_H */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>