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