This repository has been archived on 2023-02-21. You can view files and clone it, but cannot push or open issues or pull requests.
quick-text-bar/modules/pulse.c

133 lines
3.8 KiB
C

#include "pulse.h"
#include "../util.h"
#include <math.h>
#include <pthread.h>
#include <pulse/pulseaudio.h>
#include <stdio.h>
#include <string.h>
#define CONTEXT_NAME "quick-text-bar-audio"
#define CONTEXT_CONNECTING 0
#define CONTEXT_CONNECTED 1
#define CONTEXT_FAILED 2
static pa_threaded_mainloop *mainloop;
static pa_mainloop_api *mainloop_api;
static pa_context *context;
static int volume;
static int mute;
static void sink_info_callback(pa_context *ctx, const pa_sink_info *info,
int eol, void *user_data) {
if (info) {
pa_volume_t arg = pa_cvolume_avg(&info->volume);
float float_volume = ((float)arg / (float)PA_VOLUME_NORM) * 100.0f;
int new_volume = round(float_volume);
if (mute != info->mute || volume != new_volume) {
mute = info->mute;
volume = new_volume;
qtb_signal_modules(1);
}
}
}
static void server_info_callback(pa_context *ctx, const pa_server_info *info,
void *user_data) {
pa_operation *op = pa_context_get_sink_info_by_name(
ctx, info->default_sink_name, &sink_info_callback, NULL);
pa_operation_unref(op);
}
static void subscribe_callback(pa_context *ctx,
pa_subscription_event_type_t type, uint32_t idx,
void *user_data) {
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, &sink_info_callback,
NULL);
break;
default:
break;
}
if (op) {
pa_operation_unref(op);
}
}
static void state_callback(pa_context *ctx, void *user_data) {
pa_operation *op;
switch (pa_context_get_state(ctx)) {
case PA_CONTEXT_READY:
op = pa_context_get_server_info(ctx, &server_info_callback, NULL);
pa_operation_unref(op);
pa_context_set_subscribe_callback(ctx, &subscribe_callback, NULL);
op = pa_context_subscribe(ctx, PA_SUBSCRIPTION_MASK_SINK, NULL, NULL);
pa_operation_unref(op);
break;
case PA_CONTEXT_FAILED:
volume = -1;
qtb_signal_modules(1);
break;
default:
break;
}
}
void pulse_module_init() {
mainloop = pa_threaded_mainloop_new();
if (!mainloop) {
qtb_log("could not create mainloop");
qtb_die();
}
mainloop_api = pa_threaded_mainloop_get_api(mainloop);
if (!mainloop_api) {
qtb_log("could not get api");
qtb_die();
}
context = pa_context_new(mainloop_api, CONTEXT_NAME);
if (!context) {
qtb_log("could not create context");
qtb_die();
}
pa_context_set_state_callback(
context, (pa_context_notify_cb_t)&state_callback, NULL);
if (pa_context_connect(context, NULL, PA_CONTEXT_NOAUTOSPAWN, NULL) < 0) {
qtb_log("could not connect");
qtb_die();
}
if (pa_threaded_mainloop_start(mainloop) < 0) {
qtb_log("could not start mainloop");
qtb_die();
}
}
static const char *get_volume_icon() {
if (mute) {
return "";
} else if (volume > 50) {
return "";
} else if (volume > 0) {
return "奔";
}
return "";
}
char *pulse_module_poll() {
char *output = qtb_calloc(32, 1);
if (volume < 0) { /* not connected */
sprintf(output, "ﱝ ??%%");
pa_threaded_mainloop_stop(
mainloop); /* free the old mainloop and reset this module */
pa_threaded_mainloop_free(mainloop);
pulse_module_init();
} else {
const char *volume_icon = get_volume_icon();
sprintf(output, "%s%3d%%", volume_icon, volume);
}
return output;
}