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: }