summaryrefslogtreecommitdiff
path: root/src/modules/pulse.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/modules/pulse.c')
-rw-r--r--src/modules/pulse.c136
1 files changed, 136 insertions, 0 deletions
diff --git a/src/modules/pulse.c b/src/modules/pulse.c
new file mode 100644
index 0000000..cbbfe35
--- /dev/null
+++ b/src/modules/pulse.c
@@ -0,0 +1,136 @@
+#include "pulse.h"
+
+#include "../signal.h"
+
+#include <pulse/mainloop.h>
+#include <pulse/context.h>
+#include <pulse/introspect.h>
+#include <pulse/volume.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <tgmath.h>
+
+static void
+run_loop(struct pulse * p)
+{
+ p->run_loop = true;
+ while(p->run_loop && signal_running) {
+ pa_mainloop_iterate(p->ml, 1, NULL);
+ }
+}
+
+static void
+stop_loop(struct pulse * p)
+{
+ p->run_loop = false;
+}
+
+static void
+server_info_cb(pa_context * ctx, const pa_server_info * info, void * ud)
+{
+ struct pulse * p = (struct pulse *) ud;
+
+ size_t s = strlen(info->default_sink_name);
+
+ p->default_sink = malloc(s + 1);
+ memset(p->default_sink, '\0', s + 1);
+ strncpy(p->default_sink, info->default_sink_name, s);
+
+ stop_loop(p);
+}
+
+static void
+state_cb(pa_context * ctx, void * ud)
+{
+ pa_context_state_t state = pa_context_get_state(ctx);
+ struct pulse * p = (struct pulse *) ud;
+
+ switch(state) {
+
+ case PA_CONTEXT_READY:
+ pa_context_get_server_info(p->ctx, server_info_cb, p);
+ break;
+ case PA_CONTEXT_FAILED:
+ case PA_CONTEXT_TERMINATED:
+ stop_loop(p);
+ break;
+ default: break;
+
+ }
+}
+
+struct pulse *
+pulse_new()
+{
+ struct pulse * p = malloc(sizeof(struct pulse));
+
+ memset(p->value, '\0', PULSE_VALUE_SIZE);
+
+ p->default_sink = NULL;
+ p->run_loop = false;
+
+ p->ml = pa_mainloop_new();
+ p->ctx = pa_context_new(pa_mainloop_get_api(p->ml), NULL);
+
+ pa_context_set_state_callback(p->ctx, state_cb, p);
+
+ pa_context_connect(p->ctx, NULL, PA_CONTEXT_NOAUTOSPAWN, NULL);
+
+ run_loop(p);
+
+ return p;
+}
+
+void
+pulse_free(struct pulse * p)
+{
+ if(p->default_sink != NULL) free(p->default_sink);
+
+ if(p->ctx->proplist) {
+ pa_proplist_free(p->ctx->proplist);
+ }
+
+ pa_context_disconnect(p->ctx);
+ pa_context_unref(p->ctx);
+ pa_mainloop_free(p->ml);
+
+ free(p);
+}
+
+static void
+sink_info_cb(pa_context * ctx, const pa_sink_info * info, int eol, void * ud)
+{
+ struct pulse * p = (struct pulse *) ud;
+ pa_volume_t vol, norm;
+
+ if(eol > 0) {
+ stop_loop(p);
+ }
+ else {
+ if(info->mute) {
+ strncpy(p->value, "M", PULSE_VALUE_SIZE);
+ }
+ else {
+ vol = pa_cvolume_avg(&info->volume);
+ vol -= PA_VOLUME_MUTED;
+ norm = PA_VOLUME_NORM - PA_VOLUME_MUTED;
+
+ vol = round((100.0f / norm) * vol);
+ snprintf(p->value, PULSE_VALUE_SIZE, "%d%%", vol);
+ }
+ }
+}
+
+void
+pulse_update(struct pulse * p)
+{
+ pa_operation * op;
+
+ if(p->default_sink != NULL) {
+ op = pa_context_get_sink_info_by_name(p->ctx, p->default_sink, sink_info_cb, p);
+ pa_operation_unref(op);
+ run_loop(p);
+ }
+}