2023-09-08 23:39:55 -07:00
|
|
|
#include "pulse-listener.h"
|
|
|
|
|
2023-02-23 09:22:54 -08:00
|
|
|
#include <pulse/pulseaudio.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <errno.h>
|
2023-09-08 23:39:55 -07:00
|
|
|
#include <signal.h>
|
2023-02-23 09:22:54 -08:00
|
|
|
#include <limits.h>
|
|
|
|
|
|
|
|
#define ERROR(...) fprintf(stderr, "error: " __VA_ARGS__)
|
|
|
|
|
2023-02-23 12:07:46 -08:00
|
|
|
#ifdef __OpenBSD__
|
|
|
|
#define SIGMAX (SIGUSR2 - 1)
|
|
|
|
#define SIGMIN (SIGUSR1 - 1)
|
|
|
|
#else
|
|
|
|
#define SIGMAX SIGRTMAX
|
|
|
|
#define SIGMIN SIGRTMIN
|
|
|
|
#endif
|
|
|
|
|
2023-02-23 09:22:54 -08:00
|
|
|
static void sink_info_callback(pa_context *ctx, const pa_sink_info *info,
|
2023-09-08 23:39:55 -07:00
|
|
|
int eol, pthread_t *main_thread) {
|
|
|
|
pthread_kill(*main_thread, SIGMIN + 1);
|
2023-02-23 09:22:54 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void server_info_callback(pa_context *ctx, const pa_server_info *info,
|
2023-09-08 23:39:55 -07:00
|
|
|
pthread_t *main_thread) {
|
2023-02-23 09:22:54 -08:00
|
|
|
pa_operation *op = pa_context_get_sink_info_by_name(
|
|
|
|
ctx,
|
|
|
|
info->default_sink_name,
|
|
|
|
(pa_sink_info_cb_t) sink_info_callback,
|
2023-09-08 23:39:55 -07:00
|
|
|
main_thread);
|
2023-02-23 09:22:54 -08:00
|
|
|
pa_operation_unref(op);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void subscribe_callback(pa_context *ctx,
|
|
|
|
pa_subscription_event_type_t type, uint32_t idx,
|
2023-09-08 23:39:55 -07:00
|
|
|
pthread_t *main_thread) {
|
2023-03-06 12:53:36 -08:00
|
|
|
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,
|
2023-09-08 23:39:55 -07:00
|
|
|
main_thread);
|
2023-02-23 09:22:54 -08:00
|
|
|
pa_operation_unref(op);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-08 23:39:55 -07:00
|
|
|
static void state_callback(pa_context *ctx, pthread_t *main_thread) {
|
2023-02-23 09:22:54 -08:00
|
|
|
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,
|
2023-09-08 23:39:55 -07:00
|
|
|
main_thread);
|
2023-02-23 09:22:54 -08:00
|
|
|
pa_operation_unref(op);
|
|
|
|
pa_context_set_subscribe_callback(ctx,
|
|
|
|
(pa_context_subscribe_cb_t) subscribe_callback,
|
2023-09-08 23:39:55 -07:00
|
|
|
main_thread);
|
2023-02-23 09:22:54 -08:00
|
|
|
op = pa_context_subscribe(ctx, PA_SUBSCRIPTION_MASK_SINK, NULL, NULL);
|
|
|
|
pa_operation_unref(op);
|
|
|
|
break;
|
|
|
|
case PA_CONTEXT_FAILED:
|
2023-09-08 23:39:55 -07:00
|
|
|
pthread_kill(*main_thread, SIGMIN + 1);
|
2023-02-23 09:22:54 -08:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-09 00:31:15 -07:00
|
|
|
static void cleanup(void *data_to_free[2]) {
|
|
|
|
pa_context_unref(data_to_free[1]);
|
|
|
|
pa_mainloop_free(data_to_free[0]);
|
|
|
|
}
|
|
|
|
|
2023-09-08 23:39:55 -07:00
|
|
|
void pulse_listener_main(pthread_t *main_thread) {
|
2023-09-16 11:02:44 -07:00
|
|
|
pthread_setcanceltype(PTHREAD_CANCEL_DISABLE, NULL);
|
2023-02-23 09:22:54 -08:00
|
|
|
pa_mainloop *mainloop = pa_mainloop_new();
|
|
|
|
if (!mainloop) {
|
|
|
|
ERROR("could not create pulse mainloop\n");
|
2023-09-08 23:39:55 -07:00
|
|
|
return;
|
2023-02-23 09:22:54 -08:00
|
|
|
}
|
|
|
|
pa_mainloop_api *api = pa_mainloop_get_api(mainloop);
|
|
|
|
if (!api) {
|
|
|
|
ERROR("could not create pulse mainloop api\n");
|
2023-09-08 23:39:55 -07:00
|
|
|
return;
|
2023-02-23 09:22:54 -08:00
|
|
|
}
|
|
|
|
pa_context *context = pa_context_new(api, "dwmblocks-listener");
|
|
|
|
if (!context) {
|
|
|
|
ERROR("could not create pulse context\n");
|
2023-09-08 23:39:55 -07:00
|
|
|
return;
|
2023-02-23 09:22:54 -08:00
|
|
|
}
|
2023-09-08 23:39:55 -07:00
|
|
|
pa_context_set_state_callback(context,
|
2023-02-23 09:22:54 -08:00
|
|
|
(pa_context_notify_cb_t)&state_callback,
|
2023-09-08 23:39:55 -07:00
|
|
|
main_thread);
|
2023-02-23 09:22:54 -08:00
|
|
|
if (pa_context_connect(context, NULL, PA_CONTEXT_NOAUTOSPAWN, NULL) < 0) {
|
2023-09-16 11:02:44 -07:00
|
|
|
ERROR("could not connect to pulse\n");
|
2023-09-08 23:39:55 -07:00
|
|
|
return;
|
2023-02-23 09:22:54 -08:00
|
|
|
}
|
2023-09-09 00:31:15 -07:00
|
|
|
void *data_to_free[2] = { mainloop, context };
|
|
|
|
pthread_cleanup_push((void(*)(void *)) cleanup, data_to_free);
|
2023-09-16 11:02:44 -07:00
|
|
|
pthread_setcanceltype(PTHREAD_CANCEL_ENABLE, NULL);
|
2023-02-23 09:22:54 -08:00
|
|
|
pa_mainloop_run(mainloop, NULL);
|
2023-09-09 00:31:15 -07:00
|
|
|
pthread_cleanup_pop(1);
|
2023-02-23 09:22:54 -08:00
|
|
|
}
|