[BACK]Return to audioctl.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / audioctl

Annotation of src/usr.bin/audioctl/audioctl.c, Revision 1.31

1.31    ! ratchov     1: /*     $OpenBSD$       */
1.1       provos      2: /*
1.31    ! ratchov     3:  * Copyright (c) 2016 Alexandre Ratchov <alex@caoua.org>
1.1       provos      4:  *
1.31    ! ratchov     5:  * Permission to use, copy, modify, and distribute this software for any
        !             6:  * purpose with or without fee is hereby granted, provided that the above
        !             7:  * copyright notice and this permission notice appear in all copies.
1.1       provos      8:  *
1.31    ! ratchov     9:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
        !            10:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
        !            11:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
        !            12:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
        !            13:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
        !            14:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
        !            15:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1.1       provos     16:  */
1.31    ! ratchov    17: #include <sys/types.h>
        !            18: #include <sys/ioctl.h>
        !            19: #include <sys/audioio.h>
        !            20: #include <fcntl.h>
        !            21: #include <limits.h>
1.1       provos     22: #include <stdio.h>
1.3       provos     23: #include <stdlib.h>
1.1       provos     24: #include <unistd.h>
                     25: #include <string.h>
1.31    ! ratchov    26: #include <err.h>
1.1       provos     27:
1.31    ! ratchov    28: /*
        !            29:  * Default bytes per sample for the given bits per sample.
        !            30:  */
        !            31: #define BPS(bits) (((bits) <= 8) ? 1 : (((bits) <= 16) ? 2 : 4))
1.1       provos     32:
1.31    ! ratchov    33: struct audio_device rname;
        !            34: struct audio_status rstatus;
        !            35: struct audio_swpar rpar, wpar;
        !            36: struct audio_pos rpos;
1.30      ratchov    37:
1.1       provos     38: struct field {
1.31    ! ratchov    39:        char *name;
        !            40:        void *raddr, *waddr;
        !            41: #define MODE   0
        !            42: #define NUM    1
        !            43: #define STR    2
        !            44: #define ENC    3
        !            45:        int type;
        !            46:        int set;
1.1       provos     47: } fields[] = {
1.31    ! ratchov    48:        {"name",                &rname.name,            NULL,           STR},
        !            49:        {"mode",                &rstatus.mode,          NULL,           MODE},
        !            50:        {"pause",               &rstatus.pause,         NULL,           NUM},
        !            51:        {"active",              &rstatus.active,        NULL,           NUM},
        !            52:        {"nblks",               &rpar.nblks,            &wpar.nblks,    NUM},
        !            53:        {"blksz",               &rpar.round,            &wpar.round,    NUM},
        !            54:        {"rate",                &rpar.rate,             &wpar.rate,     NUM},
        !            55:        {"encoding",            &rpar,                  &wpar,          ENC},
        !            56:        {"play.channels",       &rpar.pchan,            &wpar.pchan,    NUM},
        !            57:        {"play.bytes",          &rpos.play_pos,         NULL,           NUM},
        !            58:        {"play.errors",         &rpos.play_xrun,        NULL,           NUM},
        !            59:        {"record.channels",     &rpar.rchan,            &wpar.rchan,    NUM},
        !            60:        {"record.bytes",        &rpos.rec_pos,          NULL,           NUM},
        !            61:        {"record.errors",       &rpos.rec_xrun,         NULL,           NUM},
        !            62:        {NULL,                  NULL,                   0}
1.1       provos     63: };
                     64:
1.31    ! ratchov    65: const char usagestr[] = "usage: audioctl [-nq] [-f path] [name=[value]] ...\n";
1.1       provos     66:
1.31    ! ratchov    67: /*
        !            68:  * parse encoding string (examples: s8, u8, s16, s16le, s24be ...)
        !            69:  * and fill enconding fields of audio_swpar structure
        !            70:  */
        !            71: int
        !            72: strtoenc(struct audio_swpar *ap, char *p)
