In case the same jack causes one port to become available and another one unavailable, the available should be reported first. This is to avoid unnecessary changes: e g, consider a 'Headphone Jack' making 'Headphone' available and 'Speaker' unavailable. In case the unavailable change triggers first, and there is also a currently available third port (e g 'Digital out'), the routing system might choose to route to this port because neither of the 'Speaker' and 'Headphone' ports are available. Signed-off-by: David Henningsson <david.henningsson at canonical.com> --- src/modules/alsa/module-alsa-card.c | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/src/modules/alsa/module-alsa-card.c b/src/modules/alsa/module-alsa-card.c index 2af7979..c550bd4 100644 --- a/src/modules/alsa/module-alsa-card.c +++ b/src/modules/alsa/module-alsa-card.c @@ -306,7 +306,7 @@ static void init_profile(struct userdata *u) { am->source = pa_alsa_source_new(u->module, u->modargs, __FILE__, u->card, am); } -static void report_port_state(pa_device_port *p, struct userdata *u) { +static pa_available_t calc_port_state(pa_device_port *p, struct userdata *u) { void *state; pa_alsa_jack *jack; pa_available_t pa = PA_AVAILABLE_UNKNOWN; @@ -350,10 +350,14 @@ static void report_port_state(pa_device_port *p, struct userdata *u) { pa = cpa; } } - - pa_device_port_set_available(p, pa); + return pa; } +struct temp_port_avail { + pa_device_port *port; + pa_available_t avail; +}; + static int report_jack_state(snd_mixer_elem_t *melem, unsigned int mask) { struct userdata *u = snd_mixer_elem_get_callback_private(melem); snd_hctl_elem_t *elem = snd_mixer_elem_get_private(melem); @@ -361,7 +365,7 @@ static int report_jack_state(snd_mixer_elem_t *melem, unsigned int mask) { bool plugged_in; void *state; pa_alsa_jack *jack; - pa_device_port *port; + struct temp_port_avail *tp, *tports; pa_assert(u); @@ -378,20 +382,36 @@ static int report_jack_state(snd_mixer_elem_t *melem, unsigned int mask) { pa_log_debug("Jack '%s' is now %s", pa_strnull(snd_hctl_elem_get_name(elem)), plugged_in ? "plugged in" : "unplugged"); + tports = tp = pa_xnew0(struct temp_port_avail, pa_hashmap_size(u->jacks)+1); + PA_HASHMAP_FOREACH(jack, u->jacks, state) if (jack->melem == melem) { jack->plugged_in = plugged_in; if (u->use_ucm) { pa_assert(u->card->ports); - port = pa_hashmap_get(u->card->ports, jack->name); - pa_assert(port); + tp->port = pa_hashmap_get(u->card->ports, jack->name); + pa_assert(tp->port); } else { pa_assert(jack->path); - pa_assert_se(port = jack->path->port); + pa_assert_se(tp->port = jack->path->port); } - report_port_state(port, u); + + tp->avail = calc_port_state(tp->port, u); + tp++; } + + /* Report available ports before unavailable ones: in case port 1 becomes available when port 2 becomes unavailable, + this prevents an unnecessary switch port 1 -> port 3 -> port 2 */ + + for (tp = tports; tp->port; tp++) + if (tp->avail != PA_AVAILABLE_NO) + pa_device_port_set_available(tp->port, tp->avail); + for (tp = tports; tp->port; tp++) + if (tp->avail == PA_AVAILABLE_NO) + pa_device_port_set_available(tp->port, tp->avail); + + pa_xfree(tports); return 0; } -- 1.9.1