Home | History | Annotate | Line # | Download | only in mixerctl
mixerctl.c revision 1.8
      1 /*	$NetBSD: mixerctl.c,v 1.8 1997/10/16 23:28:17 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 FOUNDATION OR CONTRIBUTORS
     29  * BE 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 char *catstr __P((char *p, char *q));
     48 struct field *findfield __P((char *name));
     49 void prfield __P((struct field *p, char *sep, int prvalset));
     50 int rdfield __P((struct field *p, char *q));
     51 int main(int argc, char **argv);
     52 
     53 FILE *out = stdout;
     54 
     55 char *prog;
     56 
     57 struct field {
     58 	char *name;
     59 	mixer_ctrl_t *valp;
     60 	mixer_devinfo_t *infp;
     61 	char changed;
     62 } *fields, *rfields;
     63 
     64 mixer_ctrl_t *values;
     65 mixer_devinfo_t *infos;
     66 
     67 char *
     68 catstr(p, q)
     69 	char *p;
     70         char *q;
     71 {
     72 	char *r = malloc(strlen(p) + strlen(q) + 2);
     73 	strcpy(r, p);
     74 	strcat(r, ".");
     75 	strcat(r, q);
     76 	return r;
     77 }
     78 
     79 struct field *
     80 findfield(name)
     81 	char *name;
     82 {
     83 	int i;
     84 	for(i = 0; fields[i].name; i++)
     85 		if (strcmp(fields[i].name, name) == 0)
     86 			return &fields[i];
     87 	return 0;
     88 }
     89 
     90 void
     91 prfield(p, sep, prvalset)
     92 	struct field *p;
     93         char *sep;
     94         int prvalset;
     95 {
     96 	mixer_ctrl_t *m;
     97 	int i, n;
     98 
     99 	if (sep)
    100 		fprintf(out, "%s%s", p->name, sep);
    101 	m = p->valp;
    102 	switch(m->type) {
    103 	case AUDIO_MIXER_ENUM:
    104 		for(i = 0; i < p->infp->un.e.num_mem; i++)
    105 			if (p->infp->un.e.member[i].ord == m->un.ord)
    106 				fprintf(out, "%s",
    107 					p->infp->un.e.member[i].label.name);
    108 		if (prvalset) {
    109 			fprintf(out, "  [ ");
    110 			for(i = 0; i < p->infp->un.e.num_mem; i++)
    111 				fprintf(out, "%s ", p->infp->un.e.member[i].label.name);
    112 			fprintf(out, "]");
    113 		}
    114 		break;
    115 	case AUDIO_MIXER_SET:
    116 		for(n = i = 0; i < p->infp->un.s.num_mem; i++)
    117 			if (m->un.mask & p->infp->un.s.member[i].mask)
    118 				fprintf(out, "%s%s", n++ ? "," : "",
    119 					p->infp->un.s.member[i].label.name);
    120 		if (prvalset) {
    121 			fprintf(out, "  { ");
    122 			for(i = 0; i < p->infp->un.s.num_mem; i++)
    123 				fprintf(out, "%s ", p->infp->un.s.member[i].label.name);
    124 			fprintf(out, "}");
    125 		}
    126 		break;
    127 	case AUDIO_MIXER_VALUE:
    128 		if (m->un.value.num_channels == 1)
    129 			fprintf(out, "%d", m->un.value.level[0]);
    130 		else
    131 			fprintf(out, "%d,%d", m->un.value.level[0],
    132 			       m->un.value.level[1]);
    133 		break;
    134 	default:
    135 		printf("\n");
    136 		errx(1, "Invalid format.");
    137 	}
    138 }
    139 
    140 int
    141 rdfield(p, q)
    142 	struct field *p;
    143         char *q;
    144 {
    145 	mixer_ctrl_t *m;
    146 	int v, v0, v1, mask;
    147 	int i;
    148 	char *s;
    149 
    150 	m = p->valp;
    151 	switch(m->type) {
    152 	case AUDIO_MIXER_ENUM:
    153 		for(i = 0; i < p->infp->un.e.num_mem; i++)
    154 			if (strcmp(p->infp->un.e.member[i].label.name, q) == 0)
    155 				break;
    156 		if (i < p->infp->un.e.num_mem)
    157 			m->un.ord = p->infp->un.e.member[i].ord;
    158 		else {
    159 			warnx("Bad enum value %s", q);
    160 			return 0;
    161 		}
    162 		break;
    163 	case AUDIO_MIXER_SET:
    164 		mask = 0;
    165 		for(v = 0; q && *q; q = s) {
    166 			s = strchr(q, ',');
    167 			if (s)
    168 				*s++ = 0;
    169 			for(i = 0; i < p->infp->un.s.num_mem; i++)
    170 				if (strcmp(p->infp->un.s.member[i].label.name, q) == 0)
    171 					break;
    172 			if (i < p->infp->un.s.num_mem) {
    173 				mask |= p->infp->un.s.member[i].mask;
    174 			} else {
    175 				warnx("Bad set value %s", q);
    176 				return 0;
    177 			}
    178 		}
    179 		m->un.mask = mask;
    180 		break;
    181 	case AUDIO_MIXER_VALUE:
    182 		if (m->un.value.num_channels == 1) {
    183 			if (sscanf(q, "%d", &v) == 1) {
    184 				m->un.value.level[0] = v;
    185 			} else {
    186 				warnx("Bad number %s", q);
    187 				return 0;
    188 			}
    189 		} else {
    190 			if (sscanf(q, "%d,%d", &v0, &v1) == 2) {
    191 				m->un.value.level[0] = v0;
    192 				m->un.value.level[1] = v1;
    193 			} else if (sscanf(q, "%d", &v) == 1) {
    194 				m->un.value.level[0] = m->un.value.level[1] = v;
    195 			} else {
    196 				warnx("Bad numbers %s", q);
    197 				return 0;
    198 			}
    199 		}
    200 		break;
    201 	default:
    202 		errx(1, "Invalid format.");
    203 	}
    204 	p->changed = 1;
    205 	return 1;
    206 }
    207 
    208 int
    209 main(argc, argv)
    210 	int argc;
    211         char **argv;
    212 {
    213 	int fd, i, j, ch, pos;
    214 	int aflag = 0, wflag = 0, vflag = 0;
    215 	char *file = "/dev/mixer";
    216 	char *sep = "=";
    217 	mixer_devinfo_t dinfo;
    218 	mixer_ctrl_t val;
    219 	int ndev;
    220 
    221 	prog = *argv;
    222 
    223 	while ((ch = getopt(argc, argv, "af:nvw")) != -1) {
    224 		switch(ch) {
    225 		case 'a':
    226 			aflag++;
    227 			break;
    228 		case 'w':
    229 			wflag++;
    230 			break;
    231 		case 'v':
    232 			vflag++;
    233 			break;
    234 		case 'n':
    235 			sep = 0;
    236 			break;
    237 		case 'f':
    238 			file = optarg;
    239 			break;
    240 		case '?':
    241 		default:
    242 		usage:
    243 		fprintf(out, "%s [-f file] [-v] [-n] name ...\n", prog);
    244 		fprintf(out, "%s [-f file] [-v] [-n] -w name=value ...\n", prog);
    245 		fprintf(out, "%s [-f file] [-v] [-n] -a\n", prog);
    246 		exit(0);
    247 		}
    248 	}
    249 	argc -= optind;
    250 	argv += optind;
    251 
    252 	fd = open(file, O_RDWR);
    253 	if (fd < 0)
    254 		err(1, "%s", file);
    255 
    256 	for(ndev = 0; ; ndev++) {
    257 		dinfo.index = ndev;
    258 		if (ioctl(fd, AUDIO_MIXER_DEVINFO, &dinfo) < 0)
    259 			break;
    260 	}
    261 	rfields = calloc(ndev, sizeof *rfields);
    262 	fields = calloc(ndev, sizeof *fields);
    263 	infos = calloc(ndev, sizeof *infos);
    264 	values = calloc(ndev, sizeof *values);
    265 
    266 	for(i = 0; i < ndev; i++) {
    267 		infos[i].index = i;
    268 		ioctl(fd, AUDIO_MIXER_DEVINFO, &infos[i]);
    269 	}
    270 
    271 	for(i = 0; i < ndev; i++) {
    272 		rfields[i].name = infos[i].label.name;
    273 		rfields[i].valp = &values[i];
    274 		rfields[i].infp = &infos[i];
    275 	}
    276 
    277 	for(i = 0; i < ndev; i++) {
    278 		values[i].dev = i;
    279 		values[i].type = infos[i].type;
    280 		if (infos[i].type != AUDIO_MIXER_CLASS) {
    281 			values[i].un.value.num_channels = 2;
    282 			if (ioctl(fd, AUDIO_MIXER_READ, &values[i]) < 0) {
    283 				values[i].un.value.num_channels = 1;
    284 				if (ioctl(fd, AUDIO_MIXER_READ, &values[i]) < 0)
    285 					err(1, "AUDIO_MIXER_READ");
    286 			}
    287 		}
    288 	}
    289 
    290 	for(j = i = 0; i < ndev; i++) {
    291 		if (infos[i].type != AUDIO_MIXER_CLASS &&
    292 		    infos[i].type != -1) {
    293 			fields[j++] = rfields[i];
    294 			for(pos = infos[i].next; pos != AUDIO_MIXER_LAST;
    295 			    pos = infos[pos].next) {
    296 				fields[j] = rfields[pos];
    297 				fields[j].name = catstr(rfields[i].name,
    298 							infos[pos].label.name);
    299 				infos[pos].type = -1;
    300 				j++;
    301 			}
    302 		}
    303 	}
    304 
    305 	for(i = 0; i < j; i++) {
    306 		int cls = fields[i].infp->mixer_class;
    307 		if (cls >= 0 && cls < ndev)
    308 			fields[i].name = catstr(infos[cls].label.name,
    309 						fields[i].name);
    310 	}
    311 
    312 	if (argc == 0 && aflag && !wflag) {
    313 		for(i = 0; fields[i].name; i++) {
    314 			prfield(&fields[i], sep, vflag);
    315 			fprintf(out, "\n");
    316 		}
    317 	} else if (argc > 0 && !aflag) {
    318 		struct field *p;
    319 		if (wflag) {
    320 			while(argc--) {
    321 				char *q;
    322 
    323 				q = strchr(*argv, '=');
    324 				if (q) {
    325 					*q++ = 0;
    326 					p = findfield(*argv);
    327 					if (p == 0)
    328 						warnx("field %s does not exist", *argv);
    329 					else {
    330 						val = *p->valp;
    331 						if (rdfield(p, q)) {
    332 							if (ioctl(fd, AUDIO_MIXER_WRITE, p->valp) < 0)
    333 								warn("AUDIO_MIXER_WRITE");
    334 							else if (sep) {
    335 								*p->valp = val;
    336 								prfield(p, ": ", 0);
    337 								ioctl(fd, AUDIO_MIXER_READ, p->valp);
    338 								printf(" -> ");
    339 								prfield(p, 0, 0);
    340 								printf("\n");
    341 							}
    342 						}
    343 					}
    344 				} else {
    345 					warnx("No `=' in %s", *argv);
    346 				}
    347 				argv++;
    348 			}
    349 		} else {
    350 			while(argc--) {
    351 				p = findfield(*argv);
    352 				if (p == 0)
    353 					warnx("field %s does not exist", *argv);
    354 				else
    355 					prfield(p, sep, vflag), fprintf(out, "\n");
    356 				argv++;
    357 			}
    358 		}
    359 	} else
    360 		goto usage;
    361 	exit(0);
    362 }
    363