mixer.c revision 69258
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 69258 2000-11-27 07:57:44Z kris $";
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
27char *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]] | recsrc | {^|+|-|=}rec recdev] ... ]\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;
93	int l, r;
94	char ch;
95
96	char *name;
97
98	name = strdup("/dev/mixer");
99
100	if (!strcmp(argv[0], "mixer2"))
101		name = strdup("/dev/mixer1");
102	else if (!strcmp(argv[0], "mixer3"))
103		name = strdup("/dev/mixer2");
104
105	while ((ch = getopt(argc, argv, "f:s")) != -1)
106		switch (ch) {
107			case 'f':
108				name = strdup(optarg);
109				break;
110			case 's':
111				shortflag = 1;
112				break;
113			default:
114				dusage = 1;
115		}
116	argc -= (optind - 1);
117	argv += (optind - 1);
118
119	if ((baz = open(name, O_RDWR)) < 0)
120		err(1, "%s", name);
121	free(name);
122	if (ioctl(baz, SOUND_MIXER_READ_DEVMASK, &devmask) == -1)
123		err(1, "SOUND_MIXER_READ_DEVMASK");
124	if (ioctl(baz, SOUND_MIXER_READ_RECMASK, &recmask) == -1)
125		err(1, "SOUND_MIXER_READ_RECMASK");
126	if (ioctl(baz, SOUND_MIXER_READ_RECSRC, &recsrc) == -1)
127		err(1, "SOUND_MIXER_READ_RECSRC");
128	orecsrc = recsrc;
129
130	if ((argc == 1) && (dusage == 0)) {
131		for (foo = 0; foo < SOUND_MIXER_NRDEVICES; foo++) {
132			if (!((1 << foo) & devmask))
133				continue;
134			if (ioctl(baz, MIXER_READ(foo),&bar)== -1) {
135			   	warn("MIXER_READ");
136				continue;
137			}
138			if (shortflag)
139				printf("%s %d:%d ", names[foo], bar & 0x7f, (bar >> 8) & 0x7f);
140			else
141				printf("Mixer %-8s is currently set to %3d:%d\n", names[foo], bar & 0x7f, (bar >> 8) & 0x7f);
142		}
143		return(0);
144	}
145
146	argc--; argv++;
147
148	while ((argc) && (dusage == 0)) {
149		if (!strcmp("recsrc", *argv)) {
150			drecsrc = 1;
151			argc--; argv++;
152			continue;
153		} else if (argc > 1 && !strcmp("rec", *argv + 1)) {
154			if (**argv != '+' && **argv != '-' &&
155			    **argv != '=' && **argv != '^') {
156				warnx("unknown modifier: %c", **argv);
157				dusage = 1;
158				break;
159			}
160			if ((dev = res_name(argv[1], recmask)) == -1) {
161				warnx("unknown recording device: %s", argv[1]);
162				dusage = 1;
163				break;
164			}
165			switch(**argv) {
166			case '+':
167				recsrc |= (1 << dev);
168				break;
169			case '-':
170				recsrc &= ~(1 << dev);
171				break;
172			case '=':
173				recsrc = (1 << dev);
174				break;
175			case '^':
176				recsrc ^= (1 << dev);
177				break;
178			}
179			drecsrc = 1;
180			argc -= 2; argv += 2;
181			continue;
182		}
183
184		if ((dev = res_name(*argv, devmask)) == -1) {
185			warnx("unknown device: %s", *argv);
186			dusage = 1;
187			break;
188		}
189
190		switch(argc > 1 ? sscanf(argv[1], "%d:%d", &l, &r) : 0) {
191		case 0:
192			if (ioctl(baz, MIXER_READ(dev),&bar)== -1) {
193				warn("MIXER_READ");
194				argc--; argv++;
195				continue;
196			}
197			if (shortflag)
198				printf("%s %d:%d ", names[dev], bar & 0x7f, (bar >> 8) & 0x7f);
199			else
200				printf("Mixer %-8s is currently set to %3d:%d\n",
201				  names[dev], bar & 0x7f, (bar >> 8) & 0x7f);
202
203			argc--; argv++;
204			break;
205		case 1:
206			r = l;
207		case 2:
208			if (l < 0)
209				l = 0;
210			else if (l > 100)
211				l = 100;
212			if (r < 0)
213				r = 0;
214			else if (r > 100)
215				r = 100;
216
217			printf("Setting the mixer %s to %d:%d.\n", names[dev],
218			    l, r);
219
220			l |= r << 8;
221			if (ioctl(baz, MIXER_WRITE(dev), &l) == -1)
222				warn("WRITE_MIXER");
223
224			argc -= 2; argv += 2;
225 			break;
226		}
227	}
228
229	if (dusage) {
230		close(baz);
231		usage(devmask, recmask);
232		/* Not reached */
233	}
234
235	if (orecsrc != recsrc)
236		if (ioctl(baz, SOUND_MIXER_WRITE_RECSRC, &recsrc) == -1)
237			err(1, "SOUND_MIXER_WRITE_RECSRC");
238
239	if (drecsrc) {
240		if (ioctl(baz, SOUND_MIXER_READ_RECSRC, &recsrc) == -1)
241			err(1, "SOUND_MIXER_READ_RECSRC");
242		print_recsrc(recsrc);
243	}
244
245	close(baz);
246
247	exit(0);
248}
249