mixer.c revision 29753
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 <stdio.h>
15#include <fcntl.h>
16#include <string.h>
17#include <stdlib.h>
18#include <unistd.h>
19#ifdef __FreeBSD__
20#include <machine/soundcard.h>
21#else
22#include <sys/soundcard.h>
23#endif
24
25char *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:\tmixer [[dev [voll[:volr]] | recsrc | {^|+|-|=}rec recdev] ... ]\n");
37	printf(" devices: ");
38	for (i = 0, n = 0; i < SOUND_MIXER_NRDEVICES; i++)
39		if ((1 << i) & devmask)  {
40			if (n)
41				printf(", ");
42			printf(names[i]);
43			n = 1;
44		}
45	printf("\n rec devices: ");
46	for (i = 0, n = 0; i < SOUND_MIXER_NRDEVICES; i++)
47		if ((1 << i) & recmask)  {
48			if (n)
49				printf(", ");
50			printf(names[i]);
51			n = 1;
52		}
53	printf("\n");
54	exit(1);
55}
56
57int
58res_name(const char *name, int mask)
59{
60	int foo;
61
62	for (foo = 0; foo < SOUND_MIXER_NRDEVICES; foo++)
63		if ((1 << foo) & mask && !strcmp(names[foo], name))
64			break;
65
66	return foo == SOUND_MIXER_NRDEVICES ? -1 : foo;
67}
68
69void
70print_recsrc(int recsrc)
71{
72	int i, n = 0;
73	fprintf(stderr, "Recording source: ");
74
75	for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
76		if ((1 << i) & recsrc) {
77			if (n)
78				fprintf(stderr, ", ");
79			fprintf(stderr, names[i]);
80			n = 1;
81		}
82	fprintf(stderr, "\n");
83}
84
85int
86main(int argc, char *argv[])
87{
88	int foo, bar, baz, dev;
89	int devmask = 0, recmask = 0, recsrc = 0, orecsrc;
90	int dusage = 0, drecsrc = 0;
91	int l, r;
92
93	char *name;
94
95	name = strdup("/dev/mixer");
96
97	if (!strcmp(argv[0], "mixer2"))
98		name = strdup("/dev/mixer1");
99	else if (!strcmp(argv[0], "mixer3"))
100		name = strdup("/dev/mixer2");
101
102	if (argc > 1 && !strcmp(argv[1], "-f")) {
103		name = strdup(argv[2]);
104		argc -= 2; argv += 2;
105	}
106
107	if ((baz = open(name, O_RDWR)) < 0) {
108		perror(name);
109		exit(1);
110	}
111	free(name);
112	if (ioctl(baz, SOUND_MIXER_READ_DEVMASK, &devmask) == -1) {
113		perror("SOUND_MIXER_READ_DEVMASK");
114		exit(-1);
115	}
116	if (ioctl(baz, SOUND_MIXER_READ_RECMASK, &recmask) == -1) {
117		perror("SOUND_MIXER_READ_RECMASK");
118		exit(-1);
119	}
120	if (ioctl(baz, SOUND_MIXER_READ_RECSRC, &recsrc) == -1) {
121		perror("SOUND_MIXER_READ_RECSRC");
122		exit(-1);
123	}
124	orecsrc = recsrc;
125
126	if (argc == 1) {
127		for (foo = 0; foo < SOUND_MIXER_NRDEVICES; foo++) {
128			if (!((1 << foo) & devmask))
129				continue;
130			if (ioctl(baz, MIXER_READ(foo),&bar)== -1) {
131			   	perror("MIXER_READ");
132				continue;
133			}
134			printf("Mixer %-8s is currently set to %3d:%d\n", names[foo], bar & 0x7f, (bar >> 8) & 0x7f);
135		}
136		return(0);
137	}
138
139	argc--; argv++;
140
141	while (argc) {
142		if (!strcmp("recsrc", *argv)) {
143			drecsrc = 1;
144			argc--; argv++;
145			continue;
146		} else if (argc > 1 && !strcmp("rec", *argv + 1)) {
147			if (**argv != '+' && **argv != '-' &&
148			    **argv != '=' && **argv != '^') {
149				dusage = 1;
150				argc -= 1; argv += 1;
151				continue;
152			}
153			if ((dev = res_name(argv[1], recmask)) == -1) {
154				dusage = 1;
155				argc -= 1; argv += 1;
156				continue;
157			}
158			switch(**argv) {
159			case '+':
160				recsrc |= (1 << dev);
161				break;
162			case '-':
163				recsrc &= ~(1 << dev);
164				break;
165			case '=':
166				recsrc = (1 << dev);
167				break;
168			case '^':
169				recsrc ^= (1 << dev);
170				break;
171			}
172			drecsrc = 1;
173			argc -= 2; argv += 2;
174			continue;
175		}
176
177		if ((dev = res_name(*argv, devmask)) == -1) {
178			dusage = 1;
179			argc--; argv++;
180			continue;
181		}
182
183		switch(argc > 1 ? sscanf(argv[1], "%d:%d", &l, &r) : 0) {
184		case 0:
185			if (ioctl(baz, MIXER_READ(dev),&bar)== -1) {
186				perror("MIXER_READ");
187				argc--; argv++;
188				continue;
189			}
190			printf("Mixer %-8s is currently set to %3d:%d\n",
191			    names[dev], bar & 0x7f, (bar >> 8) & 0x7f);
192
193			argc--; argv++;
194			break;
195		case 1:
196			r = l;
197		case 2:
198			if (l < 0)
199				l = 0;
200			else if (l > 100)
201				l = 100;
202			if (r < 0)
203				r = 0;
204			else if (r > 100)
205				r = 100;
206
207			printf("Setting the mixer %s to %d:%d.\n", names[dev],
208			    l, r);
209
210			l |= r << 8;
211			if (ioctl(baz, MIXER_WRITE(dev), &l) == -1)
212				perror("WRITE_MIXER");
213
214			argc -= 2; argv += 2;
215 			break;
216		}
217	}
218
219	if (orecsrc != recsrc)
220		if (ioctl(baz, SOUND_MIXER_WRITE_RECSRC, &recsrc) == -1) {
221			perror("SOUND_MIXER_WRITE_RECSRC");
222			exit(-1);
223		}
224
225	if (drecsrc) {
226		if (ioctl(baz, SOUND_MIXER_READ_RECSRC, &recsrc) == -1) {
227			perror("SOUND_MIXER_READ_RECSRC");
228			exit(-1);
229		}
230		print_recsrc(recsrc);
231	}
232
233	close(baz);
234
235	if (dusage)
236		usage(devmask, recmask);
237
238	exit(0);
239}
240