xref: /freebsd/usr.sbin/mixer/mixer.c (revision 1e413cf93298b5b97441a21d9a50fdcd0ee9945e)
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 <sys/cdefs.h>
15 __FBSDID("$FreeBSD$");
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 const char *names[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_NAMES;
26 
27 void usage(int devmask, int recmask);
28 int res_name(const char *name, int mask);
29 void print_recsrc(int recsrc, int shortflag);
30 
31 void
32 usage(int devmask, int recmask)
33 {
34 	int i, n;
35 
36 	printf("usage: mixer [-f device] [-s | -S] [dev [+|-][voll[:[+|-]volr]] ...\n"
37 	       "       mixer [-f device] [-s | -S] recsrc ...\n"
38 	       "       mixer [-f device] [-s | -S] {^|+|-|=}rec rdev ... \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 
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, int shortflag)
73 {
74 	int i, n = 0;
75 
76 	if (!shortflag)
77 		printf("Recording source: ");
78 
79 	for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
80 		if ((1 << i) & recsrc) {
81 			if (shortflag) {
82 				if (n)
83 					printf(" +rec ");
84 				else
85 					printf("=rec ");
86 			} else if (n)
87 				printf(", ");
88 			printf("%s", names[i]);
89 			n = 1;
90 		}
91 	if (!shortflag)
92 		printf("\n");
93 }
94 
95 int
96 main(int argc, char *argv[])
97 {
98 	int foo, bar, baz, dev;
99 	int devmask = 0, recmask = 0, recsrc = 0, orecsrc;
100 	int dusage = 0, drecsrc = 0, shortflag = 0, Shortflag = 0;
101 	int l = 0, r = 0, t = 0;
102 	char lstr[5], rstr[5];
103 	int n = 0, lrel = 0, rrel = 0;
104 	int ch;
105 
106 	char *name;
107 
108 	name = "/dev/mixer";
109 
110 	if (!strcmp(argv[0], "mixer2"))
111 		name = "/dev/mixer1";
112 	else if (!strcmp(argv[0], "mixer3"))
113 		name = "/dev/mixer2";
114 
115 	while ((ch = getopt(argc, argv, "f:sS")) != -1)
116 		switch (ch) {
117 			case 'f':
118 				name = optarg;
119 				break;
120 			case 's':
121 				shortflag = 1;
122 				break;
123 			case 'S':
124 				Shortflag = 1;
125 				break;
126 			default:
127 				dusage = 1;
128 		}
129 	argc -= (optind - 1);
130 	argv += (optind - 1);
131 
132 	if ((baz = open(name, O_RDWR)) < 0)
133 		err(1, "%s", name);
134 	if (ioctl(baz, SOUND_MIXER_READ_DEVMASK, &devmask) == -1)
135 		err(1, "SOUND_MIXER_READ_DEVMASK");
136 	if (ioctl(baz, SOUND_MIXER_READ_RECMASK, &recmask) == -1)
137 		err(1, "SOUND_MIXER_READ_RECMASK");
138 	if (ioctl(baz, SOUND_MIXER_READ_RECSRC, &recsrc) == -1)
139 		err(1, "SOUND_MIXER_READ_RECSRC");
140 	orecsrc = recsrc;
141 
142 	if ((argc == 1) && (dusage == 0)) {
143 		for (foo = 0; foo < SOUND_MIXER_NRDEVICES; foo++) {
144 			if (!((1 << foo) & devmask))
145 				continue;
146 			if (ioctl(baz, MIXER_READ(foo),&bar)== -1) {
147 			   	warn("MIXER_READ");
148 				continue;
149 			}
150 			if (Shortflag)
151 				printf("%s:%d:%d ", names[foo], bar & 0x7f,
152 				       (bar >> 8) & 0x7f);
153 			else if (shortflag)
154 				printf("%s %d:%d ", names[foo], bar & 0x7f,
155 				       (bar >> 8) & 0x7f);
156 			else
157 				printf("Mixer %-8s is currently set to %3d:%d\n",
158 				       names[foo], bar & 0x7f, (bar >> 8) & 0x7f);
159 		}
160 		if (ioctl(baz, SOUND_MIXER_READ_RECSRC, &recsrc) == -1)
161 			err(1, "SOUND_MIXER_READ_RECSRC");
162 		print_recsrc(recsrc, shortflag || Shortflag);
163 		return(0);
164 	}
165 
166 	argc--; argv++;
167 
168 	while ((argc > 0) && (dusage == 0)) {
169 		if (!strcmp("recsrc", *argv)) {
170 			drecsrc = 1;
171 			argc--; argv++;
172 			continue;
173 		} else if (argc > 1 && !strcmp("rec", *argv + 1)) {
174 			if (**argv != '+' && **argv != '-' &&
175 			    **argv != '=' && **argv != '^') {
176 				warnx("unknown modifier: %c", **argv);
177 				dusage = 1;
178 				break;
179 			}
180 			if ((dev = res_name(argv[1], recmask)) == -1) {
181 				warnx("unknown recording device: %s", argv[1]);
182 				dusage = 1;
183 				break;
184 			}
185 			switch(**argv) {
186 			case '+':
187 				recsrc |= (1 << dev);
188 				break;
189 			case '-':
190 				recsrc &= ~(1 << dev);
191 				break;
192 			case '=':
193 				recsrc = (1 << dev);
194 				break;
195 			case '^':
196 				recsrc ^= (1 << dev);
197 				break;
198 			}
199 			drecsrc = 1;
200 			argc -= 2; argv += 2;
201 			continue;
202 		}
203 
204 		if ((t = sscanf(*argv, "%d:%d", &l, &r)) > 0) {
205 			dev = 0;
206 		}
207 		else if((dev = res_name(*argv, devmask)) == -1) {
208 			warnx("unknown device: %s", *argv);
209 			dusage = 1;
210 			break;
211 		}
212 
213 #define	issign(c)	(((c) == '+') || ((c) == '-'))
214 
215 		if (argc > 1) {
216 			n = sscanf(argv[1], "%7[^:]:%7s", lstr, rstr);
217 			if (n > 0) {
218 				if (issign(lstr[0]))
219 					lrel = rrel = 1;
220 				l = atoi(lstr);
221 			}
222 			if (n > 1) {
223 				rrel = 0;
224 				if (issign(rstr[0]))
225 					rrel = 1;
226 				r = atoi(rstr);
227 			}
228 		}
229 
230 		switch(argc > 1 ? n : t) {
231 		case 0:
232 			if (ioctl(baz, MIXER_READ(dev),&bar)== -1) {
233 				warn("MIXER_READ");
234 				argc--; argv++;
235 				continue;
236 			}
237 			if (Shortflag)
238 				printf("%s:%d:%d ", names[dev], bar & 0x7f,
239 				       (bar >> 8) & 0x7f);
240 			else if (shortflag)
241 				printf("%s %d:%d ", names[dev], bar & 0x7f,
242 				       (bar >> 8) & 0x7f);
243 			else
244 				printf("Mixer %-8s is currently set to %3d:%d\n",
245 				  names[dev], bar & 0x7f, (bar >> 8) & 0x7f);
246 
247 			argc--; argv++;
248 			break;
249 		case 1:
250 			r = l;
251 		case 2:
252 			if (ioctl(baz, MIXER_READ(dev),&bar)== -1) {
253 				warn("MIXER_READ");
254 				argc--; argv++;
255 				continue;
256 			}
257 
258 			if (lrel)
259 				l = (bar & 0x7f) + l;
260 			if (rrel)
261 				r = ((bar >> 8) & 0x7f) + r;
262 
263 			if (l < 0)
264 				l = 0;
265 			else if (l > 100)
266 				l = 100;
267 			if (r < 0)
268 				r = 0;
269 			else if (r > 100)
270 				r = 100;
271 
272 			if (!Shortflag)
273 				printf("Setting the mixer %s from %d:%d to %d:%d.\n",
274 				       names[dev], bar & 0x7f, (bar >> 8) & 0x7f, l, r);
275 
276 			l |= r << 8;
277 			if (ioctl(baz, MIXER_WRITE(dev), &l) == -1)
278 				warn("WRITE_MIXER");
279 
280 			argc -= 2; argv += 2;
281  			break;
282 		}
283 	}
284 
285 	if (dusage) {
286 		close(baz);
287 		usage(devmask, recmask);
288 		/* Not reached */
289 	}
290 
291 	if (orecsrc != recsrc)
292 		if (ioctl(baz, SOUND_MIXER_WRITE_RECSRC, &recsrc) == -1)
293 			err(1, "SOUND_MIXER_WRITE_RECSRC");
294 
295 	if (drecsrc) {
296 		if (ioctl(baz, SOUND_MIXER_READ_RECSRC, &recsrc) == -1)
297 			err(1, "SOUND_MIXER_READ_RECSRC");
298 		print_recsrc(recsrc, shortflag || Shortflag);
299 	}
300 
301 	close(baz);
302 
303 	exit(0);
304 }
305