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: }