mixer.c revision 177198
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: head/usr.sbin/mixer/mixer.c 177198 2008-03-15 01:36:20Z jkim $"); 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; 196177197Sjkim } else if (argc > 1 && strcmp("rec", *argv + 1) == 0) { 19729612Sjmg if (**argv != '+' && **argv != '-' && 19829612Sjmg **argv != '=' && **argv != '^') { 19964657Ssobomax warnx("unknown modifier: %c", **argv); 20029612Sjmg dusage = 1; 20164657Ssobomax break; 20213435Smpp } 20329612Sjmg if ((dev = res_name(argv[1], recmask)) == -1) { 20464657Ssobomax warnx("unknown recording device: %s", argv[1]); 20529612Sjmg dusage = 1; 20664657Ssobomax break; 2076448Sache } 208177197Sjkim switch (**argv) { 20929612Sjmg case '+': 2106448Sache recsrc |= (1 << dev); 21129612Sjmg break; 21229612Sjmg case '-': 2136448Sache recsrc &= ~(1 << dev); 21429612Sjmg break; 21529612Sjmg case '=': 21629612Sjmg recsrc = (1 << dev); 21729612Sjmg break; 21829612Sjmg case '^': 21929612Sjmg recsrc ^= (1 << dev); 22029612Sjmg break; 22129612Sjmg } 22229612Sjmg drecsrc = 1; 223177197Sjkim argc -= 2; 224177197Sjkim argv += 2; 22529612Sjmg continue; 22629612Sjmg } 2276448Sache 228177197Sjkim if ((t = sscanf(*argv, "%d:%d", &l, &r)) > 0) 22975334Sgreid dev = 0; 230177197Sjkim else if ((dev = res_name(*argv, devmask)) == -1) { 23164657Ssobomax warnx("unknown device: %s", *argv); 23229612Sjmg dusage = 1; 23364657Ssobomax break; 23429612Sjmg } 23529612Sjmg 236177197Sjkim lrel = rrel = 0; 237113299Smdodd if (argc > 1) { 238177197Sjkim m = sscanf(argv[1], "%7[^:]:%7s", lstr, rstr); 239177197Sjkim if (m > 0) { 240177197Sjkim if (*lstr == '+' || *lstr == '-') 241113299Smdodd lrel = rrel = 1; 242177197Sjkim l = strtol(lstr, NULL, 10); 243113299Smdodd } 244177197Sjkim if (m > 1) { 245177197Sjkim if (*rstr == '+' || *rstr == '-') 246113299Smdodd rrel = 1; 247177197Sjkim r = strtol(rstr, NULL, 10); 248113299Smdodd } 249113299Smdodd } 250113299Smdodd 251177197Sjkim switch (argc > 1 ? m : t) { 25229612Sjmg case 0: 253177197Sjkim if (ioctl(baz, MIXER_READ(dev), &bar) == -1) { 25429963Scharnier warn("MIXER_READ"); 255177197Sjkim argc--; 256177197Sjkim argv++; 25729612Sjmg continue; 2586448Sache } 259177197Sjkim if (Sflag || sflag) { 260177197Sjkim printf("%s%s%c%d:%d", n ? " " : "", 261177197Sjkim names[dev], Sflag ? ':' : ' ', 262177197Sjkim bar & 0x7f, (bar >> 8) & 0x7f); 263177197Sjkim n++; 264177197Sjkim } else 265177197Sjkim printf("Mixer %-8s is currently set to " 266177197Sjkim "%3d:%d\n", names[dev], bar & 0x7f, 267177197Sjkim (bar >> 8) & 0x7f); 2686448Sache 269177197Sjkim argc--; 270177197Sjkim argv++; 27129612Sjmg break; 27229612Sjmg case 1: 27329612Sjmg r = l; 274177197Sjkim /* FALLTHROUGH */ 27529612Sjmg case 2: 276177197Sjkim if (ioctl(baz, MIXER_READ(dev), &bar) == -1) { 277113299Smdodd warn("MIXER_READ"); 278177197Sjkim argc--; 279177197Sjkim argv++; 280113299Smdodd continue; 281113299Smdodd } 282113299Smdodd 283113299Smdodd if (lrel) 284113299Smdodd l = (bar & 0x7f) + l; 285113299Smdodd if (rrel) 286113299Smdodd r = ((bar >> 8) & 0x7f) + r; 287113299Smdodd 28829612Sjmg if (l < 0) 28929612Sjmg l = 0; 29029612Sjmg else if (l > 100) 29129612Sjmg l = 100; 29229612Sjmg if (r < 0) 29329612Sjmg r = 0; 29429612Sjmg else if (r > 100) 29529612Sjmg r = 100; 2968857Srgrimes 297177197Sjkim if (!Sflag) 298177197Sjkim printf("Setting the mixer %s from %d:%d to " 299177197Sjkim "%d:%d.\n", names[dev], bar & 0x7f, 300177197Sjkim (bar >> 8) & 0x7f, l, r); 301108421Sjmallett 30229612Sjmg l |= r << 8; 30329612Sjmg if (ioctl(baz, MIXER_WRITE(dev), &l) == -1) 30429963Scharnier warn("WRITE_MIXER"); 3056448Sache 306177197Sjkim argc -= 2; 307177197Sjkim argv += 2; 30829612Sjmg break; 3096448Sache } 3106448Sache } 3116448Sache 31264657Ssobomax if (dusage) { 31364657Ssobomax close(baz); 31464657Ssobomax usage(devmask, recmask); 315177197Sjkim /* NOTREACHED */ 31664657Ssobomax } 31764657Ssobomax 318177195Sjkim if (orecsrc != recsrc) { 31929963Scharnier if (ioctl(baz, SOUND_MIXER_WRITE_RECSRC, &recsrc) == -1) 32030028Scharnier err(1, "SOUND_MIXER_WRITE_RECSRC"); 32129963Scharnier if (ioctl(baz, SOUND_MIXER_READ_RECSRC, &recsrc) == -1) 32230028Scharnier err(1, "SOUND_MIXER_READ_RECSRC"); 32329612Sjmg } 324177197Sjkim 325177195Sjkim if (drecsrc) 326177197Sjkim print_recsrc(recsrc, recmask, Sflag || sflag); 32729612Sjmg 3286448Sache close(baz); 32929612Sjmg 330177197Sjkim return (0); 3316448Sache} 332