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 08cd797e4e6cc44c08c1b83ab41063814ac9f537
parent e8100ba095b92ad290f80f059e9a494a429fe372
Author: Christos Margiolis <christos@margiolis.net>
Date:   Thu,  8 Jul 2021 22:39:52 +0300

kernel: return appropriate volume when muted. lib/prog: removed all device flags

Diffstat:
Mdiff/mixer_kern.diff | 100+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------
Mmixer_lib/mixer.c | 41++++++-----------------------------------
Mmixer_lib/mixer.h | 27+++++++--------------------
Mmixer_prog/mixer_prog.c | 105+++++++++++++++++++++++++++++++++++++++----------------------------------------
4 files changed, 148 insertions(+), 125 deletions(-)

diff --git a/diff/mixer_kern.diff b/diff/mixer_kern.diff @@ -1,5 +1,5 @@ diff --git a/sys/dev/sound/pcm/mixer.c b/sys/dev/sound/pcm/mixer.c -index 92c5f3d613e..a15b59eb47f 100644 +index 92c5f3d613e..d85dff6eee7 100644 --- a/sys/dev/sound/pcm/mixer.c +++ b/sys/dev/sound/pcm/mixer.c @@ -58,9 +58,11 @@ struct snd_mixer { @@ -14,10 +14,77 @@ index 92c5f3d613e..a15b59eb47f 100644 u_int8_t parent[32]; u_int32_t child[32]; u_int8_t realdev[32]; -@@ -338,6 +340,40 @@ mixer_get(struct snd_mixer *mixer, int dev) - return -1; +@@ -254,7 +256,7 @@ mixer_set(struct snd_mixer *m, u_int dev, u_int lev) + + if (m == NULL || dev >= SOUND_MIXER_NRDEVICES || + (0 == (m->devs & (1 << dev)))) +- return -1; ++ return (-1); + + l = min((lev & 0x00ff), 100); + r = min(((lev & 0xff00) >> 8), 100); +@@ -262,7 +264,7 @@ mixer_set(struct snd_mixer *m, u_int dev, u_int lev) + + d = device_get_softc(m->dev); + if (d == NULL) +- return -1; ++ return (-1); + + /* It is safe to drop this mutex due to Giant. */ + if (!(d->flags & SD_F_MPSAFE) && mtx_owned(m->lock) != 0) +@@ -287,7 +289,7 @@ mixer_set(struct snd_mixer *m, u_int dev, u_int lev) + else if (realdev != SOUND_MIXER_NONE && + MIXER_SET(m, realdev, tl, tr) < 0) { + MIXER_SET_LOCK(m, dropmtx); +- return -1; ++ return (-1); + } + } else if (child != 0) { + for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { +@@ -305,8 +307,8 @@ mixer_set(struct snd_mixer *m, u_int dev, u_int lev) + realdev = m->realdev[dev]; + if (realdev != SOUND_MIXER_NONE && + MIXER_SET(m, realdev, l, r) < 0) { +- MIXER_SET_LOCK(m, dropmtx); +- return -1; ++ MIXER_SET_LOCK(m, dropmtx); ++ return (-1); + } + } else { + if (dev == SOUND_MIXER_PCM && (d->flags & SD_F_SOFTPCMVOL)) +@@ -317,7 +319,7 @@ mixer_set(struct snd_mixer *m, u_int dev, u_int lev) + else if (realdev != SOUND_MIXER_NONE && + MIXER_SET(m, realdev, l, r) < 0) { + MIXER_SET_LOCK(m, dropmtx); +- return -1; ++ return (-1); + } + } + +@@ -326,16 +328,55 @@ mixer_set(struct snd_mixer *m, u_int dev, u_int lev) + m->level[dev] = l | (r << 8); + m->modify_counter++; + +- return 0; ++ return (0); } + static int + mixer_get(struct snd_mixer *mixer, int dev) + { +- if ((dev < SOUND_MIXER_NRDEVICES) && (mixer->devs & (1 << dev))) +- return mixer->level[dev]; ++ if ((dev < SOUND_MIXER_NRDEVICES) && (mixer->devs & (1 << dev))) { ++ if (mixer->mutedevs & (1 << dev)) ++ return (mixer->level_muted[dev]); ++ else ++ return (mixer->level[dev]); ++ } + else +- return -1; ++ return (-1); ++} ++ +static int +mixer_setmute(struct snd_mixer *mixer, u_int32_t mutedevs) +{ @@ -34,28 +101,27 @@ index 92c5f3d613e..a15b59eb47f 100644 + + /* FIXME: lock/unlock */ + -+ mutedevs &= mixer->devs; /* Filter out invalid values. */ ++ /* Filter out invalid values. */ ++ mutedevs &= mixer->devs; + for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { + if (!(mixer->devs & (1 << i))) + continue; + if ((mutedevs & (1 << i)) && mixer->level[i] != 0) { + mixer->level_muted[i] = mixer->level[i]; + v = 0; -+ } else if (!(mutedevs & (1 << i)) && mixer->level[i] == 0) ++ } else if (!(mutedevs & (1 << i)) && mixer->level[i] == 0) { + v = mixer->level_muted[i]; -+ else ++ } else + continue; + ret += mixer_set(mixer, i, v); + } + mixer->mutedevs = mutedevs; + + return (ret); -+} -+ + } + static int - mixer_setrecsrc(struct snd_mixer *mixer, u_int32_t src) - { -@@ -598,6 +634,12 @@ mix_getdevs(struct snd_mixer *m) +@@ -598,6 +639,12 @@ mix_getdevs(struct snd_mixer *m) return m->devs; } @@ -68,7 +134,7 @@ index 92c5f3d613e..a15b59eb47f 100644 u_int32_t mix_getrecdevs(struct snd_mixer *m) { -@@ -711,6 +753,7 @@ mixer_init(device_t dev, kobj_class_t cls, void *devinfo) +@@ -711,6 +758,7 @@ mixer_init(device_t dev, kobj_class_t cls, void *devinfo) if (m == NULL) return (-1); @@ -76,7 +142,7 @@ index 92c5f3d613e..a15b59eb47f 100644 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { v = snd_mixerdefaults[i]; -@@ -722,6 +765,11 @@ mixer_init(device_t dev, kobj_class_t cls, void *devinfo) +@@ -722,6 +770,11 @@ mixer_init(device_t dev, kobj_class_t cls, void *devinfo) } mixer_set(m, i, v | (v << 8)); @@ -88,7 +154,7 @@ index 92c5f3d613e..a15b59eb47f 100644 } mixer_setrecsrc(m, 0); /* Set default input. */ -@@ -1305,10 +1353,16 @@ mixer_ioctl_cmd(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode, +@@ -1305,10 +1358,16 @@ mixer_ioctl_cmd(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode, goto done; } if ((cmd & ~0xff) == MIXER_WRITE(0)) { @@ -107,7 +173,7 @@ index 92c5f3d613e..a15b59eb47f 100644 snd_mtxunlock(m->lock); return ((ret == 0) ? 0 : ENXIO); } -@@ -1319,6 +1373,9 @@ mixer_ioctl_cmd(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode, +@@ -1319,6 +1378,9 @@ mixer_ioctl_cmd(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode, case SOUND_MIXER_STEREODEVS: v = mix_getdevs(m); break; @@ -118,14 +184,14 @@ index 92c5f3d613e..a15b59eb47f 100644 v = mix_getrecdevs(m); break; diff --git a/sys/dev/sound/pcm/mixer.h b/sys/dev/sound/pcm/mixer.h -index 8e11d553a3e..6d7d861e8a6 100644 +index 8e11d553a3e..626282c803e 100644 --- a/sys/dev/sound/pcm/mixer.h +++ b/sys/dev/sound/pcm/mixer.h @@ -60,8 +60,10 @@ device_t mix_get_dev(struct snd_mixer *m); void mix_setdevs(struct snd_mixer *m, u_int32_t v); void mix_setrecdevs(struct snd_mixer *m, u_int32_t v); -+// XXX: int mix_setmutedevs(struct snd_mixer *m, u_int32_t mutedevs); ++//void mix_setmutedevs(struct snd_mixer *m, u_int32_t mutedevs); u_int32_t mix_getdevs(struct snd_mixer *m); u_int32_t mix_getrecdevs(struct snd_mixer *m); +u_int32_t mix_getmutedevs(struct snd_mixer *m); diff --git a/mixer_lib/mixer.c b/mixer_lib/mixer.c @@ -34,7 +34,6 @@ #include "mixer.h" #define BASEPATH "/dev/mixer" -#define MIN(x, y) ((x) < (y) ? (x) : (y)) static int _mixer_readvol(struct mixer *, struct mix_dev *); @@ -48,10 +47,8 @@ _mixer_readvol(struct mixer *m, struct mix_dev *dev) if (ioctl(m->fd, MIXER_READ(dev->devno), &v) < 0) return (-1); - dev->lvol = M_VOLNORM(v & 0x00ff); - dev->rvol = M_VOLNORM((v >> 8) & 0x00ff); - dev->pan = dev->rvol - dev->lvol; - dev->f_mut = M_ISMUTE(m, dev->devno); + dev->vol.left = M_VOLNORM(v & 0x00ff); + dev->vol.right = M_VOLNORM((v >> 8) & 0x00ff); return (0); } @@ -117,9 +114,6 @@ dunit: dp->devno = i; if (_mixer_readvol(m, dp) < 0) goto fail; - dp->f_pbk = !M_ISREC(m, i) ? 1 : 0; - dp->f_rec = M_ISREC(m, i) ? 1 : 0; - dp->f_src = M_ISRECSRC(m, i) ? 1 : 0; (void)strlcpy(dp->name, names[i], sizeof(dp->name)); TAILQ_INSERT_TAIL(&m->devs, dp, devs); ndev++; @@ -210,15 +204,16 @@ mixer_getdevbyname(struct mixer *m, const char *name) * be handlded by the caller. */ int -mixer_setvol(struct mixer *m, float l, float r) +mixer_setvol(struct mixer *m, mix_volume_t vol) { int v; - if (l < M_VOLMIN || l > M_VOLMAX || r < M_VOLMIN || r > M_VOLMAX) { + if (vol.left < M_VOLMIN || vol.left > M_VOLMAX || + vol.right < M_VOLMIN || vol.right > M_VOLMAX) { errno = ERANGE; return (-1); } - v = M_VOLDENORM(l) | M_VOLDENORM(r) << 8; + v = M_VOLDENORM(vol.left) | M_VOLDENORM(vol.right) << 8; if (ioctl(m->fd, MIXER_WRITE(m->dev->devno), &v) < 0) return (-1); if (_mixer_readvol(m, m->dev) < 0) @@ -227,27 +222,6 @@ mixer_setvol(struct mixer *m, float l, float r) return (0); } -/* - * TODO: Change panning. - * - * @param: `pan`: Panning value. It has to be in the range - * `M_PANMIN <= pan <= M_PANMAX`. - */ -int -mixer_setpan(struct mixer *m, float pan) -{ - int l, r; - - if (pan < M_PANMIN || pan > M_PANMAX) { - errno = ERANGE; - return (-1); - } - l = m->dev->lvol; - r = m->dev->rvol; - - return (mixer_setvol(m, l, r)); -} - int mixer_setmute(struct mixer *m, int opt) { @@ -269,8 +243,6 @@ mixer_setmute(struct mixer *m, int opt) return (-1); if (ioctl(m->fd, SOUND_MIXER_READ_MUTE, &m->mutemask) < 0) return (-1); - if (_mixer_readvol(m, m->dev) < 0) - return (-1); return 0; } @@ -307,7 +279,6 @@ mixer_modrecsrc(struct mixer *m, int opt) return (-1); if (ioctl(m->fd, SOUND_MIXER_READ_RECSRC, &m->recsrc) < 0) return (-1); - m->dev->f_src = M_ISRECSRC(m, m->dev->devno); return (0); } diff --git a/mixer_lib/mixer.h b/mixer_lib/mixer.h @@ -48,31 +48,19 @@ __FBSDID("$FreeBSD$"); #define M_VOLNORM(v) ((v) / 100.0f) #define M_VOLDENORM(v) ((int)roundf((v) * 100.0f)) -#define M_PANMIN (-1.0f) -#define M_PANMAX 1.0f - -#define M_ISSET(n, f) ((1 << (n)) & (f)) +#define M_ISSET(n, f) (((1 << (n)) & (f)) ? 1 : 0) #define M_ISDEV(m, n) M_ISSET(n, (m)->devmask) #define M_ISMUTE(m, n) M_ISSET(n, (m)->mutemask) #define M_ISREC(m, n) M_ISSET(n, (m)->recmask) #define M_ISRECSRC(m, n) M_ISSET(n, (m)->recsrc) -//struct mix_vol { - //float l; - //float r; - //float pan; -//}; - struct mix_dev { char name[NAME_MAX]; int devno; - int f_mut; - int f_pbk; - int f_rec; - int f_src; - float lvol; - float rvol; - float pan; + struct mix_volume { + float left; + float right; + } vol; TAILQ_ENTRY(mix_dev) devs; }; @@ -91,14 +79,13 @@ struct mixer { int f_default; }; -/* XXX: move control handling here? */ +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 *, float, float); -int mixer_setpan(struct mixer *, float); +int mixer_setvol(struct mixer *, mix_volume_t); int mixer_setmute(struct mixer *, int); int mixer_modrecsrc(struct mixer *, int); int mixer_getdunit(void); diff --git a/mixer_prog/mixer_prog.c b/mixer_prog/mixer_prog.c @@ -46,7 +46,7 @@ struct mix_ctl { static void usage(void) __dead2; static void printall(struct mixer *, int); static void printminfo(struct mixer *, int); -static void printdev(struct mix_dev *, int); +static void printdev(struct mixer *, struct mix_dev *, int); static void printrecsrc(struct mixer *, int); static int findctl(const char *); /* Control handlers */ @@ -157,7 +157,7 @@ parse: } /* Input: `dev`. */ if (p == NULL) { - printdev(m->dev, 1); + printdev(m, m->dev, 1); pall = 0; goto next; } @@ -204,7 +204,7 @@ printall(struct mixer *m, int oflag) printminfo(m, oflag); TAILQ_FOREACH(dp, &m->devs, devs) { - printdev(dp, oflag); + printdev(m, dp, oflag); } } @@ -220,26 +220,31 @@ printminfo(struct mixer *m, int oflag) } static void -printdev(struct mix_dev *d, int oflag) +printdev(struct mixer *m, struct mix_dev *d, int oflag) { + float pan; + + pan = d->vol.right - d->vol.left; if (!oflag) { printf(" %-11s= %.2f:%.2f\t%+.2f\t", - d->name, d->lvol, d->rvol, d->pan); - if (d->f_pbk) - printf(" pbk"); - if (d->f_rec) - printf(" rec"); - if (d->f_src) + d->name, d->vol.left, d->vol.right, pan); + if (!M_ISREC(m, d->devno)) + printf(" pbk"); + if (M_ISREC(m, d->devno)) + printf(" rec"); + if (M_ISRECSRC(m, d->devno)) printf(" src"); - if (d->f_mut) + if (M_ISMUTE(m, d->devno)) printf(" mute"); printf("\n"); } else { printf("%s.%s=%.2f:%.2f\n", - d->name, ctls[MCTL_VOL].name, d->lvol, d->rvol); - if (d->f_src) + d->name, ctls[MCTL_VOL].name, d->vol.left, d->vol.right); + printf("%s.%s=%d\n", + d->name, ctls[MCTL_MUT].name, M_ISMUTE(m, d->devno)); + printf("%s.%s=%.2f\n", d->name, ctls[MCTL_PAN].name, pan); + if (M_ISRECSRC(m, d->devno)) printf("%s.%s=+\n", d->name, ctls[MCTL_SRC].name); - /* TODO: add f_mut */ } } @@ -279,8 +284,9 @@ findctl(const char *ctl) static void mod_volume(struct mixer *m, const char *val) { + mix_volume_t v; char lstr[8], rstr[8]; - float l, r, lprev, rprev, lrel, rrel; + float lprev, rprev, lrel, rrel; int n; n = sscanf(val, "%7[^:]:%7s", lstr, rstr); @@ -292,55 +298,47 @@ mod_volume(struct mixer *m, const char *val) if (n > 0) { if (*lstr == '+' || *lstr == '-') lrel = rrel = 1; - l = strtof(lstr, NULL); + v.left = strtof(lstr, NULL); } if (n > 1) { if (*rstr == '+' || *rstr == '-') rrel = 1; - r = strtof(rstr, NULL); + v.right = strtof(rstr, NULL); } switch (n) { case 1: - r = l; /* FALLTHROUGH */ + v.right = v.left; /* FALLTHROUGH */ case 2: if (lrel) - l += m->dev->lvol; + v.left += m->dev->vol.left; if (rrel) - r += m->dev->rvol; - - if (l < M_VOLMIN) - l = M_VOLMIN; - else if (l > M_VOLMAX) - l = M_VOLMAX; - if (r < M_VOLMIN) - r = M_VOLMIN; - else if (r > M_VOLMAX) - r = M_VOLMAX; - - lprev = m->dev->lvol; - rprev = m->dev->rvol; - if (mixer_setvol(m, l, r) < 0) + v.right += m->dev->vol.right; + + if (v.left < M_VOLMIN) + v.left = M_VOLMIN; + else if (v.left > M_VOLMAX) + v.left = M_VOLMAX; + if (v.right < M_VOLMIN) + v.right = M_VOLMIN; + else if (v.right > M_VOLMAX) + v.right = M_VOLMAX; + + lprev = m->dev->vol.left; + rprev = m->dev->vol.right; + if (mixer_setvol(m, v) < 0) warn("%s.%s=%.2f:%.2f", - m->dev->name, ctls[MCTL_VOL].name, l, r); + m->dev->name, ctls[MCTL_VOL].name, v.left, v.right); else printf("%s.%s: %.2f:%.2f -> %.2f:%.2f\n", m->dev->name, ctls[MCTL_VOL].name, - lprev, rprev, l, r); + lprev, rprev, v.left, v.right); } } static void mod_panning(struct mixer *m, const char *val) { - float n, v; - - n = m->dev->pan; - v = strtof(val, NULL); - if (mixer_setpan(m, v) < 0) - warn("%s.%s=%.2f", m->dev->name, ctls[MCTL_PAN].name, v); - else - printf("%s.%s: %.2f -> %.2f\n", - m->dev->name, ctls[MCTL_PAN].name, n, v); + /* XXX: */ } static void @@ -362,12 +360,12 @@ mod_mute(struct mixer *m, const char *val) warnx("%c: no such modifier", *val); return; } - n = m->dev->f_mut; + n = M_ISMUTE(m, m->dev->devno); if (mixer_setmute(m, opt) < 0) warn("%s.%s=%c", m->dev->name, ctls[MCTL_MUT].name, *val); else printf("%s.%s: %d -> %d\n", - m->dev->name, ctls[MCTL_MUT].name, n, m->dev->f_mut); + m->dev->name, ctls[MCTL_MUT].name, n, M_ISMUTE(m, m->dev->devno)); } static void @@ -392,37 +390,38 @@ mod_recsrc(struct mixer *m, const char *val) warnx("%c: no such modifier", *val); return; } - n = m->dev->f_src; + n = M_ISRECSRC(m, m->dev->devno); if (mixer_modrecsrc(m, opt) < 0) warn("%s.%s=%c", m->dev->name, ctls[MCTL_SRC].name, *val); else printf("%s.%s: %d -> %d\n", - m->dev->name, ctls[MCTL_SRC].name, n, m->dev->f_src); + m->dev->name, ctls[MCTL_SRC].name, + n, M_ISRECSRC(m, m->dev->devno)); } static void print_volume(struct mixer *m) { printf("%s.%s=%.2f:%.2f\n", - m->dev->name, ctls[MCTL_VOL].name, m->dev->lvol, m->dev->rvol); + m->dev->name, ctls[MCTL_VOL].name, m->dev->vol.left, m->dev->vol.right); } static void print_panning(struct mixer *m) { - printf("%s.%s=%.2f\n", - m->dev->name, ctls[MCTL_PAN].name, m->dev->pan); + /* XXX: */ } static void print_mute(struct mixer *m) { - printf("%s.%s=%d\n", m->dev->name, ctls[MCTL_MUT].name, m->dev->f_mut); + printf("%s.%s=%d\n", m->dev->name, ctls[MCTL_MUT].name, + M_ISMUTE(m, m->dev->devno)); } static void print_recsrc(struct mixer *m) { printf("%s.%s=%d\n", - m->dev->name, ctls[MCTL_SRC].name, m->dev->f_rec); + m->dev->name, ctls[MCTL_SRC].name, M_ISRECSRC(m, m->dev->devno)); }