#include "pulse-listener.h" #include #include #include #include #include #include #define ERROR(...) fprintf(stderr, "error: " __VA_ARGS__) #ifdef __OpenBSD__ #define SIGMAX (SIGUSR2 - 1) #define SIGMIN (SIGUSR1 - 1) #else #define SIGMAX SIGRTMAX #define SIGMIN SIGRTMIN #endif static void sink_info_callback(pa_context *ctx, const pa_sink_info *info, int eol, pthread_t *main_thread) { pthread_kill(*main_thread, SIGMIN + 1); } static void server_info_callback(pa_context *ctx, const pa_server_info *info, pthread_t *main_thread) { pa_operation *op = pa_context_get_sink_info_by_name( ctx, info->default_sink_name, (pa_sink_info_cb_t) sink_info_callback, main_thread); pa_operation_unref(op); } static void subscribe_callback(pa_context *ctx, pa_subscription_event_type_t type, uint32_t idx, pthread_t *main_thread) { if ((type & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SINK) { pa_operation *op = pa_context_get_sink_info_by_index(ctx, idx, (pa_sink_info_cb_t) sink_info_callback, main_thread); pa_operation_unref(op); } } static void state_callback(pa_context *ctx, pthread_t *main_thread) { pa_operation *op; switch (pa_context_get_state(ctx)) { case PA_CONTEXT_READY: op = pa_context_get_server_info(ctx, (pa_server_info_cb_t) server_info_callback, main_thread); pa_operation_unref(op); pa_context_set_subscribe_callback(ctx, (pa_context_subscribe_cb_t) subscribe_callback, main_thread); op = pa_context_subscribe(ctx, PA_SUBSCRIPTION_MASK_SINK, NULL, NULL); pa_operation_unref(op); break; case PA_CONTEXT_FAILED: pthread_kill(*main_thread, SIGMIN + 1); break; default: break; } } static void cleanup(void *data_to_free[2]) { pa_context_unref(data_to_free[1]); pa_mainloop_free(data_to_free[0]); } void pulse_listener_main(pthread_t *main_thread) { pthread_setcanceltype(PTHREAD_CANCEL_DISABLE, NULL); pa_mainloop *mainloop = pa_mainloop_new(); if (!mainloop) { ERROR("could not create pulse mainloop\n"); return; } pa_mainloop_api *api = pa_mainloop_get_api(mainloop); if (!api) { ERROR("could not create pulse mainloop api\n"); return; } pa_context *context = pa_context_new(api, "dwmblocks-listener"); if (!context) { ERROR("could not create pulse context\n"); return; } pa_context_set_state_callback(context, (pa_context_notify_cb_t)&state_callback, main_thread); if (pa_context_connect(context, NULL, PA_CONTEXT_NOAUTOSPAWN, NULL) < 0) { ERROR("could not connect to pulse\n"); return; } void *data_to_free[2] = { mainloop, context }; pthread_cleanup_push((void(*)(void *)) cleanup, data_to_free); pthread_setcanceltype(PTHREAD_CANCEL_ENABLE, NULL); pa_mainloop_run(mainloop, NULL); pthread_cleanup_pop(1); }