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