--- LICENSE | 3 +- components/volume.c | 210 +++++++++++++++++++++++++++++++++----------- config.def.h | 1 + config.mk | 1 + 4 files changed, 163 insertions(+), 52 deletions(-) diff --git a/LICENSE b/LICENSE index 0eec587..c61489f 100644 --- a/LICENSE +++ b/LICENSE _AT_@ -19,7 +19,8 @@ Copyright 2018 David Demelier <markand_AT_malikania.fr> Copyright 2018-2019 Michael Buch <michaelbuch12_AT_gmail.com> Copyright 2018 Ian Remmler <ian_AT_remmler.org> Copyright 2016-2019 Joerg Jung <jung_AT_openbsd.org> -Copyright 2019 Ingo Feinerer <feinerer_AT_logic.at> +Copyright 2019-2020 Ingo Feinerer <feinerer_AT_logic.at> +Copyright 2020 Alexandre Ratchov <alex_AT_caoua.org> Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above diff --git a/components/volume.c b/components/volume.c index 61cec90..b6665da 100644 --- a/components/volume.c +++ b/components/volume.c _AT_@ -8,69 +8,177 @@ #include "../util.h" #if defined(__OpenBSD__) - #include <sys/audioio.h> + #include <sys/queue.h> + #include <poll.h> + #include <sndio.h> + #include <stdlib.h> + + struct control { + LIST_ENTRY(control) next; + unsigned int addr; + #define CTRL_NONE 0 + #define CTRL_LEVEL 1 + #define CTRL_MUTE 2 + unsigned int type; + unsigned int maxval; + unsigned int val; + }; + + static LIST_HEAD(, control) controls = LIST_HEAD_INITIALIZER(controls); + static struct pollfd *pfds; + static struct sioctl_hdl *hdl; + static int initialized; + + /* + * Call-back to obtain the description of all audio controls. + */ + static void + ondesc(void *unused, struct sioctl_desc *desc, int val) + { + struct control *c, *ctmp; + unsigned int type = CTRL_NONE; + + if (desc == NULL) + return; + + /* Delete existing audio control with the same address. */ + LIST_FOREACH_SAFE(c, &controls, next, ctmp) { + if (desc->addr == c->addr) { + LIST_REMOVE(c, next); + free(c); + break; + } + } + + /* Only match output.level and output.mute audio controls. */ + if (desc->group[0] != 0 || + strcmp(desc->node0.name, "output") != 0) + return; + if (desc->type == SIOCTL_NUM && + strcmp(desc->func, "level") == 0) + type = CTRL_LEVEL; + else if (desc->type == SIOCTL_SW && + strcmp(desc->func, "mute") == 0) + type = CTRL_MUTE; + else + return; + + c = malloc(sizeof(struct control)); + if (c == NULL) { + warn("sndio: failed to allocate audio control\n"); + return; + } + + c->addr = desc->addr; + c->type = type; + c->maxval = desc->maxval; + c->val = val; + LIST_INSERT_HEAD(&controls, c, next); + } + + /* + * Call-back invoked whenever an audio control changes. + */ + static void + onval(void *unused, unsigned int addr, unsigned int val) + { + struct control *c; + + LIST_FOREACH(c, &controls, next) { + if (c->addr == addr) + break; + } + c->val = val; + } + + static void + cleanup(void) + { + struct control *c; + + if (hdl) { + sioctl_close(hdl); + hdl = NULL; + } + + free(pfds); + pfds = NULL; + + while (!LIST_EMPTY(&controls)) { + c = LIST_FIRST(&controls); + LIST_REMOVE(c, next); + free(c); + } + } + + static int + init(void) + { + hdl = sioctl_open(SIO_DEVANY, SIOCTL_READ, 0); + if (hdl == NULL) { + warn("sndio: cannot open device"); + goto failed; + } + + if (!sioctl_ondesc(hdl, ondesc, NULL)) { + warn("sndio: cannot set control description call-back"); + goto failed; + } + + if (!sioctl_onval(hdl, onval, NULL)) { + warn("sndio: cannot set control values call-back"); + goto failed; + } + + pfds = calloc(sioctl_nfds(hdl), sizeof(struct pollfd)); + if (pfds == NULL) { + warn("sndio: cannot allocate pollfd structures"); + goto failed; + } + + return 1; + failed: + cleanup(); + return 0; + } const char * - vol_perc(const char *card) + vol_perc(const char *unused) { - static int cls = -1; - mixer_devinfo_t mdi; - mixer_ctrl_t mc; - int afd = -1, m = -1, v = -1; + struct control *c; + int n, v, value; - if ((afd = open(card, O_RDONLY)) < 0) { - warn("open '%s':", card); + if (!initialized) + initialized = init(); + + if (hdl == NULL) return NULL; - } - for (mdi.index = 0; cls == -1; mdi.index++) { - if (ioctl(afd, AUDIO_MIXER_DEVINFO, &mdi) < 0) { - warn("ioctl 'AUDIO_MIXER_DEVINFO':"); - close(afd); - return NULL; - } - if (mdi.type == AUDIO_MIXER_CLASS && - !strncmp(mdi.label.name, - AudioCoutputs, - MAX_AUDIO_DEV_LEN)) - cls = mdi.index; - } - for (mdi.index = 0; v == -1 || m == -1; mdi.index++) { - if (ioctl(afd, AUDIO_MIXER_DEVINFO, &mdi) < 0) { - warn("ioctl 'AUDIO_MIXER_DEVINFO':"); - close(afd); - return NULL; - } - if (mdi.mixer_class == cls && - ((mdi.type == AUDIO_MIXER_VALUE && - !strncmp(mdi.label.name, - AudioNmaster, - MAX_AUDIO_DEV_LEN)) || - (mdi.type == AUDIO_MIXER_ENUM && - !strncmp(mdi.label.name, - AudioNmute, - MAX_AUDIO_DEV_LEN)))) { - mc.dev = mdi.index, mc.type = mdi.type; - if (ioctl(afd, AUDIO_MIXER_READ, &mc) < 0) { - warn("ioctl 'AUDIO_MIXER_READ':"); - close(afd); + n = sioctl_pollfd(hdl, pfds, POLLIN); + if (n > 0) { + n = poll(pfds, n, 0); + if (n > 0) { + if (sioctl_revents(hdl, pfds) & POLLHUP) { + warn("sndio: disconnected"); + cleanup(); return NULL; } - if (mc.type == AUDIO_MIXER_VALUE) - v = mc.un.value.num_channels == 1 ? - mc.un.value.level[AUDIO_MIXER_LEVEL_MONO] : - (mc.un.value.level[AUDIO_MIXER_LEVEL_LEFT] > - mc.un.value.level[AUDIO_MIXER_LEVEL_RIGHT] ? - mc.un.value.level[AUDIO_MIXER_LEVEL_LEFT] : - mc.un.value.level[AUDIO_MIXER_LEVEL_RIGHT]); - else if (mc.type == AUDIO_MIXER_ENUM) - m = mc.un.ord; } } - close(afd); + value = 100; + LIST_FOREACH(c, &controls, next) { + if (c->type == CTRL_MUTE && c->val == 1) + value = 0; + else if (c->type == CTRL_LEVEL) { + v = (c->val * 100 + c->maxval / 2) / c->maxval; + /* For multiple channels return the minimum. */ + if (v < value) + value = v; + } + } - return bprintf("%d", m ? 0 : v * 100 / 255); + return bprintf("%d", value); } #else #include <sys/soundcard.h> diff --git a/config.def.h b/config.def.h index e06be66..8b392cf 100644 --- a/config.def.h +++ b/config.def.h _AT_@ -58,6 +58,7 @@ static const char unknown_str[] = "n/a"; * uptime system uptime NULL * username username of current user NULL * vol_perc OSS/ALSA volume in percent mixer file (/dev/mixer) + * NULL on OpenBSD * wifi_perc WiFi signal in percent interface name (wlan0) * wifi_essid WiFi ESSID interface name (wlan0) */ diff --git a/config.mk b/config.mk index 3b32b7c..d88695c 100644 --- a/config.mk +++ b/config.mk _AT_@ -14,6 +14,7 @@ X11LIB = /usr/X11R6/lib CPPFLAGS = -I$(X11INC) -D_DEFAULT_SOURCE CFLAGS = -std=c99 -pedantic -Wall -Wextra -Os LDFLAGS = -L$(X11LIB) -s +# OpenBSD: add -lsndio LDLIBS = -lX11 # compiler and linker -- 2.26.2Received on Sat May 09 2020 - 12:03:20 CEST
This archive was generated by hypermail 2.3.0 : Sat May 09 2020 - 12:48:33 CEST