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