X-Git-Url: http://mj.ucw.cz/gitweb/?a=blobdiff_plain;f=ursaryd.c;h=66ac0c6cab25fd313accd0bf08c61c09d98f9da9;hb=c575ff2359fd1627c538616c8be44aea27314a51;hp=0315c344efce35272315f0a80db54c1dee4c5a28;hpb=aa69825f5413a3a213a8cd557b5e9f24793dad5f;p=ursary.git diff --git a/ursaryd.c b/ursaryd.c index 0315c34..66ac0c6 100644 --- a/ursaryd.c +++ b/ursaryd.c @@ -1,19 +1,24 @@ /* * The Ursary Audio Controls * - * (c) 2014 Martin Mares + * (c) 2014--2018 Martin Mares */ -#define LOCAL_DEBUG +#undef LOCAL_DEBUG #include #include +#include +#include #include +#include #include +#include #include #include #include +#include #include "ursaryd.h" @@ -21,19 +26,21 @@ * Map of all controls * * rotary red button green button - * 0 sink Ursarium mute select as default (or assign to client selected by touch) - * 1 sink Catarium mute dtto - * 2 sink Compress - dtto + * 0 sink PCH mute - + * 1 - - - + * 2 - - - * 3 - - - * 4 MPD mute play/pause/stop - * 5 Albireo mute - - * 6 Ogion mute - - * 7 Ursula mute - + * 5 Albireo MPV mute - + * 6 Albireo other mute - + * 7 other machines mute - * - * center all sinks + * center - * slider - */ +#define PCH_SINK "alsa_output.pci-0000_00_1f.3.analog-stereo" + /*** Sink controls ***/ static double volume_from_pa(pa_volume_t vol) @@ -68,6 +75,18 @@ static void update_ring_from_sink(int ring, const char *sink_name) noct_set_button(ring, 0); } +static void update_button_from_port(int button, const char *sink_name, const char *port_name) +{ + struct pulse_sink *s = pulse_sink_by_name(sink_name); + if (!s) + { + noct_set_button(button, 0); + return; + } + + noct_set_button(button, !strcmp(s->active_port, port_name)); +} + static void update_sink_from_rotary(int delta, const char *sink_name) { struct pulse_sink *s = pulse_sink_by_name(sink_name); @@ -98,47 +117,68 @@ static void update_sink_mute_from_button(int on, const char *sink_name) pulse_sink_set_mute(s->idx, !s->mute); } +static void update_port_from_button(int on, const char *sink_name, const char *port1, const char *port2) +{ + if (!on) + return; + + struct pulse_sink *s = pulse_sink_by_name(sink_name); + if (!s) + return; + + const char *port = port1; + if (!strcmp(s->active_port, port1)) + port = port2; + + DBG("## Setting port of sink %s to %s", s->name, port); + pulse_sink_set_port(s->idx, port); +} + /*** Client controls ***/ struct client_map { - int rotary; + int group; const char *client; const char *host; - double range; }; static struct client_map client_map[] = { - { 4, "Music Player Daemon", "albireo", 1.5 }, - { 5, NULL, "albireo", 1.5 }, - { 6, NULL, "ogion", 1.5 }, - { 7, NULL, "ursula", 1.5 }, + { 4, "Music Player Daemon", "albireo", }, + { 5, "mpv", "albireo", }, + { 6, NULL, "albireo", }, + { 7, NULL, NULL, }, }; -#define NUM_CLIENTS ARRAY_SIZE(client_map) +#define CLIENT_MAP_SIZE ARRAY_SIZE(client_map) -struct client_state { +struct group_config { + bool enabled; + double range; +}; + +struct group_state { double volume; bool have_muted[2]; }; -static struct client_state client_state[NUM_CLIENTS]; +#define NUM_GROUPS 9 -static int find_client_by_rotary(int rotary) -{ - uns i; - for (i=0; i < NUM_CLIENTS; i++) - if (client_map[i].rotary == rotary) - return i; - return -1; -} +static struct group_config group_config[NUM_GROUPS] = { + [4] = { .enabled = 1, .range = 1.5 }, + [5] = { .enabled = 1, .range = 1.5 }, + [6] = { .enabled = 1, .range = 1.5 }, + [7] = { .enabled = 1, .range = 1.5 }, +}; + +static struct group_state group_state[NUM_GROUPS]; -static void calc_clients(void) +static void calc_groups(void) { - bzero(client_state, sizeof(client_state)); + bzero(group_state, sizeof(group_state)); CLIST_FOR_EACH(struct pulse_sink_input *, s, pulse_sink_input_list) { - s->noct_client_idx = -1; + s->noct_group_idx = -1; if (s->client_idx < 0 || s->sink_idx < 0) continue; @@ -147,67 +187,74 @@ static void calc_clients(void) if (!c) continue; - for (uns i=0; i < NUM_CLIENTS; i++) + for (uns i=0; i < CLIENT_MAP_SIZE; i++) { struct client_map *cm = &client_map[i]; - struct client_state *cs = &client_state[i]; if ((!cm->client || !strcmp(cm->client, c->name)) && (!cm->host || !strcmp(cm->host, c->host))) { - // DBG("@@ Client #%d, sink input #%d -> rotary %d", s->client_idx, s->idx, cm->rotary); - s->noct_client_idx = i; - cs->volume = MAX(cs->volume, s->volume); - cs->have_muted[!!s->mute] = 1; + int g = cm->group; + struct group_state *gs = &group_state[g]; + DBG("@@ Client #%d, sink input #%d -> group %d", s->client_idx, s->idx, g); + s->noct_group_idx = g; + gs->volume = MAX(gs->volume, s->volume); + gs->have_muted[!!s->mute] = 1; break; } } } } -static void update_clients(void) +static void update_groups(void) { - calc_clients(); + calc_groups(); - for (uns i=0; i < NUM_CLIENTS; i++) + for (uns i=0; i < NUM_GROUPS; i++) { - struct client_map *cm = &client_map[i]; - struct client_state *cs = &client_state[i]; - if (!cs->have_muted[0] && !cs->have_muted[1]) + struct group_config *gc = &group_config[i]; + struct group_state *gs = &group_state[i]; + if (!gc->enabled) + continue; + + DBG("@@ Group #%d: mute=%d/%d volume=%.3f/%.3f", i, gs->have_muted[0], gs->have_muted[1], volume_from_pa(gs->volume), gc->range); + + if (!gs->have_muted[0] && !gs->have_muted[1]) { - noct_set_ring(cm->rotary, RING_MODE_LEFT, 0); - noct_set_button(cm->rotary, 0); + noct_set_ring(i, RING_MODE_LEFT, 0); + noct_set_button(i, 0); } - else if (!cs->have_muted[0]) + else if (!gs->have_muted[0]) { - noct_set_ring(cm->rotary, RING_MODE_SINGLE_ON, 0x7f); - noct_set_button(cm->rotary, 1); + noct_set_ring(i, RING_MODE_SINGLE_ON, 0x7f); + noct_set_button(i, 1); } else { - double vol = CLAMP(volume_from_pa(cs->volume), 0, cm->range); - int val = 0x7f * vol / cm->range; + double vol = CLAMP(volume_from_pa(gs->volume), 0, gc->range); + int val = 0x7f * vol / gc->range; val = CLAMP(val, 12, 0x7f); - noct_set_ring(cm->rotary, RING_MODE_LEFT, val); - noct_set_button(cm->rotary, 0); + noct_set_ring(i, RING_MODE_LEFT, val); + noct_set_button(i, 0); } } } -static void update_client_from_rotary(int rotary, int delta) +static void update_group_from_rotary(int i, int delta) { - int i = find_client_by_rotary(rotary); - if (i < 0) + if (i >= NUM_GROUPS) + return; + struct group_config *gc = &group_config[i]; + struct group_state *gs = &group_state[i]; + if (!gc->enabled) return; - struct client_map *cm = &client_map[i]; - struct client_state *cs = &client_state[i]; - calc_clients(); - double vol = volume_from_pa(cs->volume) + delta*0.02; - pa_volume_t pavol = volume_to_pa(CLAMP(vol, 0, cm->range)); + calc_groups(); + double vol = volume_from_pa(gs->volume) + delta*0.02; + pa_volume_t pavol = volume_to_pa(CLAMP(vol, 0, gc->range)); CLIST_FOR_EACH(struct pulse_sink_input *, s, pulse_sink_input_list) { - if (s->noct_client_idx == i && s->volume != pavol) + if (s->noct_group_idx == i && s->volume != pavol) { DBG("@@ Client #%d, sink input #%d: setting volume=%u", s->client_idx, s->idx, pavol); pa_cvolume cvol; @@ -217,24 +264,25 @@ static void update_client_from_rotary(int rotary, int delta) } } -static void update_client_from_button(int button, int on) +static void update_group_from_button(int i, int on) { - if (button >= 8 || !on) + if (!on) return; - - int i = find_client_by_rotary(button); - if (i < 0) + if (i >= NUM_GROUPS) + return; + struct group_config *gc = &group_config[i]; + struct group_state *gs = &group_state[i]; + if (!gc->enabled) return; - struct client_state *cs = &client_state[i]; - calc_clients(); - if (!cs->have_muted[0] && !cs->have_muted[1]) + calc_groups(); + if (!gs->have_muted[0] && !gs->have_muted[1]) return; - uns mute = !cs->have_muted[1]; + uns mute = !gs->have_muted[1]; CLIST_FOR_EACH(struct pulse_sink_input *, s, pulse_sink_input_list) { - if (s->noct_client_idx == i) + if (s->noct_group_idx == i) { DBG("@@ Client #%d, sink input #%d: setting mute=%u", s->client_idx, s->idx, mute); pulse_sink_input_set_mute(s->idx, mute); @@ -242,12 +290,14 @@ static void update_client_from_button(int button, int on) } } +#if 0 // Not used at the moment + static int find_touched_client(void) { int touched = -1; - for (uns i=0; i < NUM_CLIENTS; i++) - if (noct_rotary_touched[client_map[i].rotary]) + for (uns i=0; i < NUM_GROUPS; i++) + if (group_config[i].enabled && noct_rotary_touched[i]) { if (touched >= 0) return -1; @@ -256,14 +306,18 @@ static int find_touched_client(void) return touched; } +#endif + /*** Default sink controls ***/ +#if 0 // Not mapped to any button at the moment + static const char *get_client_sink(int i) { const char *sink = NULL; CLIST_FOR_EACH(struct pulse_sink_input *, s, pulse_sink_input_list) - if (s->noct_client_idx == i) + if (s->noct_group_idx == i) { struct pulse_sink *sk = (s->sink_idx >= 0) ? pulse_sink_by_idx(s->sink_idx) : NULL; const char *ss = sk ? sk->name : NULL; @@ -355,7 +409,7 @@ static void update_default_sink_from_button(int button, int on) return; CLIST_FOR_EACH(struct pulse_sink_input *, s, pulse_sink_input_list) - if (s->noct_client_idx == i) + if (s->noct_group_idx == i) { DBG("Moving input #%d to sink #%d", s->idx, sk->idx); pulse_sink_input_move(s->idx, sk->idx); @@ -368,6 +422,8 @@ static void update_default_sink_from_button(int button, int on) } } +#endif + /*** MPD controls ***/ static bool mpd_flash_state; @@ -550,10 +606,12 @@ static void do_update(struct main_timer *t) } // Everything normal - update_ring_from_sink(0, "ursarium"); - update_ring_from_sink(1, "catarium"); - update_clients(); + update_ring_from_sink(0, PCH_SINK); + update_button_from_port(8, PCH_SINK, "analog-output-headphones"); + update_groups(); +#if 0 update_default_sink(); +#endif update_mpd(); } @@ -588,17 +646,10 @@ void notify_rotary(int rotary, int delta) switch (rotary) { case 0: - update_sink_from_rotary(delta, "ursarium"); - break; - case 1: - update_sink_from_rotary(delta, "catarium"); - break; - case 8: - update_sink_from_rotary(delta, "ursarium"); - update_sink_from_rotary(delta, "catarium"); + update_sink_from_rotary(delta, PCH_SINK); break; default: - update_client_from_rotary(rotary, delta); + update_group_from_rotary(rotary, delta); } } @@ -610,21 +661,34 @@ void notify_button(int button, int on) switch (button) { case 0: - update_sink_mute_from_button(on, "ursarium"); - break; - case 1: - update_sink_mute_from_button(on, "catarium"); + update_sink_mute_from_button(on, PCH_SINK); break; case 8: + update_port_from_button(on, PCH_SINK, "analog-output-lineout", "analog-output-headphones"); + break; +#if 0 case 9: case 10: update_default_sink_from_button(button, on); break; +#endif case 12: update_mpd_from_button(button, on); break; + case 13: + if (on) + mpd_stop(); + break; + case 14: + if (on) + mpd_prev(); + break; + case 15: + if (on) + mpd_next(); + break; default: - update_client_from_button(button, on); + update_group_from_button(button, on); } } @@ -640,9 +704,28 @@ void notify_touch(int rotary, int on UNUSED) /*** Main entry point ***/ -int main(int argc UNUSED, char **argv) +static int debug; +static int no_fork; + +static struct opt_section options = { + OPT_ITEMS { + OPT_HELP("Control console for the Ursary"), + OPT_HELP(""), + OPT_HELP("Options:"), + OPT_HELP_OPTION, + OPT_BOOL('d', "debug", debug, 0, "\tEnable debugging mode (no fork etc.)"), + OPT_BOOL(0, "no-fork", no_fork, 0, "\tDo not fork\n"), + OPT_END + } +}; + +static void sigterm_handler(struct main_signal *ms UNUSED) +{ + main_shut_down(); +} + +static void daemon_body(struct daemon_params *dp) { - log_init(argv[0]); main_init(); update_timer.handler = do_update; @@ -650,8 +733,39 @@ int main(int argc UNUSED, char **argv) pulse_init(); mpd_init(); - msg(L_DEBUG, "Entering main loop"); + static struct main_signal term_sig = { + .signum = SIGTERM, + .handler = sigterm_handler, + }; + signal_add(&term_sig); + + msg(L_INFO, "Ursary daemon starting"); main_loop(); + msg(L_INFO, "Ursary daemon shut down"); + daemon_exit(dp); +} + +int main(int argc UNUSED, char **argv) +{ + opt_parse(&options, argv+1); + unsetenv("DISPLAY"); + unsetenv("HOME"); + + struct daemon_params dp = { + .flags = ((debug || no_fork) ? DAEMON_FLAG_SIMULATE : 0), + .pid_file = "/run/ursaryd.pid", + .run_as_user = "ursary", + }; + daemon_init(&dp); + + log_init(argv[0]); + if (!debug) + { + struct log_stream *ls = log_new_syslog("daemon", LOG_PID); + ls->levels = ~(1U << L_DEBUG); + log_set_default_stream(ls); + } + daemon_run(&dp, daemon_body); return 0; }