From 408b9f8cc048fac657553aec615d6946563c3cef Mon Sep 17 00:00:00 2001 From: Arun Raghavan Date: Mon, 9 May 2016 15:09:57 +0530 Subject: alsa: Reread and upate jack status when a card is unsuspended This is needed so we don't keep stale jack availability information while the card is suspended. Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=93259 Signed-off-by: Arun Raghavan --- src/modules/alsa/module-alsa-card.c | 36 ++++++++++++++++++++---------------- src/pulsecore/card.c | 13 +++++++++++-- src/pulsecore/core.h | 1 + 3 files changed, 32 insertions(+), 18 deletions(-) diff --git a/src/modules/alsa/module-alsa-card.c b/src/modules/alsa/module-alsa-card.c index b1e3e633b..e5cc4aea5 100644 --- a/src/modules/alsa/module-alsa-card.c +++ b/src/modules/alsa/module-alsa-card.c @@ -369,10 +369,7 @@ static int report_jack_state(snd_mixer_elem_t *melem, unsigned int mask) { pa_assert(u); - /* Quick and dirty fix for - * https://bugs.freedesktop.org/show_bug.cgi?id=93259 - * - * Changing the jack state may cause a port change, and a port change will + /* Changing the jack state may cause a port change, and a port change will * make the sink or source change the mixer settings. If there are multiple * users having pulseaudio running, the mixer changes done by inactive * users may mess up the volume settings for the active users, because when @@ -382,18 +379,8 @@ static int report_jack_state(snd_mixer_elem_t *melem, unsigned int mask) { * with alsamixer. Even single-user systems suffer from this, because gdm * runs its own pulseaudio instance. * - * Returning early here means that jack state events get ignored while the - * user is inactive. When the user becomes active again, the routing may - * not any more match the real jack state. While this is bad, this should - * nevertheless be better than messing up the volume every time headphones - * are plugged in or out. - * - * It might be better to unload the card altogether when the user becomes - * inactive and udev removes the permission to the card. That requires at - * least improving the default sink handling so that if the unloaded card - * contained the default sink, the default sink should be restored to what - * it was earlier, when the user becomes active and the card becomes - * accessible. */ + * We rerun this function when being unsuspended to catch up on jack state + * changes */ if (u->card->suspend_cause & PA_SUSPEND_SESSION) return 0; @@ -604,6 +591,20 @@ static void set_card_name(pa_card_new_data *data, pa_modargs *ma, const char *de pa_xfree(t); } +static pa_hook_result_t card_suspend_changed(pa_core *c, pa_card *card, struct userdata *u) { + void *state; + pa_alsa_jack *jack; + + if (card->suspend_cause == 0) { + /* We were unsuspended, update jack state in case it changed while we were suspended */ + PA_HASHMAP_FOREACH(jack, u->jacks, state) { + report_jack_state(jack->melem, 0); + } + } + + return PA_HOOK_OK; +} + static pa_hook_result_t sink_input_put_hook_callback(pa_core *c, pa_sink_input *sink_input, struct userdata *u) { const char *role; pa_sink *sink = sink_input->sink; @@ -810,6 +811,9 @@ int pa__init(pa_module *m) { u->card->userdata = u; u->card->set_profile = card_set_profile; + pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_CARD_SUSPEND_CHANGED], PA_HOOK_NORMAL, + (pa_hook_cb_t) card_suspend_changed, u); + init_jacks(u); init_profile(u); init_eld_ctls(u); diff --git a/src/pulsecore/card.c b/src/pulsecore/card.c index 72ecd4e80..410746bf6 100644 --- a/src/pulsecore/card.c +++ b/src/pulsecore/card.c @@ -358,16 +358,25 @@ void pa_card_set_preferred_port(pa_card *c, pa_direction_t direction, pa_device_ int pa_card_suspend(pa_card *c, bool suspend, pa_suspend_cause_t cause) { pa_sink *sink; pa_source *source; + pa_suspend_cause_t suspend_cause; uint32_t idx; int ret = 0; pa_assert(c); pa_assert(cause != 0); + suspend_cause = c->suspend_cause; + if (suspend) - c->suspend_cause |= cause; + suspend_cause |= cause; else - c->suspend_cause &= ~cause; + suspend_cause &= ~cause; + + if (c->suspend_cause != suspend_cause) { + pa_log_debug("Card suspend causes/state changed"); + c->suspend_cause = suspend_cause; + pa_hook_fire(&c->core->hooks[PA_CORE_HOOK_CARD_SUSPEND_CHANGED], c); + } PA_IDXSET_FOREACH(sink, c->sinks, idx) { int r; diff --git a/src/pulsecore/core.h b/src/pulsecore/core.h index 69ab4d0ca..00d7f2f2d 100644 --- a/src/pulsecore/core.h +++ b/src/pulsecore/core.h @@ -124,6 +124,7 @@ typedef enum pa_core_hook { PA_CORE_HOOK_CARD_PROFILE_CHANGED, PA_CORE_HOOK_CARD_PROFILE_ADDED, PA_CORE_HOOK_CARD_PROFILE_AVAILABLE_CHANGED, + PA_CORE_HOOK_CARD_SUSPEND_CHANGED, PA_CORE_HOOK_PORT_AVAILABLE_CHANGED, PA_CORE_HOOK_PORT_LATENCY_OFFSET_CHANGED, PA_CORE_HOOK_DEFAULT_SINK_CHANGED, -- cgit v1.2.1