mixer.c revision 144999
16448Sache/*
26448Sache *	This is an example of a mixer program for Linux
36448Sache *
46448Sache *	updated 1/1/93 to add stereo, level query, broken
58857Srgrimes *      	devmask kludge - cmetz@thor.tjhsst.edu
66448Sache *
76448Sache * (C) Craig Metz and Hannu Savolainen 1993.
86448Sache *
96448Sache * You may do anything you wish with this program.
1029612Sjmg *
1129612Sjmg * ditto for my modifications (John-Mark Gurney, 1997)
126448Sache */
136448Sache
14114601Sobrien#include <sys/cdefs.h>
15114601Sobrien__FBSDID("$FreeBSD: head/usr.sbin/mixer/mixer.c 144999 2005-04-13 07:11:54Z mdodd $");
1629963Scharnier
1729963Scharnier#include <err.h>
1829963Scharnier#include <fcntl.h>
196448Sache#include <stdio.h>
206448Sache#include <string.h>
2129612Sjmg#include <stdlib.h>
2229612Sjmg#include <unistd.h>
236448Sache#include <sys/soundcard.h>
246448Sache
2578778Sddconst char *names[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_NAMES;
266448Sache
2729612Sjmgvoid usage(int devmask, int recmask);
2829612Sjmgint res_name(const char *name, int mask);
2929612Sjmgvoid print_recsrc(int recsrc);
306448Sache
3129612Sjmgvoid
3229612Sjmgusage(int devmask, int recmask)
336448Sache{
3429612Sjmg	int i, n;
356448Sache
36144999Smdodd	printf("usage: mixer [-f device] [-s | -S] [dev [+|-][voll[:[+|-]volr]] ...\n"
37144999Smdodd	       "       mixer [-f device] [-s | -S] recsrc ...\n"
38144999Smdodd	       "       mixer [-f device] [-s | -S] {^|+|-|=}rec rdev ... \n");
3929753Sache	printf(" devices: ");
4029612Sjmg	for (i = 0, n = 0; i < SOUND_MIXER_NRDEVICES; i++)
416448Sache		if ((1 << i) & devmask)  {
426448Sache			if (n)
4329612Sjmg				printf(", ");
4469258Skris			printf("%s", names[i]);
456448Sache			n = 1;
468857Srgrimes		}
4729753Sache	printf("\n rec devices: ");
4829612Sjmg	for (i = 0, n = 0; i < SOUND_MIXER_NRDEVICES; i++)
4929612Sjmg		if ((1 << i) & recmask)  {
5029612Sjmg			if (n)
5129612Sjmg				printf(", ");
5269258Skris			printf("%s", names[i]);
5329612Sjmg			n = 1;
5429612Sjmg		}
5529612Sjmg	printf("\n");
566448Sache	exit(1);
576448Sache}
586448Sache
5929612Sjmgint
6029612Sjmgres_name(const char *name, int mask)
616448Sache{
6229612Sjmg	int foo;
6329612Sjmg
6429612Sjmg	for (foo = 0; foo < SOUND_MIXER_NRDEVICES; foo++)
6529612Sjmg		if ((1 << foo) & mask && !strcmp(names[foo], name))
6629612Sjmg			break;
6729612Sjmg
6829612Sjmg	return foo == SOUND_MIXER_NRDEVICES ? -1 : foo;
6929612Sjmg}
7029612Sjmg
7129612Sjmgvoid
7229612Sjmgprint_recsrc(int recsrc)
7329612Sjmg{
746448Sache	int i, n = 0;
756448Sache	fprintf(stderr, "Recording source: ");
766448Sache
776448Sache	for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
786448Sache		if ((1 << i) & recsrc) {
796448Sache			if (n)
806448Sache				fprintf(stderr, ", ");
8169258Skris			fprintf(stderr, "%s", names[i]);
826448Sache			n = 1;
836448Sache		}
846448Sache	fprintf(stderr, "\n");
856448Sache}
866448Sache
878857Srgrimesint
886448Sachemain(int argc, char *argv[])
896448Sache{
906448Sache	int foo, bar, baz, dev;
9129612Sjmg	int devmask = 0, recmask = 0, recsrc = 0, orecsrc;
92144999Smdodd	int dusage = 0, drecsrc = 0, shortflag = 0, Shortflag = 0;
9375334Sgreid	int l = 0, r = 0, t = 0;
94113299Smdodd	char lstr[5], rstr[5];
95113299Smdodd	int n = 0, lrel = 0, rrel = 0;
96124830Sgrehan	int ch;
976448Sache
9829612Sjmg	char *name;
996448Sache
10029612Sjmg	name = strdup("/dev/mixer");
10129612Sjmg
1026448Sache	if (!strcmp(argv[0], "mixer2"))
10329612Sjmg		name = strdup("/dev/mixer1");
10429612Sjmg	else if (!strcmp(argv[0], "mixer3"))
10529612Sjmg		name = strdup("/dev/mixer2");
1066448Sache
107144999Smdodd	while ((ch = getopt(argc, argv, "f:sS")) != -1)
10864657Ssobomax		switch (ch) {
10964657Ssobomax			case 'f':
11064657Ssobomax				name = strdup(optarg);
11164657Ssobomax				break;
11264657Ssobomax			case 's':
11364657Ssobomax				shortflag = 1;
11464657Ssobomax				break;
115144999Smdodd			case 'S':
116144999Smdodd				Shortflag = 1;
117144999Smdodd				break;
11864657Ssobomax			default:
11964657Ssobomax				dusage = 1;
12064657Ssobomax		}
12164657Ssobomax	argc -= (optind - 1);
12264657Ssobomax	argv += (optind - 1);
12329612Sjmg
12429963Scharnier	if ((baz = open(name, O_RDWR)) < 0)
12529963Scharnier		err(1, "%s", name);
12629612Sjmg	free(name);
12729963Scharnier	if (ioctl(baz, SOUND_MIXER_READ_DEVMASK, &devmask) == -1)
12830028Scharnier		err(1, "SOUND_MIXER_READ_DEVMASK");
12929963Scharnier	if (ioctl(baz, SOUND_MIXER_READ_RECMASK, &recmask) == -1)
13030028Scharnier		err(1, "SOUND_MIXER_READ_RECMASK");
13129963Scharnier	if (ioctl(baz, SOUND_MIXER_READ_RECSRC, &recsrc) == -1)
13230028Scharnier		err(1, "SOUND_MIXER_READ_RECSRC");
13329612Sjmg	orecsrc = recsrc;
1346448Sache
13564657Ssobomax	if ((argc == 1) && (dusage == 0)) {
13613803Smpp		for (foo = 0; foo < SOUND_MIXER_NRDEVICES; foo++) {
13713803Smpp			if (!((1 << foo) & devmask))
13813803Smpp				continue;
13913803Smpp			if (ioctl(baz, MIXER_READ(foo),&bar)== -1) {
14029963Scharnier			   	warn("MIXER_READ");
14113803Smpp				continue;
14213803Smpp			}
143144999Smdodd			if (Shortflag)
144144999Smdodd				printf("%s:%d:%d ", names[foo], bar & 0x7f,
145144999Smdodd				       (bar >> 8) & 0x7f);
146144999Smdodd			else if (shortflag)
147116388Sgrog				printf("%s %d:%d ", names[foo], bar & 0x7f,
148116388Sgrog				       (bar >> 8) & 0x7f);
14960741Sjkh			else
150116388Sgrog				printf("Mixer %-8s is currently set to %3d:%d\n",
151116388Sgrog				       names[foo], bar & 0x7f, (bar >> 8) & 0x7f);
15213803Smpp		}
153116388Sgrog		if (ioctl(baz, SOUND_MIXER_READ_RECSRC, &recsrc) == -1)
154116388Sgrog			err(1, "SOUND_MIXER_READ_RECSRC");
155116388Sgrog		print_recsrc(recsrc);
15613803Smpp		return(0);
15713803Smpp	}
15813803Smpp
15929612Sjmg	argc--; argv++;
1606448Sache
16175334Sgreid	while ((argc > 0) && (dusage == 0)) {
16229612Sjmg		if (!strcmp("recsrc", *argv)) {
16329612Sjmg			drecsrc = 1;
16429612Sjmg			argc--; argv++;
16529612Sjmg			continue;
16629612Sjmg		} else if (argc > 1 && !strcmp("rec", *argv + 1)) {
16729612Sjmg			if (**argv != '+' && **argv != '-' &&
16829612Sjmg			    **argv != '=' && **argv != '^') {
16964657Ssobomax				warnx("unknown modifier: %c", **argv);
17029612Sjmg				dusage = 1;
17164657Ssobomax				break;
17213435Smpp			}
17329612Sjmg			if ((dev = res_name(argv[1], recmask)) == -1) {
17464657Ssobomax				warnx("unknown recording device: %s", argv[1]);
17529612Sjmg				dusage = 1;
17664657Ssobomax				break;
1776448Sache			}
17829612Sjmg			switch(**argv) {
17929612Sjmg			case '+':
1806448Sache				recsrc |= (1 << dev);
18129612Sjmg				break;
18229612Sjmg			case '-':
1836448Sache				recsrc &= ~(1 << dev);
18429612Sjmg				break;
18529612Sjmg			case '=':
18629612Sjmg				recsrc = (1 << dev);
18729612Sjmg				break;
18829612Sjmg			case '^':
18929612Sjmg				recsrc ^= (1 << dev);
19029612Sjmg				break;
19129612Sjmg			}
19229612Sjmg			drecsrc = 1;
19329612Sjmg			argc -= 2; argv += 2;
19429612Sjmg			continue;
19529612Sjmg		}
1966448Sache
19775334Sgreid		if ((t = sscanf(*argv, "%d:%d", &l, &r)) > 0) {
19875334Sgreid			dev = 0;
19975334Sgreid		}
20075334Sgreid		else if((dev = res_name(*argv, devmask)) == -1) {
20164657Ssobomax			warnx("unknown device: %s", *argv);
20229612Sjmg			dusage = 1;
20364657Ssobomax			break;
20429612Sjmg		}
20529612Sjmg
206113299Smdodd#define	issign(c)	(((c) == '+') || ((c) == '-'))
207113299Smdodd
208113299Smdodd		if (argc > 1) {
209113299Smdodd			n = sscanf(argv[1], "%7[^:]:%7s", lstr, rstr);
210113299Smdodd			if (n > 0) {
211113299Smdodd				if (issign(lstr[0]))
212113299Smdodd					lrel = rrel = 1;
213113299Smdodd				l = atoi(lstr);
214113299Smdodd			}
215113299Smdodd			if (n > 1) {
216113299Smdodd				rrel = 0;
217113299Smdodd				if (issign(rstr[0]))
218113299Smdodd					rrel = 1;
219113299Smdodd				r = atoi(rstr);
220113299Smdodd			}
221113299Smdodd		}
222113299Smdodd
223113299Smdodd		switch(argc > 1 ? n : t) {
22429612Sjmg		case 0:
22529612Sjmg			if (ioctl(baz, MIXER_READ(dev),&bar)== -1) {
22629963Scharnier				warn("MIXER_READ");
22729612Sjmg				argc--; argv++;
22829612Sjmg				continue;
2296448Sache			}
230144999Smdodd			if (Shortflag)
231144999Smdodd				printf("%s:%d:%d ", names[dev], bar & 0x7f,
232144999Smdodd				       (bar >> 8) & 0x7f);
233144999Smdodd			else if (shortflag)
234116388Sgrog				printf("%s %d:%d ", names[dev], bar & 0x7f,
235116388Sgrog				       (bar >> 8) & 0x7f);
23660741Sjkh			else
23760741Sjkh				printf("Mixer %-8s is currently set to %3d:%d\n",
23860741Sjkh				  names[dev], bar & 0x7f, (bar >> 8) & 0x7f);
2396448Sache
24029612Sjmg			argc--; argv++;
24129612Sjmg			break;
24229612Sjmg		case 1:
24329612Sjmg			r = l;
24429612Sjmg		case 2:
245113299Smdodd			if (ioctl(baz, MIXER_READ(dev),&bar)== -1) {
246113299Smdodd				warn("MIXER_READ");
247113299Smdodd				argc--; argv++;
248113299Smdodd				continue;
249113299Smdodd			}
250113299Smdodd
251113299Smdodd			if (lrel)
252113299Smdodd				l = (bar & 0x7f) + l;
253113299Smdodd			if (rrel)
254113299Smdodd				r = ((bar >> 8) & 0x7f) + r;
255113299Smdodd
25629612Sjmg			if (l < 0)
25729612Sjmg				l = 0;
25829612Sjmg			else if (l > 100)
25929612Sjmg				l = 100;
26029612Sjmg			if (r < 0)
26129612Sjmg				r = 0;
26229612Sjmg			else if (r > 100)
26329612Sjmg				r = 100;
2648857Srgrimes
265144999Smdodd			if (!Shortflag)
266144999Smdodd				printf("Setting the mixer %s from %d:%d to %d:%d.\n",
267144999Smdodd				       names[dev], bar & 0x7f, (bar >> 8) & 0x7f, l, r);
268108421Sjmallett
26929612Sjmg			l |= r << 8;
27029612Sjmg			if (ioctl(baz, MIXER_WRITE(dev), &l) == -1)
27129963Scharnier				warn("WRITE_MIXER");
2726448Sache
27329612Sjmg			argc -= 2; argv += 2;
27429612Sjmg 			break;
2756448Sache		}
2766448Sache	}
2776448Sache
27864657Ssobomax	if (dusage) {
27964657Ssobomax		close(baz);
28064657Ssobomax		usage(devmask, recmask);
28164657Ssobomax		/* Not reached */
28264657Ssobomax	}
28364657Ssobomax
28429612Sjmg	if (orecsrc != recsrc)
28529963Scharnier		if (ioctl(baz, SOUND_MIXER_WRITE_RECSRC, &recsrc) == -1)
28630028Scharnier			err(1, "SOUND_MIXER_WRITE_RECSRC");
28729612Sjmg
28829612Sjmg	if (drecsrc) {
28929963Scharnier		if (ioctl(baz, SOUND_MIXER_READ_RECSRC, &recsrc) == -1)
29030028Scharnier			err(1, "SOUND_MIXER_READ_RECSRC");
29129612Sjmg		print_recsrc(recsrc);
29229612Sjmg	}
29329612Sjmg
2946448Sache	close(baz);
29529612Sjmg
29629612Sjmg	exit(0);
2976448Sache}
298