version 1.18, 2005/01/04 18:22:09 |
version 1.19, 2005/02/02 08:08:33 |
|
|
* mixerctl(1) - a program to control audio mixing. |
* mixerctl(1) - a program to control audio mixing. |
*/ |
*/ |
|
|
#include <stdio.h> |
|
#include <stdlib.h> |
|
#include <fcntl.h> |
|
#include <err.h> |
|
#include <unistd.h> |
|
#include <string.h> |
|
#include <sys/types.h> |
#include <sys/types.h> |
#include <sys/ioctl.h> |
#include <sys/ioctl.h> |
#include <sys/audioio.h> |
#include <sys/audioio.h> |
|
|
char *catstr(char *p, char *q); |
#include <err.h> |
struct field *findfield(char *name); |
#include <fcntl.h> |
void prfield(struct field *p, char *sep, int prvalset); |
#include <stdio.h> |
int rdfield(struct field *p, char *q); |
#include <stdlib.h> |
int main(int argc, char **argv); |
#include <string.h> |
void usage(void); |
#include <unistd.h> |
|
|
FILE *out = stdout; |
void catstr(char *, char *, char *); |
|
struct field *findfield(char *); |
|
void prfield(struct field *, char *, int); |
|
void rdfield(int, struct field *, char *); |
|
__dead void usage(void); |
|
|
|
#define FIELD_NAME_MAX 64 |
|
|
struct field { |
struct field { |
char *name; |
char name[FIELD_NAME_MAX]; |
mixer_ctrl_t *valp; |
mixer_ctrl_t *valp; |
mixer_devinfo_t *infp; |
mixer_devinfo_t *infp; |
} *fields, *rfields; |
} *fields, *rfields; |
|
|
mixer_ctrl_t *values; |
mixer_ctrl_t *values; |
mixer_devinfo_t *infos; |
mixer_devinfo_t *infos; |
|
|
char * |
void |
catstr(char *p, char *q) |
catstr(char *p, char *q, char *out) |
{ |
{ |
int len; |
char tmp[FIELD_NAME_MAX]; |
char *r; |
|
|
|
len = strlen(p) + 1 + strlen(q) + 1; |
snprintf(tmp, FIELD_NAME_MAX, "%s.%s", p, q); |
if ((r = malloc(len)) == NULL) |
strlcpy(out, tmp, FIELD_NAME_MAX); |
err(1, "malloc()"); |
|
strlcpy(r, p, len); |
|
strlcat(r, ".", len); |
|
strlcat(r, q, len); |
|
return (r); |
|
} |
} |
|
|
struct field * |
struct field * |
findfield(char *name) |
findfield(char *name) |
{ |
{ |
int i; |
int i; |
for (i = 0; fields[i].name; i++) |
for (i = 0; fields[i].name[0] != '\0'; i++) |
if (strcmp(fields[i].name, name) == 0) |
if (strcmp(fields[i].name, name) == 0) |
return &fields[i]; |
return &fields[i]; |
return (0); |
return (0); |
} |
} |
|
|
|
#define e_member_name un.e.member[i].label.name |
|
#define s_member_name un.s.member[i].label.name |
|
|
void |
void |
prfield(struct field *p, char *sep, int prvalset) |
prfield(struct field *p, char *sep, int prvalset) |
{ |
{ |
|
|
int i, n; |
int i, n; |
|
|
if (sep) |
if (sep) |
fprintf(out, "%s%s", p->name, sep); |
printf("%s%s", p->name, sep); |
m = p->valp; |
m = p->valp; |
switch(m->type) { |
switch (m->type) { |
case AUDIO_MIXER_ENUM: |
case AUDIO_MIXER_ENUM: |
for (i = 0; i < p->infp->un.e.num_mem; i++) |
for (i = 0; i < p->infp->un.e.num_mem; i++) |
if (p->infp->un.e.member[i].ord == m->un.ord) |
if (p->infp->un.e.member[i].ord == m->un.ord) |
fprintf(out, "%s", |
printf("%s", |
p->infp->un.e.member[i].label.name); |
p->infp->e_member_name); |
if (prvalset) { |
if (prvalset) { |
fprintf(out, " [ "); |
printf(" [ "); |
for (i = 0; i < p->infp->un.e.num_mem; i++) |
for (i = 0; i < p->infp->un.e.num_mem; i++) |
fprintf(out, "%s ", p->infp->un.e.member[i].label.name); |
printf("%s ", p->infp->e_member_name); |
fprintf(out, "]"); |
printf("]"); |
} |
} |
break; |
break; |
case AUDIO_MIXER_SET: |
case AUDIO_MIXER_SET: |
for (n = i = 0; i < p->infp->un.s.num_mem; i++) |
for (n = i = 0; i < p->infp->un.s.num_mem; i++) |
if (m->un.mask & p->infp->un.s.member[i].mask) |
if (m->un.mask & p->infp->un.s.member[i].mask) |
fprintf(out, "%s%s", n++ ? "," : "", |
printf("%s%s", n++ ? "," : "", |
p->infp->un.s.member[i].label.name); |
p->infp->s_member_name); |
if (prvalset) { |
if (prvalset) { |
fprintf(out, " { "); |
printf(" { "); |
for (i = 0; i < p->infp->un.s.num_mem; i++) |
for (i = 0; i < p->infp->un.s.num_mem; i++) |
fprintf(out, "%s ", p->infp->un.s.member[i].label.name); |
printf("%s ", p->infp->s_member_name); |
fprintf(out, "}"); |
printf("}"); |
} |
} |
break; |
break; |
case AUDIO_MIXER_VALUE: |
case AUDIO_MIXER_VALUE: |
if (m->un.value.num_channels == 1) |
if (m->un.value.num_channels == 1) |
fprintf(out, "%d", m->un.value.level[0]); |
printf("%d", m->un.value.level[0]); |
else |
else |
fprintf(out, "%d,%d", m->un.value.level[0], |
printf("%d,%d", m->un.value.level[0], |
m->un.value.level[1]); |
m->un.value.level[1]); |
if (prvalset) |
if (prvalset) |
fprintf(out, " %s", p->infp->un.v.units.name); |
printf(" %s", p->infp->un.v.units.name); |
break; |
break; |
default: |
default: |
errx(1, "Invalid format."); |
errx(1, "Invalid format."); |
} |
} |
} |
} |
|
|
int |
void |
rdfield(struct field *p, char *q) |
rdfield(int fd, struct field *p, char *q) |
{ |
{ |
mixer_ctrl_t *m; |
mixer_ctrl_t *m, oldval; |
int v, v0, v1, mask; |
int v, v0, v1, mask; |
int i; |
int i; |
char *s; |
char *s; |
|
|
|
oldval = *p->valp; |
m = p->valp; |
m = p->valp; |
switch(m->type) { |
|
|
switch (m->type) { |
case AUDIO_MIXER_ENUM: |
case AUDIO_MIXER_ENUM: |
for (i = 0; i < p->infp->un.e.num_mem; i++) |
for (i = 0; i < p->infp->un.e.num_mem; i++) |
if (strcmp(p->infp->un.e.member[i].label.name, q) == 0) |
if (strcmp(p->infp->e_member_name, q) == 0) |
break; |
break; |
if (i < p->infp->un.e.num_mem) |
if (i < p->infp->un.e.num_mem) |
m->un.ord = p->infp->un.e.member[i].ord; |
m->un.ord = p->infp->un.e.member[i].ord; |
|
|
case AUDIO_MIXER_SET: |
case AUDIO_MIXER_SET: |
mask = 0; |
mask = 0; |
for (v = 0; q && *q; q = s) { |
for (v = 0; q && *q; q = s) { |
if (s = strchr(q, ',')) |
if ((s = strchr(q, ',')) != NULL) |
*s++ = 0; |
*s++ = 0; |
for (i = 0; i < p->infp->un.s.num_mem; i++) |
for (i = 0; i < p->infp->un.s.num_mem; i++) |
if (strcmp(p->infp->un.s.member[i].label.name, q) == 0) |
if (strcmp(p->infp->s_member_name, q) == 0) |
break; |
break; |
if (i < p->infp->un.s.num_mem) |
if (i < p->infp->un.s.num_mem) |
mask |= p->infp->un.s.member[i].mask; |
mask |= p->infp->un.s.member[i].mask; |
|
|
default: |
default: |
errx(1, "Invalid format."); |
errx(1, "Invalid format."); |
} |
} |
return (1); |
|
|
if (ioctl(fd, AUDIO_MIXER_WRITE, p->valp) < 0) { |
|
warn("AUDIO_MIXER_WRITE"); |
|
} else { |
|
*p->valp = oldval; |
|
prfield(p, ": ", 0); |
|
if (ioctl(fd, AUDIO_MIXER_READ, p->valp) < 0) { |
|
warn("AUDIO_MIXER_READ"); |
|
} else { |
|
printf(" -> "); |
|
prfield(p, NULL, 0); |
|
printf("\n"); |
|
} |
|
} |
} |
} |
|
|
int |
int |
|
|
char *file; |
char *file; |
char *sep = "="; |
char *sep = "="; |
mixer_devinfo_t dinfo; |
mixer_devinfo_t dinfo; |
mixer_ctrl_t val; |
|
int ndev; |
int ndev; |
|
|
if ((file = getenv("MIXERDEVICE")) == 0 || *file == '\0') |
if ((file = getenv("MIXERDEVICE")) == 0 || *file == '\0') |
|
|
for (i = 0; i < ndev; i++) { |
for (i = 0; i < ndev; i++) { |
infos[i].index = i; |
infos[i].index = i; |
if (ioctl(fd, AUDIO_MIXER_DEVINFO, &infos[i]) < 0) { |
if (ioctl(fd, AUDIO_MIXER_DEVINFO, &infos[i]) < 0) { |
ndev--, i--; |
ndev--; |
|
i--; |
continue; |
continue; |
} |
} |
} |
} |
|
|
for (i = 0; i < ndev; i++) { |
for (i = 0; i < ndev; i++) { |
rfields[i].name = infos[i].label.name; |
strlcpy(rfields[i].name, infos[i].label.name, FIELD_NAME_MAX); |
rfields[i].valp = &values[i]; |
rfields[i].valp = &values[i]; |
rfields[i].infp = &infos[i]; |
rfields[i].infp = &infos[i]; |
} |
} |
|
|
for (pos = infos[i].next; pos != AUDIO_MIXER_LAST; |
for (pos = infos[i].next; pos != AUDIO_MIXER_LAST; |
pos = infos[pos].next) { |
pos = infos[pos].next) { |
fields[j] = rfields[pos]; |
fields[j] = rfields[pos]; |
fields[j].name = catstr(rfields[i].name, |
catstr(rfields[i].name, infos[pos].label.name, |
infos[pos].label.name); |
fields[j].name); |
infos[pos].type = -1; |
infos[pos].type = -1; |
j++; |
j++; |
} |
} |
|
|
for (i = 0; i < j; i++) { |
for (i = 0; i < j; i++) { |
int cls = fields[i].infp->mixer_class; |
int cls = fields[i].infp->mixer_class; |
if (cls >= 0 && cls < ndev) |
if (cls >= 0 && cls < ndev) |
fields[i].name = catstr(infos[cls].label.name, |
catstr(infos[cls].label.name, fields[i].name, |
fields[i].name); |
fields[i].name); |
} |
} |
|
|
if (!argc && aflag) { |
if (!argc && aflag) { |
for (i = 0; fields[i].name; i++) { |
for (i = 0; fields[i].name[0] != '\0'; i++) { |
prfield(&fields[i], sep, vflag); |
prfield(&fields[i], sep, vflag); |
fprintf(out, "\n"); |
printf("\n"); |
} |
} |
} else if (argc > 0 && !aflag) { |
} else if (argc > 0 && !aflag) { |
struct field *p; |
struct field *p; |
|
|
while(argc--) { |
while (argc--) { |
char *q; |
char *q; |
|
|
if (q = strchr(*argv, '=')) { |
ch = 0; |
*q++ = 0; |
if ((q = strchr(*argv, '=')) != NULL) { |
p = findfield(*argv); |
*q++ = '\0'; |
if (p == NULL) |
ch = 1; |
warnx("field %s does not exist", *argv); |
} |
else { |
|
val = *p->valp; |
if ((p = findfield(*argv)) == NULL) { |
if (rdfield(p, q)) { |
warnx("field %s does not exist", *argv); |
if (ioctl(fd, AUDIO_MIXER_WRITE, p->valp) < 0) |
} else if (ch) { |
warn("AUDIO_MIXER_WRITE"); |
rdfield(fd, p, q); |
else if (sep && !qflag) { |
|
*p->valp = val; |
|
prfield(p, ": ", 0); |
|
ioctl(fd, AUDIO_MIXER_READ, p->valp); |
|
printf(" -> "); |
|
prfield(p, 0, 0); |
|
printf("\n"); |
|
} |
|
} |
|
} |
|
} else { |
} else { |
p = findfield(*argv); |
prfield(p, sep, vflag); |
if (p == NULL) |
printf("\n"); |
warnx("field %s does not exist", *argv); |
|
else { |
|
prfield(p, sep, vflag); |
|
fprintf(out, "\n"); |
|
} |
|
} |
} |
|
|
argv++; |
argv++; |
} |
} |
} else |
} else |
|
|
exit(0); |
exit(0); |
} |
} |
|
|
void |
__dead void |
usage(void) |
usage(void) |
{ |
{ |
extern char *__progname; /* from crt0.o */ |
extern char *__progname; /* from crt0.o */ |