diff --git a/usr.bin/Makefile b/usr.bin/Makefile index a4d3981cd85d..4644a0a468ac 100644 --- a/usr.bin/Makefile +++ b/usr.bin/Makefile @@ -1,18 +1,18 @@ -# $NetBSD: Makefile,v 1.70 1997/04/19 05:17:45 thorpej Exp $ +# $NetBSD: Makefile,v 1.71 1997/05/13 17:35:50 augustss Exp $ # from: @(#)Makefile 8.3 (Berkeley) 1/7/94 .include # for EXPORTABLE_SYSTEM definition -SUBDIR= apply apropos asa at banner basename bdes biff cal calendar \ +SUBDIR= apply apropos asa at audioctl banner basename bdes biff cal calendar \ cap_mkdb checknr chflags chpass cksum cmp col colcrt colrm column \ comm compress crontab ctags cut dirname du \ eject env error expand false file find finger fmt fold fpr from \ fsplit fstat ftp gencat getconf getopt head hexdump id indent \ ipcrm ipcs join jot kdump ktrace lam last lastcomm leave less lex \ locate lock logger login logname look lorder m4 machine mail make man \ - mesg mkdep mkfifo mkstr modstat msgs netstat newsyslog nfsstat nice \ - nohup pagesize passwd paste patch pr printenv printf quota \ - rdist renice rev rlogin rpcgen rpcinfo rs \ + mesg mixerctl mkdep mkfifo mkstr modstat msgs netstat newsyslog \ + nfsstat nice nohup pagesize passwd paste patch pr printenv printf \ + quota rdist renice rev rlogin rpcgen rpcinfo rs \ rsh rup ruptime rusers rwall rwho \ script sed shar showmount skey skeyinit soelim split strings \ su systat tail talk tcopy tee tftp time \ diff --git a/usr.bin/audio/ctl/audioctl.1 b/usr.bin/audio/ctl/audioctl.1 new file mode 100644 index 000000000000..50e2b3124a58 --- /dev/null +++ b/usr.bin/audio/ctl/audioctl.1 @@ -0,0 +1,100 @@ +.\" $NetBSD: audioctl.1,v 1.1 1997/05/13 17:35:52 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 REGENTS 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 audioctl +.Op Fl f Ar file +.Op Fl n +.Fl a +.Nm audioctl +.Op Fl f Ar file +.Op Fl n +.Ar name ... +.Nm audioctl +.Op Fl f Ar file +.Op Fl n +.Fl w +.Ar name=value ... +.Sh DESCRIPTION +The +.Nm audioctl +command displays or sets various audio system driver variables. +If a list of variables is present on the command line, then +.Nm audioctl +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 audioctl +attempts to set the specified variables to the given values. +.Pp +The +.Fl f +flag can be used to give an alternative sound device, the default is +.Pa /dev/sound. +.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 audioctl +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/sound +.It Pa /dev/sound +audio device +.El +.Sh SEE ALSO +.Xr mixerctl 1 , +.Xr audio 4 , +.Xr sysctl 8 +.Sh AUTHOR +Lennart Augustsson, augustss@cs.chalmers.se diff --git a/usr.bin/audio/ctl/ctl.c b/usr.bin/audio/ctl/ctl.c new file mode 100644 index 000000000000..1136aff4b178 --- /dev/null +++ b/usr.bin/audio/ctl/ctl.c @@ -0,0 +1,351 @@ +/* $NetBSD: ctl.c,v 1.1 1997/05/13 17:35:53 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 REGENTS 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 +#include +#include +#include +#include +#include +#include +#include + +FILE *out = stdout; + +char *prog; + +audio_device_t adev; + +audio_info_t info; + +char encbuf[1000]; + +int 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 + char readonly; +} fields[] = { + { "name", &adev.name, STRING, 1 }, + { "version", &adev.version, STRING, 1 }, + { "config", &adev.config, STRING, 1 }, + { "encodings", encbuf, STRING, 1 }, + { "full_duplex", &fullduplex, INT, 0 }, + { "blocksize", &info.blocksize, UINT, 0 }, + { "hiwat", &info.hiwat, UINT, 0 }, + { "lowat", &info.lowat, UINT, 0 }, + { "backlog", &info.backlog, UINT, 0 }, + { "mode", &info.mode, P_R, 1 }, + { "play.rate", &info.play.sample_rate, UINT, 0 }, + { "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.port", &info.play.port, UINT, 0 }, + { "play.seek", &info.play.seek, ULONG, 1 }, + { "play.samples", &info.play.samples, UINT, 1 }, + { "play.eof", &info.play.eof, UINT, 1 }, + { "play.pause", &info.play.pause, UCHAR, 0 }, + { "play.error", &info.play.error, UCHAR, 1 }, + { "play.waiting", &info.play.waiting, UCHAR, 1 }, + { "play.open", &info.play.open, UCHAR, 1 }, + { "play.active", &info.play.active, UCHAR, 1 }, + { "record.rate", &info.record.sample_rate,UINT, 0 }, + { "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.port", &info.record.port, UINT, 0 }, + { "record.seek", &info.record.seek, ULONG, 1 }, + { "record.samples", &info.record.samples, UINT, 1 }, + { "record.eof", &info.record.eof, UINT, 1 }, + { "record.pause", &info.record.pause, UCHAR, 0 }, + { "record.error", &info.record.error, UCHAR, 1 }, + { "record.waiting", &info.record.waiting, UCHAR, 1 }, + { "record.open", &info.record.open, UCHAR, 1 }, + { "record.active", &info.record.active, UCHAR, 1 }, + { "record.errors", &rerror, INT, 1 }, + { 0 } +}; + +struct { + char *ename; + int eno; +} encs[] = { + { "ulaw", AUDIO_ENCODING_ULAW }, + { "alaw", AUDIO_ENCODING_ALAW }, + { "linear", AUDIO_ENCODING_LINEAR }, + { "ulinear", AUDIO_ENCODING_ULINEAR }, + { "adpcm", AUDIO_ENCODING_ADPCM }, + { "ADPCM", AUDIO_ENCODING_ADPCM }, + { "mulaw", AUDIO_ENCODING_ULAW }, + { "linear_le", AUDIO_ENCODING_LINEAR_LE }, + { "ulinear_le", AUDIO_ENCODING_ULINEAR_LE }, + { "linear_be", AUDIO_ENCODING_LINEAR_BE }, + { "ulinear_be", AUDIO_ENCODING_ULINEAR_BE }, + { 0 } +}; + +struct field * +findfield(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(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 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; + default: + errx(1, "Invalid format."); + } +} + +void +rdfield(struct field *p, char *q, char *sep) +{ + u_int v; + int i; + +#if 0 + if (sep) + prfield(p, ": "); +#else + if (sep) + fprintf(out, "%s: ", p->name); +#endif + switch(p->format) { + case UINT: + if (sscanf(q, "%u", 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 format."); + } + if (sep) { + fprintf(out, " -> "); + prfield(p, 0); + fprintf(out, "\n"); + } +} + +void +main(int argc, char **argv) +{ + int fd, r, i, ch, pos; + int aflag = 0, wflag = 0; + char *file = "/dev/sound"; + 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; + /* XXX this test should be more clever */ + if (strcmp(file, "/dev/stdout") == 0) + out = stderr; + break; + case '?': + default: + 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(0); + } + } + argc -= optind; + argv += optind; + + fd = open(file, O_RDWR); + if (fd < 0) + fd = open(file, O_WRONLY); + if (fd < 0) + fd = open(file, O_RDONLY); + if (fd < 0) + err(1, "%s", file); + + if (!wflag) { + if (ioctl(fd, AUDIO_GETDEV, &adev) < 0) + err(1, NULL); + 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, NULL); + if (ioctl(fd, AUDIO_RERROR, &rerror) < 0) + err(1, NULL); + if (ioctl(fd, AUDIO_GETINFO, &info) < 0) + err(1, NULL); + } + + if (argc == 0 && aflag && !wflag) { + for(i = 0; fields[i].name; i++) { + 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->readonly) + warnx("%s is read only", *argv); + else { + rdfield(p, q, sep); + 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"); + } else { + while(argc--) { + p = findfield(*argv); + if (p == 0) + warnx("field %s does not exist", *argv); + else + prfield(p, sep), fprintf(out, "\n"); + argv++; + } + } + } else + goto usage; + exit(0); +} + diff --git a/usr.bin/audioctl/Makefile b/usr.bin/audioctl/Makefile new file mode 100644 index 000000000000..8067f90849ee --- /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 diff --git a/usr.bin/audioctl/audioctl.1 b/usr.bin/audioctl/audioctl.1 new file mode 100644 index 000000000000..50e2b3124a58 --- /dev/null +++ b/usr.bin/audioctl/audioctl.1 @@ -0,0 +1,100 @@ +.\" $NetBSD: audioctl.1,v 1.1 1997/05/13 17:35:52 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 REGENTS 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 audioctl +.Op Fl f Ar file +.Op Fl n +.Fl a +.Nm audioctl +.Op Fl f Ar file +.Op Fl n +.Ar name ... +.Nm audioctl +.Op Fl f Ar file +.Op Fl n +.Fl w +.Ar name=value ... +.Sh DESCRIPTION +The +.Nm audioctl +command displays or sets various audio system driver variables. +If a list of variables is present on the command line, then +.Nm audioctl +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 audioctl +attempts to set the specified variables to the given values. +.Pp +The +.Fl f +flag can be used to give an alternative sound device, the default is +.Pa /dev/sound. +.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 audioctl +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/sound +.It Pa /dev/sound +audio device +.El +.Sh SEE ALSO +.Xr mixerctl 1 , +.Xr audio 4 , +.Xr sysctl 8 +.Sh AUTHOR +Lennart Augustsson, augustss@cs.chalmers.se diff --git a/usr.bin/audioctl/audioctl.c b/usr.bin/audioctl/audioctl.c new file mode 100644 index 000000000000..5698eeffd391 --- /dev/null +++ b/usr.bin/audioctl/audioctl.c @@ -0,0 +1,351 @@ +/* $NetBSD: audioctl.c,v 1.1 1997/05/13 17:35:53 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 REGENTS 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 +#include +#include +#include +#include +#include +#include +#include + +FILE *out = stdout; + +char *prog; + +audio_device_t adev; + +audio_info_t info; + +char encbuf[1000]; + +int 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 + char readonly; +} fields[] = { + { "name", &adev.name, STRING, 1 }, + { "version", &adev.version, STRING, 1 }, + { "config", &adev.config, STRING, 1 }, + { "encodings", encbuf, STRING, 1 }, + { "full_duplex", &fullduplex, INT, 0 }, + { "blocksize", &info.blocksize, UINT, 0 }, + { "hiwat", &info.hiwat, UINT, 0 }, + { "lowat", &info.lowat, UINT, 0 }, + { "backlog", &info.backlog, UINT, 0 }, + { "mode", &info.mode, P_R, 1 }, + { "play.rate", &info.play.sample_rate, UINT, 0 }, + { "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.port", &info.play.port, UINT, 0 }, + { "play.seek", &info.play.seek, ULONG, 1 }, + { "play.samples", &info.play.samples, UINT, 1 }, + { "play.eof", &info.play.eof, UINT, 1 }, + { "play.pause", &info.play.pause, UCHAR, 0 }, + { "play.error", &info.play.error, UCHAR, 1 }, + { "play.waiting", &info.play.waiting, UCHAR, 1 }, + { "play.open", &info.play.open, UCHAR, 1 }, + { "play.active", &info.play.active, UCHAR, 1 }, + { "record.rate", &info.record.sample_rate,UINT, 0 }, + { "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.port", &info.record.port, UINT, 0 }, + { "record.seek", &info.record.seek, ULONG, 1 }, + { "record.samples", &info.record.samples, UINT, 1 }, + { "record.eof", &info.record.eof, UINT, 1 }, + { "record.pause", &info.record.pause, UCHAR, 0 }, + { "record.error", &info.record.error, UCHAR, 1 }, + { "record.waiting", &info.record.waiting, UCHAR, 1 }, + { "record.open", &info.record.open, UCHAR, 1 }, + { "record.active", &info.record.active, UCHAR, 1 }, + { "record.errors", &rerror, INT, 1 }, + { 0 } +}; + +struct { + char *ename; + int eno; +} encs[] = { + { "ulaw", AUDIO_ENCODING_ULAW }, + { "alaw", AUDIO_ENCODING_ALAW }, + { "linear", AUDIO_ENCODING_LINEAR }, + { "ulinear", AUDIO_ENCODING_ULINEAR }, + { "adpcm", AUDIO_ENCODING_ADPCM }, + { "ADPCM", AUDIO_ENCODING_ADPCM }, + { "mulaw", AUDIO_ENCODING_ULAW }, + { "linear_le", AUDIO_ENCODING_LINEAR_LE }, + { "ulinear_le", AUDIO_ENCODING_ULINEAR_LE }, + { "linear_be", AUDIO_ENCODING_LINEAR_BE }, + { "ulinear_be", AUDIO_ENCODING_ULINEAR_BE }, + { 0 } +}; + +struct field * +findfield(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(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 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; + default: + errx(1, "Invalid format."); + } +} + +void +rdfield(struct field *p, char *q, char *sep) +{ + u_int v; + int i; + +#if 0 + if (sep) + prfield(p, ": "); +#else + if (sep) + fprintf(out, "%s: ", p->name); +#endif + switch(p->format) { + case UINT: + if (sscanf(q, "%u", 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 format."); + } + if (sep) { + fprintf(out, " -> "); + prfield(p, 0); + fprintf(out, "\n"); + } +} + +void +main(int argc, char **argv) +{ + int fd, r, i, ch, pos; + int aflag = 0, wflag = 0; + char *file = "/dev/sound"; + 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; + /* XXX this test should be more clever */ + if (strcmp(file, "/dev/stdout") == 0) + out = stderr; + break; + case '?': + default: + 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(0); + } + } + argc -= optind; + argv += optind; + + fd = open(file, O_RDWR); + if (fd < 0) + fd = open(file, O_WRONLY); + if (fd < 0) + fd = open(file, O_RDONLY); + if (fd < 0) + err(1, "%s", file); + + if (!wflag) { + if (ioctl(fd, AUDIO_GETDEV, &adev) < 0) + err(1, NULL); + 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, NULL); + if (ioctl(fd, AUDIO_RERROR, &rerror) < 0) + err(1, NULL); + if (ioctl(fd, AUDIO_GETINFO, &info) < 0) + err(1, NULL); + } + + if (argc == 0 && aflag && !wflag) { + for(i = 0; fields[i].name; i++) { + 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->readonly) + warnx("%s is read only", *argv); + else { + rdfield(p, q, sep); + 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"); + } else { + while(argc--) { + p = findfield(*argv); + if (p == 0) + warnx("field %s does not exist", *argv); + else + prfield(p, sep), fprintf(out, "\n"); + argv++; + } + } + } else + goto usage; + exit(0); +} + diff --git a/usr.bin/mixerctl/Makefile b/usr.bin/mixerctl/Makefile new file mode 100644 index 000000000000..dfd62de2b346 --- /dev/null +++ b/usr.bin/mixerctl/Makefile @@ -0,0 +1,6 @@ +# $NetBSD: Makefile,v 1.1 1997/05/13 17:35:54 augustss Exp $ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= mixerctl + +.include diff --git a/usr.bin/mixerctl/mixerctl.1 b/usr.bin/mixerctl/mixerctl.1 new file mode 100644 index 000000000000..47ed30742afe --- /dev/null +++ b/usr.bin/mixerctl/mixerctl.1 @@ -0,0 +1,97 @@ +.\" $NetBSD: mixerctl.1,v 1.1 1997/05/13 17:35:55 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 REGENTS 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 MIXERCTL 1 +.Os +.Sh NAME +.Nm mixerctl +.Nd control audio mixing +.Sh SYNOPSIS +.Nm mixerctl +.Op Fl f Ar file +.Op Fl n +.Op Fl v +.Fl a +.Nm mixerctl +.Op Fl f Ar file +.Op Fl n +.Op Fl v +.Ar name ... +.Nm mixerctl +.Op Fl f Ar file +.Op Fl n +.Fl w +.Ar name=value ... +.Sh DESCRIPTION +The +.Nm mixerctl +command displays or sets various audio system mixing variables. +If a list of variables is present on the command line, then +.Nm mixerctl +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 mixerctl +attempts to set the specified variables to the given values. +.Pp +The +.Fl f +flag can be used to give an alternative mixer device, the default is +.Pa /dev/mixer. +.Pp +The +.Fl n +flag suppresses printing of the variable name. +.Pp +The +.Fl v +flag shows the possible values of enumeration and set valued +variables. Enumerated values are shown in [] and set values +are shown in {}. +.Sh FILES +.Bl -tag -width /dev/mixer +.It Pa /dev/mixer +mixer audio device +.El +.Sh SEE ALSO +.Xr audioctl 1 , +.Xr audio 4 , +.Xr sysctl 8 +.Sh AUTHOR +Lennart Augustsson, augustss@cs.chalmers.se diff --git a/usr.bin/mixerctl/mixerctl.c b/usr.bin/mixerctl/mixerctl.c new file mode 100644 index 000000000000..cc88b975d066 --- /dev/null +++ b/usr.bin/mixerctl/mixerctl.c @@ -0,0 +1,326 @@ +/* $NetBSD: mixerctl.c,v 1.1 1997/05/13 17:35:55 augustss Exp $ */ + +/* + * Copyright (c) 1997 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Author: Lennart Augustsson, with some code and ideas from Chuck Cranor. + * + * 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 REGENTS 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 +#include +#include +#include +#include +#include +#include +#include +#include + +FILE *out = stdout; + +char *prog; + +struct field { + char *name; + mixer_ctrl_t *valp; + mixer_devinfo_t *infp; +} *fields, *rfields; + +mixer_ctrl_t *values; +mixer_devinfo_t *infos; + +char * +catstr(char *p, char *q) +{ + char *r = malloc(strlen(p) + strlen(q) + 2); + strcpy(r, p); + strcat(r, "."); + strcat(r, q); + return r; +} + +struct field * +findfield(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(struct field *p, char *sep, int prvalset) +{ + mixer_ctrl_t *m; + int i, v; + + if (sep) + fprintf(out, "%s%s", p->name, sep); + m = p->valp; + switch(m->type) { + case AUDIO_MIXER_ENUM: + fprintf(out, "%s", p->infp->un.e.member[m->un.ord].label.name); + if (prvalset) { + fprintf(out, " [ "); + for(i = 0; i < p->infp->un.e.num_mem; i++) + fprintf(out, "%s ", p->infp->un.e.member[i].label.name); + fprintf(out, "]"); + } + break; + case AUDIO_MIXER_SET: + for(i = 0, v = m->un.mask; v; i++, v >>= 1) + if (v & 1) + fprintf(out, "%s%s", p->infp->un.s.member[i].label.name, + v >> 1 ? "," : ""); + if (prvalset) { + fprintf(out, " { "); + for(i = 0; i < p->infp->un.s.num_mem; i++) + fprintf(out, "%s ", p->infp->un.s.member[i].label.name); + fprintf(out, "}"); + } + break; + case AUDIO_MIXER_VALUE: + if (m->un.value.num_channels == 1) + fprintf(out, "%d", m->un.value.level[0]); + else + fprintf(out, "%d,%d", m->un.value.level[0], + m->un.value.level[1]); + break; + default: + errx(1, "Invalid format."); + } +} + +void +rdfield(struct field *p, char *q, char *sep) +{ + mixer_ctrl_t *m; + int v, v0, v1; + int i; + char *s; + + if (sep) + prfield(p, ": ", 0); + + m = p->valp; + switch(m->type) { + case AUDIO_MIXER_ENUM: + for(i = 0; i < p->infp->un.e.num_mem; i++) + if (strcmp(p->infp->un.e.member[i].label.name, q) == 0) + break; + if (i < p->infp->un.e.num_mem) + m->un.ord = i; + else + warnx("Bad enum value %s", q); + break; + case AUDIO_MIXER_SET: + for(v = 0; q && *q; q = s) { + s = strchr(q, ','); + if (s) + *s++ = 0; + for(i = 0; i < p->infp->un.s.num_mem; i++) + if (strcmp(p->infp->un.s.member[i].label.name, q) == 0) + break; + if (i < p->infp->un.s.num_mem) + m->un.mask = 1 << i; + else + warnx("Bad enum value %s", q); + } + break; + case AUDIO_MIXER_VALUE: + if (m->un.value.num_channels == 1) { + if (sscanf(q, "%d", &v) == 1) { + m->un.value.level[0] = v; + } else { + warnx("Bad number %s", q); + } + } else { + if (sscanf(q, "%d,%d", &v0, &v1) == 2) { + m->un.value.level[0] = v0; + m->un.value.level[1] = v1; + } else if (sscanf(q, "%d", &v) == 1) { + m->un.value.level[0] = m->un.value.level[1] = v; + } else { + warnx("Bad numbers %s", q); + } + } + break; + default: + errx(1, "Invalid format."); + } + + if (sep) { + fprintf(out, " -> "); + prfield(p, 0, 0); + fprintf(out, "\n"); + } +} + +void +main(int argc, char **argv) +{ + int fd, r, i, j, ch, pos; + int aflag = 0, wflag = 0, vflag = 0; + char *file = "/dev/mixer"; + char *sep = "="; + mixer_devinfo_t dinfo; + int ndev; + + prog = *argv; + + while ((ch = getopt(argc, argv, "af:nvw")) != -1) { + switch(ch) { + case 'a': + aflag++; + break; + case 'w': + wflag++; + break; + case 'v': + vflag++; + break; + case 'n': + sep = 0; + break; + case 'f': + file = optarg; + break; + case '?': + default: + usage: + fprintf(out, "%s [-f file] [-v] [-n] name ...\n", prog); + fprintf(out, "%s [-f file] [-v] [-n] -w name=value ...\n", prog); + fprintf(out, "%s [-f file] [-v] [-n] -a\n", prog); + exit(0); + } + } + argc -= optind; + argv += optind; + + fd = open(file, O_RDWR); + if (fd < 0) + err(1, "%s", file); + + for(ndev = 0; ; ndev++) { + dinfo.index = ndev; + if (ioctl(fd, AUDIO_MIXER_DEVINFO, &dinfo) < 0) + break; + } + rfields = calloc(ndev, sizeof *rfields); + fields = calloc(ndev, sizeof *fields); + infos = calloc(ndev, sizeof *infos); + values = calloc(ndev, sizeof *values); + + for(i = 0; i < ndev; i++) { + infos[i].index = i; + ioctl(fd, AUDIO_MIXER_DEVINFO, &infos[i]); + } + + for(i = 0; i < ndev; i++) { + if (infos[i].mixer_class >= 0 && infos[i].mixer_class < ndev) + rfields[i].name = catstr(infos[infos[i].mixer_class].label.name, + infos[i].label.name); + else + rfields[i].name = infos[i].label.name; + rfields[i].valp = &values[i]; + rfields[i].infp = &infos[i]; + } + + for(i = 0; i < ndev; i++) { + values[i].dev = i; + values[i].type = infos[i].type; + if (infos[i].type != AUDIO_MIXER_CLASS) { + values[i].un.value.num_channels = 2; + if (ioctl(fd, AUDIO_MIXER_READ, &values[i]) < 0) { + values[i].un.value.num_channels = 1; + if (ioctl(fd, AUDIO_MIXER_READ, &values[i]) < 0) + err(1, NULL); + } + } + } + + for(j = i = 0; i < ndev; i++) { + if (infos[i].type != AUDIO_MIXER_CLASS && + infos[i].type != -1) { + fields[j++] = rfields[i]; + for(pos = infos[i].next; pos != AUDIO_MIXER_LAST; + pos = infos[pos].next) { + fields[j] = rfields[pos]; + fields[j].name = catstr(rfields[i].name, + infos[pos].label.name); + infos[pos].type = -1; + j++; + } + } + } + + if (argc == 0 && aflag && !wflag) { + for(i = 0; fields[i].name; i++) { + prfield(&fields[i], sep, vflag); + fprintf(out, "\n"); + } + } else if (argc > 0 && !aflag) { + struct field *p; + if (wflag) { + 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 { + rdfield(p, q, sep); + if (ioctl(fd, AUDIO_MIXER_WRITE, p->valp) < 0) + warn(NULL); + } + } else { + warnx("No `=' in %s", *argv); + } + argv++; + } + } else { + while(argc--) { + p = findfield(*argv); + if (p == 0) + warnx("field %s does not exist", *argv); + else + prfield(p, sep, vflag), fprintf(out, "\n"); + argv++; + } + } + } else + goto usage; + exit(0); +}