mixer.c revision 177195
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 177195 2008-03-15 01:09:47Z jkim $");
1629963Scharnier
1729963Scharnier#include <err.h>
1829963Scharnier#include <fcntl.h>
19177195Sjkim#include <libgen.h>
20177195Sjkim#include <limits.h>
216448Sache#include <stdio.h>
226448Sache#include <string.h>
2329612Sjmg#include <stdlib.h>
2429612Sjmg#include <unistd.h>
256448Sache#include <sys/soundcard.h>
266448Sache
2778778Sddconst char *names[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_NAMES;
286448Sache
2929612Sjmgvoid usage(int devmask, int recmask);
3029612Sjmgint res_name(const char *name, int mask);
31177195Sjkimvoid print_recsrc(int recsrc, int recmask, int shortflag);
326448Sache
3329612Sjmgvoid
3429612Sjmgusage(int devmask, int recmask)
356448Sache{
3629612Sjmg	int i, n;
376448Sache
38144999Smdodd	printf("usage: mixer [-f device] [-s | -S] [dev [+|-][voll[:[+|-]volr]] ...\n"
39144999Smdodd	       "       mixer [-f device] [-s | -S] recsrc ...\n"
40144999Smdodd	       "       mixer [-f device] [-s | -S] {^|+|-|=}rec rdev ... \n");
41177195Sjkim	if (devmask != 0) {
42177195Sjkim		printf(" devices: ");
43177195Sjkim		for (i = 0, n = 0; i < SOUND_MIXER_NRDEVICES; i++)
44177195Sjkim			if ((1 << i) & devmask)  {
45177195Sjkim				if (n)
46177195Sjkim					printf(", ");
47177195Sjkim				printf("%s", names[i]);
48177195Sjkim				n = 1;
49177195Sjkim			}
50177195Sjkim	}
51177195Sjkim	if (recmask != 0) {
52177195Sjkim		printf("\n rec devices: ");
53177195Sjkim		for (i = 0, n = 0; i < SOUND_MIXER_NRDEVICES; i++)
54177195Sjkim			if ((1 << i) & recmask)  {
55177195Sjkim				if (n)
56177195Sjkim					printf(", ");
57177195Sjkim				printf("%s", names[i]);
58177195Sjkim				n = 1;
59177195Sjkim			}
60177195Sjkim	}
6129612Sjmg	printf("\n");
626448Sache	exit(1);
636448Sache}
646448Sache
6529612Sjmgint
6629612Sjmgres_name(const char *name, int mask)
676448Sache{
6829612Sjmg	int foo;
6929612Sjmg
7029612Sjmg	for (foo = 0; foo < SOUND_MIXER_NRDEVICES; foo++)
7129612Sjmg		if ((1 << foo) & mask && !strcmp(names[foo], name))
7229612Sjmg			break;
7329612Sjmg
7429612Sjmg	return foo == SOUND_MIXER_NRDEVICES ? -1 : foo;
7529612Sjmg}
7629612Sjmg
7729612Sjmgvoid
78177195Sjkimprint_recsrc(int recsrc, int recmask, int shortflag)
7929612Sjmg{
806448Sache	int i, n = 0;
816448Sache
82177195Sjkim	if (recmask == 0)
83177195Sjkim		return;
84177195Sjkim
85153953Sariff	if (!shortflag)
86153953Sariff		printf("Recording source: ");
87153953Sariff
886448Sache	for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
896448Sache		if ((1 << i) & recsrc) {
90153953Sariff			if (shortflag) {
91153953Sariff				if (n)
92153953Sariff					printf(" +rec ");
93153953Sariff				else
94153953Sariff					printf("=rec ");
95153953Sariff			} else if (n)
96153953Sariff				printf(", ");
97153953Sariff			printf("%s", names[i]);
986448Sache			n = 1;
996448Sache		}
100153953Sariff	if (!shortflag)
101153953Sariff		printf("\n");
1026448Sache}
1036448Sache
1048857Srgrimesint
1056448Sachemain(int argc, char *argv[])
1066448Sache{
107177195Sjkim	char mixer[PATH_MAX] = "/dev/mixer";
108177195Sjkim	char *name, *eptr;
1096448Sache	int foo, bar, baz, dev;
11029612Sjmg	int devmask = 0, recmask = 0, recsrc = 0, orecsrc;
111144999Smdodd	int dusage = 0, drecsrc = 0, shortflag = 0, Shortflag = 0;
11275334Sgreid	int l = 0, r = 0, t = 0;
113113299Smdodd	char lstr[5], rstr[5];
114177195Sjkim	int n, lrel = 0, rrel = 0;
115177195Sjkim	char ch;
1166448Sache
117177195Sjkim	if ((name = strdup(basename(argv[0]))) == NULL)
118177195Sjkim		err(1, "strdup()");
119177195Sjkim	if (strncmp(name, "mixer", 5) == 0 && name[5] != '\0') {
120177195Sjkim		n = strtol(name + 5, &eptr, 10) - 1;
121177195Sjkim		if (n > 0 && *eptr == '\0')
122177195Sjkim			snprintf(mixer, PATH_MAX - 1, "/dev/mixer%d", n);
123177195Sjkim	}
124177195Sjkim	free(name);
125177195Sjkim	name = mixer;
1266448Sache
127177195Sjkim	n = 1;
128177195Sjkim	for (;;) {
129177195Sjkim		if (n >= argc || *argv[n] != '-')
130177195Sjkim			break;
131177195Sjkim		if (strlen(argv[n]) != 2) {
132177195Sjkim			if (strcmp(argv[n] + 1, "rec") != 0)
13364657Ssobomax				dusage = 1;
134177195Sjkim			break;
13564657Ssobomax		}
136177195Sjkim		ch = *(argv[n] + 1);
137177195Sjkim		if (ch == 'f' && n < argc - 1) {
138177195Sjkim			name = argv[n + 1];
139177195Sjkim			n += 2;
140177195Sjkim		} else if (ch == 's') {
141177195Sjkim			shortflag = 1;
142177195Sjkim			n++;
143177195Sjkim		} else if (ch == 'S') {
144177195Sjkim			Shortflag = 1;
145177195Sjkim			n++;
146177195Sjkim		} else {
147177195Sjkim			dusage = 1;
148177195Sjkim			break;
149177195Sjkim		}
150177195Sjkim	}
151177195Sjkim	if (shortflag && Shortflag)
152177195Sjkim		dusage = 1;
15329612Sjmg
154177195Sjkim	argc -= n - 1;
155177195Sjkim	argv += n - 1;
156177195Sjkim
15729963Scharnier	if ((baz = open(name, O_RDWR)) < 0)
15829963Scharnier		err(1, "%s", name);
15929963Scharnier	if (ioctl(baz, SOUND_MIXER_READ_DEVMASK, &devmask) == -1)
16030028Scharnier		err(1, "SOUND_MIXER_READ_DEVMASK");
16129963Scharnier	if (ioctl(baz, SOUND_MIXER_READ_RECMASK, &recmask) == -1)
16230028Scharnier		err(1, "SOUND_MIXER_READ_RECMASK");
16329963Scharnier	if (ioctl(baz, SOUND_MIXER_READ_RECSRC, &recsrc) == -1)
16430028Scharnier		err(1, "SOUND_MIXER_READ_RECSRC");
16529612Sjmg	orecsrc = recsrc;
1666448Sache
16764657Ssobomax	if ((argc == 1) && (dusage == 0)) {
16813803Smpp		for (foo = 0; foo < SOUND_MIXER_NRDEVICES; foo++) {
16913803Smpp			if (!((1 << foo) & devmask))
17013803Smpp				continue;
17113803Smpp			if (ioctl(baz, MIXER_READ(foo),&bar)== -1) {
17229963Scharnier			   	warn("MIXER_READ");
17313803Smpp				continue;
17413803Smpp			}
175144999Smdodd			if (Shortflag)
176144999Smdodd				printf("%s:%d:%d ", names[foo], bar & 0x7f,
177144999Smdodd				       (bar >> 8) & 0x7f);
178144999Smdodd			else if (shortflag)
179116388Sgrog				printf("%s %d:%d ", names[foo], bar & 0x7f,
180116388Sgrog				       (bar >> 8) & 0x7f);
18160741Sjkh			else
182116388Sgrog				printf("Mixer %-8s is currently set to %3d:%d\n",
183116388Sgrog				       names[foo], bar & 0x7f, (bar >> 8) & 0x7f);
18413803Smpp		}
185116388Sgrog		if (ioctl(baz, SOUND_MIXER_READ_RECSRC, &recsrc) == -1)
186116388Sgrog			err(1, "SOUND_MIXER_READ_RECSRC");
187177195Sjkim		print_recsrc(recsrc, recmask, shortflag || Shortflag);
18813803Smpp		return(0);
18913803Smpp	}
19013803Smpp
19129612Sjmg	argc--; argv++;
1926448Sache
19375334Sgreid	while ((argc > 0) && (dusage == 0)) {
19429612Sjmg		if (!strcmp("recsrc", *argv)) {
19529612Sjmg			drecsrc = 1;
19629612Sjmg			argc--; argv++;
19729612Sjmg			continue;
19829612Sjmg		} else if (argc > 1 && !strcmp("rec", *argv + 1)) {
19929612Sjmg			if (**argv != '+' && **argv != '-' &&
20029612Sjmg			    **argv != '=' && **argv != '^') {
20164657Ssobomax				warnx("unknown modifier: %c", **argv);
20229612Sjmg				dusage = 1;
20364657Ssobomax				break;
20413435Smpp			}
20529612Sjmg			if ((dev = res_name(argv[1], recmask)) == -1) {
20664657Ssobomax				warnx("unknown recording device: %s", argv[1]);
20729612Sjmg				dusage = 1;
20864657Ssobomax				break;
2096448Sache			}
21029612Sjmg			switch(**argv) {
21129612Sjmg			case '+':
2126448Sache				recsrc |= (1 << dev);
21329612Sjmg				break;
21429612Sjmg			case '-':
2156448Sache				recsrc &= ~(1 << dev);
21629612Sjmg				break;
21729612Sjmg			case '=':
21829612Sjmg				recsrc = (1 << dev);
21929612Sjmg				break;
22029612Sjmg			case '^':
22129612Sjmg				recsrc ^= (1 << dev);
22229612Sjmg				break;
22329612Sjmg			}
22429612Sjmg			drecsrc = 1;
22529612Sjmg			argc -= 2; argv += 2;
22629612Sjmg			continue;
22729612Sjmg		}
2286448Sache
22975334Sgreid		if ((t = sscanf(*argv, "%d:%d", &l, &r)) > 0) {
23075334Sgreid			dev = 0;
23175334Sgreid		}
23275334Sgreid		else if((dev = res_name(*argv, devmask)) == -1) {
23364657Ssobomax			warnx("unknown device: %s", *argv);
23429612Sjmg			dusage = 1;
23564657Ssobomax			break;
23629612Sjmg		}
23729612Sjmg
238113299Smdodd#define	issign(c)	(((c) == '+') || ((c) == '-'))
239113299Smdodd
240113299Smdodd		if (argc > 1) {
241113299Smdodd			n = sscanf(argv[1], "%7[^:]:%7s", lstr, rstr);
242113299Smdodd			if (n > 0) {
243113299Smdodd				if (issign(lstr[0]))
244113299Smdodd					lrel = rrel = 1;
245113299Smdodd				l = atoi(lstr);
246113299Smdodd			}
247113299Smdodd			if (n > 1) {
248113299Smdodd				rrel = 0;
249113299Smdodd				if (issign(rstr[0]))
250113299Smdodd					rrel = 1;
251113299Smdodd				r = atoi(rstr);
252113299Smdodd			}
253113299Smdodd		}
254113299Smdodd
255113299Smdodd		switch(argc > 1 ? n : t) {
25629612Sjmg		case 0:
25729612Sjmg			if (ioctl(baz, MIXER_READ(dev),&bar)== -1) {
25829963Scharnier				warn("MIXER_READ");
25929612Sjmg				argc--; argv++;
26029612Sjmg				continue;
2616448Sache			}
262144999Smdodd			if (Shortflag)
263144999Smdodd				printf("%s:%d:%d ", names[dev], bar & 0x7f,
264144999Smdodd				       (bar >> 8) & 0x7f);
265144999Smdodd			else if (shortflag)
266116388Sgrog				printf("%s %d:%d ", names[dev], bar & 0x7f,
267116388Sgrog				       (bar >> 8) & 0x7f);
26860741Sjkh			else
26960741Sjkh				printf("Mixer %-8s is currently set to %3d:%d\n",
27060741Sjkh				  names[dev], bar & 0x7f, (bar >> 8) & 0x7f);
2716448Sache
27229612Sjmg			argc--; argv++;
27329612Sjmg			break;
27429612Sjmg		case 1:
27529612Sjmg			r = l;
27629612Sjmg		case 2:
277113299Smdodd			if (ioctl(baz, MIXER_READ(dev),&bar)== -1) {
278113299Smdodd				warn("MIXER_READ");
279113299Smdodd				argc--; argv++;
280113299Smdodd				continue;
281113299Smdodd			}
282113299Smdodd
283113299Smdodd			if (lrel)
284113299Smdodd				l = (bar & 0x7f) + l;
285113299Smdodd			if (rrel)
286113299Smdodd				r = ((bar >> 8) & 0x7f) + r;
287113299Smdodd
28829612Sjmg			if (l < 0)
28929612Sjmg				l = 0;
29029612Sjmg			else if (l > 100)
29129612Sjmg				l = 100;
29229612Sjmg			if (r < 0)
29329612Sjmg				r = 0;
29429612Sjmg			else if (r > 100)
29529612Sjmg				r = 100;
2968857Srgrimes
297144999Smdodd			if (!Shortflag)
298144999Smdodd				printf("Setting the mixer %s from %d:%d to %d:%d.\n",
299144999Smdodd				       names[dev], bar & 0x7f, (bar >> 8) & 0x7f, l, r);
300108421Sjmallett
30129612Sjmg			l |= r << 8;
30229612Sjmg			if (ioctl(baz, MIXER_WRITE(dev), &l) == -1)
30329963Scharnier				warn("WRITE_MIXER");
3046448Sache
30529612Sjmg			argc -= 2; argv += 2;
30629612Sjmg 			break;
3076448Sache		}
3086448Sache	}
3096448Sache
31064657Ssobomax	if (dusage) {
31164657Ssobomax		close(baz);
31264657Ssobomax		usage(devmask, recmask);
31364657Ssobomax		/* Not reached */
31464657Ssobomax	}
31564657Ssobomax
316177195Sjkim	if (orecsrc != recsrc) {
31729963Scharnier		if (ioctl(baz, SOUND_MIXER_WRITE_RECSRC, &recsrc) == -1)
31830028Scharnier			err(1, "SOUND_MIXER_WRITE_RECSRC");
31929963Scharnier		if (ioctl(baz, SOUND_MIXER_READ_RECSRC, &recsrc) == -1)
32030028Scharnier			err(1, "SOUND_MIXER_READ_RECSRC");
32129612Sjmg	}
322177195Sjkim
323177195Sjkim	if (drecsrc)
324177195Sjkim		print_recsrc(recsrc, recmask, shortflag || Shortflag);
32529612Sjmg
3266448Sache	close(baz);
32729612Sjmg
32829612Sjmg	exit(0);
3296448Sache}
330