Add audio utility programs.

The audio device can be inspected and changed by audioctl,
and the mixer device by mixerctl.  The command syntax was
inspired by sysctl.
This commit is contained in:
augustss 1997-05-13 17:35:50 +00:00
parent 1aa91b893d
commit 9d5e7c9a4c
9 changed files with 1342 additions and 5 deletions

View File

@ -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 <bsd.own.mk> # 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 \

View File

@ -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

351
usr.bin/audio/ctl/ctl.c Normal file
View File

@ -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 <stdio.h>
#include <fcntl.h>
#include <err.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/audioio.h>
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);
}

View File

@ -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>

100
usr.bin/audioctl/audioctl.1 Normal file
View File

@ -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

351
usr.bin/audioctl/audioctl.c Normal file
View File

@ -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 <stdio.h>
#include <fcntl.h>
#include <err.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/audioio.h>
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);
}

View File

@ -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 <bsd.prog.mk>

View File

@ -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

326
usr.bin/mixerctl/mixerctl.c Normal file
View File

@ -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 <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <err.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/audioio.h>
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);
}