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); 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 (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 > 0) { 245 if (*lstr == '+' || *lstr == '-') 246 lrel = rrel = 1; 247 l = strtol(lstr, NULL, 10); 248 } 249 if (m > 1) { 250 if (*rstr == '+' || *rstr == '-') 251 rrel = 1; 252 r = strtol(rstr, NULL, 10); 253 } 254 } 255 256 switch (argc > 1 ? m : t) { 257 case 0: 258 if (ioctl(baz, MIXER_READ(dev), &bar) == -1) { 259 warn("MIXER_READ"); 260 argc--; 261 argv++; 262 continue; 263 } 264 if (Sflag || sflag) { 265 printf("%s%s%c%d:%d", n ? " " : "", 266 names[dev], Sflag ? ':' : ' ', 267 bar & 0x7f, (bar >> 8) & 0x7f); 268 n++; 269 } else 270 printf("Mixer %-8s is currently set to " 271 "%3d:%d\n", names[dev], bar & 0x7f, 272 (bar >> 8) & 0x7f); 273 274 argc--; 275 argv++; 276 break; 277 case 1: 278 r = l; 279 /* FALLTHROUGH */ 280 case 2: 281 if (ioctl(baz, MIXER_READ(dev), &bar) == -1) { 282 warn("MIXER_READ"); 283 argc--; 284 argv++; 285 continue; 286 } 287 288 if (lrel) 289 l = (bar & 0x7f) + l; 290 if (rrel) 291 r = ((bar >> 8) & 0x7f) + r; 292 293 if (l < 0) 294 l = 0; 295 else if (l > 100) 296 l = 100; 297 if (r < 0) 298 r = 0; 299 else if (r > 100) 300 r = 100; 301 302 if (!Sflag) 303 printf("Setting the mixer %s from %d:%d to " 304 "%d:%d.\n", names[dev], bar & 0x7f, 305 (bar >> 8) & 0x7f, l, r); 306 307 l |= r << 8; 308 if (ioctl(baz, MIXER_WRITE(dev), &l) == -1) 309 warn("WRITE_MIXER"); 310 311 argc -= 2; 312 argv += 2; 313 break; 314 } 315 } 316 317 if (dusage) { 318 close(baz); 319 usage(devmask, recmask); 320 /* NOTREACHED */ 321 } 322 323 if (orecsrc != recsrc) { 324 if (ioctl(baz, SOUND_MIXER_WRITE_RECSRC, &recsrc) == -1) 325 err(1, "SOUND_MIXER_WRITE_RECSRC"); 326 if (ioctl(baz, SOUND_MIXER_READ_RECSRC, &recsrc) == -1) 327 err(1, "SOUND_MIXER_READ_RECSRC"); 328 } 329 330 if (drecsrc) 331 print_recsrc(recsrc, recmask, Sflag || sflag); 332 333 close(baz); 334 335 return (0); 336 } 337