From 81d4eeca11f67db9510c70a8c76ff9a9c30b3799 Mon Sep 17 00:00:00 2001 From: Martin Mares Date: Fri, 24 Apr 2020 20:24:12 +0200 Subject: [PATCH] Muting of sources --- pulse.c | 99 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- ursaryd.c | 35 +++++++++++++++++++- ursaryd.h | 19 ++++++++++- 3 files changed, 147 insertions(+), 6 deletions(-) diff --git a/pulse.c b/pulse.c index 53478dc..f16d0ab 100644 --- a/pulse.c +++ b/pulse.c @@ -1,7 +1,7 @@ /* * Asynchronous Interface to PulseAudio * - * (c) 2014--2018 Martin Mares + * (c) 2014--2020 Martin Mares */ #undef LOCAL_DEBUG @@ -23,6 +23,7 @@ enum pulse_state { PS_GET_CLIENTS, PS_GET_SINKS, PS_GET_SINK_INPUTS, + PS_GET_SOURCES, PS_GET_SERVER, PS_ONLINE, }; @@ -30,7 +31,7 @@ enum pulse_state { enum pulse_state pulse_state; #define PULSE_STATE(s) do { pulse_state = s; DBG("Pulse: " #s); } while (0) -clist pulse_client_list, pulse_sink_list, pulse_sink_input_list; +clist pulse_client_list, pulse_source_list, pulse_sink_list, pulse_sink_input_list; static pa_context *pulse_ctx; static struct main_timer pulse_connect_timer; @@ -138,6 +139,87 @@ void pulse_server_set_default_sink(const char *name) PULSE_ASYNC_RUN(pa_context_set_default_sink, name, pulse_success_cb); } +/*** Sources ***/ + +#define HASH_NODE struct pulse_source +#define HASH_PREFIX(x) pulse_source_##x +#define HASH_KEY_ATOMIC idx +#define HASH_WANT_CLEANUP +#define HASH_WANT_LOOKUP +#define HASH_WANT_REMOVE +#define HASH_ZERO_FILL +#include + +static void pulse_source_cb(pa_context *ctx UNUSED, const pa_source_info *i, int eol, void *userdata) +{ + struct pulse_op *op = userdata; + + if (eol) + { + if (op->is_init) + { + PULSE_STATE(PS_GET_SERVER); + PULSE_ASYNC_INIT_RUN(pa_context_get_server_info, pulse_server_cb); + } + pulse_op_done(op); + return; + } + + DBG("Pulse: SOURCE #%u: %s (%s) flags=%08x channels=%u volume=%u mute=%d base_vol=%u state=%u port=%s", + i->index, i->name, i->description, i->flags, i->channel_map.channels, i->volume.values[0], i->mute, i->base_volume, i->state, + (i->active_port ? i->active_port->name : "none")); + pulse_dump_proplist(i->proplist); + + struct pulse_source *s = pulse_source_lookup(i->index); + if (!clist_is_linked(&s->n)) + clist_add_tail(&pulse_source_list, &s->n); + SET_STRING(s->name, i->name); + s->channels = i->channel_map.channels; + s->volume = pa_cvolume_avg(&i->volume); + s->base_volume = i->base_volume; + s->mute = i->mute; + s->suspended = (i->state == PA_SOURCE_SUSPENDED); + SET_STRING(s->active_port, (i->active_port ? i->active_port->name : "none")); + schedule_update(); +} + +static void pulse_source_gone(int idx) +{ + DBG("Pulse: REMOVE SOURCE #%d", idx); + struct pulse_source *s = pulse_source_lookup(idx); + clist_remove(&s->n); + pulse_source_remove(s); + schedule_update(); +} + +struct pulse_source *pulse_source_by_name(const char *name) +{ + CLIST_FOR_EACH(struct pulse_source *, s, pulse_source_list) + if (!strcmp(s->name, name)) + return s; + return NULL; +} + +struct pulse_source *pulse_source_by_idx(int idx) +{ + return pulse_source_lookup(idx); +} + +void pulse_source_set_volume(int idx, pa_cvolume *cvol) +{ + PULSE_ASYNC_RUN(pa_context_set_source_volume_by_index, idx, cvol, pulse_success_cb); +} + +void pulse_source_set_mute(int idx, bool mute) +{ + PULSE_ASYNC_RUN(pa_context_set_source_mute_by_index, idx, mute, pulse_success_cb); +} + +void pulse_source_set_port(int idx, const char *port) +{ + PULSE_ASYNC_RUN(pa_context_set_source_port_by_index, idx, port, pulse_success_cb); +} + /*** Sink inputs ***/ #define HASH_NODE struct pulse_sink_input @@ -158,8 +240,8 @@ static void pulse_sink_input_cb(pa_context *ctx UNUSED, const pa_sink_input_info { if (op->is_init) { - PULSE_STATE(PS_GET_SERVER); - PULSE_ASYNC_INIT_RUN(pa_context_get_server_info, pulse_server_cb); + PULSE_STATE(PS_GET_SOURCES); + PULSE_ASYNC_INIT_RUN(pa_context_get_source_info_list, pulse_source_cb); } pulse_op_done(op); return; @@ -375,6 +457,12 @@ static void pulse_event_cb(pa_context *ctx UNUSED, pa_subscription_event_type_t else if (action == PA_SUBSCRIPTION_EVENT_REMOVE) pulse_client_gone(idx); break; + case PA_SUBSCRIPTION_EVENT_SOURCE: + if (action == PA_SUBSCRIPTION_EVENT_NEW || action == PA_SUBSCRIPTION_EVENT_CHANGE) + PULSE_ASYNC_RUN(pa_context_get_source_info_by_index, idx, pulse_source_cb); + else if (action == PA_SUBSCRIPTION_EVENT_REMOVE) + pulse_source_gone(idx); + break; case PA_SUBSCRIPTION_EVENT_SINK: if (action == PA_SUBSCRIPTION_EVENT_NEW || action == PA_SUBSCRIPTION_EVENT_CHANGE) PULSE_ASYNC_RUN(pa_context_get_sink_info_by_index, idx, pulse_sink_cb); @@ -400,6 +488,7 @@ static void pulse_shutdown(void) { DBG("Pulse: Shutting down"); pulse_client_cleanup(); + pulse_source_cleanup(); pulse_sink_cleanup(); pulse_sink_input_cleanup(); } @@ -439,9 +528,11 @@ static void pulse_connect(struct main_timer *t) clist_init(&pulse_op_list); clist_init(&pulse_client_list); + clist_init(&pulse_source_list); clist_init(&pulse_sink_list); clist_init(&pulse_sink_input_list); pulse_client_init(); + pulse_source_init(); pulse_sink_init(); pulse_sink_input_init(); diff --git a/ursaryd.c b/ursaryd.c index c128e50..50b50c5 100644 --- a/ursaryd.c +++ b/ursaryd.c @@ -31,7 +31,7 @@ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * 0 sink PCH mute switch to PCH * 1 sink BT mute switch to BT - * 2 - - - + * 2 - mic non-mute - * 3 desk brightness - desk lights on * 4 MPD mute MPD play/pause * 5 Albireo MPV mute MPD stop @@ -44,6 +44,7 @@ #define PCH_SINK "alsa_output.pci-0000_00_1f.3.analog-stereo" #define BT_SINK "bluez_sink.CC_98_8B_D0_8C_06.a2dp_sink" +#define LOGI_SOURCE "alsa_input.usb-046d_Logitech_Webcam_C925e_EF163C5F-02.analog-stereo" /*** Sink controls ***/ @@ -367,6 +368,34 @@ static void update_default_sink_from_button(int button, int on) } } +/*** Source mute controls ***/ + +static void update_source_buttons(void) +{ + struct pulse_source *source = pulse_source_by_name(LOGI_SOURCE); + if (!source) + return; + + // if (source->suspended || source->mute) + if (source->mute) + noct_set_button(2, 0); + else + noct_set_button(2, 1); +} + +static void update_source_mute_from_button(int on, const char *source_name) +{ + if (!on) + return; + + struct pulse_source *s = pulse_source_by_name(source_name); + if (!s) + return; + + DBG("## Setting mute of source %s to %d", s->name, !s->mute); + pulse_source_set_mute(s->idx, !s->mute); +} + /*** MPD controls ***/ static bool mpd_flash_state; @@ -638,6 +667,7 @@ static void do_update(struct main_timer *t) update_ring_from_sink(1, BT_SINK); update_groups(); update_default_sink(); + update_source_buttons(); update_mpd(); update_lights(); } @@ -702,6 +732,9 @@ void notify_button(int button, int on) case 1: update_sink_mute_from_button(on, BT_SINK); break; + case 2: + update_source_mute_from_button(on, LOGI_SOURCE); + break; case 8: case 9: update_default_sink_from_button(button, on); diff --git a/ursaryd.h b/ursaryd.h index 8b74334..d60a426 100644 --- a/ursaryd.h +++ b/ursaryd.h @@ -53,6 +53,18 @@ struct pulse_client { char *host; }; +struct pulse_source { + cnode n; + int idx; + char *name; + uint channels; + uint volume; + uint base_volume; + bool mute; + bool suspended; + char *active_port; +}; + struct pulse_sink { cnode n; int idx; @@ -77,11 +89,16 @@ struct pulse_sink_input { int noct_group_idx; // Used by the high-level logic below }; -extern clist pulse_client_list, pulse_sink_list, pulse_sink_input_list; +extern clist pulse_client_list, pulse_source_list, pulse_sink_list, pulse_sink_input_list; void pulse_init(void); void pulse_dump(void); bool pulse_is_ready(void); +struct pulse_source *pulse_source_by_name(const char *name); +struct pulse_source *pulse_source_by_idx(int idx); +void pulse_source_set_volume(int idx, pa_cvolume *cvol); +void pulse_source_set_mute(int idx, bool mute); +void pulse_source_set_port(int idx, const char *port); struct pulse_sink *pulse_sink_by_name(const char *name); struct pulse_sink *pulse_sink_by_idx(int idx); void pulse_sink_set_volume(int idx, pa_cvolume *cvol); -- 2.39.2