summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNiels Provos <provos@cvs.openbsd.org>1998-04-26 21:44:41 +0000
committerNiels Provos <provos@cvs.openbsd.org>1998-04-26 21:44:41 +0000
commit29afb8c3e448c891573f178ee5fcde79a8c773fe (patch)
tree8cffde11b1265ddaf556393e5de1d5a64d81c6fb
parentad6be0fbcd73c10dbdb865e29530b46c3eec250c (diff)
audioctl from NetBSD, mostly by Lennart Augustsson <augustss@cs.chalmers.se>
-rw-r--r--usr.bin/audioctl/Makefile6
-rw-r--r--usr.bin/audioctl/audioctl.1103
-rw-r--r--usr.bin/audioctl/audioctl.c448
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);
+}