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 c587058824743fe5faf3ec5b07ca9c89e2459113
parent 0a2cf822789f7543fa5d2329a9f947c1cdca418d
Author: Christos Margiolis <christos@margiolis.net>
Date:   Fri, 18 Jun 2021 19:27:15 +0300

mixer_lib: added `mixer_get_nmixers`
mixer_prog: major refactoring, added -a, -d, -s and -r options.

Diffstat:
Mmixer_lib/mixer.c | 27+++++++++++++++++++++++++--
Mmixer_lib/mixer.h | 7+++++++
Mmixer_prog/mixer_prog.c | 341+++++++++++++++++++++++++++++++++++++++----------------------------------------
3 files changed, 202 insertions(+), 173 deletions(-)

diff --git a/mixer_lib/mixer.c b/mixer_lib/mixer.c @@ -106,8 +106,10 @@ default_unit: */ dp->lmute = 0; dp->rmute = 0; + /* XXX: is this correct? */ dp->f_pbk = !M_ISREC(m, i); dp->f_rec = M_ISREC(m, i); + dp->f_src = M_ISRECSRC(m, i); (void)strlcpy(dp->name, names[i], sizeof(dp->name)); TAILQ_INSERT_TAIL(&m->devs, dp, devs); } @@ -145,8 +147,8 @@ mixer_seldevbyname(struct mixer *m, const char *name, int flags) struct mix_dev *dp; TAILQ_FOREACH(dp, &m->devs, devs) { - if (M_ISSET(dp->devno, flags) - && !strncmp(dp->name, name, sizeof(dp->name))) + if (M_ISSET(dp->devno, flags) && + !strncmp(dp->name, name, sizeof(dp->name))) return (dp); } errno = EINVAL; @@ -228,6 +230,7 @@ mixer_modrecsrc(struct mixer *m, int opt) errno = EINVAL; return (-1); } + m->dev->f_src = M_ISRECSRC(m, m->dev->devno); if (ioctl(m->fd, SOUND_MIXER_WRITE_RECSRC, &m->recsrc) < 0) return (-1); if (ioctl(m->fd, SOUND_MIXER_READ_RECSRC, &m->recsrc) < 0) @@ -274,6 +277,26 @@ mixer_set_default_unit(struct mixer *m, int unit) } /* + * Get the total number of mixers in the system. + */ +int +mixer_get_nmixers(void) +{ + struct mixer *m; + oss_sysinfo si; + + if ((m = mixer_open(NULL)) == NULL) + return (-1); + if (ioctl(m->fd, OSS_SYSINFO, &si) < 0) { + (void)mixer_close(m); + return (-1); + } + (void)mixer_close(m); + + return (si.nummixers); +} + +/* * Free resources and close the mixer. */ static int diff --git a/mixer_lib/mixer.h b/mixer_lib/mixer.h @@ -23,6 +23,8 @@ #ifndef _MIXER_H_ #define _MIXER_H_ +__BEGIN_DECLS + #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); @@ -61,6 +63,7 @@ struct mix_dev { //int samples; int f_pbk; int f_rec; + int f_src; TAILQ_ENTRY(mix_dev) devs; }; @@ -87,5 +90,9 @@ int mixer_chpan(struct mixer *, float); int mixer_modrecsrc(struct mixer *, int); int mixer_get_default_unit(void); int mixer_set_default_unit(struct mixer *, int); +int mixer_get_nmixers(void); +/* TODO: get mixer/card total number */ + +__END_DECLS #endif /* _MIXER_H_ */ diff --git a/mixer_prog/mixer_prog.c b/mixer_prog/mixer_prog.c @@ -29,70 +29,53 @@ #include <mixer.h> static void usage(struct mixer *) __dead2; -static void printrecsrc(struct mixer *, int); +static void printall(struct mixer *); +static void printmixer(struct mixer *); +static void printdev(struct mix_dev *); static void __dead2 usage(struct mixer *m) { - struct mix_dev *dp; - int n; - - printf("usage: %1$s [-f device] [-s | -S] [dev [+|-][voll[:[+|-]volr]] ...\n" - " %1$s [-f device] [-s | -S] recsrc ...\n" - " %1$s [-f device] [-s | -S] {^|+|-|=}rec rdev ...\n", + printf("usage: %1$s [-f device] [-d unit] [dev [+|-][lvol[:[+|-]rvol]] ...\n" + " %1$s [-f device] [-d unit] -s ...\n" + " %1$s [-f device] [-d unit] -r {^|+|-|=}rdev ...\n" + " %1$s -a\n", getprogname()); - if (m->devmask) { - printf(" devices: "); - n = 0; - TAILQ_FOREACH(dp, &m->devs, devs) { - if (M_ISDEV(m, dp->devno)) { - if (n) - printf(", "); - printf("%s", dp->name); - n++; - } - } - } - if (m->recmask) { - printf("\n rec devices: "); - n = 0; - TAILQ_FOREACH(dp, &m->devs, devs) { - if (M_ISREC(m, dp->devno)) { - if (n) - printf(", "); - printf("%s", dp->name); - n++; - } - } - } - printf("\n"); (void)mixer_close(m); exit(1); } static void -printrecsrc(struct mixer *m, int sflag) +printall(struct mixer *m) { struct mix_dev *dp; - int n; - if (!m->recmask) - return; - if (!sflag) - printf("Recording source: "); - n = 0; + printmixer(m); TAILQ_FOREACH(dp, &m->devs, devs) { - if (M_ISRECSRC(m, dp->devno)) { - if (sflag) - printf("%srec ", n ? " +" : "="); - else if (n) - printf(", "); - printf("%s", dp->name); - n++; - } + printdev(dp); } - if (!sflag) - printf("\n"); +} + +static void +printmixer(struct mixer *m) +{ + printf("%s: <%s> %s", m->mi.name, m->ci.longname, m->ci.hw_info); + if (m->f_default) + printf(" (default)"); + printf("\n"); +} + +static void +printdev(struct mix_dev *d) +{ + printf(" %-10s%.2f:%.2f", d->name, d->lvol, d->rvol); + if (d->f_pbk) + printf("\t(playback)"); + if (d->f_rec) + printf("\t(rec)"); + if (d->f_src) + printf("\t(src)"); + printf("\n"); } int @@ -100,23 +83,32 @@ main(int argc, char *argv[]) { struct mixer *m; struct mix_dev *dp; - char lstr[8], rstr[8], *name = NULL; + char lstr[8], rstr[8], *recstr, *name = NULL, buf[NAME_MAX]; float l, r, lrel, rrel; - int dusage = 0, drecsrc = 0, sflag = 0, Sflag = 0; - char ch, n, t, k, opt = 0; + int dusage = 0, opt = 0, dunit; + int aflag = 0, dflag = 0, rflag = 0, sflag = 0; + int i, rc = 0; + char ch, t, k, n; - /* FIXME: problems with -rec */ - while ((ch = getopt(argc, argv, "f:sS")) != -1) { + while ((ch = getopt(argc, argv, "ad:f:r:s")) != -1) { switch (ch) { + case 'a': + aflag = 1; + break; + case 'd': + dunit = strtol(optarg, NULL, 10); + dflag = 1; + break; case 'f': name = optarg; break; + case 'r': + recstr = optarg; + rflag = 1; + break; case 's': sflag = 1; break; - case 'S': - Sflag = 1; - break; case '?': default: dusage = 1; @@ -126,58 +118,43 @@ main(int argc, char *argv[]) argc -= optind; argv += optind; - if (sflag && Sflag) - dusage = 1; + if (aflag) { + 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); + printall(m); + (void)mixer_close(m); + } + return (0); + } if ((m = mixer_open(name)) == NULL) err(1, "mixer_open: %s", name); - if (!argc && !dusage) { - n = 0; - TAILQ_FOREACH(dp, &m->devs, devs) { - if (sflag || Sflag) { - printf("%s%s%c%.2f:%.2f", n ? " " : "", - dp->name, Sflag ? ':' : ' ', - dp->lvol, dp->rvol); - n++; - } else - printf("Mixer %-8s is currently set to %.2f:%.2f\n", - dp->name, dp->lvol, dp->rvol); - } - if (n && m->recmask) - printf(" "); - printrecsrc(m, sflag || Sflag); - (void)mixer_close(m); - return 0; - } - - n = 0; - while (argc > 0 && !dusage) { - if (strcmp("recsrc", *argv) == 0) { - drecsrc = 1; - argc--; - argv++; - continue; - } else if (strcmp("rec", *argv + 1) == 0) { - if (**argv != '+' && **argv != '-' - && **argv != '=' && **argv != '^') { - warnx("unkown modifier: %c", **argv); - dusage = 1; - break; + while (!dusage) { + if (dflag) { + if (mixer_set_default_unit(m, dunit) < 0) { + warn("cannot set default unit to %d", dunit); + rc = 1; + goto done; } - if (argc <= 1) { - warnx("no recording device specified"); - dusage = 1; - break; - } - if ((m->dev = mixer_seldevbyname(m, argv[1], - m->recmask)) == NULL) { - warnx("unkown recording revice: %s", argv[1]); + /* Reopen the mixer, but use the default path. */ + (void)mixer_close(m); + if ((m = mixer_open(NULL)) == NULL) + err(1, "mixer_open"); + printf("changed default unit to: %d\n", dunit); + dflag = 0; + } else if (rflag) { + if (*recstr != '+' && *recstr != '-' && + *recstr != '=' && *recstr != '^') { + warnx("unkown modifier: %c", *recstr); dusage = 1; break; } - - switch (**argv) { + switch (*recstr) { case '+': opt = M_ADDRECDEV; break; @@ -191,86 +168,108 @@ main(int argc, char *argv[]) opt = M_TOGGLERECDEV; break; } - if (mixer_modrecsrc(m, opt) < 0) { - warnx("cannot modify device"); - break; - } - drecsrc = 1; - argc -= 2; - argv += 2; - continue; - } - - if ((t = sscanf(*argv, "%f:%f", &l, &r)) > 0) - ; /* nothing */ - else if ((m->dev = mixer_seldevbyname(m, *argv, - m->devmask)) == NULL) { - warnx("unkown device: %s", *argv); - dusage = 1; - break; - } - - lrel = rrel = 0; - if (argc > 1) { - k = sscanf(argv[1], "%7[^:]:%7s", lstr, rstr); - if (k == EOF) { - warnx("invalid value: %s", argv[1]); + if (*(++recstr) == '\0') { + warnx("no recording device specified"); dusage = 1; break; } - if (k > 0) { - if (*lstr == '+' || *lstr == '-') - lrel = rrel = 1; - l = strtof(lstr, NULL); + if ((m->dev = mixer_seldevbyname(m, recstr, + m->recmask)) == NULL) { + warn("unkown recording revice: %s", recstr); + rc = 1; + goto done; } - if (k > 1) { - if (*rstr == '+' || *rstr == '-') - rrel = 1; - r = strtof(rstr, NULL); + if (mixer_modrecsrc(m, opt) < 0) { + warn("cannot modify device"); + rc = 1; + goto done; + } + /* We don't want to end up here again. */ + rflag = 0; + } else if (sflag) { + if (!m->recmask) + goto done; + n = 0; + printmixer(m); + printf(" recording source: "); + TAILQ_FOREACH(dp, &m->devs, devs) { + if (M_ISRECSRC(m, dp->devno)) { + if (n) + printf(", "); + printf("%s", dp->name); + n++; + } + } + printf("\n"); + goto done; + } else if (argc > 0) { + if ((t = sscanf(*argv, "%f:%f", &l, &r)) > 0) + ; /* nothing */ + else if ((m->dev = mixer_seldevbyname(m, *argv, + m->devmask)) == NULL) { + warn("unkown device: %s", *argv); + rc = 1; + goto done; } - } - - switch (argc > 1 ? k : t) { - case 0: - printf("Mixer %-8s is currently set to %.2f:%.2f\n", - m->dev->name, m->dev->lvol, m->dev->rvol); - argc--; - argv++; - continue; - case 1: - r = l; /* FALLTHROUGH */ - case 2: - if (lrel) - l += m->dev->lvol; - 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; - if (mixer_chvol(m, l, r) < 0) { - warnx("cannot change volume"); - break; + lrel = rrel = 0; + if (argc > 1) { + k = sscanf(argv[1], "%7[^:]:%7s", lstr, rstr); + if (k == EOF) { + warnx("invalid value: %s", argv[1]); + dusage = 1; + break; + } + if (k > 0) { + if (*lstr == '+' || *lstr == '-') + lrel = rrel = 1; + l = strtof(lstr, NULL); + } + if (k > 1) { + if (*rstr == '+' || *rstr == '-') + rrel = 1; + r = strtof(rstr, NULL); + } } - if (!Sflag) - printf("Setting the mixer %s from %.2f:%.2f " - "to %.2f:%.2f\n", + + switch (argc > 1 ? k : t) { + case 0: + printmixer(m); + printdev(m->dev); + goto done; + case 1: + r = l; /* FALLTHROUGH */ + case 2: + if (lrel) + l += m->dev->lvol; + 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; + + printf("Mixer %s: %.2f:%.2f -> %.2f:%.2f\n", m->dev->name, m->dev->lvol, m->dev->rvol, l, r); - argc -= 2; - argv += 2; - } + + if (mixer_chvol(m, l, r) < 0) { + warnx("cannot change volume"); + rc = 1; + } + goto done; + } + } else + break; } - if (dusage) - usage(m); - if (drecsrc) - printrecsrc(m, sflag || Sflag); + dusage ? usage(m) : printall(m); +done: (void)mixer_close(m); - return 0; + return (rc); }