diff options
author | Niels Provos <provos@cvs.openbsd.org> | 1998-04-26 21:44:41 +0000 |
---|---|---|
committer | Niels Provos <provos@cvs.openbsd.org> | 1998-04-26 21:44:41 +0000 |
commit | 29afb8c3e448c891573f178ee5fcde79a8c773fe (patch) | |
tree | 8cffde11b1265ddaf556393e5de1d5a64d81c6fb | |
parent | ad6be0fbcd73c10dbdb865e29530b46c3eec250c (diff) |
audioctl from NetBSD, mostly by Lennart Augustsson <augustss@cs.chalmers.se>
-rw-r--r-- | usr.bin/audioctl/Makefile | 6 | ||||
-rw-r--r-- | usr.bin/audioctl/audioctl.1 | 103 | ||||
-rw-r--r-- | usr.bin/audioctl/audioctl.c | 448 |
3 files changed, 557 insertions, 0 deletions
diff --git a/usr.bin/audioctl/Makefile b/usr.bin/audioctl/Makefile new file mode 100644 index 00000000000..8067f90849e --- /dev/null +++ b/usr.bin/audioctl/Makefile @@ -0,0 +1,6 @@ +# $NetBSD: Makefile,v 1.1 1997/05/13 17:35:52 augustss Exp $ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= audioctl + +.include <bsd.prog.mk> diff --git a/usr.bin/audioctl/audioctl.1 b/usr.bin/audioctl/audioctl.1 new file mode 100644 index 00000000000..1744e912cfc --- /dev/null +++ b/usr.bin/audioctl/audioctl.1 @@ -0,0 +1,103 @@ +.\" $NetBSD: audioctl.1,v 1.5 1997/10/18 12:05:22 lukem Exp $ +.\" Copyright (c) 1997 The NetBSD Foundation, Inc. +.\" All rights reserved. +.\" +.\" Author: Lennart Augustsson +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the NetBSD +.\" Foundation, Inc. and its contributors. +.\" 4. Neither the name of The NetBSD Foundation nor the names of its +.\" contributors may be used to endorse or promote products derived +.\" from this software without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS +.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS +.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +.\" POSSIBILITY OF SUCH DAMAGE. +.\" +.Dd May 4, 1997 +.Dt AUDIOCTL 1 +.Os +.Sh NAME +.Nm audioctl +.Nd control audio device +.Sh SYNOPSIS +.Nm +.Op Fl f Ar file +.Op Fl n +.Fl a +.Nm "" +.Op Fl f Ar file +.Op Fl n +.Ar name ... +.Nm "" +.Op Fl f Ar file +.Op Fl n +.Fl w +.Ar name=value ... +.Sh DESCRIPTION +The +.Nm +command displays or sets various audio system driver variables. +If a list of variables is present on the command line, then +.Nm +prints the current value of those variables for the specified device. +If the +.Fl a +flag is specified, all variables for the device are printed. +If the +.Fl w +flag is specified +.Nm +attempts to set the specified variables to the given values. +.Pp +The +.Fl f +flag can be used to give an alternative audio control device, the default is +.Pa /dev/audioctl . +.Pp +The +.Fl n +flag suppresses printing of the variable name. +.Sh EXAMPLES +To set the playing sampling rate to 11025 you can enter +.Dl audioctl -w play.sample_rate=11025 +Note that many of the variables that can be inspected and changed +with +.Nm +are reset when the device is opened. This can be circumvented +like this +.Dl (cat file.au; audioctl -f /dev/stdout -a) > /dev/audio +or +.Dl (audioctl -f /dev/stdout -w blocksize=1024; cat file.au) > /dev/audio +.Sh FILES +.Bl -tag -width /dev/audioctl +.It Pa /dev/audioctl +audio device +.El +.Sh SEE ALSO +.Xr mixerctl 1 , +.Xr audio 4 , +.Xr sysctl 8 +.Sh HISTORY +The +.Nm +command first appeared in +.Nx 1.3 . diff --git a/usr.bin/audioctl/audioctl.c b/usr.bin/audioctl/audioctl.c new file mode 100644 index 00000000000..1e203e16827 --- /dev/null +++ b/usr.bin/audioctl/audioctl.c @@ -0,0 +1,448 @@ +/* $NetBSD: audioctl.c,v 1.12 1997/10/19 07:44:12 augustss Exp $ */ + +/* + * Copyright (c) 1997 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Author: Lennart Augustsson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <fcntl.h> +#include <err.h> +#include <unistd.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <sys/audioio.h> + +struct field *findfield __P((char *name)); +void prfield __P((struct field *p, char *sep)); +void rdfield __P((struct field *p, char *q)); +void getinfo __P((int fd)); +void usage __P((void)); +int main __P((int argc, char **argv)); + +FILE *out = stdout; + +char *prog; + +audio_device_t adev; + +audio_info_t info; + +char encbuf[1000]; + +int properties, fullduplex, rerror; + +struct field { + char *name; + void *valp; + int format; +#define STRING 1 +#define INT 2 +#define UINT 3 +#define P_R 4 +#define ULONG 5 +#define UCHAR 6 +#define ENC 7 +#define PROPS 8 +#define XINT 9 + char flags; +#define READONLY 1 +#define ALIAS 2 +#define SET 4 +} fields[] = { + { "name", &adev.name, STRING, READONLY }, + { "version", &adev.version, STRING, READONLY }, + { "config", &adev.config, STRING, READONLY }, + { "encodings", encbuf, STRING, READONLY }, + { "properties", &properties, PROPS, READONLY }, + { "full_duplex", &fullduplex, INT, 0 }, + { "blocksize", &info.blocksize, UINT, 0 }, + { "hiwat", &info.hiwat, UINT, 0 }, + { "lowat", &info.lowat, UINT, 0 }, + { "monitor_gain", &info.monitor_gain, UINT, 0 }, + { "mode", &info.mode, P_R, READONLY }, + { "play.rate", &info.play.sample_rate, UINT, 0 }, + { "play.sample_rate", &info.play.sample_rate, UINT, ALIAS }, + { "play.channels", &info.play.channels, UINT, 0 }, + { "play.precision", &info.play.precision, UINT, 0 }, + { "play.encoding", &info.play.encoding, ENC, 0 }, + { "play.gain", &info.play.gain, UINT, 0 }, + { "play.balance", &info.play.balance, UCHAR, 0 }, + { "play.port", &info.play.port, XINT, 0 }, + { "play.avail_ports", &info.play.avail_ports, XINT, 0 }, + { "play.seek", &info.play.seek, ULONG, READONLY }, + { "play.samples", &info.play.samples, UINT, READONLY }, + { "play.eof", &info.play.eof, UINT, READONLY }, + { "play.pause", &info.play.pause, UCHAR, 0 }, + { "play.error", &info.play.error, UCHAR, READONLY }, + { "play.waiting", &info.play.waiting, UCHAR, READONLY }, + { "play.open", &info.play.open, UCHAR, READONLY }, + { "play.active", &info.play.active, UCHAR, READONLY }, + { "play.buffer_size", &info.play.buffer_size, UINT, 0 }, + { "record.rate", &info.record.sample_rate,UINT, 0 }, + { "record.sample_rate", &info.record.sample_rate,UINT, ALIAS }, + { "record.channels", &info.record.channels, UINT, 0 }, + { "record.precision", &info.record.precision, UINT, 0 }, + { "record.encoding", &info.record.encoding, ENC, 0 }, + { "record.gain", &info.record.gain, UINT, 0 }, + { "record.balance", &info.record.balance, UCHAR, 0 }, + { "record.port", &info.record.port, XINT, 0 }, + { "record.avail_ports", &info.record.avail_ports,XINT, 0 }, + { "record.seek", &info.record.seek, ULONG, READONLY }, + { "record.samples", &info.record.samples, UINT, READONLY }, + { "record.eof", &info.record.eof, UINT, READONLY }, + { "record.pause", &info.record.pause, UCHAR, 0 }, + { "record.error", &info.record.error, UCHAR, READONLY }, + { "record.waiting", &info.record.waiting, UCHAR, READONLY }, + { "record.open", &info.record.open, UCHAR, READONLY }, + { "record.active", &info.record.active, UCHAR, READONLY }, + { "record.buffer_size", &info.record.buffer_size,UINT, 0 }, + { "record.errors", &rerror, INT, READONLY }, + { 0 } +}; + +struct { + char *ename; + int eno; +} encs[] = { + { AudioEmulaw, AUDIO_ENCODING_ULAW }, + { "ulaw", AUDIO_ENCODING_ULAW }, + { AudioEalaw, AUDIO_ENCODING_ALAW }, + { AudioEslinear, AUDIO_ENCODING_SLINEAR }, + { "linear", AUDIO_ENCODING_SLINEAR }, + { AudioEulinear, AUDIO_ENCODING_ULINEAR }, + { AudioEadpcm, AUDIO_ENCODING_ADPCM }, + { "ADPCM", AUDIO_ENCODING_ADPCM }, + { AudioEslinear_le, AUDIO_ENCODING_SLINEAR_LE }, + { "linear_le", AUDIO_ENCODING_SLINEAR_LE }, + { AudioEulinear_le, AUDIO_ENCODING_ULINEAR_LE }, + { AudioEslinear_be, AUDIO_ENCODING_SLINEAR_BE }, + { "linear_be", AUDIO_ENCODING_SLINEAR_BE }, + { AudioEulinear_be, AUDIO_ENCODING_ULINEAR_BE }, + { AudioEmpeg_l1_stream, AUDIO_ENCODING_MPEG_L1_STREAM }, + { AudioEmpeg_l1_packets,AUDIO_ENCODING_MPEG_L1_PACKETS }, + { AudioEmpeg_l1_system, AUDIO_ENCODING_MPEG_L1_SYSTEM }, + { AudioEmpeg_l2_stream, AUDIO_ENCODING_MPEG_L2_STREAM }, + { AudioEmpeg_l2_packets,AUDIO_ENCODING_MPEG_L2_PACKETS }, + { AudioEmpeg_l2_system, AUDIO_ENCODING_MPEG_L2_SYSTEM }, + { 0 } +}; + +static struct { + char *name; + u_int prop; +} props[] = { + { "full_duplex", AUDIO_PROP_FULLDUPLEX }, + { "mmap", AUDIO_PROP_MMAP }, + { "independent", AUDIO_PROP_INDEPENDENT }, + { 0 } +}; + +struct field * +findfield(name) + char *name; +{ + int i; + for(i = 0; fields[i].name; i++) + if (strcmp(fields[i].name, name) == 0) + return &fields[i]; + return 0; +} + +void +prfield(p, sep) + struct field *p; + char *sep; +{ + u_int v; + char *cm; + int i; + + if (sep) + fprintf(out, "%s%s", p->name, sep); + switch(p->format) { + case STRING: + fprintf(out, "%s", (char*)p->valp); + break; + case INT: + fprintf(out, "%d", *(int*)p->valp); + break; + case UINT: + fprintf(out, "%u", *(u_int*)p->valp); + break; + case XINT: + fprintf(out, "0x%x", *(u_int*)p->valp); + break; + case UCHAR: + fprintf(out, "%u", *(u_char*)p->valp); + break; + case ULONG: + fprintf(out, "%lu", *(u_long*)p->valp); + break; + case P_R: + v = *(u_int*)p->valp; + cm = ""; + if (v & AUMODE_PLAY) { + if (v & AUMODE_PLAY_ALL) + fprintf(out, "play"); + else + fprintf(out, "playsync"); + cm = ","; + } + if (v & AUMODE_RECORD) + fprintf(out, "%srecord", cm); + break; + case ENC: + v = *(u_int*)p->valp; + for(i = 0; encs[i].ename; i++) + if (encs[i].eno == v) + break; + if (encs[i].ename) + fprintf(out, "%s", encs[i].ename); + else + fprintf(out, "%u", v); + break; + case PROPS: + v = *(u_int*)p->valp; + for (cm = "", i = 0; props[i].name; i++) { + if (v & props[i].prop) { + fprintf(out, "%s%s", cm, props[i].name); + cm = ","; + } + } + break; + default: + errx(1, "Invalid print format."); + } +} + +void +rdfield(p, q) + struct field *p; + char *q; +{ + int i; + u_int u; + + switch(p->format) { + case UINT: + if (sscanf(q, "%u", (unsigned int *)p->valp) != 1) + warnx("Bad number %s", q); + break; + case UCHAR: + if (sscanf(q, "%u", &u) != 1) + warnx("Bad number %s", q); + else + *(u_char *)p->valp = u; + break; + case XINT: + if (sscanf(q, "0x%x", (unsigned int *)p->valp) != 1 && + sscanf(q, "%x", (unsigned int *)p->valp) != 1) + warnx("Bad number %s", q); + break; + case ENC: + for(i = 0; encs[i].ename; i++) + if (strcmp(encs[i].ename, q) == 0) + break; + if (encs[i].ename) + *(u_int*)p->valp = encs[i].eno; + else + warnx("Unknown encoding: %s", q); + break; + default: + errx(1, "Invalid read format."); + } + p->flags |= SET; +} + +void +getinfo(fd) + int fd; +{ + int pos, i; + + if (ioctl(fd, AUDIO_GETDEV, &adev) < 0) + err(1, "AUDIO_GETDEV"); + for(pos = 0, i = 0; ; i++) { + audio_encoding_t enc; + enc.index = i; + if (ioctl(fd, AUDIO_GETENC, &enc) < 0) + break; + if (pos) + encbuf[pos++] = ','; + sprintf(encbuf+pos, "%s:%d%s", enc.name, + enc.precision, + enc.flags & AUDIO_ENCODINGFLAG_EMULATED ? "*" : ""); + pos += strlen(encbuf+pos); + } + if (ioctl(fd, AUDIO_GETFD, &fullduplex) < 0) + err(1, "AUDIO_GETFD"); + if (ioctl(fd, AUDIO_GETPROPS, &properties) < 0) + err(1, "AUDIO_GETPROPS"); + if (ioctl(fd, AUDIO_RERROR, &rerror) < 0) + err(1, "AUDIO_RERROR"); + if (ioctl(fd, AUDIO_GETINFO, &info) < 0) + err(1, "AUDIO_GETINFO"); +} + +void +usage() +{ + fprintf(out, "%s [-f file] [-n] name ...\n", prog); + fprintf(out, "%s [-f file] [-n] -w name=value ...\n", prog); + fprintf(out, "%s [-f file] [-n] -a\n", prog); + exit(1); +} + +int +main(argc, argv) + int argc; + char **argv; +{ + int fd, i, ch; + int aflag = 0, wflag = 0; + struct stat dstat, ostat; + char *file = "/dev/audioctl"; + char *sep = "="; + + prog = *argv; + + while ((ch = getopt(argc, argv, "af:nw")) != -1) { + switch(ch) { + case 'a': + aflag++; + break; + case 'w': + wflag++; + break; + case 'n': + sep = 0; + break; + case 'f': + file = optarg; + break; + case '?': + default: + usage(); + } + } + argc -= optind; + argv += optind; + + fd = open(file, O_WRONLY); + if (fd < 0) + fd = open(file, O_RDONLY); + if (fd < 0) + err(1, "%s", file); + + /* Check if stdout is the same device as the audio device. */ + if (fstat(fd, &dstat) < 0) + err(1, "fstat au"); + if (fstat(STDOUT_FILENO, &ostat) < 0) + err(1, "fstat stdout"); + if (S_ISCHR(dstat.st_mode) && S_ISCHR(ostat.st_mode) && + major(dstat.st_dev) == major(ostat.st_dev) && + minor(dstat.st_dev) == minor(ostat.st_dev)) + /* We can't write to stdout so use stderr */ + out = stderr; + + if (!wflag) + getinfo(fd); + + if (argc == 0 && aflag && !wflag) { + for(i = 0; fields[i].name; i++) { + if (!(fields[i].flags & ALIAS)) { + prfield(&fields[i], sep); + fprintf(out, "\n"); + } + } + } else if (argc > 0 && !aflag) { + struct field *p; + if (wflag) { + AUDIO_INITINFO(&info); + while(argc--) { + char *q; + + q = strchr(*argv, '='); + if (q) { + *q++ = 0; + p = findfield(*argv); + if (p == 0) + warnx("field `%s' does not exist", *argv); + else { + if (p->flags & READONLY) + warnx("`%s' is read only", *argv); + else { + rdfield(p, q); + if (p->valp == &fullduplex) + if (ioctl(fd, AUDIO_SETFD, &fullduplex) < 0) + err(1, "set failed"); + } + } + } else + warnx("No `=' in %s", *argv); + argv++; + } + if (ioctl(fd, AUDIO_SETINFO, &info) < 0) + err(1, "set failed"); + if (sep) { + getinfo(fd); + for(i = 0; fields[i].name; i++) { + if (fields[i].flags & SET) { + fprintf(out, "%s: -> ", fields[i].name); + prfield(&fields[i], 0); + fprintf(out, "\n"); + } + } + } + } else { + while(argc--) { + p = findfield(*argv); + if (p == 0) { + if (strchr(*argv, '=')) + warnx("field %s does not exist (use -w to set a variable)", *argv); + else + warnx("field %s does not exist", *argv); + } else { + prfield(p, sep); + fprintf(out, "\n"); + } + argv++; + } + } + } else + usage(); + exit(0); +} |