This diff makes gqmpeg use sndio to display and control the volume. This fixes the crash when the volume slider is touched. As a side effect, this makes gqmpeg use the right device (one that's playing) and nicely updates the slider position when other programs change the master volume.
OK? Index: Makefile =================================================================== RCS file: /cvs/ports/audio/gqmpeg/Makefile,v retrieving revision 1.64 diff -u -p -r1.64 Makefile --- Makefile 12 Jul 2019 20:43:33 -0000 1.64 +++ Makefile 8 Mar 2020 15:39:53 -0000 @@ -3,7 +3,7 @@ COMMENT= front-end to various audio players DISTNAME= gqmpeg-0.91.1 -REVISION= 14 +REVISION= 15 CATEGORIES= audio HOMEPAGE= http://gqmpeg.sourceforge.net/ Index: patches/patch-src_Makefile_in =================================================================== RCS file: patches/patch-src_Makefile_in diff -N patches/patch-src_Makefile_in --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ patches/patch-src_Makefile_in 8 Mar 2020 15:39:53 -0000 @@ -0,0 +1,14 @@ +$OpenBSD$ + +Index: src/Makefile.in +--- src/Makefile.in.orig ++++ src/Makefile.in +@@ -342,7 +342,7 @@ gqmpeg_SOURCES = \ + $(module_mpg123) $(module_xmp) $(module_ogg123) $(module_radio) + + +-gqmpeg_LDADD = $(GTK_LIBS) $(LIBPNG) ++gqmpeg_LDADD = $(GTK_LIBS) $(LIBPNG) -lsndio + + EXTRA_DIST = \ + $(extra_SLIK) \ Index: patches/patch-src_mixer_c =================================================================== RCS file: /cvs/ports/audio/gqmpeg/patches/patch-src_mixer_c,v retrieving revision 1.2 diff -u -p -r1.2 patch-src_mixer_c --- patches/patch-src_mixer_c 14 Oct 2007 14:12:42 -0000 1.2 +++ patches/patch-src_mixer_c 8 Mar 2020 15:39:53 -0000 @@ -1,39 +1,288 @@ $OpenBSD: patch-src_mixer_c,v 1.2 2007/10/14 14:12:42 jasper Exp $ ---- src/mixer.c.orig Tue Sep 10 16:16:26 2002 -+++ src/mixer.c Sun Oct 14 15:47:27 2007 -@@ -285,7 +285,11 @@ void mixer_init(gint init_device_id) - - mixer_device = getenv("MIXERDEVICE"); - if (mixer_device == NULL) -+#ifdef __OpenBSD__ -+ mixer_device = "/dev/mixer"; -+#else - mixer_device = "/dev/mixer0"; -+#endif +Index: src/mixer.c +--- src/mixer.c.orig ++++ src/mixer.c +@@ -39,10 +39,16 @@ + #include <sys/soundcard.h> + #endif - if ((fd = open(mixer_device, O_RDWR)) == -1) { - perror(mixer_device); -@@ -362,7 +366,11 @@ static void mixer_set_vol(DeviceData *device, gint vol - - mixer_device = getenv("MIXERDEVICE"); - if (mixer_device == NULL) -+#ifdef __OpenBSD__ -+ mixer_device = "/dev/mixer"; -+#else - mixer_device = "/dev/mixer0"; -+#endif +-#if defined(__NetBSD__) || defined(__OpenBSD__) ++#if defined(__NetBSD__) + #include <sys/audioio.h> + #endif - if ((fd = open(mixer_device, O_RDWR)) == -1) { - perror(mixer_device); -@@ -406,7 +414,11 @@ static gint mixer_get_vol(DeviceData *device) - - mixer_device = getenv("MIXERDEVICE"); - if (mixer_device == NULL) -+#ifdef __OpenBSD__ -+ mixer_device = "/dev/mixer"; -+#else - mixer_device = "/dev/mixer0"; ++#if defined(__OpenBSD__) ++#include <poll.h> ++#include <sndio.h> ++#include "display.h" +#endif ++ + #if defined(sun) && defined(__svr4__) + #include <sys/audioio.h> + #endif +@@ -267,11 +273,11 @@ static gint mixer_get_vol(DeviceData *device) + + /* + *-------------------------------------------------------------------- +- * NetBSD and OpenBSD ++ * NetBSD + *-------------------------------------------------------------------- + */ + +-#elif defined(__NetBSD__) || defined(__OpenBSD__) ++#elif defined(__NetBSD__) + + mixer_devinfo_t *infos; + mixer_ctrl_t *values; +@@ -442,6 +448,242 @@ static gint mixer_get_vol(DeviceData *device) + + /* + *-------------------------------------------------------------------- ++ * OpenBSD ++ *-------------------------------------------------------------------- ++ */ ++ ++#elif defined(__OpenBSD__) ++ ++struct control { ++ struct control *next; ++ unsigned int addr; ++ unsigned int max, value; ++}; ++ ++static struct control *controls; ++static struct sioctl_hdl *hdl; ++static struct pollfd *pfds; ++static int initialized; ++ ++/* ++ * new control registered ++ */ ++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; ++ } ++ } ++ ++ /* ++ * SIOCTL_NONE means control was deleted from the device ++ */ ++ if (d->type == SIOCTL_NONE) ++ return; ++ ++ /* ++ * we're interested in top-level output.level controls only ++ */ ++ if (d->group[0] != 0 || ++ strcmp(d->node0.name, "output") != 0 || ++ strcmp(d->func, "level") != 0) ++ return; ++ ++ i = malloc(sizeof(struct control)); ++ if (i == NULL) { ++ perror("malloc"); ++ return; ++ } ++ ++ i->addr = d->addr; ++ i->max = d->maxval; ++ i->value = val; ++ i->next = controls; ++ controls = i; ++ ++ if (debug_mode) ++ fprintf(stderr, "found output.level at %d\n", i->addr); ++} ++ ++/* ++ * control value changed ++ */ ++static void onval(void *unused, unsigned int addr, unsigned int value) ++{ ++ struct control *c; ++ ++ if (debug_mode) ++ fprintf(stderr, "control %d changed to %d\n", addr, value); ++ ++ for (c = controls; ; c = c->next) { ++ if (c == NULL) ++ return; ++ if (c->addr == addr) ++ break; ++ } ++ ++ c->value = value; ++ ++ if (debug_mode) ++ fprintf(stderr, "refreshing\n"); ++ display_set_volume(); ++} ++ ++/* ++ * Call poll(2), for both gtk and sndio descriptors. ++ */ ++int ++do_poll(GPollFD *gtk_pfds, guint gtk_nfds, gint timeout) ++{ ++#define MAXFDS 64 ++ struct pollfd pfds[MAXFDS], *sioctl_pfds; ++ unsigned int sioctl_nfds; ++ unsigned int i; ++ int revents; ++ int rc; ++ ++ for (i = 0; i < gtk_nfds; i++) { ++ pfds[i].fd = gtk_pfds[i].fd; ++ pfds[i].events = gtk_pfds[i].events; ++ } ++ if (hdl != NULL) { ++ sioctl_pfds = pfds + gtk_nfds; ++ sioctl_nfds = sioctl_pollfd(hdl, sioctl_pfds, POLLIN); ++ } else ++ sioctl_nfds = 0; ++ ++ rc = poll(pfds, gtk_nfds + sioctl_nfds, timeout); ++ if (rc > 0 && hdl != NULL) { ++ revents = sioctl_revents(hdl, sioctl_pfds); ++ if (revents & POLLHUP) { ++ fprintf(stderr, "Device disconnected\n"); ++ sioctl_close(hdl); ++ hdl = NULL; ++ } ++ } ++ ++ for (i = 0; i < gtk_nfds; i++) ++ gtk_pfds[i].revents = pfds[i].revents; ++ ++ return rc; ++} ++ ++void mixer_init(gint init_device_id) ++{ ++ if (debug_mode) ++ fprintf(stderr, "mixer, initializing...\n"); ++ ++ if (initialized) { ++ fprintf(stderr, "mixer, already initialized\n"); ++ return; ++ } ++ ++ initialized = 1; ++ ++ hdl = sioctl_open(SIO_DEVANY, SIOCTL_READ | SIOCTL_WRITE, 0); ++ if (hdl == NULL) { ++ fprintf(stderr, "Cannot open audio control device\n"); ++ mixer_enabled = FALSE; ++ return; ++ } ++ if (!sioctl_ondesc(hdl, ondesc, NULL)) { ++ sioctl_close(hdl); ++ fprintf(stderr, "Cannot get mixer information\n"); ++ mixer_enabled = FALSE; ++ return; ++ } ++ ++ /* register call-back for external volume changes */ ++ if (!sioctl_onval(hdl, onval, NULL)) { ++ sioctl_close(hdl); ++ fprintf(stderr, "Cannot get mixer values\n"); ++ mixer_enabled = FALSE; ++ return; ++ } ++ ++ pfds = malloc(sizeof(struct pollfd) * sioctl_nfds(hdl)); ++ if (pfds == NULL) { ++ sioctl_close(hdl); ++ fprintf(stderr, "Cannot allocate pollfd structures\n"); ++ mixer_enabled = FALSE; ++ return; ++ } ++ ++ if (controls != NULL) { ++ DeviceData *device = g_new0(DeviceData, 1); ++ device->device_id = 0; ++ device->device_name = "output.level"; ++ device->stereo = (controls->next != NULL); ++ device->recordable = 0; ++ device_list = g_list_append(device_list, device); ++ current_device = device_list->data; ++ current_vol = mixer_get_vol(current_device); ++ mixer_enabled = TRUE; ++ } else ++ mixer_enabled = FALSE; ++ ++ if (debug_mode) ++ fprintf(stderr, "setting gtk poll function\n"); ++ g_main_context_set_poll_func(g_main_context_default(), do_poll); ++ ++} ++ ++static void mixer_poll(void) ++{ ++ int n, nfds; ++ ++ nfds = sioctl_pollfd(hdl, pfds, 0); ++ if (nfds > 0) { ++ n = poll(pfds, nfds, 0); ++ if (n >= 0) ++ sioctl_revents(hdl, pfds); ++ } ++} ++ ++static void mixer_set_vol(DeviceData *device, gint vol) ++{ ++ struct control *c; ++ ++ if (hdl == NULL) ++ return; ++ ++ for (c = controls; c != NULL; c = c->next) { ++ sioctl_setval(hdl, c->addr, (vol * c->max + 50) / 100); ++ if (debug_mode) ++ fprintf(stderr, "setting %d to %d%%\n", c->addr, vol); ++ } ++} ++ ++static gint mixer_get_vol(DeviceData *device) ++{ ++ struct control *c; ++ int vol, minvol = 100; ++ ++ for (c = controls; c != NULL; c = c->next) { ++ vol = (c->value * 100 + c->max / 2) / c->max; ++ if (vol < minvol) ++ minvol = vol; ++ } ++ ++ if (debug_mode) ++ fprintf(stderr, "get volume: %d\n", minvol); ++ ++ return minvol; ++} ++ ++/* ++ *-------------------------------------------------------------------- + * Sun (svr4) + *-------------------------------------------------------------------- + */ +@@ -1266,7 +1508,7 @@ gint get_volume(void) + * but some platforms did not have it update the volume (mixer_get_vol), + * and I am not going to mess with it. + */ +-#if defined (linux) || defined (__FreeBSD__) ++#if defined (linux) || defined (__FreeBSD__) || defined (__OpenBSD__) + current_vol = mixer_get_vol(current_device); + #endif - if ((fd = open(mixer_device, O_RDWR)) == -1) { - perror(mixer_device);