mixer.c revision 153953
1/*
2 *	This is an example of a mixer program for Linux
3 *
4 *	updated 1/1/93 to add stereo, level query, broken
5 *      	devmask kludge - cmetz@thor.tjhsst.edu
6 *
7 * (C) Craig Metz and Hannu Savolainen 1993.
8 *
9 * You may do anything you wish with this program.
10 *
11 * ditto for my modifications (John-Mark Gurney, 1997)
12 */
13
14#include <sys/cdefs.h>
15__FBSDID("$FreeBSD: head/usr.sbin/mixer/mixer.c 153953 2006-01-01 20:19:49Z ariff $");
16
17#include <err.h>
18#include <fcntl.h>
19#include <stdio.h>
20#include <string.h>
21#include <stdlib.h>
22#include <unistd.h>
23#include <sys/soundcard.h>
24
25const char *names[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_NAMES;
26
27void usage(int devmask, int recmask);
28int res_name(const char *name, int mask);
29void print_recsrc(int recsrc, int shortflag);
30
31void
32usage(int devmask, int recmask)
33{
34	int i, n;
35
36	printf("usage: mixer [-f device] [-s | -S] [dev [+|-][voll[:[+|-]volr]] ...\n"
37	       "       mixer [-f device] [-s | -S] recsrc ...\n"
38	       "       mixer [-f device] [-s | -S] {^|+|-|=}rec rdev ... \n");
39	printf(" devices: ");
40	for (i = 0, n = 0; i < SOUND_MIXER_NRDEVICES; i++)
41		if ((1 << i) & devmask)  {
42			if (n)
43				printf(", ");
44			printf("%s", names[i]);
45			n = 1;
46		}
47	printf("\n rec devices: ");
48	for (i = 0, n = 0; i < SOUND_MIXER_NRDEVICES; i++)
49		if ((1 << i) & recmask)  {
50			if (n)
51				printf(", ");
52			printf("%s", names[i]);
53			n = 1;
54		}
55	printf("\n");
56	exit(1);
57}
58
59int
60res_name(const char *name, int mask)
61{
62	int foo;
63
64	for (foo = 0; foo < SOUND_MIXER_NRDEVICES; foo++)
65		if ((1 << foo) & mask && !strcmp(names[foo], name))
66			break;
67
68	return foo == SOUND_MIXER_NRDEVICES ? -1 : foo;
69}
70
71void
72print_recsrc(int recsrc, int shortflag)
73{
74	int i, n = 0;
75
76	if (!shortflag)
77		printf("Recording source: ");
78
79	for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
80		if ((1 << i) & recsrc) {
81			if (shortflag) {
82				if (n)
83					printf(" +rec ");
84				else
85					printf("=rec ");
86			} else if (n)
87				printf(", ");
88			printf("%s", names[i]);
89			n = 1;
90		}
91	if (!shortflag)
92		printf("\n");
93}
94
95int
96main(int argc, char *argv[])
97{
98	int foo, bar, baz, dev;
99	int devmask = 0, recmask = 0, recsrc = 0, orecsrc;
100	int dusage = 0, drecsrc = 0, shortflag = 0, Shortflag = 0;
101	int l = 0, r = 0, t = 0;
102	char lstr[5], rstr[5];
103	int n = 0, lrel = 0, rrel = 0;
104	int ch;
105
106	char *name;
107
108	name = "/dev/mixer";
109
110	if (!strcmp(argv[0], "mixer2"))
111		name = "/dev/mixer1";
112	else if (!strcmp(argv[0], "mixer3"))
113		name = "/dev/mixer2";
114
115	while ((ch = getopt(argc, argv, "f:sS")) != -1)
116		switch (ch) {
117			case 'f':
118				name = optarg;
119				break;
120			case 's':
121				shortflag = 1;
122				break;
123			case 'S':
124				Shortflag = 1;
125				break;
126			default:
127				dusage = 1;
128		}
129	argc -= (optind - 1);
130	argv += (optind - 1);
131
132	if ((baz = open(name, O_RDWR)) < 0)
133		err(1, "%s", name);
134	if (ioctl(baz, SOUND_MIXER_READ_DEVMASK, &devmask) == -1)
135		err(1, "SOUND_MIXER_READ_DEVMASK");
136	if (ioctl(baz, SOUND_MIXER_READ_RECMASK, &recmask) == -1)
137		err(1, "SOUND_MIXER_READ_RECMASK");
138	if (ioctl(baz, SOUND_MIXER_READ_RECSRC, &recsrc) == -1)
139		err(1, "SOUND_MIXER_READ_RECSRC");
140	orecsrc = recsrc;
141
142	if ((argc == 1) && (dusage == 0)) {
143		for (foo = 0; foo < SOUND_MIXER_NRDEVICES; foo++) {
144			if (!((1 << foo) & devmask))
145				continue;
146			if (ioctl(baz, MIXER_READ(foo),&bar)== -1) {
147			   	warn("MIXER_READ");
148				continue;
149			}
150			if (Shortflag)
151				printf("%s:%d:%d ", names[foo], bar & 0x7f,
152				       (bar >> 8) & 0x7f);
153			else if (shortflag)
154				printf("%s %d:%d ", names[foo], bar & 0x7f,
155				       (bar >> 8) & 0x7f);
156			else
157				printf("Mixer %-8s is currently set to %3d:%d\n",
158				       names[foo], bar & 0x7f, (bar >> 8) & 0x7f);
159		}
160		if (ioctl(baz, SOUND_MIXER_READ_RECSRC, &recsrc) == -1)
161			err(1, "SOUND_MIXER_READ_RECSRC");
162		print_recsrc(recsrc, shortflag || Shortflag);
163		return(0);
164	}
165
166	argc--; argv++;
167
168	while ((argc > 0) && (dusage == 0)) {
169		if (!strcmp("recsrc", *argv)) {
170			drecsrc = 1;
171			argc--; argv++;
172			continue;
173		} else if (argc > 1 && !strcmp("rec", *argv + 1)) {
174			if (**argv != '+' && **argv != '-' &&
175			    **argv != '=' && **argv != '^') {
176				warnx("unknown modifier: %c", **argv);
177				dusage = 1;
178				break;
179			}
180			if ((dev = res_name(argv[1], recmask)) == -1) {
181				warnx("unknown recording device: %s", argv[1]);
182				dusage = 1;
183				break;
184			}
185			switch(**argv) {
186			case '+':
187				recsrc |= (1 << dev);
188				break;
189			case '-':
190				recsrc &= ~(1 << dev);
191				break;
192			case '=':
193				recsrc = (1 << dev);
194				break;
195			case '^':
196				recsrc ^= (1 << dev);
197				break;
198			}
199			drecsrc = 1;
200			argc -= 2; argv += 2;
201			continue;
202		}
203
204		if ((t = sscanf(*argv, "%d:%d", &l, &r)) > 0) {
205			dev = 0;
206		}
207		else if((dev = res_name(*argv, devmask)) == -1) {
208			warnx("unknown device: %s", *argv);
209			dusage = 1;
210			break;
211		}
212
213#define	issign(c)	(((c) == '+') || ((c) == '-'))
214
215		if (argc > 1) {
216			n = sscanf(argv[1], "%7[^:]:%7s", lstr, rstr);
217			if (n > 0) {
218				if (issign(lstr[0]))
219					lrel = rrel = 1;
220				l = atoi(lstr);
221			}
222			if (n > 1) {
223				rrel = 0;
224				if (issign(rstr[0]))
225					rrel = 1;
226				r = atoi(rstr);
227			}
228		}
229
230		switch(argc > 1 ? n : t) {
231		case 0:
232			if (ioctl(baz, MIXER_READ(dev),&bar)== -1) {
233				warn("MIXER_READ");
234				argc--; argv++;
235				continue;
236			}
237			if (Shortflag)
238				printf("%s:%d:%d ", names[dev], bar & 0x7f,
239				       (bar >> 8) & 0x7f);
240			else if (shortflag)
241				printf("%s %d:%d ", names[dev], bar & 0x7f,
242				       (bar >> 8) & 0x7f);
243			else
244				printf("Mixer %-8s is currently set to %3d:%d\n",
245				  names[dev], bar & 0x7f, (bar >> 8) & 0x7f);
246
247			argc--; argv++;
248			break;
249		case 1:
250			r = l;
251		case 2:
252			if (ioctl(baz, MIXER_READ(dev),&bar)== -1) {
253				warn("MIXER_READ");
254				argc--; argv++;
255				continue;
256			}
257
258			if (lrel)
259				l = (bar & 0x7f) + l;
260			if (rrel)
261				r = ((bar >> 8) & 0x7f) + r;
262
263			if (l < 0)
264				l = 0;
265			else if (l > 100)
266				l = 100;
267			if (r < 0)
268				r = 0;
269			else if (r > 100)
270				r = 100;
271
272			if (!Shortflag)
273				printf("Setting the mixer %s from %d:%d to %d:%d.\n",
274				       names[dev], bar & 0x7f, (bar >> 8) & 0x7f, l, r);
275
276			l |= r << 8;
277			if (ioctl(baz, MIXER_WRITE(dev), &l) == -1)
278				warn("WRITE_MIXER");
279
280			argc -= 2; argv += 2;
281 			break;
282		}
283	}
284
285	if (dusage) {
286		close(baz);
287		usage(devmask, recmask);
288		/* Not reached */
289	}
290
291	if (orecsrc != recsrc)
292		if (ioctl(baz, SOUND_MIXER_WRITE_RECSRC, &recsrc) == -1)
293			err(1, "SOUND_MIXER_WRITE_RECSRC");
294
295	if (drecsrc) {
296		if (ioctl(baz, SOUND_MIXER_READ_RECSRC, &recsrc) == -1)
297			err(1, "SOUND_MIXER_READ_RECSRC");
298		print_recsrc(recsrc, shortflag || Shortflag);
299	}
300
301	close(baz);
302
303	exit(0);
304}
305