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