mixer.c revision 177195
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: head/usr.sbin/mixer/mixer.c 177195 2008-03-15 01:09:47Z jkim $"); 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 27const char *names[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_NAMES; 28 29void usage(int devmask, int recmask); 30int res_name(const char *name, int mask); 31void print_recsrc(int recsrc, int recmask, int shortflag); 32 33void 34usage(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 = 1; 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 = 1; 59 } 60 } 61 printf("\n"); 62 exit(1); 63} 64 65int 66res_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)) 72 break; 73 74 return foo == SOUND_MIXER_NRDEVICES ? -1 : foo; 75} 76 77void 78print_recsrc(int recsrc, int recmask, int shortflag) 79{ 80 int i, n = 0; 81 82 if (recmask == 0) 83 return; 84 85 if (!shortflag) 86 printf("Recording source: "); 87 88 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) 89 if ((1 << i) & recsrc) { 90 if (shortflag) { 91 if (n) 92 printf(" +rec "); 93 else 94 printf("=rec "); 95 } else if (n) 96 printf(", "); 97 printf("%s", names[i]); 98 n = 1; 99 } 100 if (!shortflag) 101 printf("\n"); 102} 103 104int 105main(int argc, char *argv[]) 106{ 107 char mixer[PATH_MAX] = "/dev/mixer"; 108 char *name, *eptr; 109 int foo, bar, baz, dev; 110 int devmask = 0, recmask = 0, recsrc = 0, orecsrc; 111 int dusage = 0, drecsrc = 0, shortflag = 0, Shortflag = 0; 112 int l = 0, r = 0, t = 0; 113 char lstr[5], rstr[5]; 114 int n, lrel = 0, rrel = 0; 115 char ch; 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 shortflag = 1; 142 n++; 143 } else if (ch == 'S') { 144 Shortflag = 1; 145 n++; 146 } else { 147 dusage = 1; 148 break; 149 } 150 } 151 if (shortflag && Shortflag) 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 (foo = 0; foo < SOUND_MIXER_NRDEVICES; foo++) { 169 if (!((1 << foo) & devmask)) 170 continue; 171 if (ioctl(baz, MIXER_READ(foo),&bar)== -1) { 172 warn("MIXER_READ"); 173 continue; 174 } 175 if (Shortflag) 176 printf("%s:%d:%d ", names[foo], bar & 0x7f, 177 (bar >> 8) & 0x7f); 178 else if (shortflag) 179 printf("%s %d:%d ", names[foo], bar & 0x7f, 180 (bar >> 8) & 0x7f); 181 else 182 printf("Mixer %-8s is currently set to %3d:%d\n", 183 names[foo], bar & 0x7f, (bar >> 8) & 0x7f); 184 } 185 if (ioctl(baz, SOUND_MIXER_READ_RECSRC, &recsrc) == -1) 186 err(1, "SOUND_MIXER_READ_RECSRC"); 187 print_recsrc(recsrc, recmask, shortflag || Shortflag); 188 return(0); 189 } 190 191 argc--; argv++; 192 193 while ((argc > 0) && (dusage == 0)) { 194 if (!strcmp("recsrc", *argv)) { 195 drecsrc = 1; 196 argc--; argv++; 197 continue; 198 } else if (argc > 1 && !strcmp("rec", *argv + 1)) { 199 if (**argv != '+' && **argv != '-' && 200 **argv != '=' && **argv != '^') { 201 warnx("unknown modifier: %c", **argv); 202 dusage = 1; 203 break; 204 } 205 if ((dev = res_name(argv[1], recmask)) == -1) { 206 warnx("unknown recording device: %s", argv[1]); 207 dusage = 1; 208 break; 209 } 210 switch(**argv) { 211 case '+': 212 recsrc |= (1 << dev); 213 break; 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 } 224 drecsrc = 1; 225 argc -= 2; argv += 2; 226 continue; 227 } 228 229 if ((t = sscanf(*argv, "%d:%d", &l, &r)) > 0) { 230 dev = 0; 231 } 232 else if((dev = res_name(*argv, devmask)) == -1) { 233 warnx("unknown device: %s", *argv); 234 dusage = 1; 235 break; 236 } 237 238#define issign(c) (((c) == '+') || ((c) == '-')) 239 240 if (argc > 1) { 241 n = sscanf(argv[1], "%7[^:]:%7s", lstr, rstr); 242 if (n > 0) { 243 if (issign(lstr[0])) 244 lrel = rrel = 1; 245 l = atoi(lstr); 246 } 247 if (n > 1) { 248 rrel = 0; 249 if (issign(rstr[0])) 250 rrel = 1; 251 r = atoi(rstr); 252 } 253 } 254 255 switch(argc > 1 ? n : t) { 256 case 0: 257 if (ioctl(baz, MIXER_READ(dev),&bar)== -1) { 258 warn("MIXER_READ"); 259 argc--; argv++; 260 continue; 261 } 262 if (Shortflag) 263 printf("%s:%d:%d ", names[dev], bar & 0x7f, 264 (bar >> 8) & 0x7f); 265 else if (shortflag) 266 printf("%s %d:%d ", names[dev], bar & 0x7f, 267 (bar >> 8) & 0x7f); 268 else 269 printf("Mixer %-8s is currently set to %3d:%d\n", 270 names[dev], bar & 0x7f, (bar >> 8) & 0x7f); 271 272 argc--; argv++; 273 break; 274 case 1: 275 r = l; 276 case 2: 277 if (ioctl(baz, MIXER_READ(dev),&bar)== -1) { 278 warn("MIXER_READ"); 279 argc--; 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 (!Shortflag) 298 printf("Setting the mixer %s from %d:%d to %d:%d.\n", 299 names[dev], bar & 0x7f, (bar >> 8) & 0x7f, l, r); 300 301 l |= r << 8; 302 if (ioctl(baz, MIXER_WRITE(dev), &l) == -1) 303 warn("WRITE_MIXER"); 304 305 argc -= 2; argv += 2; 306 break; 307 } 308 } 309 310 if (dusage) { 311 close(baz); 312 usage(devmask, recmask); 313 /* Not reached */ 314 } 315 316 if (orecsrc != recsrc) { 317 if (ioctl(baz, SOUND_MIXER_WRITE_RECSRC, &recsrc) == -1) 318 err(1, "SOUND_MIXER_WRITE_RECSRC"); 319 if (ioctl(baz, SOUND_MIXER_READ_RECSRC, &recsrc) == -1) 320 err(1, "SOUND_MIXER_READ_RECSRC"); 321 } 322 323 if (drecsrc) 324 print_recsrc(recsrc, recmask, shortflag || Shortflag); 325 326 close(baz); 327 328 exit(0); 329} 330