mixer

FreeBSD OSS mixer library implementation and a complete rewrite of mixer(8)
git clone git://git.margiolis.net/mixer.git
Log | Files | Refs | README

commit 75e74d4a795cc470cc766bebc2a0a53f285e780a
parent 59e86ffbff3a421127aae4df5645dd0912c076b6
Author: Christos Margiolis <christos@margiolis.net>
Date:   Wed, 28 Jul 2021 18:37:18 +0300

mixer(3): moved control handling here

Diffstat:
Mdiff/mixer_kern.diff | 36+++++++++++++++++++-----------------
Mmixer_lib/mixer.c | 147++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------
Mmixer_lib/mixer.h | 48++++++++++++++++++++++++++++++++++--------------
Mmixer_prog/mixer_prog.c | 226++++++++++++++++++++++++++++++++++++++++++++++---------------------------------
4 files changed, 312 insertions(+), 145 deletions(-)

diff --git a/diff/mixer_kern.diff b/diff/mixer_kern.diff @@ -308,51 +308,53 @@ index 8e11d553a3e..7857609b289 100644 void mix_setrealdev(struct snd_mixer *m, u_int32_t dev, u_int32_t realdev); u_int32_t mix_getparent(struct snd_mixer *m, u_int32_t dev); diff --git a/sys/dev/sound/pcm/sound.c b/sys/dev/sound/pcm/sound.c -index b4be28aeff8..2638885d431 100644 +index b4be28aeff8..e2014a70f9b 100644 --- a/sys/dev/sound/pcm/sound.c +++ b/sys/dev/sound/pcm/sound.c -@@ -1012,12 +1012,28 @@ SYSCTL_PROC(_hw_snd, OID_AUTO, clone_gc, CTLTYPE_INT | CTLFLAG_RWTUN, +@@ -1012,12 +1012,30 @@ SYSCTL_PROC(_hw_snd, OID_AUTO, clone_gc, CTLTYPE_INT | CTLFLAG_RWTUN, "global clone garbage collector"); #endif +static u_int8_t -+pcm_status_init(struct snddev_info *d) ++pcm_mode_init(struct snddev_info *d) +{ -+ u_int8_t status = PCM_STATUS_NONE; ++ u_int8_t mode = 0; + + if (d->playcount > 0) -+ status |= PCM_STATUS_PLAY; ++ mode |= PCM_MODE_PLAY; + if (d->reccount > 0) -+ status |= PCM_STATUS_REC; ++ mode |= PCM_MODE_REC; ++ if (d->playcount == 0 && d->reccount == 0) ++ mode = PCM_MODE_NONE; + -+ return (status); ++ return (mode); +} + static void pcm_sysinit(device_t dev) { struct snddev_info *d = device_get_softc(dev); -+ u_int8_t status; ++ u_int8_t mode; + -+ status = pcm_status_init(d); ++ mode = pcm_mode_init(d); - /* XXX: an user should be able to set this with a control tool, the + /* XXX: a user should be able to set this with a control tool, the sysadmin then needs min+max sysctls for this */ SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev), SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), -@@ -1027,6 +1043,10 @@ pcm_sysinit(device_t dev) +@@ -1027,6 +1045,10 @@ pcm_sysinit(device_t dev) "bitperfect", CTLTYPE_INT | CTLFLAG_RWTUN, d, sizeof(d), sysctl_dev_pcm_bitperfect, "I", "bit-perfect playback/recording (0=disable, 1=enable)"); + SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev), + SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), -+ OID_AUTO, "status", CTLFLAG_RD, NULL, status, -+ "playback/recording status (0=none, 1=play, 2=rec, 3=play+rec)"); ++ OID_AUTO, "mode", CTLFLAG_RD, NULL, mode, ++ "mode (0=none, 1=play, 2=rec, 3=play+rec)"); #ifdef SND_DEBUG SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, -@@ -1130,7 +1150,7 @@ pcm_register(device_t dev, void *devinfo, int numplay, int numrec) +@@ -1130,7 +1152,7 @@ pcm_register(device_t dev, void *devinfo, int numplay, int numrec) sysctl_ctx_init(&d->rec_sysctl_ctx); d->rec_sysctl_tree = SYSCTL_ADD_NODE(&d->rec_sysctl_ctx, SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "rec", @@ -362,16 +364,16 @@ index b4be28aeff8..2638885d431 100644 if (numplay > 0 || numrec > 0) d->flags |= SD_F_AUTOVCHAN; diff --git a/sys/dev/sound/pcm/sound.h b/sys/dev/sound/pcm/sound.h -index d4b3a23e8eb..c16555f830a 100644 +index d4b3a23e8eb..eda4012a517 100644 --- a/sys/dev/sound/pcm/sound.h +++ b/sys/dev/sound/pcm/sound.h @@ -411,6 +411,10 @@ struct snddev_info { void sound_oss_sysinfo(oss_sysinfo *); int sound_oss_card_info(oss_card_info *); -+#define PCM_STATUS_NONE 0x00 -+#define PCM_STATUS_PLAY 0x01 -+#define PCM_STATUS_REC 0x02 ++#define PCM_MODE_NONE 0x01 ++#define PCM_MODE_PLAY 0x02 ++#define PCM_MODE_REC 0x04 + #define PCM_LOCKOWNED(d) mtx_owned((d)->lock) #define PCM_LOCK(d) mtx_lock((d)->lock) diff --git a/mixer_lib/mixer.c b/mixer_lib/mixer.c @@ -86,7 +86,7 @@ mixer_open(const char *name) (void)strlcpy(m->name, name, sizeof(m->name)); } else { dunit: - if ((m->unit = mixer_getdunit()) < 0) + if ((m->unit = mixer_get_dunit()) < 0) goto fail; (void)snprintf(m->name, sizeof(m->name) - 1, "/dev/mixer%d", m->unit); } @@ -95,8 +95,8 @@ dunit: goto fail; m->devmask = m->recmask = m->recsrc = 0; - m->f_default = m->unit == mixer_getdunit(); - m->status = mixer_getstatus(m->unit); + m->f_default = m->unit == mixer_get_dunit(); + m->mode = mixer_get_mode(m->unit); /* The unit number _must_ be set before the ioctl. */ m->mi.dev = m->unit; m->ci.card = m->unit; @@ -115,9 +115,11 @@ dunit: if ((dp = calloc(1, sizeof(struct mix_dev))) == NULL) goto fail; dp->devno = i; + dp->nctl = 0; if (_mixer_readvol(m, dp) < 0) goto fail; (void)strlcpy(dp->name, names[i], sizeof(dp->name)); + TAILQ_INIT(&dp->ctls); TAILQ_INSERT_TAIL(&m->devs, dp, devs); m->ndev++; } @@ -140,12 +142,18 @@ int mixer_close(struct mixer *m) { struct mix_dev *dp; + mix_ctl_t *cp; int r; r = close(m->fd); while (!TAILQ_EMPTY(&m->devs)) { dp = TAILQ_FIRST(&m->devs); TAILQ_REMOVE(&m->devs, dp, devs); + while (!TAILQ_EMPTY(&dp->ctls)) { + cp = TAILQ_FIRST(&dp->ctls); + TAILQ_REMOVE(&dp->ctls, cp, ctls); + free(cp); + } free(dp); } free(m); @@ -162,7 +170,7 @@ mixer_close(struct mixer *m) * The caller must manually assign the return value to `m->dev`. */ struct mix_dev * -mixer_getdev(struct mixer *m, int dev) +mixer_get_dev(struct mixer *m, int dev) { struct mix_dev *dp; @@ -185,7 +193,7 @@ mixer_getdev(struct mixer *m, int dev) * @param name device name (e.g vol, pcm, ...) */ struct mix_dev * -mixer_getdevbyname(struct mixer *m, const char *name) +mixer_get_dev_byname(struct mixer *m, const char *name) { struct mix_dev *dp; @@ -199,6 +207,107 @@ mixer_getdevbyname(struct mixer *m, const char *name) } /* + * Make a mixer control. + */ +mix_ctl_t * +mixer_make_ctl(int id, const char *name, + int (*mod)(struct mixer *m, void *p), int (*print)(struct mixer *m, void *p)) +{ + mix_ctl_t *ctl; + + if ((ctl = calloc(1, sizeof(mix_ctl_t))) == NULL) + return (NULL); + ctl->id = id; + if (name != NULL) + (void)strlcpy(ctl->name, name, sizeof(ctl->name)); + ctl->mod = mod; + ctl->print = print; + + return (ctl); +} + +/* + * Add a mixer control to a device by passing all fields as arguments. + */ +int +mixer_add_ctl(struct mix_dev *d, int id, const char *name, + int (*mod)(struct mixer *m, void *p), int (*print)(struct mixer *m, void *p)) +{ + mix_ctl_t *ctl; + + if ((ctl = mixer_make_ctl(id, name, mod, print)) == NULL) + return (-1); + + return (mixer_add_ctl_s(d, ctl)); +} + +/* + * Add a mixer control to a device. + */ +int +mixer_add_ctl_s(struct mix_dev *d, mix_ctl_t *ctl) +{ + if (ctl == NULL || ctl->mod == NULL || ctl->print == NULL) + return (-1); + TAILQ_INSERT_TAIL(&d->ctls, ctl, ctls); + d->nctl++; + + return (0); +} + +/* + * Remove a mixer control from a device. + */ +int +mixer_remove_ctl(struct mix_dev *d, mix_ctl_t *ctl) +{ + if (ctl == NULL) { + errno = EINVAL; + return (-1); + } + if (!TAILQ_EMPTY(&d->ctls)) { + TAILQ_REMOVE(&d->ctls, ctl, ctls); + free(ctl); + } + + return (0); +} + +/* + * Get a mixer control by id. + */ +mix_ctl_t * +mixer_get_ctl(struct mix_dev *d, int id) +{ + mix_ctl_t *cp; + + TAILQ_FOREACH(cp, &d->ctls, ctls) { + if (cp->id == id) + return (cp); + } + errno = EINVAL; + + return (NULL); +} + +/* + * Get a mixer control by name. + */ +mix_ctl_t * +mixer_get_ctl_byname(struct mix_dev *d, const char *name) +{ + mix_ctl_t *cp; + + TAILQ_FOREACH(cp, &d->ctls, ctls) { + if (!strncmp(cp->name, name, sizeof(cp->name))) + return (cp); + } + errno = EINVAL; + + return (NULL); +} + +/* * Change the mixer's left and right volume. The allowed volume values are * between MIX_VOLMIN and MIX_VOLMAX. The `ioctl` for volume change requires * an integer value between 0 and 100 stored as `lvol | rvol << 8` -- for @@ -208,7 +317,7 @@ mixer_getdevbyname(struct mixer *m, const char *name) * Volume clumping should be done by the caller. */ int -mixer_setvol(struct mixer *m, mix_volume_t vol) +mixer_set_vol(struct mixer *m, mix_volume_t vol) { int v; @@ -234,7 +343,7 @@ mixer_setvol(struct mixer *m, mix_volume_t vol) * MIX_TOGGLEMUTE toggle device's mute */ int -mixer_setmute(struct mixer *m, int opt) +mixer_set_mute(struct mixer *m, int opt) { switch (opt) { case MIX_MUTE: @@ -268,7 +377,7 @@ mixer_setmute(struct mixer *m, int opt) * MIX_TOGGLERECSRC toggle device from recording sources */ int -mixer_modrecsrc(struct mixer *m, int opt) +mixer_mod_recsrc(struct mixer *m, int opt) { if (!m->recmask || !MIX_ISREC(m, m->dev->devno)) { errno = ENODEV; @@ -304,7 +413,7 @@ mixer_modrecsrc(struct mixer *m, int opt) * and set the mixer structure's `f_default` flag. */ int -mixer_getdunit(void) +mixer_get_dunit(void) { size_t size; int unit; @@ -324,7 +433,7 @@ mixer_getdunit(void) * @param unit the audio card number (e.g pcm0, pcm1, ...). */ int -mixer_setdunit(struct mixer *m, int unit) +mixer_set_dunit(struct mixer *m, int unit) { size_t size; @@ -337,29 +446,29 @@ mixer_setdunit(struct mixer *m, int unit) } /* - * Get sound device status (none, play, rec, play+rec). Userland programs can - * use the MIX_STATUS_* flags to determine the status of the device. + * Get sound device mode (none, play, rec, play+rec). Userland programs can + * use the MIX_STATUS_* flags to determine the mode of the device. */ int -mixer_getstatus(int unit) +mixer_get_mode(int unit) { - char buf[BUFSIZ]; + char buf[64]; size_t size; - unsigned int status; + unsigned int mode; - (void)snprintf(buf, sizeof(buf) - 1, "dev.pcm.%d.status", unit); + (void)snprintf(buf, sizeof(buf) - 1, "dev.pcm.%d.mode", unit); size = sizeof(unsigned int); - if (sysctlbyname(buf, &status, &size, NULL, 0) < 0) + if (sysctlbyname(buf, &mode, &size, NULL, 0) < 0) return (-1); - return (status); + return (mode); } /* * Get the total number of mixers in the system. */ int -mixer_getnmixers(void) +mixer_get_nmixers(void) { struct mixer *m; oss_sysinfo si; diff --git a/mixer_lib/mixer.h b/mixer_lib/mixer.h @@ -40,6 +40,16 @@ __FBSDID("$FreeBSD$"); #define MIX_ISREC(m,n) MIX_ISSET(n, (m)->recmask) #define MIX_ISRECSRC(m,n) MIX_ISSET(n, (m)->recsrc) +struct mixer; + +typedef struct mix_ctl { + int id; + char name[NAME_MAX]; + int (*mod)(struct mixer *, void *); + int (*print)(struct mixer *, void *); + TAILQ_ENTRY(mix_ctl) ctls; +} mix_ctl_t; + struct mix_dev { char name[NAME_MAX]; int devno; @@ -51,6 +61,8 @@ struct mix_dev { float left; float right; } vol; + int nctl; + TAILQ_HEAD(, mix_ctl) ctls; TAILQ_ENTRY(mix_dev) devs; }; @@ -74,26 +86,34 @@ struct mixer { #define MIX_SETRECSRC 0x04 #define MIX_TOGGLERECSRC 0x08 int recsrc; - int f_default; /* TODO: combine with status? */ -#define MIX_STATUS_NONE 0x00 -#define MIX_STATUS_PLAY 0x01 -#define MIX_STATUS_REC 0x02 - int status; + int f_default; +#define MIX_MODE_NONE 0x01 +#define MIX_MODE_PLAY 0x02 +#define MIX_MODE_REC 0x04 + int mode; }; typedef struct mix_volume mix_volume_t; struct mixer *mixer_open(const char *); int mixer_close(struct mixer *); -struct mix_dev *mixer_getdev(struct mixer *, int); -struct mix_dev *mixer_getdevbyname(struct mixer *, const char *); -int mixer_setvol(struct mixer *, mix_volume_t); -int mixer_setmute(struct mixer *, int); -int mixer_modrecsrc(struct mixer *, int); -int mixer_getdunit(void); -int mixer_setdunit(struct mixer *, int); -int mixer_getstatus(int); -int mixer_getnmixers(void); +struct mix_dev *mixer_get_dev(struct mixer *, int); +struct mix_dev *mixer_get_dev_byname(struct mixer *, const char *); +mix_ctl_t *mixer_make_ctl(int, const char *, + int (*)(struct mixer *, void *), int (*)(struct mixer *, void *)); +int mixer_add_ctl(struct mix_dev *, int, const char *, + int (*)(struct mixer *, void *), int (*)(struct mixer *, void *)); +int mixer_add_ctl_s(struct mix_dev *, mix_ctl_t *); +int mixer_remove_ctl(struct mix_dev *, mix_ctl_t *); +mix_ctl_t *mixer_get_ctl(struct mix_dev *, int); +mix_ctl_t *mixer_get_ctl_byname(struct mix_dev *, const char *); +int mixer_set_vol(struct mixer *, mix_volume_t); +int mixer_set_mute(struct mixer *, int); +int mixer_mod_recsrc(struct mixer *, int); +int mixer_get_dunit(void); +int mixer_set_dunit(struct mixer *, int); +int mixer_get_mode(int); +int mixer_get_nmixers(void); __END_DECLS diff --git a/mixer_prog/mixer_prog.c b/mixer_prog/mixer_prog.c @@ -31,42 +31,28 @@ #define LEN(x) (sizeof(x) / sizeof(x[0])) -#define MCTL_VOL 0 -#define MCTL_PAN 1 -#define MCTL_MUT 2 -#define MCTL_SRC 3 - -struct mix_ctl { - char name[NAME_MAX]; - void (*mod)(struct mixer *, const char *); - void (*print)(struct mixer *); - /* TODO: printed flag */ -}; - static void usage(void) __dead2; +static void initctls(struct mixer *); static void printall(struct mixer *, int); static void printminfo(struct mixer *, int); -static void printdev(struct mixer *, struct mix_dev *, int); +static void printdev(struct mixer *, int); static void printrecsrc(struct mixer *, int); -static int findctl(const char *); /* Control handlers */ -static void mod_volume(struct mixer *, const char *); -static void mod_mute(struct mixer *, const char *); -static void mod_recsrc(struct mixer *, const char *); -static void print_volume(struct mixer *); -static void print_mute(struct mixer *); -static void print_recsrc(struct mixer *); - -static const struct mix_ctl ctls[] = { - [MCTL_VOL] = { "volume", mod_volume, print_volume }, - [MCTL_MUT] = { "mute", mod_mute, print_mute }, - [MCTL_SRC] = { "recsrc", mod_recsrc, print_recsrc }, -}; +static int mod_dunit(struct mixer *, void *); +static int mod_volume(struct mixer *, void *); +static int mod_mute(struct mixer *, void *); +static int mod_recsrc(struct mixer *, void *); +static int print_volume(struct mixer *, void *); +static int print_mute(struct mixer *, void *); +static int print_recsrc(struct mixer *, void *); + +static mix_ctl_t *ctl_dunit; int main(int argc, char *argv[]) { struct mixer *m; + mix_ctl_t *cp; char *name = NULL, buf[NAME_MAX]; char *p, *bufp, *devstr, *ctlstr, *valstr = NULL; int dunit, i, n, pall = 1; @@ -103,12 +89,13 @@ main(int argc, char *argv[]) /* Print all mixers and exit. */ if (aflag) { - if ((n = mixer_getnmixers()) < 0) + if ((n = mixer_get_nmixers()) < 0) err(1, "mixer_get_nmixers"); for (i = 0; i < n; i++) { (void)snprintf(buf, sizeof(buf), "/dev/mixer%d", i); if ((m = mixer_open(buf)) == NULL) err(1, "mixer_open: %s", buf); + initctls(m); if (sflag) printrecsrc(m, oflag); else { @@ -124,18 +111,10 @@ main(int argc, char *argv[]) if ((m = mixer_open(name)) == NULL) err(1, "mixer_open: %s", name); - /* XXX: make it a control? */ - if (dflag) { - if ((n = mixer_getdunit()) < 0) { - warn("cannot get default unit"); - goto parse; - } - if (mixer_setdunit(m, dunit) < 0) { - warn("cannot set default unit to: %d", dunit); - goto parse; - } - printf("default_unit: %d -> %d\n", n, dunit); - } + initctls(m); + + if (dflag && ctl_dunit->mod(m, &dunit) < 0) + goto parse; if (sflag) { printrecsrc(m, oflag); (void)mixer_close(m); @@ -148,30 +127,31 @@ parse: err(1, "strdup(%s)", *argv); /* Split the string into device, control and value. */ devstr = strsep(&p, "."); - if ((m->dev = mixer_getdevbyname(m, devstr)) == NULL) { + if ((m->dev = mixer_get_dev_byname(m, devstr)) == NULL) { warnx("%s: no such device", devstr); goto next; } /* Input: `dev`. */ if (p == NULL) { - printdev(m, m->dev, 1); + printdev(m, 1); pall = 0; goto next; } ctlstr = strsep(&p, "="); - if ((n = findctl(ctlstr)) < 0) { + if ((cp = mixer_get_ctl_byname(m->dev, ctlstr)) == NULL) { warnx("%s.%s: no such control", devstr, ctlstr); goto next; } + /* Input: `dev.control`. */ if (p == NULL) { - ctls[n].print(m); + (void)cp->print(m, cp->name); pall = 0; goto next; } valstr = p; /* Input: `dev.control=val`. */ - ctls[n].mod(m, valstr); + cp->mod(m, valstr); next: free(p); argc--; @@ -195,13 +175,31 @@ usage(void) } static void +initctls(struct mixer *m) +{ + struct mix_dev *dp; + +#define C_VOL 0 +#define C_MUT 1 +#define C_SRC 2 + TAILQ_FOREACH(dp, &m->devs, devs) { + (void)mixer_add_ctl(dp, C_VOL, "volume", mod_volume, print_volume); + (void)mixer_add_ctl(dp, C_MUT, "mute", mod_mute, print_mute); + (void)mixer_add_ctl(dp, C_SRC, "recsrc", mod_recsrc, print_recsrc); + } + ctl_dunit = mixer_make_ctl(-1, "default_unit", mod_dunit, NULL); + +} + +static void printall(struct mixer *m, int oflag) { struct mix_dev *dp; printminfo(m, oflag); TAILQ_FOREACH(dp, &m->devs, devs) { - printdev(m, dp, oflag); + m->dev = dp; + printdev(m, oflag); } } @@ -211,21 +209,27 @@ printminfo(struct mixer *m, int oflag) if (oflag) return; printf("%s: <%s> %s", m->mi.name, m->ci.longname, m->ci.hw_info); - /* TODO: clean up the mess */ - if (m->status & MIX_STATUS_PLAY) - printf(" (play%s", m->status & MIX_STATUS_REC ? "" : ")"); - if (m->status == (MIX_STATUS_PLAY | MIX_STATUS_REC)) + if (!(m->mode & MIX_MODE_NONE)) + printf(" ("); + if (m->mode & MIX_MODE_PLAY) + printf("play"); + if (m->mode == (MIX_MODE_PLAY | MIX_MODE_REC)) printf("/"); - if (m->status & MIX_STATUS_REC) - printf("%srec)", m->status & MIX_STATUS_PLAY ? "" : " ("); + if (m->mode & MIX_MODE_REC) + printf("rec"); + if (!(m->mode & MIX_MODE_NONE)) + printf(")"); if (m->f_default) printf(" (default)"); printf("\n"); } static void -printdev(struct mixer *m, struct mix_dev *d, int oflag) +printdev(struct mixer *m, int oflag) { + struct mix_dev *d = m->dev; + mix_ctl_t *cp; + if (!oflag) { printf(" %-11s= %.2f:%.2f\t", d->name, d->vol.left, d->vol.right); @@ -239,12 +243,9 @@ printdev(struct mixer *m, struct mix_dev *d, int oflag) printf(" mute"); printf("\n"); } else { - printf("%s.%s=%.2f:%.2f\n", - d->name, ctls[MCTL_VOL].name, d->vol.left, d->vol.right); - printf("%s.%s=%d\n", - d->name, ctls[MCTL_MUT].name, MIX_ISMUTE(m, d->devno)); - if (MIX_ISRECSRC(m, d->devno)) - printf("%s.%s=+\n", d->name, ctls[MCTL_SRC].name); + TAILQ_FOREACH(cp, &d->ctls, ctls) { + (void)cp->print(m, cp->name); + } } } @@ -270,29 +271,40 @@ printrecsrc(struct mixer *m, int oflag) } static int -findctl(const char *ctl) +mod_dunit(struct mixer *m, void *p) { - int i; + int dunit = *((int *)p); + int n; - for (i = 0; i < LEN(ctls); i++) - if (strcmp(ctl, ctls[i].name) == 0) - return (i); + if ((n = mixer_get_dunit()) < 0) { + warn("cannot get default unit"); + return (-1); + } + if (mixer_set_dunit(m, dunit) < 0) { + warn("cannot set default unit to: %d", dunit); + return (-1); + } + printf("%s: %d -> %d\n", ctl_dunit->name, n, dunit); - return (-1); + return (0); } -static void -mod_volume(struct mixer *m, const char *val) +static int +mod_volume(struct mixer *m, void *p) { + mix_ctl_t *cp; mix_volume_t v; + const char *val; char lstr[8], rstr[8]; float lprev, rprev, lrel, rrel; int n; + cp = mixer_get_ctl(m->dev, C_VOL); + val = p; n = sscanf(val, "%7[^:]:%7s", lstr, rstr); if (n == EOF) { warnx("invalid volume value: %s", val); - return; + return (-1); } lrel = rrel = 0; if (n > 0) { @@ -325,21 +337,26 @@ mod_volume(struct mixer *m, const char *val) lprev = m->dev->vol.left; rprev = m->dev->vol.right; - if (mixer_setvol(m, v) < 0) + if (mixer_set_vol(m, v) < 0) warn("%s.%s=%.2f:%.2f", - m->dev->name, ctls[MCTL_VOL].name, v.left, v.right); + m->dev->name, cp->name, v.left, v.right); else printf("%s.%s: %.2f:%.2f -> %.2f:%.2f\n", - m->dev->name, ctls[MCTL_VOL].name, - lprev, rprev, v.left, v.right); + m->dev->name, cp->name, lprev, rprev, v.left, v.right); } + + return (0); } -static void -mod_mute(struct mixer *m, const char *val) +static int +mod_mute(struct mixer *m, void *p) { + mix_ctl_t *cp; + const char *val; int n, opt = -1; + cp = mixer_get_ctl(m->dev, C_MUT); + val = p; switch (*val) { case '0': opt = MIX_UNMUTE; @@ -352,21 +369,27 @@ mod_mute(struct mixer *m, const char *val) break; default: warnx("%c: no such modifier", *val); - return; + return (-1); } n = MIX_ISMUTE(m, m->dev->devno); - if (mixer_setmute(m, opt) < 0) - warn("%s.%s=%c", m->dev->name, ctls[MCTL_MUT].name, *val); + if (mixer_set_mute(m, opt) < 0) + warn("%s.%s=%c", m->dev->name, cp->name, *val); else printf("%s.%s: %d -> %d\n", - m->dev->name, ctls[MCTL_MUT].name, n, MIX_ISMUTE(m, m->dev->devno)); + m->dev->name, cp->name, n, MIX_ISMUTE(m, m->dev->devno)); + + return (0); } -static void -mod_recsrc(struct mixer *m, const char *val) +static int +mod_recsrc(struct mixer *m, void *p) { + mix_ctl_t *cp; + const char *val; int n, opt = -1; + cp = mixer_get_ctl(m->dev, C_SRC); + val = p; switch (*val) { case '+': opt = MIX_ADDRECSRC; @@ -382,34 +405,47 @@ mod_recsrc(struct mixer *m, const char *val) break; default: warnx("%c: no such modifier", *val); - return; + return (-1); } n = MIX_ISRECSRC(m, m->dev->devno); - if (mixer_modrecsrc(m, opt) < 0) - warn("%s.%s=%c", m->dev->name, ctls[MCTL_SRC].name, *val); + if (mixer_mod_recsrc(m, opt) < 0) + warn("%s.%s=%c", m->dev->name, cp->name, *val); else printf("%s.%s: %d -> %d\n", - m->dev->name, ctls[MCTL_SRC].name, - n, MIX_ISRECSRC(m, m->dev->devno)); + m->dev->name, cp->name, n, MIX_ISRECSRC(m, m->dev->devno)); + + return (0); } -static void -print_volume(struct mixer *m) +static int +print_volume(struct mixer *m, void *p) { + const char *ctl_name = p; + printf("%s.%s=%.2f:%.2f\n", - m->dev->name, ctls[MCTL_VOL].name, m->dev->vol.left, m->dev->vol.right); + m->dev->name, ctl_name, m->dev->vol.left, m->dev->vol.right); + + return (0); } -static void -print_mute(struct mixer *m) +static int +print_mute(struct mixer *m, void *p) { - printf("%s.%s=%d\n", m->dev->name, ctls[MCTL_MUT].name, - MIX_ISMUTE(m, m->dev->devno)); + const char *ctl_name = p; + + printf("%s.%s=%d\n", m->dev->name, ctl_name, MIX_ISMUTE(m, m->dev->devno)); + + return (0); } -static void -print_recsrc(struct mixer *m) +static int +print_recsrc(struct mixer *m, void *p) { - printf("%s.%s=%d\n", - m->dev->name, ctls[MCTL_SRC].name, MIX_ISRECSRC(m, m->dev->devno)); + const char *ctl_name = p; + + if (!MIX_ISRECSRC(m, m->dev->devno)) + return (-1); + printf("%s.%s=+\n", m->dev->name, ctl_name); + + return (0); }