diff options
Diffstat (limited to 'src/modules/pulse.c')
| -rw-r--r-- | src/modules/pulse.c | 136 |
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); + } +} |
