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 - [email protected]
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 <libgen.h>
20 #include <limits.h>
21 #include <stdio.h>
22 #include <string.h>
23 #include <stdlib.h>
24 #include <unistd.h>
25 #include <sys/soundcard.h>
26
27 static const char *names[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_NAMES;
28
29 static void usage(int devmask, int recmask) __dead2;
30 static int res_name(const char *name, int mask);
31 static void print_recsrc(int recsrc, int recmask, int sflag);
32
33 static void __dead2
usage(int devmask,int recmask)34 usage(int devmask, int recmask)
35 {
36 int i, n;
37
38 printf("usage: mixer [-f device] [-s | -S] [dev [+|-][voll[:[+|-]volr]] ...\n"
39 " mixer [-f device] [-s | -S] recsrc ...\n"
40 " mixer [-f device] [-s | -S] {^|+|-|=}rec rdev ...\n");
41 if (devmask != 0) {
42 printf(" devices: ");
43 for (i = 0, n = 0; i < SOUND_MIXER_NRDEVICES; i++)
44 if ((1 << i) & devmask) {
45 if (n)
46 printf(", ");
47 printf("%s", names[i]);
48 n++;
49 }
50 }
51 if (recmask != 0) {
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++;
59 }
60 }
61 printf("\n");
62 exit(1);
63 }
64
65 static int
res_name(const char * name,int mask)66 res_name(const char *name, int mask)
67 {
68 int foo;
69
70 for (foo = 0; foo < SOUND_MIXER_NRDEVICES; foo++)
71 if ((1 << foo) & mask && strcmp(names[foo], name) == 0)
72 break;
73
74 return (foo == SOUND_MIXER_NRDEVICES ? -1 : foo);
75 }
76
77 static void
print_recsrc(int recsrc,int recmask,int sflag)78 print_recsrc(int recsrc, int recmask, int sflag)
79 {
80 int i, n;
81
82 if (recmask == 0)
83 return;
84
85 if (!sflag)
86 printf("Recording source: ");
87
88 for (i = 0, n = 0; i < SOUND_MIXER_NRDEVICES; i++)
89 if ((1 << i) & recsrc) {
90 if (sflag)
91 printf("%srec ", n ? " +" : "=");
92 else if (n)
93 printf(", ");
94 printf("%s", names[i]);
95 n++;
96 }
97 if (!sflag)
98 printf("\n");
99 }
100
101 int
main(int argc,char * argv[])102 main(int argc, char *argv[])
103 {
104 char mixer[PATH_MAX] = "/dev/mixer";
105 char lstr[8], rstr[8];
106 char *name, *eptr;
107 int devmask = 0, recmask = 0, recsrc = 0, orecsrc;
108 int dusage = 0, drecsrc = 0, sflag = 0, Sflag = 0;
109 int l, r, lrel, rrel;
110 int ch, foo, bar, baz, dev, m, n, t;
111
112 if ((name = strdup(basename(argv[0]))) == NULL)
113 err(1, "strdup()");
114 if (strncmp(name, "mixer", 5) == 0 && name[5] != '\0') {
115 n = strtol(name + 5, &eptr, 10) - 1;
116 if (n > 0 && *eptr == '\0')
117 snprintf(mixer, PATH_MAX - 1, "/dev/mixer%d", n);
118 }
119 free(name);
120 name = mixer;
121
122 n = 1;
123 for (;;) {
124 if (n >= argc || *argv[n] != '-')
125 break;
126 if (strlen(argv[n]) != 2) {
127 if (strcmp(argv[n] + 1, "rec") != 0)
128 dusage = 1;
129 break;
130 }
131 ch = *(argv[n] + 1);
132 if (ch == 'f' && n < argc - 1) {
133 name = argv[n + 1];
134 n += 2;
135 } else if (ch == 's') {
136 sflag = 1;
137 n++;
138 } else if (ch == 'S') {
139 Sflag = 1;
140 n++;
141 } else {
142 dusage = 1;
143 break;
144 }
145 }
146 if (sflag && Sflag)
147 dusage = 1;
148
149 argc -= n - 1;
150 argv += n - 1;
151
152 if ((baz = open(name, O_RDWR)) < 0)
153 err(1, "%s", name);
154 if (ioctl(baz, SOUND_MIXER_READ_DEVMASK, &devmask) == -1)
155 err(1, "SOUND_MIXER_READ_DEVMASK");
156 if (ioctl(baz, SOUND_MIXER_READ_RECMASK, &recmask) == -1)
157 err(1, "SOUND_MIXER_READ_RECMASK");
158 if (ioctl(baz, SOUND_MIXER_READ_RECSRC, &recsrc) == -1)
159 err(1, "SOUND_MIXER_READ_RECSRC");
160 orecsrc = recsrc;
161
162 if (argc == 1 && dusage == 0) {
163 for (foo = 0, n = 0; foo < SOUND_MIXER_NRDEVICES; foo++) {
164 if (!((1 << foo) & devmask))
165 continue;
166 if (ioctl(baz, MIXER_READ(foo),&bar) == -1) {
167 warn("MIXER_READ");
168 continue;
169 }
170 if (Sflag || sflag) {
171 printf("%s%s%c%d:%d", n ? " " : "",
172 names[foo], Sflag ? ':' : ' ',
173 bar & 0x7f, (bar >> 8) & 0x7f);
174 n++;
175 } else
176 printf("Mixer %-8s is currently set to "
177 "%3d:%d\n", names[foo], bar & 0x7f,
178 (bar >> 8) & 0x7f);
179 }
180 if (n && recmask)
181 printf(" ");
182 print_recsrc(recsrc, recmask, Sflag || sflag);
183 return (0);
184 }
185
186 argc--;
187 argv++;
188
189 n = 0;
190 while (argc > 0 && dusage == 0) {
191 if (strcmp("recsrc", *argv) == 0) {
192 drecsrc = 1;
193 argc--;
194 argv++;
195 continue;
196 } else if (strcmp("rec", *argv + 1) == 0) {
197 if (**argv != '+' && **argv != '-' &&
198 **argv != '=' && **argv != '^') {
199 warnx("unknown modifier: %c", **argv);
200 dusage = 1;
201 break;
202 }
203 if (argc <= 1) {
204 warnx("no recording device specified");
205 dusage = 1;
206 break;
207 }
208 if ((dev = res_name(argv[1], recmask)) == -1) {
209 warnx("unknown recording device: %s", argv[1]);
210 dusage = 1;
211 break;
212 }
213 switch (**argv) {
214 case '+':
215 recsrc |= (1 << dev);
216 break;
217 case '-':
218 recsrc &= ~(1 << dev);
219 break;
220 case '=':
221 recsrc = (1 << dev);
222 break;
223 case '^':
224 recsrc ^= (1 << dev);
225 break;
226 }
227 drecsrc = 1;
228 argc -= 2;
229 argv += 2;
230 continue;
231 }
232
233 if ((t = sscanf(*argv, "%d:%d", &l, &r)) > 0)
234 dev = 0;
235 else if ((dev = res_name(*argv, devmask)) == -1) {
236 warnx("unknown device: %s", *argv);
237 dusage = 1;
238 break;
239 }
240
241 lrel = rrel = 0;
242 if (argc > 1) {
243 m = sscanf(argv[1], "%7[^:]:%7s", lstr, rstr);
244 if (m == EOF) {
245 warnx("invalid value: %s", argv[1]);
246 dusage = 1;
247 break;
248 }
249 if (m > 0) {
250 if (*lstr == '+' || *lstr == '-')
251 lrel = rrel = 1;
252 l = strtol(lstr, NULL, 10);
253 }
254 if (m > 1) {
255 if (*rstr == '+' || *rstr == '-')
256 rrel = 1;
257 r = strtol(rstr, NULL, 10);
258 }
259 }
260
261 switch (argc > 1 ? m : t) {
262 case 0:
263 if (ioctl(baz, MIXER_READ(dev), &bar) == -1) {
264 warn("MIXER_READ");
265 argc--;
266 argv++;
267 continue;
268 }
269 if (Sflag || sflag) {
270 printf("%s%s%c%d:%d", n ? " " : "",
271 names[dev], Sflag ? ':' : ' ',
272 bar & 0x7f, (bar >> 8) & 0x7f);
273 n++;
274 } else
275 printf("Mixer %-8s is currently set to "
276 "%3d:%d\n", names[dev], bar & 0x7f,
277 (bar >> 8) & 0x7f);
278
279 argc--;
280 argv++;
281 break;
282 case 1:
283 r = l;
284 /* FALLTHROUGH */
285 case 2:
286 if (ioctl(baz, MIXER_READ(dev), &bar) == -1) {
287 warn("MIXER_READ");
288 argc--;
289 argv++;
290 continue;
291 }
292
293 if (lrel)
294 l = (bar & 0x7f) + l;
295 if (rrel)
296 r = ((bar >> 8) & 0x7f) + r;
297
298 if (l < 0)
299 l = 0;
300 else if (l > 100)
301 l = 100;
302 if (r < 0)
303 r = 0;
304 else if (r > 100)
305 r = 100;
306
307 if (!Sflag)
308 printf("Setting the mixer %s from %d:%d to "
309 "%d:%d.\n", names[dev], bar & 0x7f,
310 (bar >> 8) & 0x7f, l, r);
311
312 l |= r << 8;
313 if (ioctl(baz, MIXER_WRITE(dev), &l) == -1)
314 warn("WRITE_MIXER");
315
316 argc -= 2;
317 argv += 2;
318 break;
319 }
320 }
321
322 if (dusage) {
323 close(baz);
324 usage(devmask, recmask);
325 /* NOTREACHED */
326 }
327
328 if (orecsrc != recsrc) {
329 if (ioctl(baz, SOUND_MIXER_WRITE_RECSRC, &recsrc) == -1)
330 err(1, "SOUND_MIXER_WRITE_RECSRC");
331 if (ioctl(baz, SOUND_MIXER_READ_RECSRC, &recsrc) == -1)
332 err(1, "SOUND_MIXER_READ_RECSRC");
333 }
334
335 if (drecsrc)
336 print_recsrc(recsrc, recmask, Sflag || sflag);
337
338 close(baz);
339
340 return (0);
341 }
342