16448Sache/* 26448Sache * This is an example of a mixer program for Linux 36448Sache * 46448Sache * updated 1/1/93 to add stereo, level query, broken 58857Srgrimes * devmask kludge - cmetz@thor.tjhsst.edu 66448Sache * 76448Sache * (C) Craig Metz and Hannu Savolainen 1993. 86448Sache * 96448Sache * You may do anything you wish with this program. 1029612Sjmg * 1129612Sjmg * ditto for my modifications (John-Mark Gurney, 1997) 126448Sache */ 136448Sache 14114601Sobrien#include <sys/cdefs.h> 15114601Sobrien__FBSDID("$FreeBSD$"); 1629963Scharnier 1729963Scharnier#include <err.h> 1829963Scharnier#include <fcntl.h> 19177195Sjkim#include <libgen.h> 20177195Sjkim#include <limits.h> 216448Sache#include <stdio.h> 226448Sache#include <string.h> 2329612Sjmg#include <stdlib.h> 2429612Sjmg#include <unistd.h> 256448Sache#include <sys/soundcard.h> 266448Sache 27177197Sjkimconst char *names[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_NAMES; 286448Sache 29177197Sjkimstatic void usage(int devmask, int recmask); 30177197Sjkimstatic int res_name(const char *name, int mask); 31177197Sjkimstatic void print_recsrc(int recsrc, int recmask, int sflag); 326448Sache 33177197Sjkimstatic void 3429612Sjmgusage(int devmask, int recmask) 356448Sache{ 36177197Sjkim int i, n; 376448Sache 38144999Smdodd printf("usage: mixer [-f device] [-s | -S] [dev [+|-][voll[:[+|-]volr]] ...\n" 39177197Sjkim " mixer [-f device] [-s | -S] recsrc ...\n" 40177197Sjkim " mixer [-f device] [-s | -S] {^|+|-|=}rec rdev ...\n"); 41177195Sjkim if (devmask != 0) { 42177195Sjkim printf(" devices: "); 43177195Sjkim for (i = 0, n = 0; i < SOUND_MIXER_NRDEVICES; i++) 44177195Sjkim if ((1 << i) & devmask) { 45177195Sjkim if (n) 46177195Sjkim printf(", "); 47177195Sjkim printf("%s", names[i]); 48177197Sjkim n++; 49177195Sjkim } 50177195Sjkim } 51177195Sjkim if (recmask != 0) { 52177195Sjkim printf("\n rec devices: "); 53177195Sjkim for (i = 0, n = 0; i < SOUND_MIXER_NRDEVICES; i++) 54177195Sjkim if ((1 << i) & recmask) { 55177195Sjkim if (n) 56177195Sjkim printf(", "); 57177195Sjkim printf("%s", names[i]); 58177197Sjkim n++; 59177195Sjkim } 60177195Sjkim } 6129612Sjmg printf("\n"); 626448Sache exit(1); 636448Sache} 646448Sache 65177197Sjkimstatic int 6629612Sjmgres_name(const char *name, int mask) 676448Sache{ 68177197Sjkim int foo; 6929612Sjmg 7029612Sjmg for (foo = 0; foo < SOUND_MIXER_NRDEVICES; foo++) 71177197Sjkim if ((1 << foo) & mask && strcmp(names[foo], name) == 0) 7229612Sjmg break; 7329612Sjmg 74177197Sjkim return (foo == SOUND_MIXER_NRDEVICES ? -1 : foo); 7529612Sjmg} 7629612Sjmg 77177197Sjkimstatic void 78177197Sjkimprint_recsrc(int recsrc, int recmask, int sflag) 7929612Sjmg{ 80177197Sjkim int i, n; 816448Sache 82177195Sjkim if (recmask == 0) 83177195Sjkim return; 84177195Sjkim 85177197Sjkim if (!sflag) 86153953Sariff printf("Recording source: "); 87153953Sariff 88177197Sjkim for (i = 0, n = 0; i < SOUND_MIXER_NRDEVICES; i++) 896448Sache if ((1 << i) & recsrc) { 90177197Sjkim if (sflag) 91177197Sjkim printf("%srec ", n ? " +" : "="); 92177197Sjkim else if (n) 93153953Sariff printf(", "); 94153953Sariff printf("%s", names[i]); 95177197Sjkim n++; 966448Sache } 97177197Sjkim if (!sflag) 98153953Sariff printf("\n"); 996448Sache} 1006448Sache 1018857Srgrimesint 1026448Sachemain(int argc, char *argv[]) 1036448Sache{ 104177197Sjkim char mixer[PATH_MAX] = "/dev/mixer"; 105177197Sjkim char lstr[5], rstr[5]; 106177197Sjkim char *name, *eptr; 107177197Sjkim int devmask = 0, recmask = 0, recsrc = 0, orecsrc; 108177197Sjkim int dusage = 0, drecsrc = 0, sflag = 0, Sflag = 0; 109177197Sjkim int l, r, lrel, rrel; 110177197Sjkim int ch, foo, bar, baz, dev, m, n, t; 1116448Sache 112177195Sjkim if ((name = strdup(basename(argv[0]))) == NULL) 113177195Sjkim err(1, "strdup()"); 114177195Sjkim if (strncmp(name, "mixer", 5) == 0 && name[5] != '\0') { 115177195Sjkim n = strtol(name + 5, &eptr, 10) - 1; 116177195Sjkim if (n > 0 && *eptr == '\0') 117177195Sjkim snprintf(mixer, PATH_MAX - 1, "/dev/mixer%d", n); 118177195Sjkim } 119177195Sjkim free(name); 120177195Sjkim name = mixer; 1216448Sache 122177195Sjkim n = 1; 123177195Sjkim for (;;) { 124177195Sjkim if (n >= argc || *argv[n] != '-') 125177195Sjkim break; 126177195Sjkim if (strlen(argv[n]) != 2) { 127177195Sjkim if (strcmp(argv[n] + 1, "rec") != 0) 12864657Ssobomax dusage = 1; 129177195Sjkim break; 13064657Ssobomax } 131177195Sjkim ch = *(argv[n] + 1); 132177195Sjkim if (ch == 'f' && n < argc - 1) { 133177195Sjkim name = argv[n + 1]; 134177195Sjkim n += 2; 135177195Sjkim } else if (ch == 's') { 136177197Sjkim sflag = 1; 137177195Sjkim n++; 138177195Sjkim } else if (ch == 'S') { 139177197Sjkim Sflag = 1; 140177195Sjkim n++; 141177195Sjkim } else { 142177195Sjkim dusage = 1; 143177195Sjkim break; 144177195Sjkim } 145177195Sjkim } 146177197Sjkim if (sflag && Sflag) 147177195Sjkim dusage = 1; 14829612Sjmg 149177195Sjkim argc -= n - 1; 150177195Sjkim argv += n - 1; 151177195Sjkim 15229963Scharnier if ((baz = open(name, O_RDWR)) < 0) 15329963Scharnier err(1, "%s", name); 15429963Scharnier if (ioctl(baz, SOUND_MIXER_READ_DEVMASK, &devmask) == -1) 15530028Scharnier err(1, "SOUND_MIXER_READ_DEVMASK"); 15629963Scharnier if (ioctl(baz, SOUND_MIXER_READ_RECMASK, &recmask) == -1) 15730028Scharnier err(1, "SOUND_MIXER_READ_RECMASK"); 15829963Scharnier if (ioctl(baz, SOUND_MIXER_READ_RECSRC, &recsrc) == -1) 15930028Scharnier err(1, "SOUND_MIXER_READ_RECSRC"); 16029612Sjmg orecsrc = recsrc; 1616448Sache 162177197Sjkim if (argc == 1 && dusage == 0) { 163177197Sjkim for (foo = 0, n = 0; foo < SOUND_MIXER_NRDEVICES; foo++) { 164177197Sjkim if (!((1 << foo) & devmask)) 16513803Smpp continue; 166177197Sjkim if (ioctl(baz, MIXER_READ(foo),&bar) == -1) { 16729963Scharnier warn("MIXER_READ"); 16813803Smpp continue; 16913803Smpp } 170177197Sjkim if (Sflag || sflag) { 171177197Sjkim printf("%s%s%c%d:%d", n ? " " : "", 172177197Sjkim names[foo], Sflag ? ':' : ' ', 173177197Sjkim bar & 0x7f, (bar >> 8) & 0x7f); 174177197Sjkim n++; 175177197Sjkim } else 176177197Sjkim printf("Mixer %-8s is currently set to " 177177197Sjkim "%3d:%d\n", names[foo], bar & 0x7f, 178177197Sjkim (bar >> 8) & 0x7f); 17913803Smpp } 180177197Sjkim if (n && recmask) 181177197Sjkim printf(" "); 182177198Sjkim print_recsrc(recsrc, recmask, Sflag || sflag); 183177197Sjkim return (0); 18413803Smpp } 18513803Smpp 186177197Sjkim argc--; 187177197Sjkim argv++; 1886448Sache 189177197Sjkim n = 0; 190177197Sjkim while (argc > 0 && dusage == 0) { 191177197Sjkim if (strcmp("recsrc", *argv) == 0) { 19229612Sjmg drecsrc = 1; 193177197Sjkim argc--; 194177197Sjkim argv++; 19529612Sjmg continue; 196230982Smav } else if (strcmp("rec", *argv + 1) == 0) { 19729612Sjmg if (**argv != '+' && **argv != '-' && 19829612Sjmg **argv != '=' && **argv != '^') { 19964657Ssobomax warnx("unknown modifier: %c", **argv); 20029612Sjmg dusage = 1; 20164657Ssobomax break; 20213435Smpp } 203230982Smav if (argc <= 1) { 204230982Smav warnx("no recording device specified"); 205230982Smav dusage = 1; 206230982Smav break; 207230982Smav } 20829612Sjmg if ((dev = res_name(argv[1], recmask)) == -1) { 20964657Ssobomax warnx("unknown recording device: %s", argv[1]); 21029612Sjmg dusage = 1; 21164657Ssobomax break; 2126448Sache } 213177197Sjkim switch (**argv) { 21429612Sjmg case '+': 2156448Sache recsrc |= (1 << dev); 21629612Sjmg break; 21729612Sjmg case '-': 2186448Sache recsrc &= ~(1 << dev); 21929612Sjmg break; 22029612Sjmg case '=': 22129612Sjmg recsrc = (1 << dev); 22229612Sjmg break; 22329612Sjmg case '^': 22429612Sjmg recsrc ^= (1 << dev); 22529612Sjmg break; 22629612Sjmg } 22729612Sjmg drecsrc = 1; 228177197Sjkim argc -= 2; 229177197Sjkim argv += 2; 23029612Sjmg continue; 23129612Sjmg } 2326448Sache 233177197Sjkim if ((t = sscanf(*argv, "%d:%d", &l, &r)) > 0) 23475334Sgreid dev = 0; 235177197Sjkim else if ((dev = res_name(*argv, devmask)) == -1) { 23664657Ssobomax warnx("unknown device: %s", *argv); 23729612Sjmg dusage = 1; 23864657Ssobomax break; 23929612Sjmg } 24029612Sjmg 241177197Sjkim lrel = rrel = 0; 242113299Smdodd if (argc > 1) { 243177197Sjkim m = sscanf(argv[1], "%7[^:]:%7s", lstr, rstr); 244177197Sjkim if (m > 0) { 245177197Sjkim if (*lstr == '+' || *lstr == '-') 246113299Smdodd lrel = rrel = 1; 247177197Sjkim l = strtol(lstr, NULL, 10); 248113299Smdodd } 249177197Sjkim if (m > 1) { 250177197Sjkim if (*rstr == '+' || *rstr == '-') 251113299Smdodd rrel = 1; 252177197Sjkim r = strtol(rstr, NULL, 10); 253113299Smdodd } 254113299Smdodd } 255113299Smdodd 256177197Sjkim switch (argc > 1 ? m : t) { 25729612Sjmg case 0: 258177197Sjkim if (ioctl(baz, MIXER_READ(dev), &bar) == -1) { 25929963Scharnier warn("MIXER_READ"); 260177197Sjkim argc--; 261177197Sjkim argv++; 26229612Sjmg continue; 2636448Sache } 264177197Sjkim if (Sflag || sflag) { 265177197Sjkim printf("%s%s%c%d:%d", n ? " " : "", 266177197Sjkim names[dev], Sflag ? ':' : ' ', 267177197Sjkim bar & 0x7f, (bar >> 8) & 0x7f); 268177197Sjkim n++; 269177197Sjkim } else 270177197Sjkim printf("Mixer %-8s is currently set to " 271177197Sjkim "%3d:%d\n", names[dev], bar & 0x7f, 272177197Sjkim (bar >> 8) & 0x7f); 2736448Sache 274177197Sjkim argc--; 275177197Sjkim argv++; 27629612Sjmg break; 27729612Sjmg case 1: 27829612Sjmg r = l; 279177197Sjkim /* FALLTHROUGH */ 28029612Sjmg case 2: 281177197Sjkim if (ioctl(baz, MIXER_READ(dev), &bar) == -1) { 282113299Smdodd warn("MIXER_READ"); 283177197Sjkim argc--; 284177197Sjkim argv++; 285113299Smdodd continue; 286113299Smdodd } 287113299Smdodd 288113299Smdodd if (lrel) 289113299Smdodd l = (bar & 0x7f) + l; 290113299Smdodd if (rrel) 291113299Smdodd r = ((bar >> 8) & 0x7f) + r; 292113299Smdodd 29329612Sjmg if (l < 0) 29429612Sjmg l = 0; 29529612Sjmg else if (l > 100) 29629612Sjmg l = 100; 29729612Sjmg if (r < 0) 29829612Sjmg r = 0; 29929612Sjmg else if (r > 100) 30029612Sjmg r = 100; 3018857Srgrimes 302177197Sjkim if (!Sflag) 303177197Sjkim printf("Setting the mixer %s from %d:%d to " 304177197Sjkim "%d:%d.\n", names[dev], bar & 0x7f, 305177197Sjkim (bar >> 8) & 0x7f, l, r); 306108421Sjmallett 30729612Sjmg l |= r << 8; 30829612Sjmg if (ioctl(baz, MIXER_WRITE(dev), &l) == -1) 30929963Scharnier warn("WRITE_MIXER"); 3106448Sache 311177197Sjkim argc -= 2; 312177197Sjkim argv += 2; 31329612Sjmg break; 3146448Sache } 3156448Sache } 3166448Sache 31764657Ssobomax if (dusage) { 31864657Ssobomax close(baz); 31964657Ssobomax usage(devmask, recmask); 320177197Sjkim /* NOTREACHED */ 32164657Ssobomax } 32264657Ssobomax 323177195Sjkim if (orecsrc != recsrc) { 32429963Scharnier if (ioctl(baz, SOUND_MIXER_WRITE_RECSRC, &recsrc) == -1) 32530028Scharnier err(1, "SOUND_MIXER_WRITE_RECSRC"); 32629963Scharnier if (ioctl(baz, SOUND_MIXER_READ_RECSRC, &recsrc) == -1) 32730028Scharnier err(1, "SOUND_MIXER_READ_RECSRC"); 32829612Sjmg } 329177197Sjkim 330177195Sjkim if (drecsrc) 331177197Sjkim print_recsrc(recsrc, recmask, Sflag || sflag); 33229612Sjmg 3336448Sache close(baz); 33429612Sjmg 335177197Sjkim return (0); 3366448Sache} 337