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: head/usr.sbin/mixer/mixer.c 230611 2012-01-27 09:15:55Z mav $ 14 */ 15 16 #include <err.h> 17 #include <fcntl.h> 18 #include <libgen.h> 19 #include <limits.h> 20 #include <stdio.h> 21 #include <string.h> 22 #include <stdlib.h> 23 #include <unistd.h> 24 #include <sys/soundcard.h> 25 26 static const char *names[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_NAMES; 27 28 static void usage(int devmask, int recmask); 29 static int res_name(const char *name, int mask); 30 static void print_recsrc(int recsrc, int recmask, int sflag); 31 32 static void 33 usage(int devmask, int recmask) 34 { 35 int i, n; 36 37 printf("usage: mixer [-f device] [-s | -S] [dev [+|-][voll[:[+|-]volr]] ...\n" 38 " mixer [-f device] [-s | -S] recsrc ...\n" 39 " mixer [-f device] [-s | -S] {^|+|-|=}rec rdev ...\n"); 40 if (devmask != 0) { 41 printf(" devices: "); 42 for (i = 0, n = 0; i < SOUND_MIXER_NRDEVICES; i++) { 43 if ((1 << i) & devmask) { 44 if (n) 45 printf(", "); 46 printf("%s", names[i]); 47 n++; 48 } 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 } 62 printf("\n"); 63 exit(1); 64 } 65 66 static int 67 res_name(const char *name, int mask) 68 { 69 int i; 70 71 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) 72 if ((1 << i) & mask && strcmp(names[i], name) == 0) 73 break; 74 75 if (i == SOUND_MIXER_NRDEVICES) 76 return (-1); 77 78 return (i); 79 } 80 81 static void 82 print_recsrc(int recsrc, int recmask, int sflag) 83 { 84 int i, n; 85 86 if (recmask == 0) 87 return; 88 89 if (!sflag) 90 printf("Recording source: "); 91 92 for (i = 0, n = 0; i < SOUND_MIXER_NRDEVICES; i++) { 93 if ((1 << i) & recsrc) { 94 if (sflag) 95 printf("%srec ", n ? " +" : "="); 96 else if (n) 97 printf(", "); 98 printf("%s", names[i]); 99 n++; 100 } 101 } 102 if (!sflag) 103 printf("\n"); 104 } 105 106 int 107 main(int argc, char *argv[]) 108 { 109 char mixer[PATH_MAX] = "/dev/mixer"; 110 char lstr[5], rstr[5]; 111 char *name, *eptr; 112 int devmask = 0, recmask = 0, recsrc = 0, orecsrc; 113 int dusage = 0, drecsrc = 0, sflag = 0, Sflag = 0; 114 int l, r, lrel, rrel; 115 int ch, i, bar, baz, dev, m, n, t; 116 117 if ((name = strdup(basename(argv[0]))) == NULL) 118 err(1, "strdup()"); 119 if (strncmp(name, "mixer", 5) == 0 && name[5] != '\0') { 120 n = strtol(name + 5, &eptr, 10) - 1; 121 if (n > 0 && *eptr == '\0') 122 snprintf(mixer, PATH_MAX - 1, "/dev/mixer%d", n); 123 } 124 free(name); 125 name = mixer; 126 127 n = 1; 128 for (;;) { 129 if (n >= argc || *argv[n] != '-') 130 break; 131 if (strlen(argv[n]) != 2) { 132 if (strcmp(argv[n] + 1, "rec") != 0) 133 dusage = 1; 134 break; 135 } 136 ch = *(argv[n] + 1); 137 if (ch == 'f' && n < argc - 1) { 138 name = argv[n + 1]; 139 n += 2; 140 } else if (ch == 's') { 141 sflag = 1; 142 n++; 143 } else if (ch == 'S') { 144 Sflag = 1; 145 n++; 146 } else { 147 dusage = 1; 148 break; 149 } 150 } 151 if (sflag && Sflag) 152 dusage = 1; 153 154 argc -= n - 1; 155 argv += n - 1; 156 157 if ((baz = open(name, O_RDWR)) < 0) 158 err(1, "%s", name); 159 if (ioctl(baz, SOUND_MIXER_READ_DEVMASK, &devmask) == -1) 160 err(1, "SOUND_MIXER_READ_DEVMASK"); 161 if (ioctl(baz, SOUND_MIXER_READ_RECMASK, &recmask) == -1) 162 err(1, "SOUND_MIXER_READ_RECMASK"); 163 if (ioctl(baz, SOUND_MIXER_READ_RECSRC, &recsrc) == -1) 164 err(1, "SOUND_MIXER_READ_RECSRC"); 165 orecsrc = recsrc; 166 167 if (argc == 1 && dusage == 0) { 168 for (i = 0, n = 0; i < SOUND_MIXER_NRDEVICES; i++) { 169 if (!((1 << i) & devmask)) 170 continue; 171 if (ioctl(baz, MIXER_READ(i),&bar) == -1) { 172 warn("MIXER_READ"); 173 continue; 174 } 175 if (Sflag || sflag) { 176 printf("%s%s%c%d:%d", n ? " " : "", 177 names[i], Sflag ? ':' : ' ', 178 bar & 0x7f, (bar >> 8) & 0x7f); 179 n++; 180 } else 181 printf("Mixer %-8s is currently set to " 182 "%3d:%d\n", names[i], bar & 0x7f, 183 (bar >> 8) & 0x7f); 184 } 185 if (n && recmask) 186 printf(" "); 187 print_recsrc(recsrc, recmask, Sflag || sflag); 188 return (0); 189 } 190 191 argc--; 192 argv++; 193 194 n = 0; 195 while (argc > 0 && dusage == 0) { 196 if (strcmp("recsrc", *argv) == 0) { 197 drecsrc = 1; 198 argc--; 199 argv++; 200 continue; 201 } else if (strcmp("rec", *argv + 1) == 0) { 202 if (**argv != '+' && **argv != '-' && 203 **argv != '=' && **argv != '^') { 204 warnx("unknown modifier: %c", **argv); 205 dusage = 1; 206 break; 207 } 208 if (argc <= 1) { 209 warnx("no recording device specified"); 210 dusage = 1; 211 break; 212 } 213 if ((dev = res_name(argv[1], recmask)) == -1) { 214 warnx("unknown recording device: %s", argv[1]); 215 dusage = 1; 216 break; 217 } 218 switch (**argv) { 219 case '+': 220 recsrc |= (1 << dev); 221 break; 222 case '-': 223 recsrc &= ~(1 << dev); 224 break; 225 case '=': 226 recsrc = (1 << dev); 227 break; 228 case '^': 229 recsrc ^= (1 << dev); 230 break; 231 } 232 drecsrc = 1; 233 argc -= 2; 234 argv += 2; 235 continue; 236 } 237 238 if ((t = sscanf(*argv, "%d:%d", &l, &r)) > 0) 239 dev = 0; 240 else if ((dev = res_name(*argv, devmask)) == -1) { 241 warnx("unknown device: %s", *argv); 242 dusage = 1; 243 break; 244 } 245 246 lrel = rrel = 0; 247 if (argc > 1) { 248 m = sscanf(argv[1], "%7[^:]:%7s", lstr, rstr); 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