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 59b41ffceb9c625d13f70729ce4960d69cc511d2
parent eb835fa7f7d3f2c91b5a37a2e0e5c156b0ccef03
Author: Christos Margiolis <christos@margiolis.net>
Date:   Tue, 29 Jun 2021 01:42:21 +0300

started writing the manpages, improved function naming

Diffstat:
Mmixer_lib/mixer.3 | 27+++++++++++++++++++++++----
Mmixer_lib/mixer.c | 42+++++++++++++++++++++++++++++++-----------
Mmixer_lib/mixer.h | 17++++++++---------
Mmixer_prog/mixer_prog.8 | 90+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
Mmixer_prog/mixer_prog.c | 67+++++++++++++++++++++++++++++++++++++++----------------------------
5 files changed, 187 insertions(+), 56 deletions(-)

diff --git a/mixer_lib/mixer.3 b/mixer_lib/mixer.3 @@ -20,17 +20,36 @@ .\" THE SOFTWARE. .\" -.Dd March 11, 2021 +.Dd June 28, 2021 .Dt mixer 3 .Os .Sh NAME .Nm mixer -.Nd a mixer library +.Nd an OSS mixer library .Sh LIBRARY -Mixer (libmixer, -lmixer) +Mixer library (libmixer, -lmixer) .Sh SYNOPSIS .In mixer.h -.\" TODO +.Ft struct mixer * +.Fn mixer_open "const char *path" +.Ft int +.Fn mixer_close "struct mixer *m" +.Ft struct mix_dev * +.Fn mixer_getdev "struct mixer *m" "int devno" +.Ft struct mix_dev * +.Fn mixer_getdevbyname "struct mixer *m" "name" +.Ft int +.Fn mixer_setvol "struct mixer *m" "float lvol" "float rvol" +.Ft int +.Fn mixer_setpan "struct mixer *m" "float pan" +.Ft int +.Fn mixer_modrecsrc "struct mixer *m" "int opt" +.Ft int +.Fn mixer_getdunit "void" +.Ft int +.Fn mixer_setdunit "struct mixer *m" "int unit" +.Ft int +.Fn mixer_getnmixers "void" .Sh DESCRIPTION .\" TODO .Sh SEE ALSO diff --git a/mixer_lib/mixer.c b/mixer_lib/mixer.c @@ -38,6 +38,7 @@ static int _mixer_close(struct mixer *m); static const char *names[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_NAMES; +static int ndev = 0; /* * Open a mixer device in `/dev/mixerN`, where N is the number of the mixer @@ -65,12 +66,12 @@ mixer_open(const char *name) } /* `name` is "/dev/mixer" so, we'll use the default unit. */ if (strncmp(name, BASEPATH, strlen(name)) == 0) - goto default_unit; + goto dunit; m->unit = strtol(name + strlen(BASEPATH), NULL, 10); (void)strlcpy(m->name, name, sizeof(m->name)); } else { -default_unit: - if ((m->unit = mixer_get_default_unit()) < 0) +dunit: + if ((m->unit = mixer_getdunit()) < 0) goto fail; (void)snprintf(m->name, sizeof(m->name) - 1, "/dev/mixer%d", m->unit); } @@ -79,7 +80,7 @@ default_unit: goto fail; m->devmask = m->recmask = m->recsrc = 0; - m->f_default = m->unit == mixer_get_default_unit(); + m->f_default = m->unit == mixer_getdunit(); /* The unit number _must_ be set before the ioctl. */ m->mi.dev = m->unit; m->ci.card = m->unit; @@ -114,6 +115,7 @@ default_unit: dp->f_src = M_ISRECSRC(m, i); (void)strlcpy(dp->name, names[i], sizeof(dp->name)); TAILQ_INSERT_TAIL(&m->devs, dp, devs); + ndev++; } /* The default device is always "vol". */ m->dev = TAILQ_FIRST(&m->devs); @@ -132,6 +134,24 @@ mixer_close(struct mixer *m) return (_mixer_close(m)); } +struct mix_dev * +mixer_getdev(struct mixer *m, int dev) +{ + struct mix_dev *dp; + + if (dev < 0 || dev >= ndev) { + errno = ERANGE; + return (NULL); + } + TAILQ_FOREACH(dp, &m->devs, devs) { + if (dp->devno == dev) + return (dp); + } + errno = EINVAL; + + return (NULL); +} + /* * Select a mixer device (e.g vol, pcm, mic) by name. The mixer structure * keeps a list of all the devices the mixer has, but only one can be @@ -143,7 +163,7 @@ mixer_close(struct mixer *m) * @param: `name`: device name (e.g vol, pcm, ...) */ struct mix_dev * -mixer_seldevbyname(struct mixer *m, const char *name) +mixer_getdevbyname(struct mixer *m, const char *name) { struct mix_dev *dp; @@ -168,7 +188,7 @@ mixer_seldevbyname(struct mixer *m, const char *name) * be handlded by the caller. */ int -mixer_chvol(struct mixer *m, float l, float r) +mixer_setvol(struct mixer *m, float l, float r) { int v; @@ -192,7 +212,7 @@ mixer_chvol(struct mixer *m, float l, float r) * `M_PANMIN <= pan <= M_PANMAX`. */ int -mixer_chpan(struct mixer *m, float pan) +mixer_setpan(struct mixer *m, float pan) { int l, r; @@ -203,7 +223,7 @@ mixer_chpan(struct mixer *m, float pan) l = m->dev->lvol; r = m->dev->rvol; - return (mixer_chvol(m, l, r)); + return (mixer_setvol(m, l, r)); } /* @@ -248,7 +268,7 @@ mixer_modrecsrc(struct mixer *m, int opt) * and set the mixer structure's `f_default` flag. */ int -mixer_get_default_unit(void) +mixer_getdunit(void) { int unit; size_t size; @@ -268,7 +288,7 @@ mixer_get_default_unit(void) * @param: `unit`: the audio card number (e.g pcm0, pcm1, ...). */ int -mixer_set_default_unit(struct mixer *m, int unit) +mixer_setdunit(struct mixer *m, int unit) { size_t size; @@ -284,7 +304,7 @@ mixer_set_default_unit(struct mixer *m, int unit) * Get the total number of mixers in the system. */ int -mixer_get_nmixers(void) +mixer_getnmixers(void) { struct mixer *m; oss_sysinfo si; diff --git a/mixer_lib/mixer.h b/mixer_lib/mixer.h @@ -69,7 +69,7 @@ struct mix_dev { }; struct mixer { - TAILQ_HEAD(head, mix_dev) devs; + TAILQ_HEAD(head, mix_dev) devs; /* XXX: use LIST? */ struct mix_dev *dev; oss_mixerinfo mi; oss_card_info ci; @@ -84,15 +84,14 @@ struct mixer { struct mixer *mixer_open(const char *); int mixer_close(struct mixer *); -struct mix_dev *mixer_seldevbyname(struct mixer *, const char *); -/* XXX: change names for ch* functions? */ -int mixer_chvol(struct mixer *, float, float); -int mixer_chpan(struct mixer *, float); +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_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 */ +int mixer_getdunit(void); +int mixer_setdunit(struct mixer *, int); +int mixer_getnmixers(void); __END_DECLS diff --git a/mixer_prog/mixer_prog.8 b/mixer_prog/mixer_prog.8 @@ -20,17 +20,99 @@ .\" THE SOFTWARE. .\" -.Dd June 07, 2021 +.Dd June 28, 2021 .Dt mixer 8 .Os .Sh NAME .Nm mixer .Nd manipulate soundcard mixer values .Sh SYNOPSIS -.\" TODO: +.Nm +.Op Fl f device +.Op Fl d unit +.Op Fl o +.Oo +.Ar dev +.Sm off +.Oo +.Op Cm + | - +.Ar lvol +.Op : Oo Cm + | - Oc Ar rvol +.Oc +.Oc +.Sm on +.Ar ... +.Nm +.Op Fl f device +.Op Fl d unit +.Op Fl o +.Fl s +.Ar ... +.Nm +.Op Fl f device +.Op Fl d unit +.Op Fl o +.Sm off +.Bro +.Cm ^ | + | - | = +.Brc +.Cm rec +.Sm on +.Ar rdev ... +.Nm +.Op Fl o +.Fl a .Sh DESCRIPTION -.\" TODO: +The +.Nm +utility is used to set and display soundcard mixer device levels. The list of mixer +devices that may be modified are: +.Bd -ragged -offset indent +vol, bass, treble, synth, pcm, speaker, line, mic, cd, mix, +pcm2, rec, igain, ogain, line1, line2, line3, dig1, dig2, dig3, +phin, phout, video, radio, and monitor. +.Ed +.Pp +Without any arguments, +.Nm +displays information and the current settings for all supported devices. +If the +.Ar dev +argument is specified, +.Nm +displays only the values for +.Ar dev . +.Pp +To modify a device's volume, the optional +.Ar lvol +and/or +.Ar rvol +values have to be specified. The values have to be normalized 32-bit floats +(0.0 to 1.0). Omitting +.Ar dev +will change the value of the main channel (usually "vol"). +If the the left or right volume values are prefixed with +.Cm + +or +.Cm - , +the value following will be used as a relative adjustment, modifying the +current settings by the amount specified. +.Sh FILES +.Bl -tag -width /dev/mixerN -compact +.It Pa /dev/mixerN +the mixer device, where +.Ar N +is the number of that device, for example +.Ar /dev/mixer0 . +PCM cards and mixers have a 1:1 relationship, which means that +.Ar mixer0 +is the mixer for +.Ar pcm0 +and so on. +.El +\" TODO: write about the rest of the program. .Sh SEE ALSO -.Xr mixer 3 +.Xr mixer 3 , +.Xr sound 4 .Sh AUTHORS .An Christos Margiolis Aq Mt christos@margiolis.net diff --git a/mixer_prog/mixer_prog.c b/mixer_prog/mixer_prog.c @@ -33,6 +33,7 @@ static void usage(void) __dead2; static void printall(struct mixer *, int); static void printmixer(struct mixer *); static void printdev(struct mix_dev *, int); +static void printrecsrc(struct mixer *, int); static void __dead2 usage(void) @@ -87,11 +88,33 @@ printdev(struct mix_dev *d, int oflag) } } +static void +printrecsrc(struct mixer *m, int oflag) +{ + struct mix_dev *dp; + int n = 0; + + if (!m->recmask) + return; + if (!oflag) { + printmixer(m); + printf(" recording source: "); + } + TAILQ_FOREACH(dp, &m->devs, devs) { + if (M_ISRECSRC(m, dp->devno)) { + if (n) + printf("%s ", oflag ? " " : ", "); + printf("%s", dp->name); + n++; + } + } + printf("\n"); +} + int main(int argc, char *argv[]) { struct mixer *m; - struct mix_dev *dp; char lstr[8], rstr[8], *name = NULL, buf[NAME_MAX]; float l, r, lrel, rrel; int dusage = 0, opt = 0, dunit; @@ -118,6 +141,7 @@ main(int argc, char *argv[]) break; case 'r': /* Reserved for {+|-|^|=}rec rdev. */ + /* FIXME: problems with -rec */ break; case 's': sflag = 1; @@ -131,15 +155,19 @@ main(int argc, char *argv[]) argv += optind; if (aflag) { - if ((n = mixer_get_nmixers()) < 0) + 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); - printall(m, oflag); - if (oflag) - printf("\n"); + if (sflag) + printrecsrc(m, oflag); + else { + printall(m, oflag); + if (oflag) + printf("\n"); + } (void)mixer_close(m); } return (0); @@ -153,30 +181,17 @@ main(int argc, char *argv[]) /* We don't want to get in here again. */ dflag = 0; /* XXX: should we die if any of these two fails? */ - if ((n = mixer_get_default_unit()) < 0) { + if ((n = mixer_getdunit()) < 0) { warn("cannot get default unit"); continue; } - if (mixer_set_default_unit(m, dunit) < 0) { + if (mixer_setdunit(m, dunit) < 0) { warn("cannot set default unit to %d", dunit); continue; } printf("default_unit: %d -> %d\n", n, dunit); } 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"); + printrecsrc(m, oflag); goto done; } else if (argc > 0 && strcmp("rec", *argv + 1) == 0) { if (**argv != '+' && **argv != '-' && @@ -199,7 +214,7 @@ main(int argc, char *argv[]) opt = M_TOGGLERECDEV; break; } - if ((m->dev = mixer_seldevbyname(m, argv[1])) == NULL) { + if ((m->dev = mixer_getdevbyname(m, argv[1])) == NULL) { warn("unknown recording device: %s", argv[1]); /* XXX */ rc = 1; @@ -215,13 +230,9 @@ main(int argc, char *argv[]) argc -= 2; argv += 2; } else if (argc > 0) { - /* - * FIXME: this is causing problems if we have - * -options at the end - */ if ((k = sscanf(*argv, "%f:%f", &l, &r)) > 0) ; /* nothing */ - else if ((m->dev = mixer_seldevbyname(m, *argv)) == NULL) { + else if ((m->dev = mixer_getdevbyname(m, *argv)) == NULL) { warn("unknown device: %s", *argv); rc = 1; goto done; @@ -272,7 +283,7 @@ main(int argc, char *argv[]) printf("%s.volume: %.2f:%.2f -> %.2f:%.2f\n", m->dev->name, m->dev->lvol, m->dev->rvol, l, r); - if (mixer_chvol(m, l, r) < 0) { + if (mixer_setvol(m, l, r) < 0) { warnx("cannot change volume"); rc = 1; }