Annotation of src/usr.bin/audioctl/audioctl.c, Revision 1.2
1.2 ! provos 1: /* $OpenBSD$ */
1.1 provos 2: /* $NetBSD: audioctl.c,v 1.12 1997/10/19 07:44:12 augustss Exp $ */
3:
4: /*
5: * Copyright (c) 1997 The NetBSD Foundation, Inc.
6: * All rights reserved.
7: *
8: * Author: Lennart Augustsson
9: *
10: * Redistribution and use in source and binary forms, with or without
11: * modification, are permitted provided that the following conditions
12: * are met:
13: * 1. Redistributions of source code must retain the above copyright
14: * notice, this list of conditions and the following disclaimer.
15: * 2. Redistributions in binary form must reproduce the above copyright
16: * notice, this list of conditions and the following disclaimer in the
17: * documentation and/or other materials provided with the distribution.
18: * 3. All advertising materials mentioning features or use of this software
19: * must display the following acknowledgement:
20: * This product includes software developed by the NetBSD
21: * Foundation, Inc. and its contributors.
22: * 4. Neither the name of The NetBSD Foundation nor the names of its
23: * contributors may be used to endorse or promote products derived
24: * from this software without specific prior written permission.
25: *
26: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36: * POSSIBILITY OF SUCH DAMAGE.
37: */
38:
39: #include <stdio.h>
40: #include <fcntl.h>
41: #include <err.h>
42: #include <unistd.h>
43: #include <string.h>
44: #include <sys/types.h>
45: #include <sys/stat.h>
46: #include <sys/ioctl.h>
47: #include <sys/audioio.h>
48:
49: struct field *findfield __P((char *name));
50: void prfield __P((struct field *p, char *sep));
51: void rdfield __P((struct field *p, char *q));
52: void getinfo __P((int fd));
53: void usage __P((void));
54: int main __P((int argc, char **argv));
55:
56: FILE *out = stdout;
57:
58: char *prog;
59:
60: audio_device_t adev;
61:
62: audio_info_t info;
63:
64: char encbuf[1000];
65:
66: int properties, fullduplex, rerror;
67:
68: struct field {
69: char *name;
70: void *valp;
71: int format;
72: #define STRING 1
73: #define INT 2
74: #define UINT 3
75: #define P_R 4
76: #define ULONG 5
77: #define UCHAR 6
78: #define ENC 7
79: #define PROPS 8
80: #define XINT 9
81: char flags;
82: #define READONLY 1
83: #define ALIAS 2
84: #define SET 4
85: } fields[] = {
86: { "name", &adev.name, STRING, READONLY },
87: { "version", &adev.version, STRING, READONLY },
88: { "config", &adev.config, STRING, READONLY },
89: { "encodings", encbuf, STRING, READONLY },
90: { "properties", &properties, PROPS, READONLY },
91: { "full_duplex", &fullduplex, INT, 0 },
92: { "blocksize", &info.blocksize, UINT, 0 },
93: { "hiwat", &info.hiwat, UINT, 0 },
94: { "lowat", &info.lowat, UINT, 0 },
95: { "monitor_gain", &info.monitor_gain, UINT, 0 },
96: { "mode", &info.mode, P_R, READONLY },
97: { "play.rate", &info.play.sample_rate, UINT, 0 },
98: { "play.sample_rate", &info.play.sample_rate, UINT, ALIAS },
99: { "play.channels", &info.play.channels, UINT, 0 },
100: { "play.precision", &info.play.precision, UINT, 0 },
101: { "play.encoding", &info.play.encoding, ENC, 0 },
102: { "play.gain", &info.play.gain, UINT, 0 },
103: { "play.balance", &info.play.balance, UCHAR, 0 },
104: { "play.port", &info.play.port, XINT, 0 },
105: { "play.avail_ports", &info.play.avail_ports, XINT, 0 },
106: { "play.seek", &info.play.seek, ULONG, READONLY },
107: { "play.samples", &info.play.samples, UINT, READONLY },
108: { "play.eof", &info.play.eof, UINT, READONLY },
109: { "play.pause", &info.play.pause, UCHAR, 0 },
110: { "play.error", &info.play.error, UCHAR, READONLY },
111: { "play.waiting", &info.play.waiting, UCHAR, READONLY },
112: { "play.open", &info.play.open, UCHAR, READONLY },
113: { "play.active", &info.play.active, UCHAR, READONLY },
114: { "play.buffer_size", &info.play.buffer_size, UINT, 0 },
115: { "record.rate", &info.record.sample_rate,UINT, 0 },
116: { "record.sample_rate", &info.record.sample_rate,UINT, ALIAS },
117: { "record.channels", &info.record.channels, UINT, 0 },
118: { "record.precision", &info.record.precision, UINT, 0 },
119: { "record.encoding", &info.record.encoding, ENC, 0 },
120: { "record.gain", &info.record.gain, UINT, 0 },
121: { "record.balance", &info.record.balance, UCHAR, 0 },
122: { "record.port", &info.record.port, XINT, 0 },
123: { "record.avail_ports", &info.record.avail_ports,XINT, 0 },
124: { "record.seek", &info.record.seek, ULONG, READONLY },
125: { "record.samples", &info.record.samples, UINT, READONLY },
126: { "record.eof", &info.record.eof, UINT, READONLY },
127: { "record.pause", &info.record.pause, UCHAR, 0 },
128: { "record.error", &info.record.error, UCHAR, READONLY },
129: { "record.waiting", &info.record.waiting, UCHAR, READONLY },
130: { "record.open", &info.record.open, UCHAR, READONLY },
131: { "record.active", &info.record.active, UCHAR, READONLY },
132: { "record.buffer_size", &info.record.buffer_size,UINT, 0 },
133: { "record.errors", &rerror, INT, READONLY },
134: { 0 }
135: };
136:
137: struct {
138: char *ename;
139: int eno;
140: } encs[] = {
141: { AudioEmulaw, AUDIO_ENCODING_ULAW },
142: { "ulaw", AUDIO_ENCODING_ULAW },
143: { AudioEalaw, AUDIO_ENCODING_ALAW },
144: { AudioEslinear, AUDIO_ENCODING_SLINEAR },
145: { "linear", AUDIO_ENCODING_SLINEAR },
146: { AudioEulinear, AUDIO_ENCODING_ULINEAR },
147: { AudioEadpcm, AUDIO_ENCODING_ADPCM },
148: { "ADPCM", AUDIO_ENCODING_ADPCM },
149: { AudioEslinear_le, AUDIO_ENCODING_SLINEAR_LE },
150: { "linear_le", AUDIO_ENCODING_SLINEAR_LE },
151: { AudioEulinear_le, AUDIO_ENCODING_ULINEAR_LE },
152: { AudioEslinear_be, AUDIO_ENCODING_SLINEAR_BE },
153: { "linear_be", AUDIO_ENCODING_SLINEAR_BE },
154: { AudioEulinear_be, AUDIO_ENCODING_ULINEAR_BE },
155: { AudioEmpeg_l1_stream, AUDIO_ENCODING_MPEG_L1_STREAM },
156: { AudioEmpeg_l1_packets,AUDIO_ENCODING_MPEG_L1_PACKETS },
157: { AudioEmpeg_l1_system, AUDIO_ENCODING_MPEG_L1_SYSTEM },
158: { AudioEmpeg_l2_stream, AUDIO_ENCODING_MPEG_L2_STREAM },
159: { AudioEmpeg_l2_packets,AUDIO_ENCODING_MPEG_L2_PACKETS },
160: { AudioEmpeg_l2_system, AUDIO_ENCODING_MPEG_L2_SYSTEM },
161: { 0 }
162: };
163:
164: static struct {
165: char *name;
166: u_int prop;
167: } props[] = {
168: { "full_duplex", AUDIO_PROP_FULLDUPLEX },
169: { "mmap", AUDIO_PROP_MMAP },
170: { "independent", AUDIO_PROP_INDEPENDENT },
171: { 0 }
172: };
173:
174: struct field *
175: findfield(name)
176: char *name;
177: {
178: int i;
179: for(i = 0; fields[i].name; i++)
180: if (strcmp(fields[i].name, name) == 0)
181: return &fields[i];
182: return 0;
183: }
184:
185: void
186: prfield(p, sep)
187: struct field *p;
188: char *sep;
189: {
190: u_int v;
191: char *cm;
192: int i;
193:
194: if (sep)
195: fprintf(out, "%s%s", p->name, sep);
196: switch(p->format) {
197: case STRING:
198: fprintf(out, "%s", (char*)p->valp);
199: break;
200: case INT:
201: fprintf(out, "%d", *(int*)p->valp);
202: break;
203: case UINT:
204: fprintf(out, "%u", *(u_int*)p->valp);
205: break;
206: case XINT:
207: fprintf(out, "0x%x", *(u_int*)p->valp);
208: break;
209: case UCHAR:
210: fprintf(out, "%u", *(u_char*)p->valp);
211: break;
212: case ULONG:
213: fprintf(out, "%lu", *(u_long*)p->valp);
214: break;
215: case P_R:
216: v = *(u_int*)p->valp;
217: cm = "";
218: if (v & AUMODE_PLAY) {
219: if (v & AUMODE_PLAY_ALL)
220: fprintf(out, "play");
221: else
222: fprintf(out, "playsync");
223: cm = ",";
224: }
225: if (v & AUMODE_RECORD)
226: fprintf(out, "%srecord", cm);
227: break;
228: case ENC:
229: v = *(u_int*)p->valp;
230: for(i = 0; encs[i].ename; i++)
231: if (encs[i].eno == v)
232: break;
233: if (encs[i].ename)
234: fprintf(out, "%s", encs[i].ename);
235: else
236: fprintf(out, "%u", v);
237: break;
238: case PROPS:
239: v = *(u_int*)p->valp;
240: for (cm = "", i = 0; props[i].name; i++) {
241: if (v & props[i].prop) {
242: fprintf(out, "%s%s", cm, props[i].name);
243: cm = ",";
244: }
245: }
246: break;
247: default:
248: errx(1, "Invalid print format.");
249: }
250: }
251:
252: void
253: rdfield(p, q)
254: struct field *p;
255: char *q;
256: {
257: int i;
258: u_int u;
259:
260: switch(p->format) {
261: case UINT:
262: if (sscanf(q, "%u", (unsigned int *)p->valp) != 1)
263: warnx("Bad number %s", q);
264: break;
265: case UCHAR:
266: if (sscanf(q, "%u", &u) != 1)
267: warnx("Bad number %s", q);
268: else
269: *(u_char *)p->valp = u;
270: break;
271: case XINT:
272: if (sscanf(q, "0x%x", (unsigned int *)p->valp) != 1 &&
273: sscanf(q, "%x", (unsigned int *)p->valp) != 1)
274: warnx("Bad number %s", q);
275: break;
276: case ENC:
277: for(i = 0; encs[i].ename; i++)
278: if (strcmp(encs[i].ename, q) == 0)
279: break;
280: if (encs[i].ename)
281: *(u_int*)p->valp = encs[i].eno;
282: else
283: warnx("Unknown encoding: %s", q);
284: break;
285: default:
286: errx(1, "Invalid read format.");
287: }
288: p->flags |= SET;
289: }
290:
291: void
292: getinfo(fd)
293: int fd;
294: {
295: int pos, i;
296:
297: if (ioctl(fd, AUDIO_GETDEV, &adev) < 0)
298: err(1, "AUDIO_GETDEV");
299: for(pos = 0, i = 0; ; i++) {
300: audio_encoding_t enc;
301: enc.index = i;
302: if (ioctl(fd, AUDIO_GETENC, &enc) < 0)
303: break;
304: if (pos)
305: encbuf[pos++] = ',';
306: sprintf(encbuf+pos, "%s:%d%s", enc.name,
307: enc.precision,
308: enc.flags & AUDIO_ENCODINGFLAG_EMULATED ? "*" : "");
309: pos += strlen(encbuf+pos);
310: }
311: if (ioctl(fd, AUDIO_GETFD, &fullduplex) < 0)
312: err(1, "AUDIO_GETFD");
313: if (ioctl(fd, AUDIO_GETPROPS, &properties) < 0)
314: err(1, "AUDIO_GETPROPS");
315: if (ioctl(fd, AUDIO_RERROR, &rerror) < 0)
316: err(1, "AUDIO_RERROR");
317: if (ioctl(fd, AUDIO_GETINFO, &info) < 0)
318: err(1, "AUDIO_GETINFO");
319: }
320:
321: void
322: usage()
323: {
324: fprintf(out, "%s [-f file] [-n] name ...\n", prog);
325: fprintf(out, "%s [-f file] [-n] -w name=value ...\n", prog);
326: fprintf(out, "%s [-f file] [-n] -a\n", prog);
327: exit(1);
328: }
329:
330: int
331: main(argc, argv)
332: int argc;
333: char **argv;
334: {
335: int fd, i, ch;
336: int aflag = 0, wflag = 0;
337: struct stat dstat, ostat;
338: char *file = "/dev/audioctl";
339: char *sep = "=";
340:
341: prog = *argv;
342:
343: while ((ch = getopt(argc, argv, "af:nw")) != -1) {
344: switch(ch) {
345: case 'a':
346: aflag++;
347: break;
348: case 'w':
349: wflag++;
350: break;
351: case 'n':
352: sep = 0;
353: break;
354: case 'f':
355: file = optarg;
356: break;
357: case '?':
358: default:
359: usage();
360: }
361: }
362: argc -= optind;
363: argv += optind;
364:
365: fd = open(file, O_WRONLY);
366: if (fd < 0)
367: fd = open(file, O_RDONLY);
368: if (fd < 0)
369: err(1, "%s", file);
370:
371: /* Check if stdout is the same device as the audio device. */
372: if (fstat(fd, &dstat) < 0)
373: err(1, "fstat au");
374: if (fstat(STDOUT_FILENO, &ostat) < 0)
375: err(1, "fstat stdout");
376: if (S_ISCHR(dstat.st_mode) && S_ISCHR(ostat.st_mode) &&
377: major(dstat.st_dev) == major(ostat.st_dev) &&
378: minor(dstat.st_dev) == minor(ostat.st_dev))
379: /* We can't write to stdout so use stderr */
380: out = stderr;
381:
382: if (!wflag)
383: getinfo(fd);
384:
385: if (argc == 0 && aflag && !wflag) {
386: for(i = 0; fields[i].name; i++) {
387: if (!(fields[i].flags & ALIAS)) {
388: prfield(&fields[i], sep);
389: fprintf(out, "\n");
390: }
391: }
392: } else if (argc > 0 && !aflag) {
393: struct field *p;
394: if (wflag) {
395: AUDIO_INITINFO(&info);
396: while(argc--) {
397: char *q;
398:
399: q = strchr(*argv, '=');
400: if (q) {
401: *q++ = 0;
402: p = findfield(*argv);
403: if (p == 0)
404: warnx("field `%s' does not exist", *argv);
405: else {
406: if (p->flags & READONLY)
407: warnx("`%s' is read only", *argv);
408: else {
409: rdfield(p, q);
410: if (p->valp == &fullduplex)
411: if (ioctl(fd, AUDIO_SETFD, &fullduplex) < 0)
412: err(1, "set failed");
413: }
414: }
415: } else
416: warnx("No `=' in %s", *argv);
417: argv++;
418: }
419: if (ioctl(fd, AUDIO_SETINFO, &info) < 0)
420: err(1, "set failed");
421: if (sep) {
422: getinfo(fd);
423: for(i = 0; fields[i].name; i++) {
424: if (fields[i].flags & SET) {
425: fprintf(out, "%s: -> ", fields[i].name);
426: prfield(&fields[i], 0);
427: fprintf(out, "\n");
428: }
429: }
430: }
431: } else {
432: while(argc--) {
433: p = findfield(*argv);
434: if (p == 0) {
435: if (strchr(*argv, '='))
436: warnx("field %s does not exist (use -w to set a variable)", *argv);
437: else
438: warnx("field %s does not exist", *argv);
439: } else {
440: prfield(p, sep);
441: fprintf(out, "\n");
442: }
443: argv++;
444: }
445: }
446: } else
447: usage();
448: exit(0);
449: }