mixer.c revision 144999
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 144999 2005-04-13 07:11:54Z mdodd $");
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);
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)
73{
74	int i, n = 0;
75	fprintf(stderr, "Recording source: ");
76
77	for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
78		if ((1 << i) & recsrc) {
79			if (n)
80				fprintf(stderr, ", ");
81			fprintf(stderr, "%s", names[i]);
82			n = 1;
83		}
84	fprintf(stderr, "\n");
85}
86
87int
88main(int argc, char *argv[])
89{
90	int foo, bar, baz, dev;
91	int devmask = 0, recmask = 0, recsrc = 0, orecsrc;
92	int dusage = 0, drecsrc = 0, shortflag = 0, Shortflag = 0;
93	int l = 0, r = 0, t = 0;
94	char lstr[5], rstr[5];
95	int n = 0, lrel = 0, rrel = 0;
96	int ch;
97
98	char *name;
99
100	name = strdup("/dev/mixer");
101
102	if (!strcmp(argv[0], "mixer2"))
103		name = strdup("/dev/mixer1");
104	else if (!strcmp(argv[0], "mixer3"))
105		name = strdup("/dev/mixer2");
106
107	while ((ch = getopt(argc, argv, "f:sS")) != -1)
108		switch (ch) {
109			case 'f':
110				name = strdup(optarg);
111				break;
112			case 's':
113				shortflag = 1;
114				break;
115			case 'S':
116				Shortflag = 1;
117				break;
118			default:
119				dusage = 1;
120		}
121	argc -= (optind - 1);
122	argv += (optind - 1);
123
124	if ((baz = open(name, O_RDWR)) < 0)
125		err(1, "%s", name);
126	free(name);
127	if (ioctl(baz, SOUND_MIXER_READ_DEVMASK, &devmask) == -1)
128		err(1, "SOUND_MIXER_READ_DEVMASK");
129	if (ioctl(baz, SOUND_MIXER_READ_RECMASK, &recmask) == -1)
130		err(1, "SOUND_MIXER_READ_RECMASK");
131	if (ioctl(baz, SOUND_MIXER_READ_RECSRC, &recsrc) == -1)
132		err(1, "SOUND_MIXER_READ_RECSRC");
133	orecsrc = recsrc;
134
135	if ((argc == 1) && (dusage == 0)) {
136		for (foo = 0; foo < SOUND_MIXER_NRDEVICES; foo++) {
137			if (!((1 << foo) & devmask))
138				continue;
139			if (ioctl(baz, MIXER_READ(foo),&bar)== -1) {
140			   	warn("MIXER_READ");
141				continue;
142			}
143			if (Shortflag)
144				printf("%s:%d:%d ", names[foo], bar & 0x7f,
145				       (bar >> 8) & 0x7f);
146			else if (shortflag)
147				printf("%s %d:%d ", names[foo], bar & 0x7f,
148				       (bar >> 8) & 0x7f);
149			else
150				printf("Mixer %-8s is currently set to %3d:%d\n",
151				       names[foo], bar & 0x7f, (bar >> 8) & 0x7f);
152		}
153		if (ioctl(baz, SOUND_MIXER_READ_RECSRC, &recsrc) == -1)
154			err(1, "SOUND_MIXER_READ_RECSRC");
155		print_recsrc(recsrc);
156		return(0);
157	}
158
159	argc--; argv++;
160
161	while ((argc > 0) && (dusage == 0)) {
162		if (!strcmp("recsrc", *argv)) {
163			drecsrc = 1;
164			argc--; argv++;
165			continue;
166		} else if (argc > 1 && !strcmp("rec", *argv + 1)) {
167			if (**argv != '+' && **argv != '-' &&
168			    **argv != '=' && **argv != '^') {
169				warnx("unknown modifier: %c", **argv);
170				dusage = 1;
171				break;
172			}
173			if ((dev = res_name(argv[1], recmask)) == -1) {
174				warnx("unknown recording device: %s", argv[1]);
175				dusage = 1;
176				break;
177			}
178			switch(**argv) {
179			case '+':
180				recsrc |= (1 << dev);
181				break;
182			case '-':
183				recsrc &= ~(1 << dev);
184				break;
185			case '=':
186				recsrc = (1 << dev);
187				break;
188			case '^':
189				recsrc ^= (1 << dev);
190				break;
191			}
192			drecsrc = 1;
193			argc -= 2; argv += 2;
194			continue;
195		}
196
197		if ((t = sscanf(*argv, "%d:%d", &l, &r)) > 0) {
198			dev = 0;
199		}
200		else if((dev = res_name(*argv, devmask)) == -1) {
201			warnx("unknown device: %s", *argv);
202			dusage = 1;
203			break;
204		}
205
206#define	issign(c)	(((c) == '+') || ((c) == '-'))
207
208		if (argc > 1) {
209			n = sscanf(argv[1], "%7[^:]:%7s", lstr, rstr);
210			if (n > 0) {
211				if (issign(lstr[0]))
212					lrel = rrel = 1;
213				l = atoi(lstr);
214			}
215			if (n > 1) {
216				rrel = 0;
217				if (issign(rstr[0]))
218					rrel = 1;
219				r = atoi(rstr);
220			}
221		}
222
223		switch(argc > 1 ? n : t) {
224		case 0:
225			if (ioctl(baz, MIXER_READ(dev),&bar)== -1) {
226				warn("MIXER_READ");
227				argc--; argv++;
228				continue;
229			}
230			if (Shortflag)
231				printf("%s:%d:%d ", names[dev], bar & 0x7f,
232				       (bar >> 8) & 0x7f);
233			else if (shortflag)
234				printf("%s %d:%d ", names[dev], bar & 0x7f,
235				       (bar >> 8) & 0x7f);
236			else
237				printf("Mixer %-8s is currently set to %3d:%d\n",
238				  names[dev], bar & 0x7f, (bar >> 8) & 0x7f);
239
240			argc--; argv++;
241			break;
242		case 1:
243			r = l;
244		case 2:
245			if (ioctl(baz, MIXER_READ(dev),&bar)== -1) {
246				warn("MIXER_READ");
247				argc--; argv++;
248				continue;
249			}
250
251			if (lrel)
252				l = (bar & 0x7f) + l;
253			if (rrel)
254				r = ((bar >> 8) & 0x7f) + r;
255
256			if (l < 0)
257				l = 0;
258			else if (l > 100)
259				l = 100;
260			if (r < 0)
261				r = 0;
262			else if (r > 100)
263				r = 100;
264
265			if (!Shortflag)
266				printf("Setting the mixer %s from %d:%d to %d:%d.\n",
267				       names[dev], bar & 0x7f, (bar >> 8) & 0x7f, l, r);
268
269			l |= r << 8;
270			if (ioctl(baz, MIXER_WRITE(dev), &l) == -1)
271				warn("WRITE_MIXER");
272
273			argc -= 2; argv += 2;
274 			break;
275		}
276	}
277
278	if (dusage) {
279		close(baz);
280		usage(devmask, recmask);
281		/* Not reached */
282	}
283
284	if (orecsrc != recsrc)
285		if (ioctl(baz, SOUND_MIXER_WRITE_RECSRC, &recsrc) == -1)
286			err(1, "SOUND_MIXER_WRITE_RECSRC");
287
288	if (drecsrc) {
289		if (ioctl(baz, SOUND_MIXER_READ_RECSRC, &recsrc) == -1)
290			err(1, "SOUND_MIXER_READ_RECSRC");
291		print_recsrc(recsrc);
292	}
293
294	close(baz);
295
296	exit(0);
297}
298