[pulseaudio-discuss] [PATCH 7/8] module-alsa-card: Report available ports before unavailable ones

David Henningsson david.henningsson at canonical.com
Tue May 5 08:01:13 PDT 2015


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



More information about the pulseaudio-discuss mailing list