]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - usr.sbin/mixer/mixer.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / usr.sbin / mixer / mixer.c
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 <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 const char      *names[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_NAMES;
28
29 static void     usage(int devmask, int recmask);
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
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
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
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
102 main(int argc, char *argv[])
103 {
104         char    mixer[PATH_MAX] = "/dev/mixer";
105         char    lstr[5], rstr[5];
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 (argc > 1 && 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 ((dev = res_name(argv[1], recmask)) == -1) {
204                                 warnx("unknown recording device: %s", argv[1]);
205                                 dusage = 1;
206                                 break;
207                         }
208                         switch (**argv) {
209                         case '+':
210                                 recsrc |= (1 << dev);
211                                 break;
212                         case '-':
213                                 recsrc &= ~(1 << dev);
214                                 break;
215                         case '=':
216                                 recsrc = (1 << dev);
217                                 break;
218                         case '^':
219                                 recsrc ^= (1 << dev);
220                                 break;
221                         }
222                         drecsrc = 1;
223                         argc -= 2;
224                         argv += 2;
225                         continue;
226                 }
227
228                 if ((t = sscanf(*argv, "%d:%d", &l, &r)) > 0)
229                         dev = 0;
230                 else if ((dev = res_name(*argv, devmask)) == -1) {
231                         warnx("unknown device: %s", *argv);
232                         dusage = 1;
233                         break;
234                 }
235
236                 lrel = rrel = 0;
237                 if (argc > 1) {
238                         m = sscanf(argv[1], "%7[^:]:%7s", lstr, rstr);
239                         if (m > 0) {
240                                 if (*lstr == '+' || *lstr == '-')
241                                         lrel = rrel = 1;
242                                 l = strtol(lstr, NULL, 10);
243                         }
244                         if (m > 1) {
245                                 if (*rstr == '+' || *rstr == '-')
246                                         rrel = 1;
247                                 r = strtol(rstr, NULL, 10);
248                         }
249                 }
250
251                 switch (argc > 1 ? m : t) {
252                 case 0:
253                         if (ioctl(baz, MIXER_READ(dev), &bar) == -1) {
254                                 warn("MIXER_READ");
255                                 argc--;
256                                 argv++;
257                                 continue;
258                         }
259                         if (Sflag || sflag) {
260                                 printf("%s%s%c%d:%d", n ? " " : "",
261                                     names[dev], Sflag ? ':' : ' ',
262                                     bar & 0x7f, (bar >> 8) & 0x7f);
263                                 n++;
264                         } else
265                                 printf("Mixer %-8s is currently set to "
266                                     "%3d:%d\n", names[dev], bar & 0x7f,
267                                     (bar >> 8) & 0x7f);
268
269                         argc--;
270                         argv++;
271                         break;
272                 case 1:
273                         r = l;
274                         /* FALLTHROUGH */
275                 case 2:
276                         if (ioctl(baz, MIXER_READ(dev), &bar) == -1) {
277                                 warn("MIXER_READ");
278                                 argc--;
279                                 argv++;
280                                 continue;
281                         }
282
283                         if (lrel)
284                                 l = (bar & 0x7f) + l;
285                         if (rrel)
286                                 r = ((bar >> 8) & 0x7f) + r;
287
288                         if (l < 0)
289                                 l = 0;
290                         else if (l > 100)
291                                 l = 100;
292                         if (r < 0)
293                                 r = 0;
294                         else if (r > 100)
295                                 r = 100;
296
297                         if (!Sflag)
298                                 printf("Setting the mixer %s from %d:%d to "
299                                     "%d:%d.\n", names[dev], bar & 0x7f,
300                                     (bar >> 8) & 0x7f, l, r);
301
302                         l |= r << 8;
303                         if (ioctl(baz, MIXER_WRITE(dev), &l) == -1)
304                                 warn("WRITE_MIXER");
305
306                         argc -= 2;
307                         argv += 2;
308                         break;
309                 }
310         }
311
312         if (dusage) {
313                 close(baz);
314                 usage(devmask, recmask);
315                 /* NOTREACHED */
316         }
317
318         if (orecsrc != recsrc) {
319                 if (ioctl(baz, SOUND_MIXER_WRITE_RECSRC, &recsrc) == -1)
320                         err(1, "SOUND_MIXER_WRITE_RECSRC");
321                 if (ioctl(baz, SOUND_MIXER_READ_RECSRC, &recsrc) == -1)
322                         err(1, "SOUND_MIXER_READ_RECSRC");
323         }
324
325         if (drecsrc)
326                 print_recsrc(recsrc, recmask, Sflag || sflag);
327
328         close(baz);
329
330         return (0);
331 }