freebsd-nq/usr.sbin/mixer/mixer.c
Jung-uk Kim 35ebab0a33 - Check device masks and bypass printing headers if capable device does
not exist.  /etc/rc.d/mixer tried to restore non-existent recording
source because /var/var/db/mixer*-state contains '=rec' for example.
- Remove hardcoded mixer2 and mixer3 and do the right thing.
- Replace getopt(3) with hand-rolled option parser.  It was not able
to handle 'mixer -rec mic' although it is a valid command.
- Make '-s' and '-S' mutualy exclusive as mixer(8) says.
- Do not re-read recording source unless it has been modified.
2008-03-15 01:09:47 +00:00

330 lines
6.9 KiB
C

/*
* This is an example of a mixer program for Linux
*
* updated 1/1/93 to add stereo, level query, broken
* devmask kludge - cmetz@thor.tjhsst.edu
*
* (C) Craig Metz and Hannu Savolainen 1993.
*
* You may do anything you wish with this program.
*
* ditto for my modifications (John-Mark Gurney, 1997)
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <err.h>
#include <fcntl.h>
#include <libgen.h>
#include <limits.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/soundcard.h>
const char *names[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_NAMES;
void usage(int devmask, int recmask);
int res_name(const char *name, int mask);
void print_recsrc(int recsrc, int recmask, int shortflag);
void
usage(int devmask, int recmask)
{
int i, n;
printf("usage: mixer [-f device] [-s | -S] [dev [+|-][voll[:[+|-]volr]] ...\n"
" mixer [-f device] [-s | -S] recsrc ...\n"
" mixer [-f device] [-s | -S] {^|+|-|=}rec rdev ... \n");
if (devmask != 0) {
printf(" devices: ");
for (i = 0, n = 0; i < SOUND_MIXER_NRDEVICES; i++)
if ((1 << i) & devmask) {
if (n)
printf(", ");
printf("%s", names[i]);
n = 1;
}
}
if (recmask != 0) {
printf("\n rec devices: ");
for (i = 0, n = 0; i < SOUND_MIXER_NRDEVICES; i++)
if ((1 << i) & recmask) {
if (n)
printf(", ");
printf("%s", names[i]);
n = 1;
}
}
printf("\n");
exit(1);
}
int
res_name(const char *name, int mask)
{
int foo;
for (foo = 0; foo < SOUND_MIXER_NRDEVICES; foo++)
if ((1 << foo) & mask && !strcmp(names[foo], name))
break;
return foo == SOUND_MIXER_NRDEVICES ? -1 : foo;
}
void
print_recsrc(int recsrc, int recmask, int shortflag)
{
int i, n = 0;
if (recmask == 0)
return;
if (!shortflag)
printf("Recording source: ");
for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
if ((1 << i) & recsrc) {
if (shortflag) {
if (n)
printf(" +rec ");
else
printf("=rec ");
} else if (n)
printf(", ");
printf("%s", names[i]);
n = 1;
}
if (!shortflag)
printf("\n");
}
int
main(int argc, char *argv[])
{
char mixer[PATH_MAX] = "/dev/mixer";
char *name, *eptr;
int foo, bar, baz, dev;
int devmask = 0, recmask = 0, recsrc = 0, orecsrc;
int dusage = 0, drecsrc = 0, shortflag = 0, Shortflag = 0;
int l = 0, r = 0, t = 0;
char lstr[5], rstr[5];
int n, lrel = 0, rrel = 0;
char ch;
if ((name = strdup(basename(argv[0]))) == NULL)
err(1, "strdup()");
if (strncmp(name, "mixer", 5) == 0 && name[5] != '\0') {
n = strtol(name + 5, &eptr, 10) - 1;
if (n > 0 && *eptr == '\0')
snprintf(mixer, PATH_MAX - 1, "/dev/mixer%d", n);
}
free(name);
name = mixer;
n = 1;
for (;;) {
if (n >= argc || *argv[n] != '-')
break;
if (strlen(argv[n]) != 2) {
if (strcmp(argv[n] + 1, "rec") != 0)
dusage = 1;
break;
}
ch = *(argv[n] + 1);
if (ch == 'f' && n < argc - 1) {
name = argv[n + 1];
n += 2;
} else if (ch == 's') {
shortflag = 1;
n++;
} else if (ch == 'S') {
Shortflag = 1;
n++;
} else {
dusage = 1;
break;
}
}
if (shortflag && Shortflag)
dusage = 1;
argc -= n - 1;
argv += n - 1;
if ((baz = open(name, O_RDWR)) < 0)
err(1, "%s", name);
if (ioctl(baz, SOUND_MIXER_READ_DEVMASK, &devmask) == -1)
err(1, "SOUND_MIXER_READ_DEVMASK");
if (ioctl(baz, SOUND_MIXER_READ_RECMASK, &recmask) == -1)
err(1, "SOUND_MIXER_READ_RECMASK");
if (ioctl(baz, SOUND_MIXER_READ_RECSRC, &recsrc) == -1)
err(1, "SOUND_MIXER_READ_RECSRC");
orecsrc = recsrc;
if ((argc == 1) && (dusage == 0)) {
for (foo = 0; foo < SOUND_MIXER_NRDEVICES; foo++) {
if (!((1 << foo) & devmask))
continue;
if (ioctl(baz, MIXER_READ(foo),&bar)== -1) {
warn("MIXER_READ");
continue;
}
if (Shortflag)
printf("%s:%d:%d ", names[foo], bar & 0x7f,
(bar >> 8) & 0x7f);
else if (shortflag)
printf("%s %d:%d ", names[foo], bar & 0x7f,
(bar >> 8) & 0x7f);
else
printf("Mixer %-8s is currently set to %3d:%d\n",
names[foo], bar & 0x7f, (bar >> 8) & 0x7f);
}
if (ioctl(baz, SOUND_MIXER_READ_RECSRC, &recsrc) == -1)
err(1, "SOUND_MIXER_READ_RECSRC");
print_recsrc(recsrc, recmask, shortflag || Shortflag);
return(0);
}
argc--; argv++;
while ((argc > 0) && (dusage == 0)) {
if (!strcmp("recsrc", *argv)) {
drecsrc = 1;
argc--; argv++;
continue;
} else if (argc > 1 && !strcmp("rec", *argv + 1)) {
if (**argv != '+' && **argv != '-' &&
**argv != '=' && **argv != '^') {
warnx("unknown modifier: %c", **argv);
dusage = 1;
break;
}
if ((dev = res_name(argv[1], recmask)) == -1) {
warnx("unknown recording device: %s", argv[1]);
dusage = 1;
break;
}
switch(**argv) {
case '+':
recsrc |= (1 << dev);
break;
case '-':
recsrc &= ~(1 << dev);
break;
case '=':
recsrc = (1 << dev);
break;
case '^':
recsrc ^= (1 << dev);
break;
}
drecsrc = 1;
argc -= 2; argv += 2;
continue;
}
if ((t = sscanf(*argv, "%d:%d", &l, &r)) > 0) {
dev = 0;
}
else if((dev = res_name(*argv, devmask)) == -1) {
warnx("unknown device: %s", *argv);
dusage = 1;
break;
}
#define issign(c) (((c) == '+') || ((c) == '-'))
if (argc > 1) {
n = sscanf(argv[1], "%7[^:]:%7s", lstr, rstr);
if (n > 0) {
if (issign(lstr[0]))
lrel = rrel = 1;
l = atoi(lstr);
}
if (n > 1) {
rrel = 0;
if (issign(rstr[0]))
rrel = 1;
r = atoi(rstr);
}
}
switch(argc > 1 ? n : t) {
case 0:
if (ioctl(baz, MIXER_READ(dev),&bar)== -1) {
warn("MIXER_READ");
argc--; argv++;
continue;
}
if (Shortflag)
printf("%s:%d:%d ", names[dev], bar & 0x7f,
(bar >> 8) & 0x7f);
else if (shortflag)
printf("%s %d:%d ", names[dev], bar & 0x7f,
(bar >> 8) & 0x7f);
else
printf("Mixer %-8s is currently set to %3d:%d\n",
names[dev], bar & 0x7f, (bar >> 8) & 0x7f);
argc--; argv++;
break;
case 1:
r = l;
case 2:
if (ioctl(baz, MIXER_READ(dev),&bar)== -1) {
warn("MIXER_READ");
argc--; argv++;
continue;
}
if (lrel)
l = (bar & 0x7f) + l;
if (rrel)
r = ((bar >> 8) & 0x7f) + r;
if (l < 0)
l = 0;
else if (l > 100)
l = 100;
if (r < 0)
r = 0;
else if (r > 100)
r = 100;
if (!Shortflag)
printf("Setting the mixer %s from %d:%d to %d:%d.\n",
names[dev], bar & 0x7f, (bar >> 8) & 0x7f, l, r);
l |= r << 8;
if (ioctl(baz, MIXER_WRITE(dev), &l) == -1)
warn("WRITE_MIXER");
argc -= 2; argv += 2;
break;
}
}
if (dusage) {
close(baz);
usage(devmask, recmask);
/* Not reached */
}
if (orecsrc != recsrc) {
if (ioctl(baz, SOUND_MIXER_WRITE_RECSRC, &recsrc) == -1)
err(1, "SOUND_MIXER_WRITE_RECSRC");
if (ioctl(baz, SOUND_MIXER_READ_RECSRC, &recsrc) == -1)
err(1, "SOUND_MIXER_READ_RECSRC");
}
if (drecsrc)
print_recsrc(recsrc, recmask, shortflag || Shortflag);
close(baz);
exit(0);
}