Xinqi Bao's Git

cpu_perc: Check for division by zero
[slstatus.git] / components / volume.c
index ec653a2..61cec90 100644 (file)
 /* See LICENSE file for copyright and license details. */
-#if defined(__linux__)
 #include <fcntl.h>
-#include <sys/soundcard.h>
-#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;
-
-       afd = open(card, O_RDONLY | O_NONBLOCK);
-       if (afd == -1) {
-               fprintf(stderr, "Cannot open %s", card);
-               return NULL;
-       }
+#if defined(__OpenBSD__)
+       #include <sys/audioio.h>
 
-       if (ioctl(afd, SOUND_MIXER_READ_DEVMASK, &devmask) == -1) {
-               fprintf(stderr, "Cannot get volume for %s", card);
-               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) == -1) {
-                               fprintf(stderr, "vol_perc: ioctl");
+       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 ((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;
+
+               if ((afd = open(card, O_RDONLY | O_NONBLOCK)) < 0) {
+                       warn("open '%s':", card);
+                       return NULL;
+               }
 
-       close(afd);
+               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;
+                               }
+                       }
+               }
 
-       return bprintf("%d", v & 0xff);
-}
+               close(afd);
+
+               return bprintf("%d", v & 0xff);
+       }
 #endif