1.1       provos     73: {
1.31    ! ratchov    74:        /* expect "s" or "u" (signedness) */
        !            75:        if (*p == 's')
        !            76:                ap->sig = 1;
        !            77:        else if (*p == 'u')
        !            78:                ap->sig = 0;
        !            79:        else
        !            80:                return 0;
        !            81:        p++;
        !            82:
        !            83:        /* expect 1-2 decimal digits (bits per sample) */
        !            84:        ap->bits = 0;
        !            85:        while (*p >= '0' && *p <= '9') {
        !            86:                ap->bits = (ap->bits * 10) + *p++ - '0';
        !            87:                if (ap->bits > 32)
        !            88:                        return 0;
        !            89:        }
        !            90:        if (ap->bits < 8)
        !            91:                return 0;
1.1       provos     92:
1.31    ! ratchov    93:        /* set defaults as next tokens are optional */
        !            94:        ap->bps = BPS(ap->bits);
        !            95:        ap->le = (BYTE_ORDER == LITTLE_ENDIAN);
        !            96:        ap->msb = 1;
        !            97:        if (*p == '\0')
        !            98:                return 1;
        !            99:
        !           100:        /* expect "le" or "be" (endianness) */
        !           101:        if (p[0] == 'l' && p[1] == 'e')
        !           102:                ap->le = 1;
        !           103:        else if (p[0] == 'b' && p[1] == 'e')
        !           104:                ap->le = 0;
        !           105:        else
        !           106:                return 0;
        !           107:        p += 2;
        !           108:        if (*p == '\0')
        !           109:                return 1;
        !           110:
        !           111:        /* expect 1 decimal digit (number of bytes) */
        !           112:        if (*p < '0' || *p > '9')
        !           113:                return 0;
        !           114:        ap->bps = *p - '0';
        !           115:        if (ap->bps < ((ap->bits + 7) >> 3) || ap->bps > 4)
        !           116:                return 0;
        !           117:        if (*++p == '\0')
        !           118:                return 1;
        !           119:
        !           120:        /* expect "msb" or "lsb" (alignment) */
        !           121:        if (p[0] == 'm' && p[1] == 's' && p[2] == 'b')
        !           122:                ap->msb = 1;
        !           123:        else if (p[0] == 'l' && p[1] == 's' && p[2] == 'b')
        !           124:                ap->msb = 0;
        !           125:        else if (*p == '\0')
        !           126:                return 1;
        !           127:        p += 3;
        !           128:        if (*p == '\0')
        !           129:                return 1;
1.1       provos    130:
1.31    ! ratchov   131:        /* must be no additional junk */
        !           132:        return 0;
1.20      ratchov   133: }
                    134:
                    135: void
1.31    ! ratchov   136: print_val(struct field *p, void *addr)
1.1       provos    137: {
1.31    ! ratchov   138:        int mode;
        !           139:        struct audio_swpar *ap;
1.1       provos    140:
1.31    ! ratchov   141:        switch (p->type) {
        !           142:        case NUM:
        !           143:                printf("%u", *(unsigned int *)addr);
        !           144:                break;
        !           145:        case STR:
        !           146:                printf("%s", (char *)addr);
        !           147:                break;
        !           148:        case MODE:
        !           149:                mode = *(unsigned int *)addr;
        !           150:                if (mode & AUMODE_PLAY)
        !           151:                        printf("play");
        !           152:                if (mode & AUMODE_RECORD) {
        !           153:                        if (mode & AUMODE_PLAY)
        !           154:                                printf(",");
        !           155:                        printf("record");
1.20      ratchov   156:                }
1.1       provos    157:                break;
                    158:        case ENC:
1.31    ! ratchov   159:                ap = addr;
        !           160:                printf("%s%u", ap->sig ? "s" : "u", ap->bits);
        !           161:                if (ap->bps == 1)
        !           162:                        break;
        !           163:                printf("%s", ap->le ? "le" : "be");
        !           164:                if (ap->bps != BPS(ap->bits) || ap->bits < ap->bps * 8) {
        !           165:                        printf("%u", ap->bps);
        !           166:                        if (ap->bits < ap->bps * 8)
        !           167:                                printf("%s", ap->msb ? "msb" : "lsb");
1.20      ratchov   168:                }
1.1       provos    169:        }
                    170: }
                    171:
                    172: void
1.31    ! ratchov   173: parse_val(struct field *f, void *addr, char *p)
1.1       provos    174: {
1.31    ! ratchov   175:        const char *strerr;
1.1       provos    176:
1.31    ! ratchov   177:        switch (f->type) {
        !           178:        case NUM:
        !           179:                *(unsigned int *)addr = strtonum(p, 0, UINT_MAX, &strerr);
        !           180:                if (strerr)
        !           181:                        errx(1, "%s: %s", p, strerr);
        !           182:                break;
        !           183:        case ENC:
        !           184:                if (!strtoenc((struct audio_swpar *)addr, p))
        !           185:                        errx(1, "%s: bad encoding", p);
1.1       provos    186:        }
                    187: }
                    188:
                    189: int
