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