Annotation of embedaddon/ntp/libntp/audio.c, revision 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>