dwmblocks/dwmblocks-pulse-listener.c

134 lines
4.1 KiB
C

#include <pulse/pulseaudio.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/signal.h>
#include <limits.h>
#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
typedef struct {
size_t pid;
unsigned int signum;
} TargetData;
static void sink_info_callback(pa_context *ctx, const pa_sink_info *info,
int eol, TargetData *target) {
if (info && kill(target->pid, target->signum) < 0) {
ERROR("terget process died\n");
exit(1);
}
}
static void server_info_callback(pa_context *ctx, const pa_server_info *info,
TargetData *target) {
pa_operation *op = pa_context_get_sink_info_by_name(
ctx,
info->default_sink_name,
(pa_sink_info_cb_t) sink_info_callback,
target);
pa_operation_unref(op);
}
static void subscribe_callback(pa_context *ctx,
pa_subscription_event_type_t type, uint32_t idx,
TargetData *target) {
unsigned int facility = type & PA_SUBSCRIPTION_EVENT_FACILITY_MASK;
pa_operation *op = NULL;
switch (facility) {
case PA_SUBSCRIPTION_EVENT_SINK:
op = pa_context_get_sink_info_by_index(ctx,
idx,
(pa_sink_info_cb_t) sink_info_callback,
target);
break;
}
if (op) {
pa_operation_unref(op);
}
}
static void state_callback(pa_context *ctx, TargetData *target) {
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,
target);
pa_operation_unref(op);
pa_context_set_subscribe_callback(ctx,
(pa_context_subscribe_cb_t) subscribe_callback,
target);
op = pa_context_subscribe(ctx, PA_SUBSCRIPTION_MASK_SINK, NULL, NULL);
pa_operation_unref(op);
break;
case PA_CONTEXT_FAILED:
if (kill(target->pid, target->signum) < 0) {
ERROR("terget process died\n");
exit(1);
}
break;
default:
break;
}
}
int main(int argc, const char **argv) {
if (argc < 2) {
ERROR("no pid\n");
return 1;
}
char *endptr = NULL;
unsigned int signum = SIGMIN + 1;
if (argc >= 3 && argv[1][0] == '-') {
const char *signumstr = argv[1] + 1;
unsigned long num = strtoul(signumstr, &endptr, 10);
if (num > SIGMAX - SIGMIN) {
ERROR("signal out of range: %lu\n", num);
return 1;
}
signum = SIGMIN + num;
++argv;
}
endptr = NULL;
errno = 0;
unsigned long pid = strtoul(argv[1], &endptr, 10);
if (argv[1][0] == '-' || errno == ERANGE) {
ERROR("pid out of range: \"%s\"\n", argv[1]);
return 1;
}
pa_mainloop *mainloop = pa_mainloop_new();
if (!mainloop) {
ERROR("could not create pulse mainloop\n");
return 1;
}
pa_mainloop_api *api = pa_mainloop_get_api(mainloop);
if (!api) {
ERROR("could not create pulse mainloop api\n");
return 1;
}
pa_context *context = pa_context_new(api, "dwmblocks-listener");
if (!context) {
ERROR("could not create pulse context\n");
return 1;
}
TargetData target = { pid, signum };
pa_context_set_state_callback( context,
(pa_context_notify_cb_t)&state_callback,
&target);
if (pa_context_connect(context, NULL, PA_CONTEXT_NOAUTOSPAWN, NULL) < 0) {
ERROR("could not connect to pulse");
return 1;
}
pa_mainloop_run(mainloop, NULL);
return 0;
}