[pulseaudio-discuss] [PATCH 10/11] Jack detection: Make alsa path set have paths in a hashmap

David Henningsson david.henningsson at canonical.com
Tue Aug 30 12:25:03 PDT 2011


Now that the same path can be a part of more than one path set,
the path set must have the paths in a hashmap instead of in a
linked list.

Signed-off-by: David Henningsson <david.henningsson at canonical.com>
---
 src/modules/alsa/alsa-mixer.c  |  177 +++++++++++-----------------------------
 src/modules/alsa/alsa-mixer.h  |    8 +--
 src/modules/alsa/alsa-sink.c   |    5 +-
 src/modules/alsa/alsa-source.c |    5 +-
 4 files changed, 56 insertions(+), 139 deletions(-)

diff --git a/src/modules/alsa/alsa-mixer.c b/src/modules/alsa/alsa-mixer.c
index f248b95..38a1650 100644
--- a/src/modules/alsa/alsa-mixer.c
+++ b/src/modules/alsa/alsa-mixer.c
@@ -537,13 +537,10 @@ void pa_alsa_path_free(pa_alsa_path *p) {
 }
 
 void pa_alsa_path_set_free(pa_alsa_path_set *ps) {
-    pa_alsa_path *p;
     pa_assert(ps);
 
-    while ((p = ps->paths)) {
-        PA_LLIST_REMOVE(pa_alsa_path, ps->paths, p);
-        /* pa_alsa_path_free(p); Paths are now owned by the profile set */
-    }
+    if (ps->paths)
+        pa_hashmap_free(ps->paths, NULL, NULL);
 
     pa_xfree(ps);
 }
