133 lines
3.8 KiB
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;
|
||
|
}
|