tApply upstream patch by Lucas for sndio support on OpenBSD - spoon - dwm status utility (2f30 fork)
 (HTM) git clone git://src.adamsgaard.dk/spoon
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) LICENSE
       ---
 (DIR) commit bd47937068b0c19f7eea595f41b4acba720bd8b8
 (DIR) parent 3c6eedee86ba611a19953902f16f2c2cdddd400f
 (HTM) Author: Anders Damsgaard <anders@adamsgaard.dk>
       Date:   Sat, 23 May 2020 07:31:54 +0200
       
       Apply upstream patch by Lucas for sndio support on OpenBSD
       
       Diffstat:
         M Makefile                            |      18 +++++++++++++++---
         M mix.c                               |     178 +++++++++++++++++++++++--------
       
       2 files changed, 147 insertions(+), 49 deletions(-)
       ---
 (DIR) diff --git a/Makefile b/Makefile
       t@@ -8,16 +8,28 @@ OBJ = spoon.o batt.o wifi.o cpu.o count.o temp.o date.o load.o file.o key.o\
        BIN = spoon
        DISTFILES = $(SRC) arg.h types.h util.h config.def.h Makefile LICENSE configure
        
       -#include config.mk
       +include config.mk
        
       -CPPFLAGS = -I/usr/X11R6/include -I/usr/local/include
       -LDFLAGS = -L/usr/X11R6/lib -L/usr/local/lib
       +CPPFLAGS_OpenBSD = -I/usr/X11R6/include -I/usr/local/include
       +LDFLAGS_OpenBSD = -L/usr/X11R6/lib -L/usr/local/lib
       +CPPFLAGS_Linux = -I/usr/local/include
       +CPPFLAGS = $(CPPFLAGS_$(UNAME))
       +LDFLAGS = $(LDFLAGS_$(UNAME))
        LDLIBS = -lX11
        
       +
        # To remove extra compile time dependencies for unwanted plugins
        # comment out the following sections.  The stub implementations
        # from stub.c will be used instead.
        OBJ += mix.o
       +LDLIBS_OpenBSD_mix = -lsndio
       +# if ALSA
       +LDLIBS_Linux_mix = -lasound
       +CPPFLAGS += -DUSE_TINYALSA=0
       +# else TinyALSA
       +#LDLIBS_Linux_mix = -ltinyalsa
       +#CPPFLAGS += -DUSE_TINYALSA=1
       +LDLIBS += $(LDLIBS_$(UNAME)_mix)
        
        OBJ += xkblayout.o
        LDLIBS += -lxkbfile
 (DIR) diff --git a/mix.c b/mix.c
       t@@ -4,67 +4,153 @@
        #include "util.h"
        
        #ifdef __OpenBSD__
       -#include <sys/ioctl.h>
       -#include <sys/audioio.h>
       -
       -#include <fcntl.h>
       +#include <errno.h>
       +#include <poll.h>
       +#include <sndio.h>
       +#include <stdlib.h>
        #include <string.h>
       -#include <unistd.h>
        
       -int
       -mixread(void *arg, char *buf, size_t len)
       +#define MAX_CHANNELS 16
       +
       +static struct sioctl_hdl *hdl = NULL;
       +static struct pollfd *pfds = NULL;
       +
       +static struct {
       +        unsigned int addr;
       +        int val;
       +} channel[MAX_CHANNELS];
       +static size_t nchannels = 0;
       +
       +static int
       +get_output(void)
        {
       -        mixer_devinfo_t dinfo;
       -        mixer_ctrl_t mctl;
       -        int fd, master, ret = 0, i = -1;
       +        size_t i;
       +        int val;
        
       -        fd = open("/dev/mixer", O_RDONLY);
       -        if (fd == -1) {
       -                warn("open %s", "/dev/mixer");
       -                return -1;
       +        if (nchannels == 0)
       +                return 0;
       +
       +        val = 0;
       +        for (i = 0; i < nchannels; i++)
       +                val += channel[i].val;
       +        return 100 * ((val / (double)nchannels) / 255.0);
       +}
       +
       +static void
       +ondesc(void *arg, struct sioctl_desc *desc, int val)
       +{
       +        size_t i;
       +
       +        if (desc == NULL)
       +                return;
       +
       +        if (desc->type != SIOCTL_NUM ||
       +            strcmp(desc->func, "level") != 0 ||
       +            strcmp(desc->node0.name, "output") != 0)
       +                return;
       +
       +        for (i = 0; i < nchannels; i++)
       +                if (channel[i].addr == desc->addr)
       +                        break;
       +
       +        if (i < nchannels) {
       +                channel[i].val = val;
       +                return;
                }
       -        dinfo.index = 0;
       -        /* outputs */
       -        for (; ; dinfo.index++) {
       -                ret = ioctl(fd, AUDIO_MIXER_DEVINFO, &dinfo);
       -                if (ret == -1) {
       -                        warn("AUDIO_MIXER_DEVINFO %s", "/dev/mixer");
       -                        goto out;
       -                }
       -                if (dinfo.type == AUDIO_MIXER_CLASS &&
       -                    strcmp(dinfo.label.name, AudioCoutputs) == 0) {
       -                        i = dinfo.index;
       +
       +        if (nchannels >= MAX_CHANNELS) {
       +                warnx("too many channels");
       +                return;
       +        }
       +        channel[i].addr = desc->addr;
       +        channel[i].val = val;
       +        nchannels++;
       +}
       +
       +static void
       +onval(void *arg, unsigned int addr, unsigned int val)
       +{
       +        size_t i;
       +
       +        for (i = 0; i < nchannels; i++)
       +                if (channel[i].addr == addr) {
       +                        channel[i].val = val;
                                break;
                        }
       +}
       +
       +static int
       +do_init(void)
       +{
       +        hdl = sioctl_open(SIO_DEVANY, SIOCTL_READ, 0);
       +        if (hdl == NULL) {
       +                warnx("sioctl_open %s", SIO_DEVANY);
       +                return 0;
                }
       -        if (i == -1) {
       -                warnx("no outputs mixer class: %s", "/dev/mixer");
       -                goto out;
       +        if (!sioctl_ondesc(hdl, ondesc, NULL)) {
       +                warnx("sioctl_ondesc");
       +                sioctl_close(hdl);
       +                return 0;
                }
       -        /* outputs.master */
       -        for (; ; dinfo.index++) {
       -                ret = ioctl(fd, AUDIO_MIXER_DEVINFO, &dinfo);
       -                if (ret == -1) {
       -                        warn("AUDIO_MIXER_DEVINFO %s", "/dev/mixer");
       +        sioctl_onval(hdl, onval, NULL);
       +
       +        return 1;
       +}
       +
       +static int
       +poll_peek(void)
       +{
       +        int nfds, revents;
       +
       +        if (pfds == NULL) {
       +                pfds = malloc(sizeof(struct pollfd) * sioctl_nfds(hdl));
       +                if (pfds == NULL) {
       +                        warnx("out of memory");
                                goto out;
                        }
       -                if (dinfo.type == AUDIO_MIXER_VALUE &&
       -                    dinfo.prev == AUDIO_MIXER_LAST &&
       -                    dinfo.mixer_class == i &&
       -                    strcmp(dinfo.label.name, AudioNmaster) == 0)
       -                        break;
                }
       -        mctl.dev = dinfo.index;
       -        ret = ioctl(fd, AUDIO_MIXER_READ, &mctl);
       -        if (ret == -1) {
       -                warn("AUDIO_MIXER_READ %s", "/dev/mixer");
       +
       +        nfds = sioctl_pollfd(hdl, pfds, POLLIN);
       +        if (nfds == 0)
       +                return 1;
       +        while (poll(pfds, nfds, 0) == -1)
       +                if (errno != EINTR) {
       +                        warn("sioctl poll");
       +                        goto out;
       +                }
       +        revents = sioctl_revents(hdl, pfds);
       +        if (revents & POLLHUP) {
       +                warnx("sioctl disconnected");
                        goto out;
                }
       -        master = mctl.un.value.level[0] * 100 / 255;
       -        snprintf(buf, len, "%d%%", master);
       +
       +        return 1;
       +
        out:
       -        close(fd);
       -        return ret;
       +        free(pfds);
       +        pfds = NULL;
       +        sioctl_close(hdl);
       +
       +        return 0;
       +}
       +
       +int
       +mixread(void *arg, char *buf, size_t len)
       +{
       +        static int init_done = 0;
       +        struct pollfd *pfds;
       +        int nfds;
       +
       +        if (!init_done) {
       +                if (!do_init())
       +                        return -1;
       +                init_done = 1;
       +        }
       +
       +        init_done = poll_peek();
       +        snprintf(buf, len, "%d%%", get_output());
       +
       +        return 0;
        }
        #elif __linux__ && !USE_TINYALSA
        #include <alsa/asoundlib.h>