Synch up with FreeBSD 5 with clean up changes.
[dragonfly.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  * $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 }