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 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 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[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