From c1dc896c806693a4a368abf59e6890d32d520074 Mon Sep 17 00:00:00 2001
From: Ingo Feinerer <feinerer@logic.at>
Date: Fri, 8 Feb 2019 15:37:17 +0100
Subject: Add native OpenBSD support for mute/volume

Based on functionality in dstat by Joerg Jung.
---
 components/volume.c | 118 ++++++++++++++++++++++++++++++++++++++++------------
 1 file changed, 91 insertions(+), 27 deletions(-)

(limited to 'components')

diff --git a/components/volume.c b/components/volume.c
index 8a70b20..61cec90 100644
--- a/components/volume.c
+++ b/components/volume.c
@@ -2,44 +2,108 @@
 #include <fcntl.h>
 #include <stdio.h>
 #include <string.h>
-#if defined(__OpenBSD__)
-	#include <soundcard.h>
-#else
-	#include <sys/soundcard.h>
-#endif
 #include <sys/ioctl.h>
 #include <unistd.h>
 
 #include "../util.h"
 
-const char *
-vol_perc(const char *card)
-{
-	size_t i;
-	int v, afd, devmask;
-	char *vnames[] = SOUND_DEVICE_NAMES;
+#if defined(__OpenBSD__)
+	#include <sys/audioio.h>
 
-	if ((afd = open(card, O_RDONLY | O_NONBLOCK)) < 0) {
-		warn("open '%s':", card);
-		return NULL;
-	}
+	const char *
+	vol_perc(const char *card)
+	{
+		static int cls = -1;
+		mixer_devinfo_t mdi;
+		mixer_ctrl_t mc;
+		int afd = -1, m = -1, v = -1;
 
-	if (ioctl(afd, (int)SOUND_MIXER_READ_DEVMASK, &devmask) < 0) {
-		warn("ioctl 'SOUND_MIXER_READ_DEVMASK':");
-		close(afd);
-		return NULL;
-	}
-	for (i = 0; i < LEN(vnames); i++) {
-		if (devmask & (1 << i) && !strcmp("vol", vnames[i])) {
-			if (ioctl(afd, MIXER_READ(i), &v) < 0) {
-				warn("ioctl 'MIXER_READ(%ld)':", i);
+		if ((afd = open(card, O_RDONLY)) < 0) {
+			warn("open '%s':", card);
+			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);
+					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);
+
+		return bprintf("%d", m ? 0 : v * 100 / 255);
 	}
+#else
+	#include <sys/soundcard.h>
+
+	const char *
+	vol_perc(const char *card)
+	{
+		size_t i;
+		int v, afd, devmask;
+		char *vnames[] = SOUND_DEVICE_NAMES;
 
-	close(afd);
+		if ((afd = open(card, O_RDONLY | O_NONBLOCK)) < 0) {
+			warn("open '%s':", card);
+			return NULL;
+		}
 
-	return bprintf("%d", v & 0xff);
-}
+		if (ioctl(afd, (int)SOUND_MIXER_READ_DEVMASK, &devmask) < 0) {
+			warn("ioctl 'SOUND_MIXER_READ_DEVMASK':");
+			close(afd);
+			return NULL;
+		}
+		for (i = 0; i < LEN(vnames); i++) {
+			if (devmask & (1 << i) && !strcmp("vol", vnames[i])) {
+				if (ioctl(afd, MIXER_READ(i), &v) < 0) {
+					warn("ioctl 'MIXER_READ(%ld)':", i);
+					close(afd);
+					return NULL;
+				}
+			}
+		}
+
+		close(afd);
+
+		return bprintf("%d", v & 0xff);
+	}
+#endif
-- 
cgit v1.2.3