1.7       pvalchev  190: main(int argc, char **argv)
1.1       provos    191: {
1.31    ! ratchov   192:        struct field *f;
        !           193:        char *lhs, *rhs, *path = "/dev/audioctl0";
        !           194:        int fd, c, set = 0, print_names = 1, quiet = 0;
        !           195:
        !           196:        while ((c = getopt(argc, argv, "anf:q")) != -1) {
        !           197:                switch (c) {
        !           198:                case 'a':       /* ignored, compat */
1.1       provos    199:                        break;
                    200:                case 'n':
1.31    ! ratchov   201:                        print_names = 0;
1.1       provos    202:                        break;
                    203:                case 'f':
1.31    ! ratchov   204:                        path = optarg;
        !           205:                        break;
        !           206:                case 'q':
        !           207:                        quiet = 1;
1.1       provos    208:                        break;
                    209:                default:
1.31    ! ratchov   210:                        fputs(usagestr, stderr);
        !           211:                        return 1;
1.1       provos    212:                }
                    213:        }
                    214:        argc -= optind;
                    215:        argv += optind;
1.16      deraadt   216:
1.31    ! ratchov   217:        fd = open(path, O_RDWR);
        !           218:        if (fd < 0)
        !           219:                err(1, "%s", path);
        !           220:        if (ioctl(fd, AUDIO_GETSTATUS, &rstatus) < 0)
        !           221:                err(1, "AUDIO_GETSTATUS");
        !           222:        if (ioctl(fd, AUDIO_GETDEV, &rname) < 0)
        !           223:                err(1, "AUDIO_GETDEV");
        !           224:        if (ioctl(fd, AUDIO_GETPAR, &rpar) < 0)
        !           225:                err(1, "AUDIO_GETPAR");
        !           226:        if (ioctl(fd, AUDIO_GETPOS, &rpos) < 0)
        !           227:                err(1, "AUDIO_GETPOS");
        !           228:        if (argc == 0) {
        !           229:                for (f = fields; f->name != NULL; f++) {
        !           230:                        printf("%s=", f->name);
        !           231:                        print_val(f, f->raddr);
        !           232:                        printf("\n");
1.1       provos    233:                }
1.31    ! ratchov   234:        }
        !           235:        AUDIO_INITPAR(&wpar);
        !           236:        for (; argc > 0; argc--, argv++) {
        !           237:                lhs = *argv;
        !           238:                rhs = strchr(*argv, '=');
        !           239:                if (rhs)
        !           240:                        *rhs++ = '\0';
        !           241:                for (f = fields;; f++) {
        !           242:                        if (f->name == NULL)
        !           243:                                errx(1, "%s: unknown parameter", lhs);
        !           244:                        if (strcmp(f->name, lhs) == 0)
        !           245:                                break;
1.11      vincent   246:                }
1.31    ! ratchov   247:                if (rhs) {
        !           248:                        if (f->waddr == NULL)
        !           249:                                errx(1, "%s: is read only", f->name);
        !           250:                        parse_val(f, f->waddr, rhs);
        !           251:                        f->set = 1;
        !           252:                        set = 1;
        !           253:                } else {
        !           254:                        if (print_names)
        !           255:                                printf("%s=", f->name);
        !           256:                        print_val(f, f->raddr);
        !           257:                        printf("\n");
1.30      ratchov   258:                }
1.31    ! ratchov   259:        }
        !           260:        if (!set)
        !           261:                return 0;
        !           262:        if (ioctl(fd, AUDIO_SETPAR, &wpar) < 0)
        !           263:                err(1, "AUDIO_SETPAR");
        !           264:        if (ioctl(fd, AUDIO_GETPAR, &wpar) < 0)
        !           265:                err(1, "AUDIO_GETPAR");
        !           266:        for (f = fields; f->name != NULL; f++) {
        !           267:                if (!f->set || quiet)
        !           268:                        continue;
        !           269:                if (print_names) {
        !           270:                        printf("%s: ", f->name);
        !           271:                        print_val(f, f->raddr);
        !           272:                        printf(" -> ");
1.1       provos    273:                }
1.31    ! ratchov   274:                print_val(f, f->waddr);
        !           275:                printf("\n");
1.11      vincent   276:        }
1.31    ! ratchov   277:        return 0;
1.1       provos    278: }