@@ -2747,12 +2744,13 @@ void pa_alsa_path_set_callback(pa_alsa_path *p, snd_mixer_t *m, snd_mixer_elem_c
 
 void pa_alsa_path_set_set_callback(pa_alsa_path_set *ps, snd_mixer_t *m, snd_mixer_elem_callback_t cb, void *userdata) {
     pa_alsa_path *p;
+    void *state;
 
     pa_assert(ps);
     pa_assert(m);
     pa_assert(cb);
 
-    PA_LLIST_FOREACH(p, ps->paths)
+    PA_HASHMAP_FOREACH(p, ps->paths, state)
         pa_alsa_path_set_callback(p, m, cb, userdata);
 }
 
@@ -2760,7 +2758,7 @@ pa_alsa_path_set *pa_alsa_path_set_new(pa_alsa_mapping *m, pa_alsa_direction_t d
     pa_alsa_path_set *ps;
     char **pn = NULL, **en = NULL, **ie;
     pa_alsa_decibel_fix *db_fix;
-    void *state;
+    void *state, *state2;
     pa_hashmap *cache;
 
     pa_assert(m);
@@ -2773,6 +2771,7 @@ pa_alsa_path_set *pa_alsa_path_set_new(pa_alsa_mapping *m, pa_alsa_direction_t d
 
     ps = pa_xnew0(pa_alsa_path_set, 1);
     ps->direction = direction;
+    ps->paths = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
 
     if (direction == PA_ALSA_DIRECTION_OUTPUT) {
         pn = m->output_path_names;
@@ -2810,11 +2809,8 @@ pa_alsa_path_set *pa_alsa_path_set_new(pa_alsa_mapping *m, pa_alsa_direction_t d
             }
             pa_assert(pa_hashmap_get(cache, *in) == p);
             pa_log_debug("in = %s, probed = %d, supported = %d", *in, p->probed, p->supported);
-            if (p) {
-                PA_LLIST_INSERT_AFTER(pa_alsa_path, ps->paths, ps->last_path, p);
-                ps->last_path = p;
-            }
-
+            if (p)
+                pa_hashmap_put(ps->paths, p, p);
         }
 
         goto finish;
@@ -2854,8 +2850,7 @@ pa_alsa_path_set *pa_alsa_path_set_new(pa_alsa_mapping *m, pa_alsa_direction_t d
             p->last_element = e;
         }
 
-        PA_LLIST_INSERT_AFTER(pa_alsa_path, ps->paths, ps->last_path, p);
-        ps->last_path = p;
+        pa_hashmap_put(ps->paths, *ie, p);
     }
 
 finish:
@@ -2863,7 +2858,7 @@ finish:
     PA_HASHMAP_FOREACH(db_fix, m->profile_set->decibel_fixes, state) {
         pa_alsa_path *p;
 
-        PA_LLIST_FOREACH(p, ps->paths) {
+        PA_HASHMAP_FOREACH(p, ps->paths, state2) {
             pa_alsa_element *e;
 
             PA_LLIST_FOREACH(e, p->elements) {
@@ -2885,6 +2880,7 @@ finish:
 
 void pa_alsa_path_set_dump(pa_alsa_path_set *ps) {
     pa_alsa_path *p;
+    void *state;
     pa_assert(ps);
 
     pa_log_debug("Path Set %p, direction=%i, probed=%s",
@@ -2892,7 +2888,7 @@ void pa_alsa_path_set_dump(pa_alsa_path_set *ps) {
                  ps->direction,
                  pa_yes_no(ps->probed));
 
-    PA_LLIST_FOREACH(p, ps->paths)
+    PA_HASHMAP_FOREACH(p, ps->paths, state)
         pa_alsa_path_dump(p);
 }
 
@@ -3038,20 +3034,21 @@ static pa_bool_t element_is_subset(pa_alsa_element *a, pa_alsa_element *b, snd_m
 }
 
 static void path_set_condense(pa_alsa_path_set *ps, snd_mixer_t *m) {
-    pa_alsa_path *p, *np;
+    pa_alsa_path *p;
+    void *state;
 
     pa_assert(ps);
     pa_assert(m);
 
     /* If we only have one path, then don't bother */
-    if (!ps->paths || !ps->paths->next)
+    if (pa_hashmap_size(ps->paths) < 2)
         return;
 
-    for (p = ps->paths; p; p = np) {
+    PA_HASHMAP_FOREACH(p, ps->paths, state) {
         pa_alsa_path *p2;
-        np = p->next;
+        void *state2;
 
-        PA_LLIST_FOREACH(p2, ps->paths) {
+        PA_HASHMAP_FOREACH(p2, ps->paths, state2) {
             pa_alsa_element *ea, *eb;
             pa_bool_t is_subset = TRUE;
 
@@ -3085,24 +3082,33 @@ static void path_set_condense(pa_alsa_path_set *ps, snd_mixer_t *m) {
 
             if (is_subset) {
                 pa_log_debug("Removing path '%s' as it is a subset of '%s'.", p->name, p2->name);
-                PA_LLIST_REMOVE(pa_alsa_path, ps->paths, p);
-                /* pa_alsa_path_free(p); Paths are now owned by the profile set */
+                pa_hashmap_remove(ps->paths, p);
                 break;
             }
         }
     }
 }
 
+static pa_alsa_path* path_set_find_path_by_name(pa_alsa_path_set *ps, const char* name, pa_alsa_path *ignore)
+{
+    pa_alsa_path* p;
+    void *state;
+
+    PA_HASHMAP_FOREACH(p, ps->paths, state)
+        if (p != ignore && pa_streq(p->name, name))
+            return p;
+    return NULL;
+}
+
 static void path_set_make_paths_unique(pa_alsa_path_set *ps) {
     pa_alsa_path *p, *q;
+    void *state, *state2;
 
-    PA_LLIST_FOREACH(p, ps->paths) {
+    PA_HASHMAP_FOREACH(p, ps->paths, state) {
         unsigned i;
         char *m;
 
-        for (q = p->next; q; q = q->next)
-            if (pa_streq(q->name, p->name))
-                break;
+        q = path_set_find_path_by_name(ps, p->name, p);
 
         if (!q)
             continue;
@@ -3110,7 +3116,8 @@ static void path_set_make_paths_unique(pa_alsa_path_set *ps) {
         m = pa_xstrdup(p->name);
 
         /* OK, this name is not unique, hence let's rename */
-        for (i = 1, q = p; q; q = q->next) {
+        i = 1;
+        PA_HASHMAP_FOREACH(q, ps->paths, state2) {
             char *nn, *nd;
 
             if (!pa_streq(q->name, m))
@@ -3679,7 +3686,8 @@ fail:
 }
 
 static void mapping_paths_probe(pa_alsa_mapping *m, pa_alsa_profile *profile, pa_alsa_direction_t direction) {
-    pa_alsa_path *p, *np;
+    pa_alsa_path *p;
+    void *state;
     snd_pcm_t *pcm_handle;
     pa_alsa_path_set *ps;
     snd_mixer_t *mixer_handle;
@@ -3705,10 +3713,9 @@ static void mapping_paths_probe(pa_alsa_mapping *m, pa_alsa_profile *profile, pa
     if (!mixer_handle)
         return; /* Cannot open mixer :-( */
 
-    for (p = ps->paths; p; p = np) {
-        np = p->next;
+    PA_HASHMAP_FOREACH(p, ps->paths, state) {
         if (pa_alsa_path_probe(p, mixer_handle, m->profile_set->ignore_dB, m->profile_set) < 0) {
-            PA_LLIST_REMOVE(pa_alsa_path, ps->paths, p);
+            pa_hashmap_remove(ps->paths, p);
         }
     }
 
@@ -4361,8 +4368,10 @@ static pa_device_port* device_port_alsa_init(pa_hashmap *ports,
             pa_device_port_ref(p);
         }
     }
-    pa_log_debug("Adding port %s to profile %s", p->name, cp->name);
-    pa_hashmap_put(p->profiles, cp->name, cp);
+    if (cp) {
+        pa_log_debug("Adding port %s to profile %s", p->name, cp->name);
+        pa_hashmap_put(p->profiles, cp->name, cp);
+    }
 
     return p;
 }
@@ -4370,16 +4379,16 @@ static pa_device_port* device_port_alsa_init(pa_hashmap *ports,
 void pa_alsa_path_set_add_ports(pa_alsa_path_set *ps, pa_card_profile *cp, pa_hashmap *ports)
 {
     pa_alsa_path *path;
+    void *state;
 
-    pa_assert(cp);
     pa_assert(ports);
 
-    pa_log_debug("pa_alsa_path_set_add_ports: ps = %p, profile = %s", ps, cp->name);
+    pa_log_debug("pa_alsa_path_set_add_ports: ps = %p, profile = %s", ps, cp ? cp->name : "(null)");
 
     if (!ps)
         return;
 
-    PA_LLIST_FOREACH(path, ps->paths) {
+    PA_HASHMAP_FOREACH(path, ps->paths, state) {
         pa_log_debug("pa_alsa_path_set_add_ports: path = %p, %s", path, path->name);
         if (!path->settings || !path->settings->next) {
             /* If there is no or just one setting we only need a
@@ -4408,105 +4417,17 @@ void pa_alsa_path_set_add_ports(pa_alsa_path_set *ps, pa_card_profile *cp, pa_ha
                 pa_xfree(d);
             }
         }
-
     }
 }
 
-
-
 void pa_alsa_add_ports(pa_hashmap **p, pa_alsa_path_set *ps) {
-    pa_alsa_path *path;
-
     pa_assert(p);
     pa_assert(!*p);
     pa_assert(ps);
 
-    *p = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
-
-    /* if there is no path, we don't want a port list */
-    if (!ps->paths)
-        return;
-
-    if (!ps->paths->next){
-        pa_alsa_setting *s;
-
-        /* If there is only one path, but no or only one setting, then
-         * we want a port list either */
-        if (!ps->paths->settings || !ps->paths->settings->next)
-            return;
-
-        /* Ok, there is only one path, however with multiple settings,
-         * so let's create a port for each setting */
+    if (ps->paths && pa_hashmap_size(ps->paths) > 0) {
         *p = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
-
-        PA_LLIST_FOREACH(s, ps->paths->settings) {
-            pa_device_port *port;
-            pa_alsa_port_data *data;
-
-            port = pa_device_port_new(s->name, s->description, sizeof(pa_alsa_port_data));
-            port->priority = s->priority;
-
-            data = PA_DEVICE_PORT_DATA(port);
-            data->path = ps->paths;
-            data->setting = s;
-
-            pa_hashmap_put(*p, port->name, port);
-        }
-
-    } else {
-
-        /* We have multiple paths, so let's create a port for each
-         * one, and each of each settings */
-        *p = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
-
-        PA_LLIST_FOREACH(path, ps->paths) {
-
-            if (!path->settings || !path->settings->next) {
-                pa_device_port *port;
-                pa_alsa_port_data *data;
-
-                /* If there is no or just one setting we only need a
-                 * single entry */
-
-                port = pa_device_port_new(path->name, path->description, sizeof(pa_alsa_port_data));
-                port->priority = path->priority * 100;
-
-
-                data = PA_DEVICE_PORT_DATA(port);
-                data->path = path;
-                data->setting = path->settings;
-
-                pa_hashmap_put(*p, port->name, port);
-            } else {
-                pa_alsa_setting *s;
-
-                PA_LLIST_FOREACH(s, path->settings) {
-                    pa_device_port *port;
-                    pa_alsa_port_data *data;
-                    char *n, *d;
-
-                    n = pa_sprintf_malloc("%s;%s", path->name, s->name);
-
-                    if (s->description[0])
-                        d = pa_sprintf_malloc(_("%s / %s"), path->description, s->description);
-                    else
-                        d = pa_xstrdup(path->description);
-
-                    port = pa_device_port_new(n, d, sizeof(pa_alsa_port_data));
-                    port->priority = path->priority * 100 + s->priority;
-
-                    pa_xfree(n);
-                    pa_xfree(d);
-
-                    data = PA_DEVICE_PORT_DATA(port);
-                    data->path = path;
-                    data->setting = s;
-
-                    pa_hashmap_put(*p, port->name, port);
-                }
-            }
-        }
+        pa_alsa_path_set_add_ports(ps, NULL, *p);
     }
-
-    pa_log_debug("Added %u ports", pa_hashmap_size(*p));
+    pa_log_debug("Added %u ports", *p ? pa_hashmap_size(*p) : 0);
 }
diff --git a/src/modules/alsa/alsa-mixer.h b/src/modules/alsa/alsa-mixer.h
index 75edc02..e5d0307 100644
--- a/src/modules/alsa/alsa-mixer.h
+++ b/src/modules/alsa/alsa-mixer.h
@@ -160,8 +160,6 @@ struct pa_alsa_element {
  * used to control it as if it had a single volume slider, a single
  * mute switch and a single list of selectable options. */
 struct pa_alsa_path {
-    PA_LLIST_FIELDS(pa_alsa_path);
-
     pa_alsa_direction_t direction;
 
     char *name;
@@ -197,13 +195,9 @@ struct pa_alsa_path {
 /* A path set is simply a set of paths that are applicable to a
  * device */
 struct pa_alsa_path_set {
-    PA_LLIST_HEAD(pa_alsa_path, paths);
+    pa_hashmap *paths;
     pa_alsa_direction_t direction;
     pa_bool_t probed:1;
-
-    /* This is used during parsing only, as a shortcut so that we
-     * don't have to iterate the list all the time */
-    pa_alsa_path *last_path;
 };
 
 int pa_alsa_setting_select(pa_alsa_setting *s, snd_mixer_t *m);
diff --git a/src/modules/alsa/alsa-sink.c b/src/modules/alsa/alsa-sink.c
index 850e07b..0f3fe8c 100644
--- a/src/modules/alsa/alsa-sink.c
+++ b/src/modules/alsa/alsa-sink.c
@@ -1847,7 +1847,7 @@ static int setup_mixer(struct userdata *u, pa_bool_t ignore_dB) {
     } else {
 
         if (!u->mixer_path && u->mixer_path_set)
-            u->mixer_path = u->mixer_path_set->paths;
+            u->mixer_path = pa_hashmap_first(u->mixer_path_set->paths);
 
         if (u->mixer_path) {
             /* Hmm, we have only a single path, then let's activate it */
@@ -1865,8 +1865,9 @@ static int setup_mixer(struct userdata *u, pa_bool_t ignore_dB) {
     /* Will we need to register callbacks? */
     if (u->mixer_path_set && u->mixer_path_set->paths) {
         pa_alsa_path *p;
+        void *state;
 
-        PA_LLIST_FOREACH(p, u->mixer_path_set->paths) {
+        PA_HASHMAP_FOREACH(p, u->mixer_path_set->paths, state) {
             if (p->has_volume || p->has_mute)
                 need_mixer_callback = TRUE;
         }
diff --git a/src/modules/alsa/alsa-source.c b/src/modules/alsa/alsa-source.c
index e34e51f..9c21c3c 100644
--- a/src/modules/alsa/alsa-source.c
+++ b/src/modules/alsa/alsa-source.c
@@ -1558,7 +1558,7 @@ static int setup_mixer(struct userdata *u, pa_bool_t ignore_dB) {
     } else {
 
         if (!u->mixer_path && u->mixer_path_set)
-            u->mixer_path = u->mixer_path_set->paths;
+            u->mixer_path = pa_hashmap_first(u->mixer_path_set->paths);
 
         if (u->mixer_path) {
             /* Hmm, we have only a single path, then let's activate it */
@@ -1576,8 +1576,9 @@ static int setup_mixer(struct userdata *u, pa_bool_t ignore_dB) {
     /* Will we need to register callbacks? */
     if (u->mixer_path_set && u->mixer_path_set->paths) {
         pa_alsa_path *p;
+        void *state;
 
-        PA_LLIST_FOREACH(p, u->mixer_path_set->paths) {
+        PA_HASHMAP_FOREACH(p, u->mixer_path_set->paths, state) {
             if (p->has_volume || p->has_mute)
                 need_mixer_callback = TRUE;
         }
-- 
1.7.5.4



More information about the pulseaudio-discuss mailing list