From 9f385cbca060ae1990a68307ed84392c3cbeeed1 Mon Sep 17 00:00:00 2001 From: ratchov Date: Mon, 16 Mar 2020 14:54:45 +0000 Subject: [PATCH] Use the new sioctl_open(3) API to display current audio level. Now the programm displays the current sndiod master volume level, which is present on any device and always corresponds to the device programs are playing on. --- x11/i3status/Makefile | 8 +- x11/i3status/patches/patch-Makefile_am | 37 ++++ x11/i3status/patches/patch-Makefile_in | 15 -- x11/i3status/patches/patch-configure_ac | 19 ++ x11/i3status/patches/patch-include_i3status_h | 13 ++ x11/i3status/patches/patch-src_print_volume_c | 144 ++++++++++++++ x11/i3status/patches/patch-src_sndio_c | 176 ++++++++++++++++++ 7 files changed, 394 insertions(+), 18 deletions(-) create mode 100644 x11/i3status/patches/patch-Makefile_am delete mode 100644 x11/i3status/patches/patch-Makefile_in create mode 100644 x11/i3status/patches/patch-configure_ac create mode 100644 x11/i3status/patches/patch-include_i3status_h create mode 100644 x11/i3status/patches/patch-src_print_volume_c create mode 100644 x11/i3status/patches/patch-src_sndio_c diff --git a/x11/i3status/Makefile b/x11/i3status/Makefile index 784265ade4e..979e89b2c48 100644 --- a/x11/i3status/Makefile +++ b/x11/i3status/Makefile @@ -1,11 +1,11 @@ -# $OpenBSD: Makefile,v 1.58 2019/09/27 20:33:22 jasper Exp $ +# $OpenBSD: Makefile,v 1.59 2020/03/16 14:54:45 ratchov Exp $ ONLY_FOR_ARCHS= ${APM_ARCHS} COMMENT= generate a statusbar for use with i3/xmobar/dzen2 DISTNAME= i3status-2.13 -REVISION= 1 +REVISION= 2 CATEGORIES= x11 sysutils HOMEPAGE= https://i3wm.org/i3status/ @@ -28,7 +28,9 @@ BUILD_DEPENDS= textproc/asciidoc>=8.6.8 \ LIB_DEPENDS= devel/libconfuse \ devel/libyajl -CONFIGURE_STYLE = gnu +AUTOCONF_VERSION = 2.69 +AUTOMAKE_VERSION = 1.16 +CONFIGURE_STYLE = autoreconf SEPARATE_BUILD = Yes FAKE_FLAGS += sysconfdir=${PREFIX}/share/examples/i3status/ diff --git a/x11/i3status/patches/patch-Makefile_am b/x11/i3status/patches/patch-Makefile_am new file mode 100644 index 00000000000..3c1b2fbbf96 --- /dev/null +++ b/x11/i3status/patches/patch-Makefile_am @@ -0,0 +1,37 @@ +$OpenBSD: patch-Makefile_am,v 1.1 2020/03/16 14:54:45 ratchov Exp $ + +Index: Makefile.am +--- Makefile.am.orig ++++ Makefile.am +@@ -1,5 +1,3 @@ +-@CODE_COVERAGE_RULES@ +- + echo-version: + @echo "@I3STATUS_VERSION@" + +@@ -30,6 +28,7 @@ i3status_CFLAGS = \ + $(PULSE_CFLAGS) \ + $(NLGENL_CFLAGS) \ + $(ALSA_CFLAGS) \ ++ $(SNDIO_CFLAGS) \ + $(PTHREAD_CFLAGS) + + i3status_CPPFLAGS = \ +@@ -42,6 +41,7 @@ i3status_LDADD = \ + $(PULSE_LIBS) \ + $(NLGENL_LIBS) \ + $(ALSA_LIBS) \ ++ $(SNDIO_LIBS) \ + $(PTHREAD_LIBS) + + i3status_SOURCES = \ +@@ -69,7 +69,8 @@ i3status_SOURCES = \ + src/print_wireless_info.c \ + src/print_file_contents.c \ + src/process_runs.c \ +- src/pulse.c ++ src/pulse.c \ ++ src/sndio.c + + dist_sysconf_DATA = \ + i3status.conf diff --git a/x11/i3status/patches/patch-Makefile_in b/x11/i3status/patches/patch-Makefile_in deleted file mode 100644 index 563e0eb19db..00000000000 --- a/x11/i3status/patches/patch-Makefile_in +++ /dev/null @@ -1,15 +0,0 @@ -$OpenBSD: patch-Makefile_in,v 1.1 2019/07/06 20:20:27 jasper Exp $ - -The CODE_COVERAGE_RULES fragment contains an unmatched "if" clause. - -Index: Makefile.in ---- Makefile.in.orig -+++ Makefile.in -@@ -1851,7 +1851,6 @@ uninstall-man: uninstall-man1 - - .PRECIOUS: Makefile - --@CODE_COVERAGE_RULES@ - - echo-version: - @echo "@I3STATUS_VERSION@" diff --git a/x11/i3status/patches/patch-configure_ac b/x11/i3status/patches/patch-configure_ac new file mode 100644 index 00000000000..f59ab7e3728 --- /dev/null +++ b/x11/i3status/patches/patch-configure_ac @@ -0,0 +1,19 @@ +$OpenBSD: patch-configure_ac,v 1.1 2020/03/16 14:54:45 ratchov Exp $ + +Index: configure.ac +--- configure.ac.orig ++++ configure.ac +@@ -91,6 +91,13 @@ case $host_os in + ;; + esac + ++# if sndio is available, define USE_SNDIO ++AC_CHECK_HEADER(sndio.h, ++ [AC_CHECK_LIB([sndio], [sio_open], [ ++ AC_SUBST(SNDIO_LIBS, "-lsndio") ++ AC_DEFINE([USE_SNDIO], [], [Use sndio]) ++ ], [])], []) ++ + dnl TODO: check for libbsd for GNU/kFreeBSD + + # Checks for programs. diff --git a/x11/i3status/patches/patch-include_i3status_h b/x11/i3status/patches/patch-include_i3status_h new file mode 100644 index 00000000000..8e28bcc7d43 --- /dev/null +++ b/x11/i3status/patches/patch-include_i3status_h @@ -0,0 +1,13 @@ +$OpenBSD: patch-include_i3status_h,v 1.10 2020/03/16 14:54:45 ratchov Exp $ + +Index: include/i3status.h +--- include/i3status.h.orig ++++ include/i3status.h +@@ -232,6 +232,7 @@ int volume_pulseaudio(uint32_t sink_idx, const char *s + bool description_pulseaudio(uint32_t sink_idx, const char *sink_name, char buffer[MAX_SINK_DESCRIPTION_LEN]); + bool pulse_initialize(void); + void print_file_contents(yajl_gen json_gen, char *buffer, const char *title, const char *path, const char *format, const char *format_bad, const int max_chars); ++int volume_sndio(void); + + /* socket file descriptor for general purposes */ + extern int general_socket; diff --git a/x11/i3status/patches/patch-src_print_volume_c b/x11/i3status/patches/patch-src_print_volume_c new file mode 100644 index 00000000000..306ca60839a --- /dev/null +++ b/x11/i3status/patches/patch-src_print_volume_c @@ -0,0 +1,144 @@ +$OpenBSD: patch-src_print_volume_c,v 1.12 2020/03/16 14:54:45 ratchov Exp $ + +Index: src/print_volume.c +--- src/print_volume.c.orig ++++ src/print_volume.c +@@ -21,13 +21,6 @@ + #include + #endif + +-#ifdef __OpenBSD__ +-#include +-#include +-#include +-#include +-#endif +- + #include "i3status.h" + #include "queue.h" + +@@ -145,9 +138,20 @@ void print_volume(yajl_gen json_gen, char *buffer, con + /* negative result or NULL description means error, fail PulseAudio attempt */ + } + /* If some other device was specified or PulseAudio is not detected, +- * proceed to ALSA / OSS */ ++ * proceed to sndio / ALSA / OSS */ + #endif + ++#ifdef USE_SNDIO ++ int vol; ++ ++ vol = volume_sndio(); ++ if (vol != -1) { ++ outwalk = apply_volume_format(fmt, outwalk, vol & 0x7f, "sndio"); ++ goto out; ++ } ++/* If sndio is not detected, proceed to ALSA / OSS */ ++#endif ++ + #ifdef __linux__ + const long MAX_LINEAR_DB_SCALE = 24; + int err; +@@ -248,7 +252,8 @@ void print_volume(yajl_gen json_gen, char *buffer, con + snd_mixer_selem_id_free(sid); + + #endif +-#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) ++ ++#if defined(__FreeBSD__) || defined(__DragonFly__) + char *mixerpath; + char defaultmixer[] = "/dev/mixer"; + int mixfd, vol, devmask = 0; +@@ -261,84 +266,13 @@ void print_volume(yajl_gen json_gen, char *buffer, con + mixerpath = defaultmixer; + + if ((mixfd = open(mixerpath, O_RDWR)) < 0) { +-#if defined(__OpenBSD__) +- warn("audioio: Cannot open mixer"); +-#else + warn("OSS: Cannot open mixer"); +-#endif + goto out; + } + + if (mixer_idx > 0) + free(mixerpath); + +-#if defined(__OpenBSD__) +- int oclass_idx = -1, master_idx = -1, master_mute_idx = -1; +- int master_next = AUDIO_MIXER_LAST; +- mixer_devinfo_t devinfo, devinfo2; +- mixer_ctrl_t vinfo; +- +- devinfo.index = 0; +- while (ioctl(mixfd, AUDIO_MIXER_DEVINFO, &devinfo) >= 0) { +- if (devinfo.type != AUDIO_MIXER_CLASS) { +- devinfo.index++; +- continue; +- } +- if (strncmp(devinfo.label.name, AudioCoutputs, MAX_AUDIO_DEV_LEN) == 0) +- oclass_idx = devinfo.index; +- +- devinfo.index++; +- } +- +- devinfo2.index = 0; +- while (ioctl(mixfd, AUDIO_MIXER_DEVINFO, &devinfo2) >= 0) { +- if ((devinfo2.type == AUDIO_MIXER_VALUE) && (devinfo2.mixer_class == oclass_idx) && (strncmp(devinfo2.label.name, AudioNmaster, MAX_AUDIO_DEV_LEN) == 0)) { +- master_idx = devinfo2.index; +- master_next = devinfo2.next; +- } +- +- if ((devinfo2.type == AUDIO_MIXER_ENUM) && (devinfo2.mixer_class == oclass_idx) && (strncmp(devinfo2.label.name, AudioNmute, MAX_AUDIO_DEV_LEN) == 0)) +- if (master_next == devinfo2.index) +- master_mute_idx = devinfo2.index; +- +- if (master_next != AUDIO_MIXER_LAST) +- master_next = devinfo2.next; +- devinfo2.index++; +- } +- +- if (master_idx == -1) +- goto out; +- +- devinfo.index = master_idx; +- if (ioctl(mixfd, AUDIO_MIXER_DEVINFO, &devinfo) == -1) +- goto out; +- +- vinfo.dev = master_idx; +- vinfo.type = AUDIO_MIXER_VALUE; +- vinfo.un.value.num_channels = devinfo.un.v.num_channels; +- if (ioctl(mixfd, AUDIO_MIXER_READ, &vinfo) == -1) +- goto out; +- +- if (AUDIO_MAX_GAIN != 100) { +- float avgf = ((float)vinfo.un.value.level[AUDIO_MIXER_LEVEL_MONO] / AUDIO_MAX_GAIN) * 100; +- vol = (int)avgf; +- vol = (avgf - vol < 0.5 ? vol : (vol + 1)); +- } else { +- vol = (int)vinfo.un.value.level[AUDIO_MIXER_LEVEL_MONO]; +- } +- +- vinfo.dev = master_mute_idx; +- vinfo.type = AUDIO_MIXER_ENUM; +- if (ioctl(mixfd, AUDIO_MIXER_READ, &vinfo) == -1) +- goto out; +- +- if (master_mute_idx != -1 && vinfo.un.ord) { +- START_COLOR("color_degraded"); +- fmt = fmt_muted; +- pbval = 0; +- } +- +-#else + if (ioctl(mixfd, SOUND_MIXER_READ_DEVMASK, &devmask) == -1) { + warn("OSS: Cannot read mixer information"); + goto out; +@@ -353,7 +287,6 @@ void print_volume(yajl_gen json_gen, char *buffer, con + pbval = 0; + } + +-#endif + outwalk = apply_volume_format(fmt, outwalk, vol & 0x7f, devicename); + close(mixfd); + #endif diff --git a/x11/i3status/patches/patch-src_sndio_c b/x11/i3status/patches/patch-src_sndio_c new file mode 100644 index 00000000000..2bd21f74238 --- /dev/null +++ b/x11/i3status/patches/patch-src_sndio_c @@ -0,0 +1,176 @@ +$OpenBSD: patch-src_sndio_c,v 1.1 2020/03/16 14:54:45 ratchov Exp $ + +Add sndio volume backend. + +Index: src/sndio.c +--- src/sndio.c.orig ++++ src/sndio.c +@@ -0,0 +1,168 @@ ++#include ++#include ++#include ++#include ++#include ++#include "i3status.h" ++ ++struct control { ++ struct control *next; ++ unsigned int addr; ++ unsigned int max; ++ unsigned int value; ++}; ++ ++static int initialized; ++static struct sioctl_hdl *hdl; ++static struct control *controls; ++static struct pollfd *pfds; ++ ++/* ++ * new control registered or control changed ++ */ ++static void ondesc(void *unused, struct sioctl_desc *d, int val) ++{ ++ struct control *i, **pi; ++ ++ if (d == NULL) ++ return; ++ ++ /* ++ * delete existing control with the same address ++ */ ++ for (pi = &controls; (i = *pi) != NULL; pi = &i->next) { ++ if (d->addr == i->addr) { ++ *pi = i->next; ++ free(i); ++ break; ++ } ++ } ++ ++ /* ++ * we're interested in top-level output.level controls only ++ */ ++ if (d->type != SIOCTL_NUM || ++ d->group[0] != 0 || ++ strcmp(d->node0.name, "output") != 0 || ++ strcmp(d->func, "level") != 0) ++ return; ++ ++ i = malloc(sizeof(struct control)); ++ if (i == NULL) { ++ fprintf(stderr, "sndio: failed to allocate control\n"); ++ return; ++ } ++ ++ i->addr = d->addr; ++ i->max = d->maxval; ++ i->value = val; ++ i->next = controls; ++ controls = i; ++} ++ ++/* ++ * control value changed ++ */ ++static void onval(void *unused, unsigned int addr, unsigned int value) ++{ ++ struct control *c; ++ ++ for (c = controls; ; c = c->next) { ++ if (c == NULL) ++ return; ++ if (c->addr == addr) ++ break; ++ } ++ ++ c->value = value; ++} ++ ++static void cleanup(void) ++{ ++ struct control *c; ++ ++ if (hdl) { ++ sioctl_close(hdl); ++ hdl = NULL; ++ } ++ if (pfds) { ++ free(pfds); ++ pfds = NULL; ++ } ++ while ((c = controls) != NULL) { ++ controls = c->next; ++ free(c); ++ } ++} ++ ++static int init(void) ++{ ++ /* open device */ ++ hdl = sioctl_open(SIO_DEVANY, SIOCTL_READ, 0); ++ if (hdl == NULL) { ++ fprintf(stderr, "sndio: cannot open device\n"); ++ goto failed; ++ } ++ ++ /* register call-back for control description changes */ ++ if (!sioctl_ondesc(hdl, ondesc, NULL)) { ++ fprintf(stderr, "sndio: cannot get description\n"); ++ goto failed; ++ } ++ ++ /* register call-back for volume changes */ ++ if (!sioctl_onval(hdl, onval, NULL)) { ++ fprintf(stderr, "sndio: cannot get values\n"); ++ goto failed; ++ } ++ ++ /* allocate structures for poll() syscall */ ++ pfds = calloc(sioctl_nfds(hdl), sizeof(struct pollfd)); ++ if (pfds == NULL) { ++ fprintf(stderr, "sndio: cannot allocate pollfd structures\n"); ++ goto failed; ++ } ++ return 1; ++failed: ++ cleanup(); ++ return 0; ++} ++ ++int volume_sndio(void) ++{ ++ struct control *c; ++ int n, v, value; ++ ++ if (!initialized) { ++ initialized = 1; ++ init(); ++ } ++ if (hdl == NULL) ++ return -1; ++ ++ /* check if controls changed */ ++ n = sioctl_pollfd(hdl, pfds, POLLIN); ++ if (n > 0) { ++ n = poll(pfds, n, 0); ++ if (n > 0) { ++ if (sioctl_revents(hdl, pfds) & POLLHUP) { ++ fprintf(stderr, "sndio: disconnected\n"); ++ cleanup(); ++ return -1; ++ } ++ } ++ } ++ ++ /* ++ * get control value: as there may be multiple ++ * channels, return the minimum ++ */ ++ value = 100; ++ for (c = controls; c != NULL; c = c->next) { ++ v = (c->value * 100 + c->max / 2) / c->max; ++ if (v < value) ++ value = v; ++ } ++ ++ return value; ++}