xref: /dragonfly/usr.sbin/mixer/mixer.c (revision de5eb4c5)
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  * $FreeBSD: head/usr.sbin/mixer/mixer.c 230611 2012-01-27 09:15:55Z mav $
14  */
15 
16 #include <err.h>
17 #include <fcntl.h>
18 #include <libgen.h>
19 #include <limits.h>
20 #include <stdio.h>
21 #include <string.h>
22 #include <stdlib.h>
23 #include <unistd.h>
24 #include <sys/soundcard.h>
25 
26 static const char *names[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_NAMES;
27 
28 static void	usage(int devmask, int recmask);
29 static int	res_name(const char *name, int mask);
30 static void	print_recsrc(int recsrc, int recmask, int sflag);
31 
32 static void
33 usage(int devmask, int recmask)
34 {
35 	int	i, n;
36 
37 	printf("usage: mixer [-f device] [-s | -S] [dev [+|-][voll[:[+|-]volr]] ...\n"
38 	    "       mixer [-f device] [-s | -S] recsrc ...\n"
39 	    "       mixer [-f device] [-s | -S] {^|+|-|=}rec rdev ...\n");
40 	if (devmask != 0) {
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++;
48 			}
49 		}
50 	}
51 	if (recmask != 0) {
52 		printf("\n rec devices: ");
53 		for (i = 0, n = 0; i < SOUND_MIXER_NRDEVICES; i++) {
54 			if ((1 << i) & recmask)  {
55 				if (n)
56 					printf(", ");
57 				printf("%s", names[i]);
58 				n++;
59 			}
60 		}
61 	}
62 	printf("\n");
63 	exit(1);
64 }
65 
66 static int
67 res_name(const char *name, int mask)
68 {
69 	int	i;
70 
71 	for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
72 		if ((1 << i) & mask && strcmp(names[i], name) == 0)
73 			break;
74 
75 	if (i == SOUND_MIXER_NRDEVICES)
76 		return (-1);
77 
78 	return (i);
79 }
80 
81 static void
82 print_recsrc(int recsrc, int recmask, int sflag)
83 {
84 	int	i, n;
85 
86 	if (recmask == 0)
87 		return;
88 
89 	if (!sflag)
90 		printf("Recording source: ");
91 
92 	for (i = 0, n = 0; i < SOUND_MIXER_NRDEVICES; i++) {
93 		if ((1 << i) & recsrc) {
94 			if (sflag)
95 				printf("%srec ", n ? " +" : "=");
96 			else if (n)
97 				printf(", ");
98 			printf("%s", names[i]);
99 			n++;
100 		}
101 	}
102 	if (!sflag)
103 		printf("\n");
104 }
105 
106 int
107 main(int argc, char *argv[])
108 {
109 	char	mixer[PATH_MAX] = "/dev/mixer";
110 	char	lstr[8], rstr[8];
111 	char	*name, *eptr;
112 	int	devmask = 0, recmask = 0, recsrc = 0, orecsrc;
113 	int	dusage = 0, drecsrc = 0, sflag = 0, Sflag = 0;
114 	int	l, r, lrel, rrel;
115 	int	ch, i, bar, baz, dev, m, n, t;
116 
117 	if ((name = strdup(basename(argv[0]))) == NULL)
118 		err(1, "strdup()");
119 	if (strncmp(name, "mixer", 5) == 0 && name[5] != '\0') {
120 		n = strtol(name + 5, &eptr, 10) - 1;
121 		if (n > 0 && *eptr == '\0')
122 			snprintf(mixer, PATH_MAX - 1, "/dev/mixer%d", n);
123 	}
124 	free(name);
125 	name = mixer;
126 
127 	n = 1;
128 	for (;;) {
129 		if (n >= argc || *argv[n] != '-')
130 			break;
131 		if (strlen(argv[n]) != 2) {
132 			if (strcmp(argv[n] + 1, "rec") != 0)
133 				dusage = 1;
134 			break;
135 		}
136 		ch = *(argv[n] + 1);
137 		if (ch == 'f' && n < argc - 1) {
138 			name = argv[n + 1];
139 			n += 2;
140 		} else if (ch == 's') {
141 			sflag = 1;
142 			n++;
143 		} else if (ch == 'S') {
144 			Sflag = 1;
145 			n++;
146 		} else {
147 			dusage = 1;
148 			break;
149 		}
150 	}
151 	if (sflag && Sflag)
152 		dusage = 1;
153 
154 	argc -= n - 1;
155 	argv += n - 1;
156 
157 	if ((baz = open(name, O_RDWR)) < 0)
158 		err(1, "%s", name);
159 	if (ioctl(baz, SOUND_MIXER_READ_DEVMASK, &devmask) == -1)
160 		err(1, "SOUND_MIXER_READ_DEVMASK");
161 	if (ioctl(baz, SOUND_MIXER_READ_RECMASK, &recmask) == -1)
162 		err(1, "SOUND_MIXER_READ_RECMASK");
163 	if (ioctl(baz, SOUND_MIXER_READ_RECSRC, &recsrc) == -1)
164 		err(1, "SOUND_MIXER_READ_RECSRC");
165 	orecsrc = recsrc;
166 
167 	if (argc == 1 && dusage == 0) {
168 		for (i = 0, n = 0; i < SOUND_MIXER_NRDEVICES; i++) {
169 			if (!((1 << i) & devmask))
170 				continue;
171 			if (ioctl(baz, MIXER_READ(i),&bar) == -1) {
172 			   	warn("MIXER_READ");
173 				continue;
174 			}
175 			if (Sflag || sflag) {
176 				printf("%s%s%c%d:%d", n ? " " : "",
177 				    names[i], Sflag ? ':' : ' ',
178 				    bar & 0x7f, (bar >> 8) & 0x7f);
179 				n++;
180 			} else
181 				printf("Mixer %-8s is currently set to "
182 				    "%3d:%d\n", names[i], bar & 0x7f,
183 				    (bar >> 8) & 0x7f);
184 		}
185 		if (n && recmask)
186 			printf(" ");
187 		print_recsrc(recsrc, recmask, Sflag || sflag);
188 		return (0);
189 	}
190 
191 	argc--;
192 	argv++;
193 
194 	n = 0;
195 	while (argc > 0 && dusage == 0) {
196 		if (strcmp("recsrc", *argv) == 0) {
197 			drecsrc = 1;
198 			argc--;
199 			argv++;
200 			continue;
201 		} else if (strcmp("rec", *argv + 1) == 0) {
202 			if (**argv != '+' && **argv != '-' &&
203 			    **argv != '=' && **argv != '^') {
204 				warnx("unknown modifier: %c", **argv);
205 				dusage = 1;
206 				break;
207 			}
208 			if (argc <= 1) {
209 				warnx("no recording device specified");
210 				dusage = 1;
211 				break;
212 			}
213 			if ((dev = res_name(argv[1], recmask)) == -1) {
214 				warnx("unknown recording device: %s", argv[1]);
215 				dusage = 1;
216 				break;
217 			}
218 			switch (**argv) {
219 			case '+':
220 				recsrc |= (1 << dev);
221 				break;
222 			case '-':
223 				recsrc &= ~(1 << dev);
224 				break;
225 			case '=':
226 				recsrc = (1 << dev);
227 				break;
228 			case '^':
229 				recsrc ^= (1 << dev);
230 				break;
231 			}
232 			drecsrc = 1;
233 			argc -= 2;
234 			argv += 2;
235 			continue;
236 		}
237 
238 		if ((t = sscanf(*argv, "%d:%d", &l, &r)) > 0)
239 			dev = 0;
240 		else if ((dev = res_name(*argv, devmask)) == -1) {
241 			warnx("unknown device: %s", *argv);
242 			dusage = 1;
243 			break;
244 		}
245 
246 		lrel = rrel = 0;
247 		if (argc > 1) {
248 			m = sscanf(argv[1], "%7[^:]:%7s", lstr, rstr);
249 			if (m > 0) {
250 				if (*lstr == '+' || *lstr == '-')
251 					lrel = rrel = 1;
252 				l = strtol(lstr, NULL, 10);
253 			}
254 			if (m > 1) {
255 				if (*rstr == '+' || *rstr == '-')
256 					rrel = 1;
257 				r = strtol(rstr, NULL, 10);
258 			}
259 		}
260 
261 		switch (argc > 1 ? m : t) {
262 		case 0:
263 			if (ioctl(baz, MIXER_READ(dev), &bar) == -1) {
264 				warn("MIXER_READ");
265 				argc--;
266 				argv++;
267 				continue;
268 			}
269 			if (Sflag || sflag) {
270 				printf("%s%s%c%d:%d", n ? " " : "",
271 				    names[dev], Sflag ? ':' : ' ',
272 				    bar & 0x7f, (bar >> 8) & 0x7f);
273 				n++;
274 			} else
275 				printf("Mixer %-8s is currently set to "
276 				    "%3d:%d\n", names[dev], bar & 0x7f,
277 				    (bar >> 8) & 0x7f);
278 
279 			argc--;
280 			argv++;
281 			break;
282 		case 1:
283 			r = l;
284 			/* FALLTHROUGH */
285 		case 2:
286 			if (ioctl(baz, MIXER_READ(dev), &bar) == -1) {
287 				warn("MIXER_READ");
288 				argc--;
289 				argv++;
290 				continue;
291 			}
292 
293 			if (lrel)
294 				l = (bar & 0x7f) + l;
295 			if (rrel)
296 				r = ((bar >> 8) & 0x7f) + r;
297 
298 			if (l < 0)
299 				l = 0;
300 			else if (l > 100)
301 				l = 100;
302 			if (r < 0)
303 				r = 0;
304 			else if (r > 100)
305 				r = 100;
306 
307 			if (!Sflag)
308 				printf("Setting the mixer %s from %d:%d to "
309 				    "%d:%d.\n", names[dev], bar & 0x7f,
310 				    (bar >> 8) & 0x7f, l, r);
311 
312 			l |= r << 8;
313 			if (ioctl(baz, MIXER_WRITE(dev), &l) == -1)
314 				warn("WRITE_MIXER");
315 
316 			argc -= 2;
317 			argv += 2;
318  			break;
319 		}
320 	}
321 
322 	if (dusage) {
323 		close(baz);
324 		usage(devmask, recmask);
325 		/* NOTREACHED */
326 	}
327 
328 	if (orecsrc != recsrc) {
329 		if (ioctl(baz, SOUND_MIXER_WRITE_RECSRC, &recsrc) == -1)
330 			err(1, "SOUND_MIXER_WRITE_RECSRC");
331 		if (ioctl(baz, SOUND_MIXER_READ_RECSRC, &recsrc) == -1)
332 			err(1, "SOUND_MIXER_READ_RECSRC");
333 	}
334 
335 	if (drecsrc)
336 		print_recsrc(recsrc, recmask, Sflag || sflag);
337 
338 	close(baz);
339 
340 	return (0);
341 }
342