[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.36

1.36    ! mestre      1: /*     $OpenBSD: audioctl.c,v 1.35 2017/05/31 04:18:58 jsg Exp $       */
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.32      ratchov    65: const char usagestr[] =
1.33      jmc        66:        "usage: audioctl [-f file]\n"
                     67:        "       audioctl [-n] [-f file] name ...\n"
                     68:        "       audioctl [-nq] [-f file] name=value ...\n";
1.1       provos     69:
1.31      ratchov    70: /*
                     71:  * parse encoding string (examples: s8, u8, s16, s16le, s24be ...)
                     72:  * and fill enconding fields of audio_swpar structure
                     73:  */
                     74: int
                     75: strtoenc(struct audio_swpar *ap, char *p)
1.1       provos     76: {
1.31      ratchov    77:        /* expect "s" or "u" (signedness) */
                     78:        if (*p == 's')
                     79:                ap->sig = 1;
                     80:        else if (*p == 'u')
                     81:                ap->sig = 0;
                     82:        else
                     83:                return 0;
                     84:        p++;
                     85:
                     86:        /* expect 1-2 decimal digits (bits per sample) */
                     87:        ap->bits = 0;
                     88:        while (*p >= '0' && *p <= '9') {
                     89:                ap->bits = (ap->bits * 10) + *p++ - '0';
                     90:                if (ap->bits > 32)
                     91:                        return 0;
                     92:        }
                     93:        if (ap->bits < 8)
                     94:                return 0;
1.1       provos     95:
1.31      ratchov    96:        /* set defaults as next tokens are optional */
                     97:        ap->bps = BPS(ap->bits);
                     98:        ap->le = (BYTE_ORDER == LITTLE_ENDIAN);
                     99:        ap->msb = 1;
                    100:        if (*p == '\0')
                    101:                return 1;
                    102:
                    103:        /* expect "le" or "be" (endianness) */
                    104:        if (p[0] == 'l' && p[1] == 'e')
                    105:                ap->le = 1;
                    106:        else if (p[0] == 'b' && p[1] == 'e')
                    107:                ap->le = 0;
                    108:        else
                    109:                return 0;
                    110:        p += 2;
                    111:        if (*p == '\0')
                    112:                return 1;
                    113:
                    114:        /* expect 1 decimal digit (number of bytes) */
                    115:        if (*p < '0' || *p > '9')
                    116:                return 0;
                    117:        ap->bps = *p - '0';
                    118:        if (ap->bps < ((ap->bits + 7) >> 3) || ap->bps > 4)
                    119:                return 0;
                    120:        if (*++p == '\0')
                    121:                return 1;
                    122:
                    123:        /* expect "msb" or "lsb" (alignment) */
                    124:        if (p[0] == 'm' && p[1] == 's' && p[2] == 'b')
                    125:                ap->msb = 1;
                    126:        else if (p[0] == 'l' && p[1] == 's' && p[2] == 'b')
                    127:                ap->msb = 0;
                    128:        else if (*p == '\0')
                    129:                return 1;
                    130:        p += 3;
                    131:        if (*p == '\0')
                    132:                return 1;
1.1       provos    133:
1.31      ratchov   134:        /* must be no additional junk */
                    135:        return 0;
1.20      ratchov   136: }
                    137:
                    138: void
1.31      ratchov   139: print_val(struct field *p, void *addr)
1.1       provos    140: {
1.31      ratchov   141:        int mode;
                    142:        struct audio_swpar *ap;
1.1       provos    143:
1.31      ratchov   144:        switch (p->type) {
                    145:        case NUM:
                    146:                printf("%u", *(unsigned int *)addr);
                    147:                break;
                    148:        case STR:
                    149:                printf("%s", (char *)addr);
                    150:                break;
                    151:        case MODE:
                    152:                mode = *(unsigned int *)addr;
                    153:                if (mode & AUMODE_PLAY)
                    154:                        printf("play");
                    155:                if (mode & AUMODE_RECORD) {
                    156:                        if (mode & AUMODE_PLAY)
                    157:                                printf(",");
                    158:                        printf("record");
1.20      ratchov   159:                }
1.1       provos    160:                break;
                    161:        case ENC:
1.31      ratchov   162:                ap = addr;
                    163:                printf("%s%u", ap->sig ? "s" : "u", ap->bits);
                    164:                if (ap->bps == 1)
                    165:                        break;
                    166:                printf("%s", ap->le ? "le" : "be");
                    167:                if (ap->bps != BPS(ap->bits) || ap->bits < ap->bps * 8) {
                    168:                        printf("%u", ap->bps);
                    169:                        if (ap->bits < ap->bps * 8)
                    170:                                printf("%s", ap->msb ? "msb" : "lsb");
1.20      ratchov   171:                }
1.1       provos    172:        }
                    173: }
                    174:
                    175: void
1.31      ratchov   176: parse_val(struct field *f, void *addr, char *p)
1.1       provos    177: {
1.31      ratchov   178:        const char *strerr;
1.1       provos    179:
1.31      ratchov   180:        switch (f->type) {
                    181:        case NUM:
                    182:                *(unsigned int *)addr = strtonum(p, 0, UINT_MAX, &strerr);
                    183:                if (strerr)
                    184:                        errx(1, "%s: %s", p, strerr);
                    185:                break;
                    186:        case ENC:
                    187:                if (!strtoenc((struct audio_swpar *)addr, p))
                    188:                        errx(1, "%s: bad encoding", p);
1.1       provos    189:        }
                    190: }
                    191:
                    192: int
1.7       pvalchev  193: main(int argc, char **argv)
1.1       provos    194: {
1.31      ratchov   195:        struct field *f;
                    196:        char *lhs, *rhs, *path = "/dev/audioctl0";
                    197:        int fd, c, set = 0, print_names = 1, quiet = 0;
                    198:
                    199:        while ((c = getopt(argc, argv, "anf:q")) != -1) {
                    200:                switch (c) {
                    201:                case 'a':       /* ignored, compat */
1.1       provos    202:                        break;
                    203:                case 'n':
1.31      ratchov   204:                        print_names = 0;
1.1       provos    205:                        break;
                    206:                case 'f':
1.31      ratchov   207:                        path = optarg;
                    208:                        break;
                    209:                case 'q':
                    210:                        quiet = 1;
1.1       provos    211:                        break;
                    212:                default:
1.31      ratchov   213:                        fputs(usagestr, stderr);
                    214:                        return 1;
1.1       provos    215:                }
                    216:        }
                    217:        argc -= optind;
                    218:        argv += optind;
1.36    ! mestre    219:
        !           220:        if (unveil(path, "rw") == -1)
        !           221:                err(1, "unveil");
        !           222:        if (unveil(NULL, NULL) == -1)
        !           223:                err(1, "unveil");
1.16      deraadt   224:
1.31      ratchov   225:        fd = open(path, O_RDWR);
                    226:        if (fd < 0)
                    227:                err(1, "%s", path);
                    228:        if (ioctl(fd, AUDIO_GETSTATUS, &rstatus) < 0)
                    229:                err(1, "AUDIO_GETSTATUS");
                    230:        if (ioctl(fd, AUDIO_GETDEV, &rname) < 0)
                    231:                err(1, "AUDIO_GETDEV");
                    232:        if (ioctl(fd, AUDIO_GETPAR, &rpar) < 0)
                    233:                err(1, "AUDIO_GETPAR");
                    234:        if (ioctl(fd, AUDIO_GETPOS, &rpos) < 0)
                    235:                err(1, "AUDIO_GETPOS");
                    236:        if (argc == 0) {
                    237:                for (f = fields; f->name != NULL; f++) {
                    238:                        printf("%s=", f->name);
                    239:                        print_val(f, f->raddr);
                    240:                        printf("\n");
1.1       provos    241:                }
1.31      ratchov   242:        }
                    243:        AUDIO_INITPAR(&wpar);
                    244:        for (; argc > 0; argc--, argv++) {
                    245:                lhs = *argv;
                    246:                rhs = strchr(*argv, '=');
                    247:                if (rhs)
                    248:                        *rhs++ = '\0';
                    249:                for (f = fields;; f++) {
                    250:                        if (f->name == NULL)
                    251:                                errx(1, "%s: unknown parameter", lhs);
                    252:                        if (strcmp(f->name, lhs) == 0)
                    253:                                break;
1.11      vincent   254:                }
1.31      ratchov   255:                if (rhs) {
                    256:                        if (f->waddr == NULL)
                    257:                                errx(1, "%s: is read only", f->name);
                    258:                        parse_val(f, f->waddr, rhs);
                    259:                        f->set = 1;
                    260:                        set = 1;
                    261:                } else {
                    262:                        if (print_names)
                    263:                                printf("%s=", f->name);
                    264:                        print_val(f, f->raddr);
                    265:                        printf("\n");
1.30      ratchov   266:                }
1.31      ratchov   267:        }
1.35      jsg       268:        if (!set) {
                    269:                close(fd);
1.31      ratchov   270:                return 0;
1.35      jsg       271:        }
1.31      ratchov   272:        if (ioctl(fd, AUDIO_SETPAR, &wpar) < 0)
                    273:                err(1, "AUDIO_SETPAR");
                    274:        if (ioctl(fd, AUDIO_GETPAR, &wpar) < 0)
                    275:                err(1, "AUDIO_GETPAR");
                    276:        for (f = fields; f->name != NULL; f++) {
                    277:                if (!f->set || quiet)
                    278:                        continue;
                    279:                if (print_names) {
                    280:                        printf("%s: ", f->name);
                    281:                        print_val(f, f->raddr);
                    282:                        printf(" -> ");
1.1       provos    283:                }
1.31      ratchov   284:                print_val(f, f->waddr);
                    285:                printf("\n");
1.11      vincent   286:        }
1.34      jsg       287:        close(fd);
1.31      ratchov   288:        return 0;
1.1       provos    289: }