Home | History | Annotate | Line # | Download | only in mixerctl
mixerctl.c revision 1.5
      1 /*	$NetBSD: mixerctl.c,v 1.5 1997/08/24 23:20:04 augustss Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1997 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * Author: Lennart Augustsson, with some code and ideas from Chuck Cranor.
      8  *
      9  * Redistribution and use in source and binary forms, with or without
     10  * modification, are permitted provided that the following conditions
     11  * are met:
     12  * 1. Redistributions of source code must retain the above copyright
     13  *    notice, this list of conditions and the following disclaimer.
     14  * 2. Redistributions in binary form must reproduce the above copyright
     15  *    notice, this list of conditions and the following disclaimer in the
     16  *    documentation and/or other materials provided with the distribution.
     17  * 3. All advertising materials mentioning features or use of this software
     18  *    must display the following acknowledgement:
     19  *        This product includes software developed by the NetBSD
     20  *        Foundation, Inc. and its contributors.
     21  * 4. Neither the name of The NetBSD Foundation nor the names of its
     22  *    contributors may be used to endorse or promote products derived
     23  *    from this software without specific prior written permission.
     24  *
     25  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     26  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     27  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     28  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
     29  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     30  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     31  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     32  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     33  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     34  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     35  * POSSIBILITY OF SUCH DAMAGE.
     36  */
     37 #include <stdio.h>
     38 #include <stdlib.h>
     39 #include <fcntl.h>
     40 #include <err.h>
     41 #include <unistd.h>
     42 #include <string.h>
     43 #include <sys/types.h>
     44 #include <sys/ioctl.h>
     45 #include <sys/audioio.h>
     46 
     47 FILE *out = stdout;
     48 
     49 char *prog;
     50 
     51 struct field {
     52 	char *name;
     53 	mixer_ctrl_t *valp;
     54 	mixer_devinfo_t *infp;
     55 	char changed;
     56 } *fields, *rfields;
     57 
     58 mixer_ctrl_t *values;
     59 mixer_devinfo_t *infos;
     60 
     61 char *
     62 catstr(char *p, char *q)
     63 {
     64 	char *r = malloc(strlen(p) + strlen(q) + 2);
     65 	strcpy(r, p);
     66 	strcat(r, ".");
     67 	strcat(r, q);
     68 	return r;
     69 }
     70 
     71 struct field *
     72 findfield(char *name)
     73 {
     74 	int i;
     75 	for(i = 0; fields[i].name; i++)
     76 		if (strcmp(fields[i].name, name) == 0)
     77 			return &fields[i];
     78 	return 0;
     79 }
     80 
     81 void
     82 prfield(struct field *p, char *sep, int prvalset)
     83 {
     84 	mixer_ctrl_t *m;
     85 	int i, n;
     86 
     87 	if (sep)
     88 		fprintf(out, "%s%s", p->name, sep);
     89 	m = p->valp;
     90 	switch(m->type) {
     91 	case AUDIO_MIXER_ENUM:
     92 		for(i = 0; i < p->infp->un.e.num_mem; i++)
     93 			if (p->infp->un.e.member[i].ord == m->un.ord)
     94 				fprintf(out, "%s",
     95 					p->infp->un.e.member[i].label.name);
     96 		if (prvalset) {
     97 			fprintf(out, "  [ ");
     98 			for(i = 0; i < p->infp->un.e.num_mem; i++)
     99 				fprintf(out, "%s ", p->infp->un.e.member[i].label.name);
    100 			fprintf(out, "]");
    101 		}
    102 		break;
    103 	case AUDIO_MIXER_SET:
    104 		for(n = i = 0; i < p->infp->un.s.num_mem; i++)
    105 			if (m->un.mask & p->infp->un.s.member[i].mask)
    106 				fprintf(out, "%s%s", n++ ? "," : "",
    107 					p->infp->un.s.member[i].label.name);
    108 		if (prvalset) {
    109 			fprintf(out, "  { ");
    110 			for(i = 0; i < p->infp->un.s.num_mem; i++)
    111 				fprintf(out, "%s ", p->infp->un.s.member[i].label.name);
    112 			fprintf(out, "}");
    113 		}
    114 		break;
    115 	case AUDIO_MIXER_VALUE:
    116 		if (m->un.value.num_channels == 1)
    117 			fprintf(out, "%d", m->un.value.level[0]);
    118 		else
    119 			fprintf(out, "%d,%d", m->un.value.level[0],
    120 			       m->un.value.level[1]);
    121 		break;
    122 	default:
    123 		printf("\n");
    124 		errx(1, "Invalid format.");
    125 	}
    126 }
    127 
    128 int
    129 rdfield(struct field *p, char *q)
    130 {
    131 	mixer_ctrl_t *m;
    132 	int v, v0, v1, mask;
    133 	int i;
    134 	char *s;
    135 
    136 	m = p->valp;
    137 	switch(m->type) {
    138 	case AUDIO_MIXER_ENUM:
    139 		for(i = 0; i < p->infp->un.e.num_mem; i++)
    140 			if (strcmp(p->infp->un.e.member[i].label.name, q) == 0)
    141 				break;
    142 		if (i < p->infp->un.e.num_mem)
    143 			m->un.ord = p->infp->un.e.member[i].ord;
    144 		else {
    145 			warnx("Bad enum value %s", q);
    146 			return 0;
    147 		}
    148 		break;
    149 	case AUDIO_MIXER_SET:
    150 		mask = 0;
    151 		for(v = 0; q && *q; q = s) {
    152 			s = strchr(q, ',');
    153 			if (s)
    154 				*s++ = 0;
    155 			for(i = 0; i < p->infp->un.s.num_mem; i++)
    156 				if (strcmp(p->infp->un.s.member[i].label.name, q) == 0)
    157 					break;
    158 			if (i < p->infp->un.s.num_mem) {
    159 				mask |= p->infp->un.s.member[i].mask;
    160 			} else {
    161 				warnx("Bad set value %s", q);
    162 				return 0;
    163 			}
    164 		}
    165 		m->un.mask = mask;
    166 		break;
    167 	case AUDIO_MIXER_VALUE:
    168 		if (m->un.value.num_channels == 1) {
    169 			if (sscanf(q, "%d", &v) == 1) {
    170 				m->un.value.level[0] = v;
    171 			} else {
    172 				warnx("Bad number %s", q);
    173 				return 0;
    174 			}
    175 		} else {
    176 			if (sscanf(q, "%d,%d", &v0, &v1) == 2) {
    177 				m->un.value.level[0] = v0;
    178 				m->un.value.level[1] = v1;
    179 			} else if (sscanf(q, "%d", &v) == 1) {
    180 				m->un.value.level[0] = m->un.value.level[1] = v;
    181 			} else {
    182 				warnx("Bad numbers %s", q);
    183 				return 0;
    184 			}
    185 		}
    186 		break;
    187 	default:
    188 		errx(1, "Invalid format.");
    189 	}
    190 	p->changed = 1;
    191 	return 1;
    192 }
    193 
    194 void
    195 main(int argc, char **argv)
    196 {
    197 	int fd, r, i, j, ch, pos;
    198 	int aflag = 0, wflag = 0, vflag = 0;
    199 	char *file = "/dev/mixer";
    200 	char *sep = "=";
    201 	mixer_devinfo_t dinfo;
    202 	mixer_ctrl_t val;
    203 	int ndev;
    204 
    205 	prog = *argv;
    206 
    207 	while ((ch = getopt(argc, argv, "af:nvw")) != -1) {
    208 		switch(ch) {
    209 		case 'a':
    210 			aflag++;
    211 			break;
    212 		case 'w':
    213 			wflag++;
    214 			break;
    215 		case 'v':
    216 			vflag++;
    217 			break;
    218 		case 'n':
    219 			sep = 0;
    220 			break;
    221 		case 'f':
    222 			file = optarg;
    223 			break;
    224 		case '?':
    225 		default:
    226 		usage:
    227 		fprintf(out, "%s [-f file] [-v] [-n] name ...\n", prog);
    228 		fprintf(out, "%s [-f file] [-v] [-n] -w name=value ...\n", prog);
    229 		fprintf(out, "%s [-f file] [-v] [-n] -a\n", prog);
    230 		exit(0);
    231 		}
    232 	}
    233 	argc -= optind;
    234 	argv += optind;
    235 
    236 	fd = open(file, O_RDWR);
    237 	if (fd < 0)
    238 		err(1, "%s", file);
    239 
    240 	for(ndev = 0; ; ndev++) {
    241 		dinfo.index = ndev;
    242 		if (ioctl(fd, AUDIO_MIXER_DEVINFO, &dinfo) < 0)
    243 			break;
    244 	}
    245 	rfields = calloc(ndev, sizeof *rfields);
    246 	fields = calloc(ndev, sizeof *fields);
    247 	infos = calloc(ndev, sizeof *infos);
    248 	values = calloc(ndev, sizeof *values);
    249 
    250 	for(i = 0; i < ndev; i++) {
    251 		infos[i].index = i;
    252 		ioctl(fd, AUDIO_MIXER_DEVINFO, &infos[i]);
    253 	}
    254 
    255 	for(i = 0; i < ndev; i++) {
    256 		rfields[i].name = infos[i].label.name;
    257 		rfields[i].valp = &values[i];
    258 		rfields[i].infp = &infos[i];
    259 	}
    260 
    261 	for(i = 0; i < ndev; i++) {
    262 		values[i].dev = i;
    263 		values[i].type = infos[i].type;
    264 		if (infos[i].type != AUDIO_MIXER_CLASS) {
    265 			values[i].un.value.num_channels = 2;
    266 			if (ioctl(fd, AUDIO_MIXER_READ, &values[i]) < 0) {
    267 				values[i].un.value.num_channels = 1;
    268 				if (ioctl(fd, AUDIO_MIXER_READ, &values[i]) < 0)
    269 					err(1, NULL);
    270 			}
    271 		}
    272 	}
    273 
    274 	for(j = i = 0; i < ndev; i++) {
    275 		if (infos[i].type != AUDIO_MIXER_CLASS &&
    276 		    infos[i].type != -1) {
    277 			fields[j++] = rfields[i];
    278 			for(pos = infos[i].next; pos != AUDIO_MIXER_LAST;
    279 			    pos = infos[pos].next) {
    280 				fields[j] = rfields[pos];
    281 				fields[j].name = catstr(rfields[i].name,
    282 							infos[pos].label.name);
    283 				infos[pos].type = -1;
    284 				j++;
    285 			}
    286 		}
    287 	}
    288 
    289 	for(i = 0; i < j; i++) {
    290 		if (infos[i].mixer_class >= 0 && infos[i].mixer_class < ndev)
    291 			fields[i].name = catstr(infos[fields[i].infp->mixer_class].label.name,
    292 						fields[i].name);
    293 	}
    294 
    295 	if (argc == 0 && aflag && !wflag) {
    296 		for(i = 0; fields[i].name; i++) {
    297 			prfield(&fields[i], sep, vflag);
    298 			fprintf(out, "\n");
    299 		}
    300 	} else if (argc > 0 && !aflag) {
    301 		struct field *p;
    302 		if (wflag) {
    303 			while(argc--) {
    304 				char *q;
    305 
    306 				q = strchr(*argv, '=');
    307 				if (q) {
    308 					*q++ = 0;
    309 					p = findfield(*argv);
    310 					if (p == 0)
    311 						warnx("field %s does not exist", *argv);
    312 					else {
    313 						val = *p->valp;
    314 						if (rdfield(p, q)) {
    315 							if (ioctl(fd, AUDIO_MIXER_WRITE, p->valp) < 0)
    316 								warn(NULL);
    317 							else if (sep) {
    318 								*p->valp = val;
    319 								prfield(p, ": ", 0);
    320 								ioctl(fd, AUDIO_MIXER_READ, p->valp);
    321 								printf(" -> ");
    322 								prfield(p, 0, 0);
    323 								printf("\n");
    324 							}
    325 						}
    326 					}
    327 				} else {
    328 					warnx("No `=' in %s", *argv);
    329 				}
    330 				argv++;
    331 			}
    332 		} else {
    333 			while(argc--) {
    334 				p = findfield(*argv);
    335 				if (p == 0)
    336 					warnx("field %s does not exist", *argv);
    337 				else
    338 					prfield(p, sep, vflag), fprintf(out, "\n");
    339 				argv++;
    340 			}
    341 		}
    342 	} else
    343 		goto usage;
    344 	exit(0);
    345 }
    346