diff options
-rw-r--r-- | Makefile | 12 | ||||
-rw-r--r-- | README.md | 22 | ||||
-rw-r--r-- | main.c | 150 |
3 files changed, 184 insertions, 0 deletions
diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..2edca13 --- /dev/null +++ b/Makefile @@ -0,0 +1,12 @@ +CC=gcc +CFLAGS=-std=gnu99 -Wall -pedantic -Wextra `pkg-config --cflags ${LIBS}` +LIBS=alsa dbus-1 +LDFLAGS=`pkg-config --libs ${LIBS}` + +all: main + +main: main.o + ${CC} ${LDFLAGS} main.o -o alsa-volume-monitor + +main.o: + ${CC} ${CFLAGS} -c main.c diff --git a/README.md b/README.md new file mode 100644 index 0000000..f1bbc4c --- /dev/null +++ b/README.md @@ -0,0 +1,22 @@ +# alsa-volume-monitor + +`alsa-volume-monitor` is a simple program written in C that listens to ALSA events and emits a DBus signal when something has been changed (e.g. volume). + +It was created for use with Awesome WM in volume indicator widgets. + +### Usage +`./alsa-volume-monitor hw:0`, where `hw:0` is the name of your audio card. + +### Catch events from Awesome config + +``` +dbus.request_name("session", "com.ch1p.avm") +dbus.add_match("session", "interface='com.ch1p.avm',member='valueChanged'") +dbus.connect_signal("com.ch1p.avm", function(...) + -- Update your widget here + end +) +``` + +### License +GPLv2 @@ -0,0 +1,150 @@ +/** + * Based on alsactl/monitor.c (by Takashi Iwai <tiwai@suse.de>) from alsa-utils + * http://git.alsa-project.org/?p=alsa-utils.git;a=blob_plain;f=alsactl/monitor.c;hb=HEAD + * + * Inspired by kbdd + */ + +#include <stdio.h> +#include <alsa/asoundlib.h> +#include <dbus/dbus.h> + +int notify(DBusConnection *conn) +{ + DBusMessage *msg; + dbus_uint32_t serial = 0; + + msg = dbus_message_new_signal("/com/ch1p/Object", "com.ch1p.avm", "valueChanged"); + if (NULL == msg) { + fprintf(stderr, "DBus: Message Null\n"); + return 1; + } + + if (!dbus_connection_send(conn, msg, &serial)) { + fprintf(stderr, "DBus send: Out Of Memory!\n"); + return 1; + } + dbus_connection_flush(conn); + + dbus_message_unref(msg); + return 0; +} + +int open_ctl(const char *name, snd_ctl_t **ctlp) +{ + snd_ctl_t *ctl; + int err; + + err = snd_ctl_open(&ctl, name, SND_CTL_READONLY); + if (err < 0) { + fprintf(stderr, "Cannot open ctl %s\n", name); + return err; + } + err = snd_ctl_subscribe_events(ctl, 1); + if (err < 0) { + fprintf(stderr, "Cannot open subscribe events to ctl %s\n", name); + snd_ctl_close(ctl); + return err; + } + *ctlp = ctl; + return 0; +} + +int check_event(snd_ctl_t *ctl, DBusConnection *conn) +{ + snd_ctl_event_t *event; + unsigned int mask; + int err; + + snd_ctl_event_alloca(&event); + err = snd_ctl_read(ctl, event); + if (err < 0) + return err; + + if (snd_ctl_event_get_type(event) != SND_CTL_EVENT_ELEM) + return 0; + + mask = snd_ctl_event_elem_get_mask(event); + if (!(mask & SND_CTL_EVENT_MASK_VALUE)) + return 0; + + notify(conn); + + return 0; +} + +#define MAX_CARDS 256 + +int monitor(const char *name, DBusConnection *conn) { + snd_ctl_t *ctl; + int err = 0; + + err = open_ctl(name, &ctl); + if (err < 0) + goto error; + + while (1) { + struct pollfd fd; + + snd_ctl_poll_descriptors(ctl, &fd, 1); + + err = poll(&fd, 1, -1); + if (err <= 0) { + err = 0; + break; + } + + unsigned short revents; + snd_ctl_poll_descriptors_revents(ctl, &fd, 1, + &revents); + if (revents & POLLIN) + check_event(ctl, conn); + } + +error: + snd_ctl_close(ctl); + return err; +} + +void usage() +{ + fprintf(stderr, + "Usage:\n" + " alsa-volume-monitor <card name>\n\n" + "Example:\n" + " alsa-volume-monitor hw:0\n"); + exit(1); +} + +int main(int argc, char *argv[]) +{ + if (argc < 2) + usage(); + + DBusConnection *connection; + DBusError err; + int ret; + + dbus_error_init(&err); + connection = dbus_bus_get(DBUS_BUS_SESSION, &err); + + if (dbus_error_is_set(&err)) { + fprintf(stderr, "DBus Connection Error (%s)\n", err.message); + dbus_error_free(&err); + } + + if (!connection) { + return 1; + } + + ret = dbus_bus_request_name(connection, "com.ch1p.avm", + DBUS_NAME_FLAG_REPLACE_EXISTING , &err); + if (dbus_error_is_set(&err)) { + fprintf(stderr, "DBus Name Error (%s)\n", err.message); + dbus_error_free(&err); + } + + monitor(argv[1], connection); + + return 0; +} |