xref: /dragonfly/usr.sbin/mixer/mixer.c (revision f8f04fe3)
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: src/usr.sbin/mixer/mixer.c,v 1.11.2.6 2001/07/30 10:22:58 dd Exp $
14  * $DragonFly: src/usr.sbin/mixer/mixer.c,v 1.6 2004/04/15 12:58:12 joerg Exp $
15  */
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 
25 #define LEFT(vol) (vol & 0x7f)
26 #define RIGHT(vol) ((vol >> 8) & 0x7f)
27 
28 static const char *names[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_NAMES;
29 static const char *defaultdev = "/dev/mixer";
30 
31 static void	usage(int devmask, int recmask);
32 static int	res_name(const char *name, int mask);
33 static void	print_recsrc(int recsrc);
34 static void	print_recsrc_short(int recsrc);
35 
36 void
37 usage(int devmask, int recmask)
38 {
39 	int i, n;
40 
41 	printf("usage: mixer [-f device] [-s] [dev [+|-][voll[:[+|-]volr]] ...\n"
42 	       "       mixer [-f device] [-s] recsrc ...\n"
43 	       "       mixer [-f device] [-s] {^|+|-|=}rec recdev ...\n"
44 	       "       mixer -h\n");
45 	printf(" devices: ");
46 	for (i = 0, n = 0; i < SOUND_MIXER_NRDEVICES; i++) {
47 		if ((1 << i) & devmask)  {
48 			if (n)
49 				printf(", ");
50 			printf("%s", names[i]);
51 			n = 1;
52 		}
53 	}
54 	printf("\n rec devices: ");
55 	for (i = 0, n = 0; i < SOUND_MIXER_NRDEVICES; i++) {
56 		if ((1 << i) & recmask)  {
57 			if (n)
58 				printf(", ");
59 			printf("%s", names[i]);
60 			n = 1;
61 		}
62 	}
63 	printf("\n");
64 	exit(1);
65 }
66 
67 int
68 res_name(const char *name, int mask)
69 {
70 	int i;
71 
72 	for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
73 		if ((1 << i) & mask && !strcmp(names[i], name))
74 			break;
75 
76 	if (i == SOUND_MIXER_NRDEVICES)
77 		return(-1);
78 
79 	return(i);
80 }
81 
82 void
83 print_recsrc(int recsrc)
84 {
85 	int i, n = 0;
86 	printf("Recording source: ");
87 
88 	for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
89 		if ((1 << i) & recsrc) {
90 			if (n)
91 				printf(", ");
92 			printf("%s", names[i]);
93 			n = 1;
94 		}
95 	}
96 	printf("\n");
97 }
98 
99 void
100 print_recsrc_short(int recsrc)
101 {
102 	int i, first;
103 
104 	first = 1;
105 
106 	for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
107 		if ((1 << i) & recsrc) {
108 			if (first) {
109 				printf("=rec ");
110 				first = 0;
111 			}
112 			printf("%s ", names[i]);
113 		}
114 	}
115 }
116 
117 int
118 main(int argc, char **argv)
119 {
120 	int i, mset, fd, dev;
121 	int devmask = 0, recmask = 0, recsrc = 0, orecsrc;
122 	int dusage = 0, drecsrc = 0, shortflag = 0;
123 	int l = 0, r = 0, t = 0;
124 	int n = 0, lrel = 0, rrel = 0;
125 	char lstr[8], rstr[8];
126 	char ch;
127 
128 	const char *name = defaultdev;
129 
130 	while ((ch = getopt(argc, argv, "f:sh")) != -1)
131 		switch (ch) {
132 			case 'f':
133 				name = optarg;
134 				break;
135 			case 's':
136 				shortflag = 1;
137 				break;
138 			case 'h': /* Fall through */
139 			default:
140 				dusage = 1;
141 		}
142 	argc -= optind;
143 	argv += optind;
144 
145 	if ((fd = open(name, O_RDWR)) < 0)
146 		err(1, "%s", name);
147 	if (ioctl(fd, SOUND_MIXER_READ_DEVMASK, &devmask) == -1)
148 		err(1, "SOUND_MIXER_READ_DEVMASK");
149 	if (ioctl(fd, SOUND_MIXER_READ_RECMASK, &recmask) == -1)
150 		err(1, "SOUND_MIXER_READ_RECMASK");
151 	if (ioctl(fd, SOUND_MIXER_READ_RECSRC, &recsrc) == -1)
152 		err(1, "SOUND_MIXER_READ_RECSRC");
153 	orecsrc = recsrc;
154 
155 	if (dusage) {
156 		close(fd);
157 		usage(devmask, recmask); /* Does not return */
158 	}
159 
160 	if (argc == 0) {
161 		for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
162 			if (!((1 << i) & devmask))
163 				continue;
164 			if (ioctl(fd, MIXER_READ(i),&mset)== -1) {
165 			   	warn("MIXER_READ");
166 				continue;
167 			}
168 			if (shortflag)
169 				printf("%s %d:%d ", names[i], LEFT(mset),
170 				       RIGHT(mset));
171 			else
172 				printf("Mixer %-8s is currently set to %3d:%d\n",
173 				       names[i], LEFT(mset), RIGHT(mset));
174 		}
175 		if (ioctl(fd, SOUND_MIXER_READ_RECSRC, &recsrc) == -1)
176 			err(1, "SOUND_MIXER_READ_RECSRC");
177 		if (shortflag) {
178 			print_recsrc_short(recsrc);
179 			if (isatty(STDOUT_FILENO))
180 				printf("\n");
181 		} else
182 			print_recsrc(recsrc);
183 		exit(0);
184 	}
185 
186 
187 
188 	while (argc > 0) {
189 		if (!strcmp("recsrc", *argv)) {
190 			drecsrc = 1;
191 			argc--; argv++;
192 			continue;
193 		} else if (argc > 1 && !strcmp("rec", *argv + 1)) {
194 			if (**argv != '+' && **argv != '-' &&
195 			    **argv != '=' && **argv != '^') {
196 				warnx("unknown modifier: %c", **argv);
197 				dusage = 1;
198 				break;
199 			}
200 			if ((dev = res_name(argv[1], recmask)) == -1) {
201 				warnx("unknown recording device: %s", argv[1]);
202 				dusage = 1;
203 				break;
204 			}
205 			switch(**argv) {
206 			case '+':
207 				recsrc |= (1 << dev);
208 				break;
209 			case '-':
210 				recsrc &= ~(1 << dev);
211 				break;
212 			case '=':
213 				recsrc = (1 << dev);
214 				break;
215 			case '^':
216 				recsrc ^= (1 << dev);
217 				break;
218 			}
219 			drecsrc = 1;
220 			argc -= 2; argv += 2;
221 			continue;
222 		}
223 
224 		if ((t = sscanf(*argv, "%d:%d", &l, &r)) > 0) {
225 			dev = 0;
226 		}
227 		else if((dev = res_name(*argv, devmask)) == -1) {
228 			warnx("unknown device: %s", *argv);
229 			dusage = 1;
230 			break;
231 		}
232 
233 #define	issign(c)	(((c) == '+') || ((c) == '-'))
234 
235 		if (argc > 1) {
236 			n = sscanf(argv[1], "%7[^:]:%7s", lstr, rstr);
237 			if (n > 0) {
238 				if (issign(lstr[0]))
239 					lrel = rrel = 1;
240 				l = atoi(lstr);
241 			}
242 			if (n > 1) {
243 				rrel = 0;
244 				if (issign(rstr[0]))
245 					rrel = 1;
246 				r = atoi(rstr);
247 			}
248 		}
249 
250 		switch(argc > 1 ? n : t) {
251 		case 0:
252 			if (ioctl(fd, MIXER_READ(dev),&mset)== -1) {
253 				warn("MIXER_READ");
254 				argc--; argv++;
255 				continue;
256 			}
257 			if (shortflag)
258 				printf("%s %d:%d ", names[dev], LEFT(mset),
259 				       RIGHT(mset));
260 			else
261 				printf("Mixer %-8s is currently set to %3d:%d\n",
262 				       names[dev], LEFT(mset), RIGHT(mset));
263 
264 			argc--; argv++;
265 			break;
266 		case 1:
267 			r = l;
268 		case 2:
269 			if (ioctl(fd, MIXER_READ(dev),&mset)== -1) {
270 				warn("MIXER_READ");
271 				argc--; argv++;
272 				continue;
273 			}
274 
275 			if (lrel)
276 				l += LEFT(mset);
277 			if (rrel)
278 				r += RIGHT(mset);
279 
280 			if (l < 0)
281 				l = 0;
282 			else if (l > 100)
283 				l = 100;
284 			if (r < 0)
285 				r = 0;
286 			else if (r > 100)
287 				r = 100;
288 
289 			printf("Setting the mixer %s to %d:%d.\n", names[dev],
290 			       l, r);
291 
292 			l |= r << 8;
293 			if (ioctl(fd, MIXER_WRITE(dev), &l) == -1)
294 				warn("WRITE_MIXER");
295 
296 			argc -= 2; argv += 2;
297  			break;
298 		}
299 	}
300 
301 	if (orecsrc != recsrc)
302 		if (ioctl(fd, SOUND_MIXER_WRITE_RECSRC, &recsrc) == -1)
303 			err(1, "SOUND_MIXER_WRITE_RECSRC");
304 
305 	if (drecsrc) {
306 		if (ioctl(fd, SOUND_MIXER_READ_RECSRC, &recsrc) == -1)
307 			err(1, "SOUND_MIXER_READ_RECSRC");
308 		print_recsrc(recsrc);
309 	}
310 
311 	close(fd);
312 
313 	exit(0);
314 }
315