Annotation of src/usr.bin/audioctl/audioctl.c, Revision 1.33
1.33 ! jmc 1: /* $OpenBSD: audioctl.c,v 1.32 2016/06/21 21:16:42 ratchov 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.16 deraadt 219:
1.31 ratchov 220: fd = open(path, O_RDWR);
221: if (fd < 0)
222: err(1, "%s", path);
223: if (ioctl(fd, AUDIO_GETSTATUS, &rstatus) < 0)
224: err(1, "AUDIO_GETSTATUS");
225: if (ioctl(fd, AUDIO_GETDEV, &rname) < 0)
226: err(1, "AUDIO_GETDEV");
227: if (ioctl(fd, AUDIO_GETPAR, &rpar) < 0)
228: err(1, "AUDIO_GETPAR");
229: if (ioctl(fd, AUDIO_GETPOS, &rpos) < 0)
230: err(1, "AUDIO_GETPOS");
231: if (argc == 0) {
232: for (f = fields; f->name != NULL; f++) {
233: printf("%s=", f->name);
234: print_val(f, f->raddr);
235: printf("\n");
1.1 provos 236: }
1.31 ratchov 237: }
238: AUDIO_INITPAR(&wpar);
239: for (; argc > 0; argc--, argv++) {
240: lhs = *argv;
241: rhs = strchr(*argv, '=');
242: if (rhs)
243: *rhs++ = '\0';
244: for (f = fields;; f++) {
245: if (f->name == NULL)
246: errx(1, "%s: unknown parameter", lhs);
247: if (strcmp(f->name, lhs) == 0)
248: break;
1.11 vincent 249: }
1.31 ratchov 250: if (rhs) {
251: if (f->waddr == NULL)
252: errx(1, "%s: is read only", f->name);
253: parse_val(f, f->waddr, rhs);
254: f->set = 1;
255: set = 1;
256: } else {
257: if (print_names)
258: printf("%s=", f->name);
259: print_val(f, f->raddr);
260: printf("\n");
1.30 ratchov 261: }
1.31 ratchov 262: }
263: if (!set)
264: return 0;
265: if (ioctl(fd, AUDIO_SETPAR, &wpar) < 0)
266: err(1, "AUDIO_SETPAR");
267: if (ioctl(fd, AUDIO_GETPAR, &wpar) < 0)
268: err(1, "AUDIO_GETPAR");
269: for (f = fields; f->name != NULL; f++) {
270: if (!f->set || quiet)
271: continue;
272: if (print_names) {
273: printf("%s: ", f->name);
274: print_val(f, f->raddr);
275: printf(" -> ");
1.1 provos 276: }
1.31 ratchov 277: print_val(f, f->waddr);
278: printf("\n");
1.11 vincent 279: }
1.31 ratchov 280: return 0;
1.1 provos 281: }