Introduction
Introduction Statistics Contact Development Disclaimer Help
Use the sioctl_open(3) OpenBSD API to access vol - slstatus - status monitor
git clone git://git.suckless.org/slstatus
Log
Files
Refs
README
LICENSE
---
commit 9ac721c23fb640de2a6d1f84c84a79b2ccc26691
parent aaf279f6ddfb48146fc1a579efd83a55722910b5
Author: Ingo Feinerer <[email protected]>
Date: Sat, 9 May 2020 12:03:20 +0200
Use the sioctl_open(3) OpenBSD API to access vol
Starting with OpenBSD 6.7 regular users cannot access raw audio devices
anymore, for improved security.
Instead use the sioctl_open(3) API to access and manipulate audio
controls exposed by sndiod(8). On the first call a permanent connection
is established with the running sndiod daemon, and call-back functions
are registered which are triggered when audio controls are changed
(e.g., a USB headset is attached) or when the volume is modified. On
subsequent calls we poll for changes; if there are no volume changes
this costs virtually nothing.
Joint work with Alexandre Ratchov
Diffstat:
M components/volume.c | 210 +++++++++++++++++++++++------…
M config.def.h | 1 +
M config.mk | 1 +
3 files changed, 161 insertions(+), 51 deletions(-)
---
diff --git a/components/volume.c b/components/volume.c
@@ -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_LEVE…
- (mc.un.value.level[AUDIO_MIXER_LEV…
- mc.un.value.level[AUDIO_MIXER_LEV…
- mc.un.value.level[AUDIO_MIXER_LEV…
- mc.un.value.level[AUDIO_MIXER_LEV…
- 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
@@ -59,6 +59,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
@@ -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
You are viewing proxied material from suckless.org. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.