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