X-Git-Url: https://git.xinqibao.xyz/slstatus.git/blobdiff_plain/ee5ec756218c852385c5ba5ef0f75b47ba59ec39..10bdf01b715dcc994f3fe32a6881d5e0b2613a6c:/components/volume.c?ds=inline

diff --git a/components/volume.c b/components/volume.c
index b2ffb40..61cec90 100644
--- a/components/volume.c
+++ b/components/volume.c
@@ -1,48 +1,109 @@
 /* See LICENSE file for copyright and license details. */
-#include <errno.h>
 #include <fcntl.h>
-#if defined(__OpenBSD__)
-# include <soundcard.h>
-#else
-# include <sys/soundcard.h>
-#endif
-#include <sys/ioctl.h>
 #include <stdio.h>
 #include <string.h>
+#include <sys/ioctl.h>
 #include <unistd.h>
 
 #include "../util.h"
 
-const char *
-vol_perc(const char *card)
-{
-	unsigned int 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) {
-		fprintf(stderr, "open '%s': %s\n", card, strerror(errno));
-		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) {
-		fprintf(stderr, "ioctl 'SOUND_MIXER_READ_DEVMASK': %s\n",
-		        strerror(errno));
-		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) {
-				fprintf(stderr, "ioctl 'MIXER_READ(%d)': %s\n", i,
-				        strerror(errno));
+		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