From 9b0904a59af7e8c02cd2039a1cd18926bee51e72 Mon Sep 17 00:00:00 2001 From: Timmy Keller Date: Fri, 4 Oct 2024 21:58:41 -0500 Subject: add command for volume control and change name to pavolctld --- Makefile | 4 +- pavolctld.c | 148 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ pavolctrld.c | 105 ------------------------------------------ todo | 19 ++++++++ 4 files changed, 169 insertions(+), 107 deletions(-) create mode 100644 pavolctld.c delete mode 100644 pavolctrld.c create mode 100644 todo diff --git a/Makefile b/Makefile index c99c777..6f50833 100644 --- a/Makefile +++ b/Makefile @@ -4,8 +4,8 @@ CC = gcc CFLAGS = -Wall LDFLAGS = -lpulse -TARGET = pavolctrld -SOURCES = pavolctrld.c +TARGET = pavolctld +SOURCES = pavolctld.c all: $(TARGET) diff --git a/pavolctld.c b/pavolctld.c new file mode 100644 index 0000000..deb5796 --- /dev/null +++ b/pavolctld.c @@ -0,0 +1,148 @@ +#include +#include +#include +#include + +//TODO pa_operation_unref(o); + +static int default_sink_index; +static int command_sink_index; // commands will modify this sink + + +static void sink_info_volume_callback(pa_context *c, const pa_sink_info *i, int eol, void *userdata) { + pa_volume_t vol; + if (eol) return; + + vol = pa_cvolume_avg(&i->volume); + printf("v%d,%d,%.02f,%d\n", i->index, vol*100/PA_VOLUME_NORM, pa_sw_volume_to_dB(vol), i->mute); + fflush(stdout); +} + +static void sink_info_default_index_callback(pa_context *c, const pa_sink_info *i, int eol, void *userdata) { + if (eol) return; + default_sink_index = i->index; +} + +static void sink_info_sink_desc_callback(pa_context *c, const pa_sink_info *i, int eol, void *userdata) { + if (eol) return; + printf("s%d,%s,%s\n", i->index, i->name, i->description); + fflush(stdout); +} + +static void server_info_default_sink_callback(pa_context *c, const pa_server_info *i, void *userdata) { + pa_context_get_sink_info_by_name(c, i->default_sink_name, sink_info_default_index_callback, userdata); + printf("f%d\n", default_sink_index); + fflush(stdout); +} + +static void subscription_callback(pa_context *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata) { + switch (t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) { + case PA_SUBSCRIPTION_EVENT_SINK: + // check if sink was removed + if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) { + printf("x%d\n", idx); + fflush(stdout); + return; + } + + // check if sink was added + if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW) + pa_context_get_sink_info_by_index(c, idx, sink_info_sink_desc_callback, userdata); + + // output the volume + pa_context_get_sink_info_by_index(c, idx, sink_info_volume_callback, userdata); + break; + case PA_SUBSCRIPTION_EVENT_SERVER: + pa_context_get_server_info(c, server_info_default_sink_callback, userdata); + break; + } +} + +static void context_state_callback(pa_context *c, void *userdata) { + if (pa_context_get_state(c) == PA_CONTEXT_READY) { + pa_context_set_subscribe_callback(c, subscription_callback, userdata); + + // output initial default sink + pa_context_get_server_info(c, server_info_default_sink_callback, userdata); + + // set command sink equal to the default sink on startup + command_sink_index = default_sink_index; + + // output initial sink descriptions for each sink + pa_context_get_sink_info_list(c, sink_info_sink_desc_callback, userdata); + + // output initial volume levels for each sink + pa_context_get_sink_info_list(c, sink_info_volume_callback, userdata); + + // subscribe to sink & server events to listen to changes + pa_context_subscribe(c, PA_SUBSCRIPTION_MASK_SINK|PA_SUBSCRIPTION_MASK_SERVER, NULL, NULL); + } +} + +/* commands */ +static void sink_info_set_volume_callback(pa_context *c, const pa_sink_info *i, int eol, void *userdata) { + pa_cvolume *vol; + double input_vol; + char *cmd = (char *)userdata; + if (eol) return; + + vol = (pa_cvolume *)&i->volume; // disregard const qualifier, avoid warnings :) + switch(cmd[1]) { + case '\n': + pa_context_get_sink_info_by_index(c, i->index, sink_info_volume_callback, userdata); + return; + case '+': + input_vol = atof(&cmd[2])/100; + vol = pa_cvolume_inc(vol, (pa_volume_t)(input_vol * PA_VOLUME_NORM)); + break; + case '-': + input_vol = atof(&cmd[2])/100; + vol = pa_cvolume_dec(vol, (pa_volume_t)(input_vol * PA_VOLUME_NORM)); + break; + default: + input_vol = atof(&cmd[1])/100; + vol = pa_cvolume_set(vol, i->volume.channels, (pa_volume_t)(input_vol * PA_VOLUME_NORM * -1)); + break; + } + + pa_context_set_sink_volume_by_index(c, i->index, vol, NULL, NULL); +} + +static void handle_command(pa_context *c, char *cmd) { + // send the command to each callback using userdata + switch (cmd[0]) { + case 'v': + pa_context_get_sink_info_by_index(c, command_sink_index, sink_info_set_volume_callback, (void *)cmd); + break; + } +} + +int main() { + pa_threaded_mainloop *mainloop = pa_threaded_mainloop_new(); + pa_mainloop_api *mainloop_api = pa_threaded_mainloop_get_api(mainloop); + pa_context *context = pa_context_new(mainloop_api, "pavolctld"); + char stdin_buffer[256]; + + pa_context_connect(context, NULL, PA_CONTEXT_NOAUTOSPAWN, NULL); + + pa_context_set_state_callback(context, context_state_callback, NULL); + + // main loop + pa_threaded_mainloop_start(mainloop); + + while(1) { + if (fgets(stdin_buffer, sizeof(stdin_buffer), stdin) != NULL) { + handle_command(context, stdin_buffer); + //printf("You entered: %s", stdin_buffer); + //fflush(stdout); + } + } + + // clean up + pa_context_disconnect(context); + pa_context_unref(context); + pa_threaded_mainloop_free(mainloop); + + return 0; +} + diff --git a/pavolctrld.c b/pavolctrld.c deleted file mode 100644 index dc56292..0000000 --- a/pavolctrld.c +++ /dev/null @@ -1,105 +0,0 @@ -#include -#include -#include -#include - -//TODO pa_operation_unref(o); - -static int default_sink_index; - - -static void sink_info_volume_callback(pa_context *c, const pa_sink_info *i, int eol, void *userdata) { - pa_volume_t vol; - if (eol) return; - - vol = pa_cvolume_avg(&i->volume); - printf("v%d,%d,%.02f,%d\n", i->index, vol*100/PA_VOLUME_NORM, pa_sw_volume_to_dB(vol), i->mute); - fflush(stdout); -} - -static void sink_info_default_index_callback(pa_context *c, const pa_sink_info *i, int eol, void *userdata) { - if (eol) return; - default_sink_index = i->index; -} - -static void sink_info_sink_desc_callback(pa_context *c, const pa_sink_info *i, int eol, void *userdata) { - if (eol) return; - printf("s%d,%s,%s\n", i->index, i->name, i->description); - fflush(stdout); -} - -static void server_info_default_sink_callback(pa_context *c, const pa_server_info *i, void *userdata) { - pa_context_get_sink_info_by_name(c, i->default_sink_name, sink_info_default_index_callback, userdata); - printf("f%d\n", default_sink_index); - fflush(stdout); -} - -static void subscription_callback(pa_context *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata) { - switch (t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) { - case PA_SUBSCRIPTION_EVENT_SINK: - // check if sink was removed - if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) { - printf("x%d\n", idx); - fflush(stdout); - return; - } - - // check if sink was added - if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW) - pa_context_get_sink_info_by_index(c, idx, sink_info_sink_desc_callback, userdata); - - // output the volume - pa_context_get_sink_info_by_index(c, idx, sink_info_volume_callback, userdata); - break; - case PA_SUBSCRIPTION_EVENT_SERVER: - pa_context_get_server_info(c, server_info_default_sink_callback, userdata); - break; - } -} - -static void context_state_callback(pa_context *c, void *userdata) { - if (pa_context_get_state(c) == PA_CONTEXT_READY) { - pa_context_set_subscribe_callback(c, subscription_callback, userdata); - - // output initial default sink - pa_context_get_server_info(c, server_info_default_sink_callback, userdata); - - // output initial sink descriptions for each sink - pa_context_get_sink_info_list(c, sink_info_sink_desc_callback, userdata); - - // output initial volume levels for each sink - pa_context_get_sink_info_list(c, sink_info_volume_callback, userdata); - - // subscribe to sink & server events to listen to changes - pa_context_subscribe(c, PA_SUBSCRIPTION_MASK_SINK|PA_SUBSCRIPTION_MASK_SERVER, NULL, NULL); - } -} - -int main() { - pa_threaded_mainloop *mainloop = pa_threaded_mainloop_new(); - pa_mainloop_api *mainloop_api = pa_threaded_mainloop_get_api(mainloop); - pa_context *context = pa_context_new(mainloop_api, "pavolctrld"); - char stdin_buffer[256]; - - pa_context_connect(context, NULL, PA_CONTEXT_NOAUTOSPAWN, NULL); - - pa_context_set_state_callback(context, context_state_callback, NULL); - - // main loop - pa_threaded_mainloop_start(mainloop); - - while(1) { - if (fgets(stdin_buffer, sizeof(stdin_buffer), stdin) != NULL) { - printf("You entered: %s", stdin_buffer); - fflush(stdout); - } - } - - // clean up - pa_context_disconnect(context); - pa_context_unref(context); - pa_threaded_mainloop_free(mainloop); - - return 0; -} - diff --git a/todo b/todo new file mode 100644 index 0000000..148e532 --- /dev/null +++ b/todo @@ -0,0 +1,19 @@ +pavolctrld + +out # DONE +v{sink},{vol},{db},{mute} # volume change +f{idx} # default (fallback) sink change +s{idx},{name},{desc} # sink add / first connect +x{idx} # sink remove + +in +s56 # set the editing sink to 56 +v50 # set vol 50% +v+5 # inc vol 5% +v-5.2 # dec vol -5.2% +d-1.2 # dec vol 1.2dB +m0 # unmute +m1 # mute +f # make the current sink the default (fallback) sink +f35 # make sink 35 the default (fallback) sink + -- cgit v1.2.3