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 e8100ba095b92ad290f80f059e9a494a429fe372
parent a843a32e978a31becd6bd582a13a64d8c65405aa
Author: Christos Margiolis <christos@margiolis.net>
Date:   Wed,  7 Jul 2021 15:16:02 +0300

minor changes

Diffstat:
Mmixer_lib/mixer.c | 80++++++++++++++++++++++++++++++++++++++-----------------------------------------
Mmixer_lib/mixer.h | 14+++++++++-----
Mmixer_prog/mixer_prog.8 | 3++-
Mmixer_prog/mixer_prog.c | 336+++++++++++++++++++++++++++++++++++++++++++------------------------------------
4 files changed, 230 insertions(+), 203 deletions(-)

diff --git a/mixer_lib/mixer.c b/mixer_lib/mixer.c @@ -34,12 +34,28 @@ #include "mixer.h" #define BASEPATH "/dev/mixer" +#define MIN(x, y) ((x) < (y) ? (x) : (y)) -static int _mixer_close(struct mixer *m); +static int _mixer_readvol(struct mixer *, struct mix_dev *); static const char *names[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_NAMES; static int ndev = 0; +static int +_mixer_readvol(struct mixer *m, struct mix_dev *dev) +{ + int v; + + 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); + + return (0); +} + /* * Open a mixer device in `/dev/mixerN`, where N is the number of the mixer * file. Each device maps to an actual pcmN audio card, so `/dev/mixer0` @@ -53,7 +69,7 @@ mixer_open(const char *name) { struct mixer *m = NULL; struct mix_dev *dp; - int i, v; + int i; if ((m = calloc(1, sizeof(struct mixer))) == NULL) goto fail; @@ -96,18 +112,11 @@ dunit: for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { if (!M_ISDEV(m, i)) continue; - if (ioctl(m->fd, MIXER_READ(i), &v) < 0) - goto fail; if ((dp = calloc(1, sizeof(struct mix_dev))) == NULL) goto fail; dp->devno = i; - - /* XXX: Make this a seperate function? */ - dp->lvol = M_VOLNORM(v & 0x7f); - dp->rvol = M_VOLNORM((v >> 8) & 0x7f); - dp->pan = dp->rvol - dp->lvol; - - dp->f_mut = M_ISMUTE(m, i) ? 1 : 0; + 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; @@ -127,10 +136,24 @@ fail: return (NULL); } +/* + * Free resources and close the mixer. + */ int mixer_close(struct mixer *m) { - return (_mixer_close(m)); + struct mix_dev *dp; + int r; + + r = close(m->fd); + while (!TAILQ_EMPTY(&m->devs)) { + dp = TAILQ_FIRST(&m->devs); + TAILQ_REMOVE(&m->devs, dp, devs); + free(dp); + } + free(m); + + return (r); } struct mix_dev * @@ -195,11 +218,11 @@ mixer_setvol(struct mixer *m, float l, float r) errno = ERANGE; return (-1); } - m->dev->lvol = l; - m->dev->rvol = r; v = M_VOLDENORM(l) | M_VOLDENORM(r) << 8; if (ioctl(m->fd, MIXER_WRITE(m->dev->devno), &v) < 0) return (-1); + if (_mixer_readvol(m, m->dev) < 0) + return (-1); return (0); } @@ -228,8 +251,6 @@ mixer_setpan(struct mixer *m, float pan) int mixer_setmute(struct mixer *m, int opt) { - int v; - switch (opt) { case M_MUTE: m->mutemask |= (1 << m->dev->devno); @@ -248,13 +269,8 @@ mixer_setmute(struct mixer *m, int opt) return (-1); if (ioctl(m->fd, SOUND_MIXER_READ_MUTE, &m->mutemask) < 0) return (-1); - /* Update the volume. */ - if (ioctl(m->fd, MIXER_READ(m->dev->devno), &v) < 0) + if (_mixer_readvol(m, m->dev) < 0) return (-1); - m->dev->lvol = M_VOLNORM(v & 0x7f); - m->dev->rvol = M_VOLNORM((v >> 8) & 0x7f); - m->dev->pan = m->dev->rvol - m->dev->lvol; - m->dev->f_mut = M_ISMUTE(m, m->dev->devno); return 0; } @@ -356,23 +372,3 @@ mixer_getnmixers(void) return (si.nummixers); } - -/* - * Free resources and close the mixer. - */ -static int -_mixer_close(struct mixer *m) -{ - struct mix_dev *dp; - int r; - - r = close(m->fd); - while (!TAILQ_EMPTY(&m->devs)) { - dp = TAILQ_FIRST(&m->devs); - TAILQ_REMOVE(&m->devs, dp, devs); - free(dp); - } - free(m); - - return (r); -} diff --git a/mixer_lib/mixer.h b/mixer_lib/mixer.h @@ -57,18 +57,22 @@ __FBSDID("$FreeBSD$"); #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; - float lvol; - float rvol; - float pan; - //int rate; - //int samples; int f_mut; int f_pbk; int f_rec; int f_src; + float lvol; + float rvol; + float pan; TAILQ_ENTRY(mix_dev) devs; }; diff --git a/mixer_prog/mixer_prog.8 b/mixer_prog/mixer_prog.8 @@ -31,7 +31,8 @@ .Op Fl f Ar device .Op Fl d Ar unit .Op Fl os -.Op Ar command Ar ... +.Op Ar dev Ns Op . Ns Ar control Ns Op = Ns Ar value +.Ar ... .Nm .Op Fl d Ar unit .Op Fl os diff --git a/mixer_prog/mixer_prog.c b/mixer_prog/mixer_prog.c @@ -31,36 +31,172 @@ #define LEN(x) (sizeof(x) / sizeof(x[0])) -#define CTRL_VOL 0 -#define CTRL_MUT 1 -#define CTRL_SRC 2 +#define MCTL_VOL 0 +#define MCTL_PAN 1 +#define MCTL_MUT 2 +#define MCTL_SRC 3 -struct ctrl { +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 printall(struct mixer *, int); static void printminfo(struct mixer *, int); static void printdev(struct mix_dev *, int); static void printrecsrc(struct mixer *, int); -static int findctrl(const char *); +static int findctl(const char *); +/* Control handlers */ static void mod_volume(struct mixer *, const char *); +static void mod_panning(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_panning(struct mixer *); static void print_mute(struct mixer *); static void print_recsrc(struct mixer *); -static void usage(void) __dead2; -static const struct ctrl ctrls[] = { - [CTRL_VOL] = { "volume", mod_volume, print_volume }, - [CTRL_MUT] = { "mute", mod_mute, print_mute }, - [CTRL_SRC] = { "recsrc", mod_recsrc, print_recsrc }, +static const struct mix_ctl ctls[] = { + [MCTL_VOL] = { "volume", mod_volume, print_volume }, + [MCTL_PAN] = { "panning", mod_panning, print_panning }, + [MCTL_MUT] = { "mute", mod_mute, print_mute }, + [MCTL_SRC] = { "recsrc", mod_recsrc, print_recsrc }, }; +int +main(int argc, char *argv[]) +{ + struct mixer *m; + char *name = NULL, buf[NAME_MAX]; + char *p, *bufp, *devstr, *ctlstr, *valstr = NULL; + int dunit, i, n, pall = 1; + int aflag = 0, dflag = 0, oflag = 0, sflag = 0; + char ch; + + while ((ch = getopt(argc, argv, "ad:f:os")) != -1) { + switch (ch) { + case 'a': + aflag = 1; + break; + case 'd': + dunit = strtol(optarg, NULL, 10); + if (errno == EINVAL || errno == ERANGE) + err(1, "strtol"); + dflag = 1; + break; + case 'f': + name = optarg; + break; + case 'o': + oflag = 1; + break; + case 's': + sflag = 1; + break; + case '?': + default: + usage(); + } + } + argc -= optind; + argv += optind; + + /* Print all mixers and exit. */ + if (aflag) { + if ((n = mixer_getnmixers()) < 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); + if (sflag) + printrecsrc(m, oflag); + else { + printall(m, oflag); + if (oflag) + printf("\n"); + } + (void)mixer_close(m); + } + return (0); + } + + 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); + } + if (sflag) { + printrecsrc(m, oflag); + (void)mixer_close(m); + return (0); + } + +parse: + while (argc > 0) { + if ((p = bufp = strdup(*argv)) == NULL) + err(1, "strdup(%s)", *argv); + /* Split the string into device, control and value. */ + devstr = strsep(&p, "."); + if ((m->dev = mixer_getdevbyname(m, devstr)) == NULL) { + warnx("%s: no such device", devstr); + goto next; + } + /* Input: `dev`. */ + if (p == NULL) { + printdev(m->dev, 1); + pall = 0; + goto next; + } + ctlstr = strsep(&p, "="); + if ((n = findctl(ctlstr)) < 0) { + warnx("%s.%s: no such control", devstr, ctlstr); + goto next; + } + /* Input: `dev.control`. */ + if (p == NULL) { + ctls[n].print(m); + pall = 0; + goto next; + } + valstr = p; + /* Input: `dev.control=val`. */ + ctls[n].mod(m, valstr); +next: + free(p); + argc--; + argv++; + } + + if (pall) + printall(m, oflag); + (void)mixer_close(m); + + return (0); +} + +static void __dead2 +usage(void) +{ + printf("usage: %1$s [-f device] [-d unit] [-os] [dev[.control[=value]]] ...\n" + " %1$s [-d unit] [-os] -a\n", + getprogname()); + exit(1); +} + static void printall(struct mixer *m, int oflag) { @@ -100,9 +236,9 @@ printdev(struct mix_dev *d, int oflag) printf("\n"); } else { printf("%s.%s=%.2f:%.2f\n", - d->name, ctrls[CTRL_VOL].name, d->lvol, d->rvol); + d->name, ctls[MCTL_VOL].name, d->lvol, d->rvol); if (d->f_src) - printf("%s.%s=+\n", d->name, ctrls[CTRL_SRC].name); + printf("%s.%s=+\n", d->name, ctls[MCTL_SRC].name); /* TODO: add f_mut */ } } @@ -129,12 +265,12 @@ printrecsrc(struct mixer *m, int oflag) } static int -findctrl(const char *ctrl) +findctl(const char *ctl) { int i; - for (i = 0; i < LEN(ctrls); i++) - if (strcmp(ctrl, ctrls[i].name) == 0) + for (i = 0; i < LEN(ctls); i++) + if (strcmp(ctl, ctls[i].name) == 0) return (i); return (-1); @@ -185,15 +321,29 @@ mod_volume(struct mixer *m, const char *val) rprev = m->dev->rvol; if (mixer_setvol(m, l, r) < 0) warn("%s.%s=%.2f:%.2f", - m->dev->name, ctrls[CTRL_VOL].name, l, r); + m->dev->name, ctls[MCTL_VOL].name, l, r); else printf("%s.%s: %.2f:%.2f -> %.2f:%.2f\n", - m->dev->name, ctrls[CTRL_VOL].name, + m->dev->name, ctls[MCTL_VOL].name, lprev, rprev, l, r); } } 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); +} + +static void mod_mute(struct mixer *m, const char *val) { int n, opt = -1; @@ -214,10 +364,10 @@ mod_mute(struct mixer *m, const char *val) } n = m->dev->f_mut; if (mixer_setmute(m, opt) < 0) - warn("%s.%s=%c", m->dev->name, ctrls[CTRL_MUT].name, *val); + warn("%s.%s=%c", m->dev->name, ctls[MCTL_MUT].name, *val); else printf("%s.%s: %d -> %d\n", - m->dev->name, ctrls[CTRL_MUT].name, n, m->dev->f_mut); + m->dev->name, ctls[MCTL_MUT].name, n, m->dev->f_mut); } static void @@ -244,159 +394,35 @@ mod_recsrc(struct mixer *m, const char *val) } n = m->dev->f_src; if (mixer_modrecsrc(m, opt) < 0) - warn("%s.%s=%c", m->dev->name, ctrls[CTRL_SRC].name, *val); + warn("%s.%s=%c", m->dev->name, ctls[MCTL_SRC].name, *val); else printf("%s.%s: %d -> %d\n", - m->dev->name, ctrls[CTRL_SRC].name, n, m->dev->f_src); + m->dev->name, ctls[MCTL_SRC].name, n, m->dev->f_src); } static void print_volume(struct mixer *m) { printf("%s.%s=%.2f:%.2f\n", - m->dev->name, ctrls[CTRL_VOL].name, m->dev->lvol, m->dev->rvol); + m->dev->name, ctls[MCTL_VOL].name, m->dev->lvol, m->dev->rvol); } static void -print_mute(struct mixer *m) +print_panning(struct mixer *m) { - printf("%s.%s=%d\n", m->dev->name, ctrls[CTRL_MUT].name, m->dev->f_mut); + printf("%s.%s=%.2f\n", + m->dev->name, ctls[MCTL_PAN].name, m->dev->pan); } static void -print_recsrc(struct mixer *m) -{ - printf("%s.%s=%d\n", - m->dev->name, ctrls[CTRL_SRC].name, m->dev->f_rec); -} - -static void __dead2 -usage(void) +print_mute(struct mixer *m) { - printf("usage: %1$s [-f device] [-d unit] [-os] [command ...]\n" - " %1$s [-d unit] [-os] -a\n", - getprogname()); - exit(1); + printf("%s.%s=%d\n", m->dev->name, ctls[MCTL_MUT].name, m->dev->f_mut); } -int -main(int argc, char *argv[]) +static void +print_recsrc(struct mixer *m) { - struct mixer *m; - char *name = NULL, buf[NAME_MAX]; - char *p, *bufp, *devstr, *ctrlstr, *valstr = NULL; - int dunit, i, n, pall = 1; - int aflag = 0, dflag = 0, oflag = 0, sflag = 0; - char ch; - - while ((ch = getopt(argc, argv, "ad:f:os")) != -1) { - switch (ch) { - case 'a': - aflag = 1; - break; - case 'd': - dunit = strtol(optarg, NULL, 10); - if (errno == EINVAL || errno == ERANGE) - err(1, "strtol"); - dflag = 1; - break; - case 'f': - name = optarg; - break; - case 'o': - oflag = 1; - break; - case 's': - sflag = 1; - break; - case '?': - default: - usage(); - } - } - argc -= optind; - argv += optind; - - /* Print all mixers and exit. */ - if (aflag) { - if ((n = mixer_getnmixers()) < 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); - if (sflag) - printrecsrc(m, oflag); - else { - printall(m, oflag); - if (oflag) - printf("\n"); - } - (void)mixer_close(m); - } - return (0); - } - - 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); - } - if (sflag) { - printrecsrc(m, oflag); - (void)mixer_close(m); - return (0); - } - -parse: - while (argc > 0) { - if ((p = bufp = strdup(*argv)) == NULL) - err(1, "strdup(%s)", *argv); - /* Split the string into device, control and value. */ - devstr = strsep(&p, "."); - if ((m->dev = mixer_getdevbyname(m, devstr)) == NULL) { - warnx("%s: no such device", devstr); - goto next; - } - /* Input: `dev`. */ - if (p == NULL) { - printdev(m->dev, 1); - pall = 0; - goto next; - } - ctrlstr = strsep(&p, "="); - if ((n = findctrl(ctrlstr)) < 0) { - warnx("%s.%s: no such control", devstr, ctrlstr); - goto next; - } - /* Input: `dev.ctrl`. */ - if (p == NULL) { - ctrls[n].print(m); - pall = 0; - goto next; - } - valstr = p; - /* Input: `dev.ctrl=val`. */ - ctrls[n].mod(m, valstr); -next: - free(p); - argc--; - argv++; - } - - if (pall) - printall(m, oflag); - (void)mixer_close(m); - - return (0); + printf("%s.%s=%d\n", + m->dev->name, ctls[MCTL_SRC].name, m->dev->f_rec); }