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