mixer.c revision 227255
1132451Sroberto/*
2132451Sroberto *	This is an example of a mixer program for Linux
3132451Sroberto *
4132451Sroberto *	updated 1/1/93 to add stereo, level query, broken
5182007Sroberto *      	devmask kludge - cmetz@thor.tjhsst.edu
6182007Sroberto *
7182007Sroberto * (C) Craig Metz and Hannu Savolainen 1993.
8182007Sroberto *
9182007Sroberto * You may do anything you wish with this program.
10132451Sroberto *
11182007Sroberto * ditto for my modifications (John-Mark Gurney, 1997)
12182007Sroberto */
13285612Sdelphij
14285612Sdelphij#include <sys/cdefs.h>
15285612Sdelphij__FBSDID("$FreeBSD: head/usr.sbin/mixer/mixer.c 227255 2011-11-06 19:02:13Z ed $");
16182007Sroberto
17182007Sroberto#include <err.h>
18182007Sroberto#include <fcntl.h>
19182007Sroberto#include <libgen.h>
20182007Sroberto#include <limits.h>
21182007Sroberto#include <stdio.h>
22182007Sroberto#include <string.h>
23182007Sroberto#include <stdlib.h>
24182007Sroberto#include <unistd.h>
25182007Sroberto#include <sys/soundcard.h>
26182007Sroberto
27182007Srobertostatic const char *names[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_NAMES;
28182007Sroberto
29182007Srobertostatic void	usage(int devmask, int recmask);
30182007Srobertostatic int	res_name(const char *name, int mask);
31182007Srobertostatic void	print_recsrc(int recsrc, int recmask, int sflag);
32182007Sroberto
33182007Srobertostatic void
34182007Srobertousage(int devmask, int recmask)
35182007Sroberto{
36182007Sroberto	int	i, n;
37132451Sroberto
38132451Sroberto	printf("usage: mixer [-f device] [-s | -S] [dev [+|-][voll[:[+|-]volr]] ...\n"
39132451Sroberto	    "       mixer [-f device] [-s | -S] recsrc ...\n"
40132451Sroberto	    "       mixer [-f device] [-s | -S] {^|+|-|=}rec rdev ...\n");
41132451Sroberto	if (devmask != 0) {
42132451Sroberto		printf(" devices: ");
43132451Sroberto		for (i = 0, n = 0; i < SOUND_MIXER_NRDEVICES; i++)
44132451Sroberto			if ((1 << i) & devmask)  {
45132451Sroberto				if (n)
46182007Sroberto					printf(", ");
47182007Sroberto				printf("%s", names[i]);
48132451Sroberto				n++;
49132451Sroberto			}
50132451Sroberto	}
51132451Sroberto	if (recmask != 0) {
52132451Sroberto		printf("\n rec devices: ");
53132451Sroberto		for (i = 0, n = 0; i < SOUND_MIXER_NRDEVICES; i++)
54132451Sroberto			if ((1 << i) & recmask)  {
55132451Sroberto				if (n)
56132451Sroberto					printf(", ");
57132451Sroberto				printf("%s", names[i]);
58132451Sroberto				n++;
59132451Sroberto			}
60132451Sroberto	}
61132451Sroberto	printf("\n");
62182007Sroberto	exit(1);
63182007Sroberto}
64182007Sroberto
65182007Srobertostatic int
66182007Srobertores_name(const char *name, int mask)
67132451Sroberto{
68285612Sdelphij	int	foo;
69
70	for (foo = 0; foo < SOUND_MIXER_NRDEVICES; foo++)
71		if ((1 << foo) & mask && strcmp(names[foo], name) == 0)
72			break;
73
74	return (foo == SOUND_MIXER_NRDEVICES ? -1 : foo);
75}
76
77static void
78print_recsrc(int recsrc, int recmask, int sflag)
79{
80	int	i, n;
81
82	if (recmask == 0)
83		return;
84
85	if (!sflag)
86		printf("Recording source: ");
87
88	for (i = 0, n = 0; i < SOUND_MIXER_NRDEVICES; i++)
89		if ((1 << i) & recsrc) {
90			if (sflag)
91				printf("%srec ", n ? " +" : "=");
92			else if (n)
93				printf(", ");
94			printf("%s", names[i]);
95			n++;
96		}
97	if (!sflag)
98		printf("\n");
99}
100
101int
102main(int argc, char *argv[])
103{
104	char	mixer[PATH_MAX] = "/dev/mixer";
105	char	lstr[5], rstr[5];
106	char	*name, *eptr;
107	int	devmask = 0, recmask = 0, recsrc = 0, orecsrc;
108	int	dusage = 0, drecsrc = 0, sflag = 0, Sflag = 0;
109	int	l, r, lrel, rrel;
110	int	ch, foo, bar, baz, dev, m, n, t;
111
112	if ((name = strdup(basename(argv[0]))) == NULL)
113		err(1, "strdup()");
114	if (strncmp(name, "mixer", 5) == 0 && name[5] != '\0') {
115		n = strtol(name + 5, &eptr, 10) - 1;
116		if (n > 0 && *eptr == '\0')
117			snprintf(mixer, PATH_MAX - 1, "/dev/mixer%d", n);
118	}
119	free(name);
120	name = mixer;
121
122	n = 1;
123	for (;;) {
124		if (n >= argc || *argv[n] != '-')
125			break;
126		if (strlen(argv[n]) != 2) {
127			if (strcmp(argv[n] + 1, "rec") != 0)
128				dusage = 1;
129			break;
130		}
131		ch = *(argv[n] + 1);
132		if (ch == 'f' && n < argc - 1) {
133			name = argv[n + 1];
134			n += 2;
135		} else if (ch == 's') {
136			sflag = 1;
137			n++;
138		} else if (ch == 'S') {
139			Sflag = 1;
140			n++;
141		} else {
142			dusage = 1;
143			break;
144		}
145	}
146	if (sflag && Sflag)
147		dusage = 1;
148
149	argc -= n - 1;
150	argv += n - 1;
151
152	if ((baz = open(name, O_RDWR)) < 0)
153		err(1, "%s", name);
154	if (ioctl(baz, SOUND_MIXER_READ_DEVMASK, &devmask) == -1)
155		err(1, "SOUND_MIXER_READ_DEVMASK");
156	if (ioctl(baz, SOUND_MIXER_READ_RECMASK, &recmask) == -1)
157		err(1, "SOUND_MIXER_READ_RECMASK");
158	if (ioctl(baz, SOUND_MIXER_READ_RECSRC, &recsrc) == -1)
159		err(1, "SOUND_MIXER_READ_RECSRC");
160	orecsrc = recsrc;
161
162	if (argc == 1 && dusage == 0) {
163		for (foo = 0, n = 0; foo < SOUND_MIXER_NRDEVICES; foo++) {
164			if (!((1 << foo) & devmask))
165				continue;
166			if (ioctl(baz, MIXER_READ(foo),&bar) == -1) {
167			   	warn("MIXER_READ");
168				continue;
169			}
170			if (Sflag || sflag) {
171				printf("%s%s%c%d:%d", n ? " " : "",
172				    names[foo], Sflag ? ':' : ' ',
173				    bar & 0x7f, (bar >> 8) & 0x7f);
174				n++;
175			} else
176				printf("Mixer %-8s is currently set to "
177				    "%3d:%d\n", names[foo], bar & 0x7f,
178				    (bar >> 8) & 0x7f);
179		}
180		if (n && recmask)
181			printf(" ");
182		print_recsrc(recsrc, recmask, Sflag || sflag);
183		return (0);
184	}
185
186	argc--;
187	argv++;
188
189	n = 0;
190	while (argc > 0 && dusage == 0) {
191		if (strcmp("recsrc", *argv) == 0) {
192			drecsrc = 1;
193			argc--;
194			argv++;
195			continue;
196		} else if (argc > 1 && strcmp("rec", *argv + 1) == 0) {
197			if (**argv != '+' && **argv != '-' &&
198			    **argv != '=' && **argv != '^') {
199				warnx("unknown modifier: %c", **argv);
200				dusage = 1;
201				break;
202			}
203			if ((dev = res_name(argv[1], recmask)) == -1) {
204				warnx("unknown recording device: %s", argv[1]);
205				dusage = 1;
206				break;
207			}
208			switch (**argv) {
209			case '+':
210				recsrc |= (1 << dev);
211				break;
212			case '-':
213				recsrc &= ~(1 << dev);
214				break;
215			case '=':
216				recsrc = (1 << dev);
217				break;
218			case '^':
219				recsrc ^= (1 << dev);
220				break;
221			}
222			drecsrc = 1;
223			argc -= 2;
224			argv += 2;
225			continue;
226		}
227
228		if ((t = sscanf(*argv, "%d:%d", &l, &r)) > 0)
229			dev = 0;
230		else if ((dev = res_name(*argv, devmask)) == -1) {
231			warnx("unknown device: %s", *argv);
232			dusage = 1;
233			break;
234		}
235
236		lrel = rrel = 0;
237		if (argc > 1) {
238			m = sscanf(argv[1], "%7[^:]:%7s", lstr, rstr);
239			if (m > 0) {
240				if (*lstr == '+' || *lstr == '-')
241					lrel = rrel = 1;
242				l = strtol(lstr, NULL, 10);
243			}
244			if (m > 1) {
245				if (*rstr == '+' || *rstr == '-')
246					rrel = 1;
247				r = strtol(rstr, NULL, 10);
248			}
249		}
250
251		switch (argc > 1 ? m : t) {
252		case 0:
253			if (ioctl(baz, MIXER_READ(dev), &bar) == -1) {
254				warn("MIXER_READ");
255				argc--;
256				argv++;
257				continue;
258			}
259			if (Sflag || sflag) {
260				printf("%s%s%c%d:%d", n ? " " : "",
261				    names[dev], Sflag ? ':' : ' ',
262				    bar & 0x7f, (bar >> 8) & 0x7f);
263				n++;
264			} else
265				printf("Mixer %-8s is currently set to "
266				    "%3d:%d\n", names[dev], bar & 0x7f,
267				    (bar >> 8) & 0x7f);
268
269			argc--;
270			argv++;
271			break;
272		case 1:
273			r = l;
274			/* FALLTHROUGH */
275		case 2:
276			if (ioctl(baz, MIXER_READ(dev), &bar) == -1) {
277				warn("MIXER_READ");
278				argc--;
279				argv++;
280				continue;
281			}
282
283			if (lrel)
284				l = (bar & 0x7f) + l;
285			if (rrel)
286				r = ((bar >> 8) & 0x7f) + r;
287
288			if (l < 0)
289				l = 0;
290			else if (l > 100)
291				l = 100;
292			if (r < 0)
293				r = 0;
294			else if (r > 100)
295				r = 100;
296
297			if (!Sflag)
298				printf("Setting the mixer %s from %d:%d to "
299				    "%d:%d.\n", names[dev], bar & 0x7f,
300				    (bar >> 8) & 0x7f, l, r);
301
302			l |= r << 8;
303			if (ioctl(baz, MIXER_WRITE(dev), &l) == -1)
304				warn("WRITE_MIXER");
305
306			argc -= 2;
307			argv += 2;
308 			break;
309		}
310	}
311
312	if (dusage) {
313		close(baz);
314		usage(devmask, recmask);
315		/* NOTREACHED */
316	}
317
318	if (orecsrc != recsrc) {
319		if (ioctl(baz, SOUND_MIXER_WRITE_RECSRC, &recsrc) == -1)
320			err(1, "SOUND_MIXER_WRITE_RECSRC");
321		if (ioctl(baz, SOUND_MIXER_READ_RECSRC, &recsrc) == -1)
322			err(1, "SOUND_MIXER_READ_RECSRC");
323	}
324
325	if (drecsrc)
326		print_recsrc(recsrc, recmask, Sflag || sflag);
327
328	close(baz);
329
330	return (0);
331}
332