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 62ae192d6951bf184b9a51e55b7e607b32eb53f2
parent 75e74d4a795cc470cc766bebc2a0a53f285e780a
Author: Christos Margiolis <christos@margiolis.net>
Date:   Sat, 31 Jul 2021 17:44:31 +0300

working on control handling, might need a clean up

Diffstat:
Mdiff/mixer_kern.diff | 17+++++++++--------
Mmixer_lib/mixer.c | 35++++++++++++++++++++++-------------
Mmixer_lib/mixer.h | 29+++++++++++++++++------------
Mmixer_prog/mixer_prog.c | 63++++++++++++++++++++++++++++++++++++---------------------------
4 files changed, 84 insertions(+), 60 deletions(-)

diff --git a/diff/mixer_kern.diff b/diff/mixer_kern.diff @@ -308,7 +308,7 @@ 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..e2014a70f9b 100644 +index b4be28aeff8..6b1b8bcbc93 100644 --- a/sys/dev/sound/pcm/sound.c +++ b/sys/dev/sound/pcm/sound.c @@ -1012,12 +1012,30 @@ SYSCTL_PROC(_hw_snd, OID_AUTO, clone_gc, CTLTYPE_INT | CTLFLAG_RWTUN, @@ -324,8 +324,8 @@ index b4be28aeff8..e2014a70f9b 100644 + mode |= PCM_MODE_PLAY; + if (d->reccount > 0) + mode |= PCM_MODE_REC; -+ if (d->playcount == 0 && d->reccount == 0) -+ mode = PCM_MODE_NONE; ++ if (d->mixer_dev != NULL) ++ mode |= PCM_MODE_MIXER; + + return (mode); +} @@ -343,18 +343,19 @@ index b4be28aeff8..e2014a70f9b 100644 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 +1045,10 @@ pcm_sysinit(device_t dev) +@@ -1027,6 +1045,11 @@ 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, "mode", CTLFLAG_RD, NULL, mode, -+ "mode (0=none, 1=play, 2=rec, 3=play+rec)"); ++ "mode (1=mixer, 2=play, 4=rec. The values are OR'ed if more than one" ++ "mode is supported)"); #ifdef SND_DEBUG SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, -@@ -1130,7 +1152,7 @@ pcm_register(device_t dev, void *devinfo, int numplay, int numrec) +@@ -1130,7 +1153,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", @@ -364,14 +365,14 @@ index b4be28aeff8..e2014a70f9b 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..eda4012a517 100644 +index d4b3a23e8eb..e9979cf426c 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_MODE_NONE 0x01 ++#define PCM_MODE_MIXER 0x01 +#define PCM_MODE_PLAY 0x02 +#define PCM_MODE_REC 0x04 + diff --git a/mixer_lib/mixer.c b/mixer_lib/mixer.c @@ -114,6 +114,7 @@ dunit: continue; if ((dp = calloc(1, sizeof(struct mix_dev))) == NULL) goto fail; + dp->parent_mixer = m; dp->devno = i; dp->nctl = 0; if (_mixer_readvol(m, dp) < 0) @@ -210,13 +211,16 @@ mixer_get_dev_byname(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)) +mixer_make_ctl(struct mix_dev *parent_dev, int id, const char *name, + int (*mod)(struct mix_dev *d, void *p), + int (*print)(struct mix_dev *d, void *p)) { mix_ctl_t *ctl; + /* XXX: do not alloc? */ if ((ctl = calloc(1, sizeof(mix_ctl_t))) == NULL) return (NULL); + ctl->parent_dev = parent_dev; ctl->id = id; if (name != NULL) (void)strlcpy(ctl->name, name, sizeof(ctl->name)); @@ -230,27 +234,30 @@ mixer_make_ctl(int id, const char *name, * 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)) +mixer_add_ctl(struct mix_dev *parent_dev, int id, const char *name, + int (*mod)(struct mix_dev *d, void *p), + int (*print)(struct mix_dev *d, void *p)) { mix_ctl_t *ctl; - if ((ctl = mixer_make_ctl(id, name, mod, print)) == NULL) + if ((ctl = mixer_make_ctl(parent_dev, id, name, mod, print)) == NULL) return (-1); - return (mixer_add_ctl_s(d, ctl)); + return (mixer_add_ctl_s(ctl)); } /* * Add a mixer control to a device. */ int -mixer_add_ctl_s(struct mix_dev *d, mix_ctl_t *ctl) +mixer_add_ctl_s(mix_ctl_t *ctl) { - if (ctl == NULL || ctl->mod == NULL || ctl->print == NULL) + struct mix_dev *p = ctl->parent_dev; + + if (ctl == NULL || p == NULL || ctl->mod == NULL || ctl->print == NULL) return (-1); - TAILQ_INSERT_TAIL(&d->ctls, ctl, ctls); - d->nctl++; + TAILQ_INSERT_TAIL(&p->ctls, ctl, ctls); + p->nctl++; return (0); } @@ -259,14 +266,16 @@ mixer_add_ctl_s(struct mix_dev *d, mix_ctl_t *ctl) * Remove a mixer control from a device. */ int -mixer_remove_ctl(struct mix_dev *d, mix_ctl_t *ctl) +mixer_remove_ctl(mix_ctl_t *ctl) { + struct mix_dev *p = ctl->parent_dev; + if (ctl == NULL) { errno = EINVAL; return (-1); } - if (!TAILQ_EMPTY(&d->ctls)) { - TAILQ_REMOVE(&d->ctls, ctl, ctls); + if (!TAILQ_EMPTY(&p->ctls)) { + TAILQ_REMOVE(&p->ctls, ctl, ctls); free(ctl); } diff --git a/mixer_lib/mixer.h b/mixer_lib/mixer.h @@ -40,17 +40,24 @@ __FBSDID("$FreeBSD$"); #define MIX_ISREC(m,n) MIX_ISSET(n, (m)->recmask) #define MIX_ISRECSRC(m,n) MIX_ISSET(n, (m)->recsrc) +/* Forward declarations */ struct mixer; +struct mix_dev; -typedef struct mix_ctl { +typedef struct mix_ctl mix_ctl_t; +typedef struct mix_volume mix_volume_t; + +struct mix_ctl { + struct mix_dev *parent_dev; int id; char name[NAME_MAX]; - int (*mod)(struct mixer *, void *); - int (*print)(struct mixer *, void *); + int (*mod)(struct mix_dev *, void *); + int (*print)(struct mix_dev *, void *); TAILQ_ENTRY(mix_ctl) ctls; -} mix_ctl_t; +}; struct mix_dev { + struct mixer *parent_mixer; char name[NAME_MAX]; int devno; struct mix_volume { @@ -87,24 +94,22 @@ struct mixer { #define MIX_TOGGLERECSRC 0x08 int recsrc; int f_default; -#define MIX_MODE_NONE 0x01 +#define MIX_MODE_MIXER 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_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 *)); +mix_ctl_t *mixer_make_ctl(struct mix_dev *, int, const char *, + int (*)(struct mix_dev *, void *), int (*)(struct mix_dev *, 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 *); + int (*)(struct mix_dev *, void *), int (*)(struct mix_dev *, void *)); +int mixer_add_ctl_s(mix_ctl_t *); +int mixer_remove_ctl(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); diff --git a/mixer_prog/mixer_prog.c b/mixer_prog/mixer_prog.c @@ -36,15 +36,15 @@ static void initctls(struct mixer *); static void printall(struct mixer *, int); static void printminfo(struct mixer *, int); static void printdev(struct mixer *, int); -static void printrecsrc(struct mixer *, int); +static void printrecsrc(struct mixer *, int); /* XXX: change name */ /* Control handlers */ -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 int mod_dunit(struct mix_dev *, void *); +static int mod_volume(struct mix_dev *, void *); +static int mod_mute(struct mix_dev *, void *); +static int mod_recsrc(struct mix_dev *, void *); +static int print_volume(struct mix_dev *, void *); +static int print_mute(struct mix_dev *, void *); +static int print_recsrc(struct mix_dev *, void *); static mix_ctl_t *ctl_dunit; @@ -113,7 +113,7 @@ main(int argc, char *argv[]) initctls(m); - if (dflag && ctl_dunit->mod(m, &dunit) < 0) + if (dflag && ctl_dunit->mod(ctl_dunit->parent_dev, &dunit) < 0) goto parse; if (sflag) { printrecsrc(m, oflag); @@ -145,13 +145,13 @@ parse: /* Input: `dev.control`. */ if (p == NULL) { - (void)cp->print(m, cp->name); + (void)cp->print(cp->parent_dev, cp->name); pall = 0; goto next; } valstr = p; /* Input: `dev.control=val`. */ - cp->mod(m, valstr); + cp->mod(cp->parent_dev, valstr); next: free(p); argc--; @@ -187,8 +187,7 @@ initctls(struct mixer *m) (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); - + ctl_dunit = mixer_make_ctl(NULL, -1, "default_unit", mod_dunit, NULL); } static void @@ -206,19 +205,19 @@ printall(struct mixer *m, int oflag) static void printminfo(struct mixer *m, int oflag) { + int playrec = MIX_MODE_PLAY | MIX_MODE_REC; + if (oflag) return; printf("%s: <%s> %s", m->mi.name, m->ci.longname, m->ci.hw_info); - if (!(m->mode & MIX_MODE_NONE)) - printf(" ("); + printf(" ("); if (m->mode & MIX_MODE_PLAY) printf("play"); - if (m->mode == (MIX_MODE_PLAY | MIX_MODE_REC)) + if ((m->mode & playrec) == playrec) printf("/"); if (m->mode & MIX_MODE_REC) printf("rec"); - if (!(m->mode & MIX_MODE_NONE)) - printf(")"); + printf(")"); if (m->f_default) printf(" (default)"); printf("\n"); @@ -244,11 +243,12 @@ printdev(struct mixer *m, int oflag) printf("\n"); } else { TAILQ_FOREACH(cp, &d->ctls, ctls) { - (void)cp->print(m, cp->name); + (void)cp->print(cp->parent_dev, cp->name); } } } +/* TODO: -o option .recsrc */ static void printrecsrc(struct mixer *m, int oflag) { @@ -271,7 +271,7 @@ printrecsrc(struct mixer *m, int oflag) } static int -mod_dunit(struct mixer *m, void *p) +mod_dunit(struct mix_dev *d, void *p) { int dunit = *((int *)p); int n; @@ -280,7 +280,7 @@ mod_dunit(struct mixer *m, void *p) warn("cannot get default unit"); return (-1); } - if (mixer_set_dunit(m, dunit) < 0) { + if (mixer_set_dunit(d->parent_mixer, dunit) < 0) { warn("cannot set default unit to: %d", dunit); return (-1); } @@ -290,8 +290,9 @@ mod_dunit(struct mixer *m, void *p) } static int -mod_volume(struct mixer *m, void *p) +mod_volume(struct mix_dev *d, void *p) { + struct mixer *m; mix_ctl_t *cp; mix_volume_t v; const char *val; @@ -299,6 +300,7 @@ mod_volume(struct mixer *m, void *p) float lprev, rprev, lrel, rrel; int n; + m = d->parent_mixer; cp = mixer_get_ctl(m->dev, C_VOL); val = p; n = sscanf(val, "%7[^:]:%7s", lstr, rstr); @@ -349,12 +351,14 @@ mod_volume(struct mixer *m, void *p) } static int -mod_mute(struct mixer *m, void *p) +mod_mute(struct mix_dev *d, void *p) { + struct mixer *m; mix_ctl_t *cp; const char *val; int n, opt = -1; + m = d->parent_mixer; cp = mixer_get_ctl(m->dev, C_MUT); val = p; switch (*val) { @@ -382,12 +386,14 @@ mod_mute(struct mixer *m, void *p) } static int -mod_recsrc(struct mixer *m, void *p) +mod_recsrc(struct mix_dev *d, void *p) { + struct mixer *m; mix_ctl_t *cp; const char *val; int n, opt = -1; + m = d->parent_mixer; cp = mixer_get_ctl(m->dev, C_SRC); val = p; switch (*val) { @@ -418,8 +424,9 @@ mod_recsrc(struct mixer *m, void *p) } static int -print_volume(struct mixer *m, void *p) +print_volume(struct mix_dev *d, void *p) { + struct mixer *m = d->parent_mixer; const char *ctl_name = p; printf("%s.%s=%.2f:%.2f\n", @@ -429,8 +436,9 @@ print_volume(struct mixer *m, void *p) } static int -print_mute(struct mixer *m, void *p) +print_mute(struct mix_dev *d, void *p) { + struct mixer *m = d->parent_mixer; const char *ctl_name = p; printf("%s.%s=%d\n", m->dev->name, ctl_name, MIX_ISMUTE(m, m->dev->devno)); @@ -439,8 +447,9 @@ print_mute(struct mixer *m, void *p) } static int -print_recsrc(struct mixer *m, void *p) +print_recsrc(struct mix_dev *d, void *p) { + struct mixer *m = d->parent_mixer; const char *ctl_name = p; if (!MIX_ISRECSRC(m, m->dev->devno))