xref: /freebsd/usr.sbin/mixer/mixer.c (revision 817420dc8eac7df799c78f5309b75092b7f7cd40)
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
15 static const char rcsid[] =
16   "$FreeBSD$";
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 
27 char *names[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_NAMES;
28 
29 void usage(int devmask, int recmask);
30 int res_name(const char *name, int mask);
31 void print_recsrc(int recsrc);
32 
33 void
34 usage(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(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(names[i]);
53 			n = 1;
54 		}
55 	printf("\n");
56 	exit(1);
57 }
58 
59 int
60 res_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 
71 void
72 print_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, names[i]);
82 			n = 1;
83 		}
84 	fprintf(stderr, "\n");
85 }
86 
87 int
88 main(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