-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) {
- warn("Cannot open %s", card);
- return NULL;
+#if defined(__OpenBSD__)
+ #include <sys/queue.h>
+ #include <poll.h>
+ #include <sndio.h>
+ #include <stdlib.h>
+
+ struct control {
+ LIST_ENTRY(control) next;
+ unsigned int addr;
+ #define CTRL_NONE 0
+ #define CTRL_LEVEL 1
+ #define CTRL_MUTE 2
+ unsigned int type;
+ unsigned int maxval;
+ unsigned int val;
+ };
+
+ static LIST_HEAD(, control) controls = LIST_HEAD_INITIALIZER(controls);
+ static struct pollfd *pfds;
+ static struct sioctl_hdl *hdl;
+ static int initialized;
+
+ /*
+ * Call-back to obtain the description of all audio controls.
+ */
+ static void
+ ondesc(void *unused, struct sioctl_desc *desc, int val)
+ {
+ struct control *c, *ctmp;
+ unsigned int type = CTRL_NONE;
+
+ if (desc == NULL)
+ return;
+
+ /* Delete existing audio control with the same address. */
+ LIST_FOREACH_SAFE(c, &controls, next, ctmp) {
+ if (desc->addr == c->addr) {
+ LIST_REMOVE(c, next);
+ free(c);
+ break;
+ }
+ }
+
+ /* Only match output.level and output.mute audio controls. */
+ if (desc->group[0] != 0 ||
+ strcmp(desc->node0.name, "output") != 0)
+ return;
+ if (desc->type == SIOCTL_NUM &&
+ strcmp(desc->func, "level") == 0)
+ type = CTRL_LEVEL;
+ else if (desc->type == SIOCTL_SW &&
+ strcmp(desc->func, "mute") == 0)
+ type = CTRL_MUTE;
+ else
+ return;
+
+ c = malloc(sizeof(struct control));
+ if (c == NULL) {
+ warn("sndio: failed to allocate audio control\n");
+ return;
+ }
+
+ c->addr = desc->addr;
+ c->type = type;
+ c->maxval = desc->maxval;
+ c->val = val;
+ LIST_INSERT_HEAD(&controls, c, next);