summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile21
-rw-r--r--mixnotify.c141
2 files changed, 162 insertions, 0 deletions
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..91e2718
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,21 @@
+CFLAGS = -std=c99 -D_XOPEN_SOURCE=700 -fPIC -g
+LDFLAGS = -lasound
+
+TARGET = mixnotify
+
+OBJS = mixnotify.o
+
+all: $(TARGET)
+
+$(TARGET): $(OBJS)
+ cc ${LDFLAGS} -o $@ $(OBJS)
+
+%.o: %.c
+ cc $(CFLAGS) -MMD -MF $(@:.o=.d) -MT $@ -c -o $@ $<
+
+clean:
+ -rm -f *.o *.d $(TARGET)
+
+-include $(OBJS:.o=.d)
+
+.PHONY: clean
diff --git a/mixnotify.c b/mixnotify.c
new file mode 100644
index 0000000..734ffc0
--- /dev/null
+++ b/mixnotify.c
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2016 Anton Khirnov <anton@khirnov.net>
+ *
+ * mixnotify is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * mixnotify is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with mixnotify. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <alsa/asoundlib.h>
+
+#include <stdio.h>
+#include <string.h>
+
+typedef struct MixerPrivate {
+ snd_mixer_elem_t *elem;
+} MixerPrivate;
+
+static int elem_callback(snd_mixer_elem_t *elem, unsigned int mask)
+{
+ MixerPrivate *s = snd_mixer_elem_get_callback_private(elem);
+ long val, min, max;
+ int ret;
+
+ if (!(mask & SND_CTL_EVENT_MASK_VALUE))
+ return 0;
+
+ ret = snd_mixer_selem_get_playback_volume(elem, SND_MIXER_SCHN_UNKNOWN, &val);
+ if (ret < 0) {
+ fprintf(stderr, "Error getting element volume: %d (%s)\n");
+ return ret;
+ }
+
+ ret = snd_mixer_selem_get_playback_volume_range(elem, &min, &max);
+ if (ret < 0) {
+ fprintf(stderr, "Error getting element volume range: %d (%s)\n",
+ ret, snd_strerror(ret));
+ return ret;
+ }
+
+ fprintf(stdout, "%ld %ld %ld\n", val, min, max);
+ fflush(stdout);
+
+ return 0;
+}
+
+int main(int argc, const char **argv)
+{
+ static const char *ctl_name = "default";
+ static const char *elem_name = "Master";
+
+ MixerPrivate priv = { NULL };
+
+ snd_mixer_t *mixer = NULL;
+ snd_mixer_elem_t *elem;
+ int ret;
+
+ if (argc > 1)
+ ctl_name = argv[1];
+ if (argc > 2)
+ elem_name = argv[2];
+
+ fprintf(stderr, "Using CTL: %s\n", ctl_name);
+ fprintf(stderr, "Using mixer element: %s\n", elem_name);
+
+ ret = snd_mixer_open(&mixer, 0);
+ if (ret < 0) {
+ fprintf(stderr, "Error opening a new mixer: %d (%s)\n",
+ ret, snd_strerror(ret));
+ return -1;
+ }
+
+ ret = snd_mixer_attach(mixer, ctl_name);
+ if (ret < 0) {
+ fprintf(stderr, "Error attachng a HCTL '%s' to the mixer: %d (%s)\n",
+ ctl_name, ret, snd_strerror(ret));
+ ret = -1;
+ goto fail;
+ }
+
+ ret = snd_mixer_selem_register(mixer, NULL, NULL);
+ if (ret < 0) {
+ fprintf(stderr, "Error registering simple element class: %d (%s)\n",
+ ctl_name, ret, snd_strerror(ret));
+ ret = -1;
+ goto fail;
+ }
+
+ ret = snd_mixer_load(mixer);
+ if (ret < 0) {
+ fprintf(stderr, "Error loading mixer elements: %d (%s)\n",
+ ret, snd_strerror(ret));
+ ret = -1;
+ goto fail;
+ }
+
+ for (elem = snd_mixer_first_elem(mixer); elem; elem = snd_mixer_elem_next(elem)) {
+ snd_mixer_elem_type_t type = snd_mixer_elem_get_type(elem);
+
+ if (type == SND_MIXER_ELEM_SIMPLE &&
+ !strcmp(snd_mixer_selem_get_name(elem), elem_name))
+ break;
+ }
+ if (!elem) {
+ fprintf(stderr, "Mixer element '%s' not found\n", elem_name);
+ ret = -1;
+ goto fail;
+ }
+
+ snd_mixer_elem_set_callback_private(elem, &priv);
+ snd_mixer_elem_set_callback(elem, elem_callback);
+
+ while (!(ret = snd_mixer_wait(mixer, -1))) {
+ ret = snd_mixer_handle_events(mixer);
+ if (ret < 0) {
+ fprintf(stderr, "Error handling events: %d (%s)\n",
+ ret, snd_strerror(ret));
+ ret = -1;
+ goto fail;
+ }
+ }
+ if (ret < 0) {
+ fprintf(stderr, "Error waiting for mixer events: %d (%s)\n",
+ ret, snd_strerror(ret));
+ ret = -1;
+ goto fail;
+ }
+
+fail:
+ snd_mixer_close(mixer);
+
+ return ret;
+}