[pulseaudio-commits] src/modules

Tanu Kaskinen tanuk at kemper.freedesktop.org
Thu Dec 1 12:05:15 PST 2011


 src/modules/alsa/alsa-mixer.c       |  351 +++++++++++++++++++++---------------
 src/modules/alsa/alsa-mixer.h       |   17 -
 src/modules/alsa/alsa-sink.c        |   25 --
 src/modules/alsa/alsa-source.c      |   25 --
 src/modules/alsa/module-alsa-card.c |   20 +-
 5 files changed, 253 insertions(+), 185 deletions(-)

New commits:
commit 426daaf6bb7670a775318f243b509ae625c9f700
Author: David Henningsson <david.henningsson at canonical.com>
Date:   Fri Nov 25 15:17:16 2011 +0100

    alsa: add card ports and path probe cache
    
    To be able to add ports to all profiles, we need to probe all
    profiles at startup. To speed this up, we now have a cache of
    probes paths which is owned by the profile set. Since paths
    are now owned by the profile set, the path set must now have
    a hashmap of paths instead of a linked list.
    
    Signed-off-by: David Henningsson <david.henningsson at canonical.com>

diff --git a/src/modules/alsa/alsa-mixer.c b/src/modules/alsa/alsa-mixer.c
index a28cb74..6a909ea 100644
--- a/src/modules/alsa/alsa-mixer.c
+++ b/src/modules/alsa/alsa-mixer.c
@@ -561,13 +561,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);
-    }
+    if (ps->paths)
+        pa_hashmap_free(ps->paths, NULL, NULL);
 
     pa_xfree(ps);
 }
@@ -2575,7 +2572,8 @@ int pa_alsa_path_probe(pa_alsa_path *p, snd_mixer_t *m, pa_bool_t ignore_dB) {
     pa_assert(m);
 
     if (p->probed)
-        return 0;
+        return p->supported ? 0 : -1;
+    p->probed = TRUE;
 
     pa_zero(min_dB);
     pa_zero(max_dB);
@@ -2650,7 +2648,6 @@ int pa_alsa_path_probe(pa_alsa_path *p, snd_mixer_t *m, pa_bool_t ignore_dB) {
     path_create_settings(p);
 
     p->supported = TRUE;
-    p->probed = TRUE;
 
     p->min_dB = INFINITY;
     p->max_dB = -INFINITY;
@@ -2767,12 +2764,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);
 }
 
@@ -2780,7 +2778,8 @@ 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);
     pa_assert(m->profile_set);
@@ -2792,19 +2791,24 @@ 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)
+    if (direction == PA_ALSA_DIRECTION_OUTPUT) {
         pn = m->output_path_names;
-    else if (direction == PA_ALSA_DIRECTION_INPUT)
+        cache = m->profile_set->output_paths;
+    }
+    else if (direction == PA_ALSA_DIRECTION_INPUT) {
         pn = m->input_path_names;
+        cache = m->profile_set->input_paths;
+    }
 
     if (pn) {
         char **in;
 
         for (in = pn; *in; in++) {
-            pa_alsa_path *p;
+            pa_alsa_path *p = NULL;
             pa_bool_t duplicate = FALSE;
-            char **kn, *fn;
+            char **kn;
 
             for (kn = pn; kn < in; kn++)
                 if (pa_streq(*kn, *in)) {
@@ -2815,15 +2819,18 @@ pa_alsa_path_set *pa_alsa_path_set_new(pa_alsa_mapping *m, pa_alsa_direction_t d
             if (duplicate)
                 continue;
 
-            fn = pa_sprintf_malloc("%s.conf", *in);
-
-            if ((p = pa_alsa_path_new(paths_dir, fn, direction))) {
-                p->path_set = ps;
-                PA_LLIST_INSERT_AFTER(pa_alsa_path, ps->paths, ps->last_path, p);
-                ps->last_path = p;
+            p = pa_hashmap_get(cache, *in);
+            if (!p) {
+                char *fn = pa_sprintf_malloc("%s.conf", *in);
+                p = pa_alsa_path_new(paths_dir, fn, direction);
+                pa_xfree(fn);
+                if (p)
+                    pa_hashmap_put(cache, *in, p);
             }
+            pa_assert(pa_hashmap_get(cache, *in) == p);
+            if (p)
+                pa_hashmap_put(ps->paths, p, p);
 
-            pa_xfree(fn);
         }
 
         goto finish;
@@ -2844,7 +2851,6 @@ pa_alsa_path_set *pa_alsa_path_set_new(pa_alsa_mapping *m, pa_alsa_direction_t d
         pa_alsa_path *p;
 
         p = pa_alsa_path_synthesize(*ie, direction);
-        p->path_set = ps;
 
         /* Mark all other passed elements for require-absent */
         for (je = en; *je; je++) {
@@ -2864,8 +2870,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:
@@ -2873,7 +2878,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) {
@@ -2895,6 +2900,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",
@@ -2902,7 +2908,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);
 }
 
@@ -3048,20 +3054,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;
 
@@ -3090,24 +3097,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);
+                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;
@@ -3115,7 +3131,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))
@@ -3136,34 +3153,6 @@ static void path_set_make_paths_unique(pa_alsa_path_set *ps) {
     }
 }
 
-void pa_alsa_path_set_probe(pa_alsa_path_set *ps, snd_mixer_t *m, pa_bool_t ignore_dB) {
-    pa_alsa_path *p, *n;
-
-    pa_assert(ps);
-
-    if (ps->probed)
-        return;
-
-    for (p = ps->paths; p; p = n) {
-        n = p->next;
-
-        if (pa_alsa_path_probe(p, m, ignore_dB) < 0) {
-            PA_LLIST_REMOVE(pa_alsa_path, ps->paths, p);
-            pa_alsa_path_free(p);
-        }
-    }
-
-    pa_log_debug("Found mixer paths (before tidying):");
-    pa_alsa_path_set_dump(ps);
-
-    path_set_condense(ps, m);
-    path_set_make_paths_unique(ps);
-    ps->probed = TRUE;
-
-    pa_log_debug("Available mixer paths (after tidying):");
-    pa_alsa_path_set_dump(ps);
-}
-
 static void mapping_free(pa_alsa_mapping *m) {
     pa_assert(m);
 
@@ -3175,6 +3164,10 @@ static void mapping_free(pa_alsa_mapping *m) {
     pa_xstrfreev(m->output_path_names);
     pa_xstrfreev(m->input_element);
     pa_xstrfreev(m->output_element);
+    if (m->input_path_set)
+        pa_alsa_path_set_free(m->input_path_set);
+    if (m->output_path_set)
+        pa_alsa_path_set_free(m->output_path_set);
 
     pa_assert(!m->input_pcm);
     pa_assert(!m->output_pcm);
@@ -3203,6 +3196,24 @@ static void profile_free(pa_alsa_profile *p) {
 void pa_alsa_profile_set_free(pa_alsa_profile_set *ps) {
     pa_assert(ps);
 
+    if (ps->input_paths) {
+        pa_alsa_path *p;
+
+        while ((p = pa_hashmap_steal_first(ps->input_paths)))
+            pa_alsa_path_free(p);
+
+        pa_hashmap_free(ps->input_paths, NULL, NULL);
+    }
+
+    if (ps->output_paths) {
+        pa_alsa_path *p;
+
+        while ((p = pa_hashmap_steal_first(ps->output_paths)))
+            pa_alsa_path_free(p);
+
+        pa_hashmap_free(ps->output_paths, NULL, NULL);
+    }
+
     if (ps->profiles) {
         pa_alsa_profile *p;
 
@@ -3688,6 +3699,53 @@ fail:
     return -1;
 }
 
+static void mapping_paths_probe(pa_alsa_mapping *m, pa_alsa_profile *profile,
+                                pa_alsa_direction_t direction) {
+
+    pa_alsa_path *p;
+    void *state;
+    snd_pcm_t *pcm_handle;
+    pa_alsa_path_set *ps;
+    snd_mixer_t *mixer_handle;
+
+    if (direction == PA_ALSA_DIRECTION_OUTPUT) {
+        if (m->output_path_set)
+            return; /* Already probed */
+        m->output_path_set = ps = pa_alsa_path_set_new(m, direction, NULL); /* FIXME: Handle paths_dir */
+        pcm_handle = m->output_pcm;
+    } else {
+        if (m->input_path_set)
+            return; /* Already probed */
+        m->input_path_set = ps = pa_alsa_path_set_new(m, direction, NULL); /* FIXME: Handle paths_dir */
+        pcm_handle = m->input_pcm;
+    }
+
+    if (!ps)
+        return; /* No paths */
+
+    pa_assert(pcm_handle);
+
+    mixer_handle = pa_alsa_open_mixer_for_pcm(pcm_handle, NULL);
+    if (!mixer_handle)
+        return; /* Cannot open mixer :-( */
+
+    PA_HASHMAP_FOREACH(p, ps->paths, state) {
+        if (pa_alsa_path_probe(p, mixer_handle, m->profile_set->ignore_dB) < 0) {
+            pa_hashmap_remove(ps->paths, p);
+        }
+    }
+
+    path_set_condense(ps, mixer_handle);
+    path_set_make_paths_unique(ps);
+    ps->probed = TRUE;
+
+    if (mixer_handle)
+        snd_mixer_close(mixer_handle);
+
+    pa_log_debug("Available mixer paths (after tidying):");
+    pa_alsa_path_set_dump(ps);
+}
+
 static int mapping_verify(pa_alsa_mapping *m, const pa_channel_map *bonus) {
 
     static const struct description_map well_known_descriptions[] = {
@@ -4051,6 +4109,8 @@ pa_alsa_profile_set* pa_alsa_profile_set_new(const char *fname, const pa_channel
     ps->mappings = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
     ps->profiles = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
     ps->decibel_fixes = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
+    ps->input_paths = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
+    ps->output_paths = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
 
     items[0].data = &ps->auto_profiles;
 
@@ -4213,8 +4273,21 @@ void pa_alsa_profile_set_probe(
 
         last = p;
 
-        if (p->supported)
-            pa_log_debug("Profile %s supported.", p->name);
+        if (!p->supported)
+            continue;
+
+        pa_log_debug("Profile %s supported.", p->name);
+
+        if (p->output_mappings)
+            PA_IDXSET_FOREACH(m, p->output_mappings, idx)
+                if (m->output_pcm)
+                    mapping_paths_probe(m, p, PA_ALSA_DIRECTION_OUTPUT);
+
+        if (p->input_mappings)
+            PA_IDXSET_FOREACH(m, p->input_mappings, idx)
+                if (m->input_pcm)
+                    mapping_paths_probe(m, p, PA_ALSA_DIRECTION_INPUT);
+
     }
 
     /* Clean up */
@@ -4286,98 +4359,100 @@ void pa_alsa_profile_set_dump(pa_alsa_profile_set *ps) {
         pa_alsa_decibel_fix_dump(db_fix);
 }
 
-void pa_alsa_add_ports(pa_core *c, pa_hashmap **p, pa_alsa_path_set *ps) {
-    pa_alsa_path *path;
+static pa_device_port* device_port_alsa_init(pa_hashmap *ports,
+    const char* name,
+    const char* description,
+    pa_alsa_path *path,
+    pa_alsa_setting *setting,
+    pa_card_profile *cp,
+    pa_hashmap *extra,
+    pa_core *core) {
 
-    pa_assert(c);
-    pa_assert(p);
-    pa_assert(!*p);
-    pa_assert(ps);
+    pa_device_port * p = pa_hashmap_get(ports, name);
+    if (!p) {
+        pa_alsa_port_data *data;
 
-    /* if there is no path, we don't want a port list */
-    if (!ps->paths)
-        return;
+        p = pa_device_port_new(core, name, description, sizeof(pa_alsa_port_data));
+        pa_assert(p);
+        pa_hashmap_put(ports, name, p);
+        p->profiles = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
 
-    if (!ps->paths->next){
-        pa_alsa_setting *s;
+        data = PA_DEVICE_PORT_DATA(p);
+        data->path = path;
+        data->setting = setting;
+    }
 
-        /* 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;
+    p->is_input |= path->direction == PA_ALSA_DIRECTION_ANY || path->direction == PA_ALSA_DIRECTION_INPUT;
+    p->is_output |= path->direction == PA_ALSA_DIRECTION_ANY || path->direction == PA_ALSA_DIRECTION_OUTPUT;
 
-        /* Ok, there is only one path, however with multiple settings,
-         * so let's create a port for each setting */
-        *p = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
+    if (cp)
+        pa_hashmap_put(p->profiles, cp->name, cp);
 
-        PA_LLIST_FOREACH(s, ps->paths->settings) {
-            pa_device_port *port;
-            pa_alsa_port_data *data;
+    if (extra) {
+        pa_hashmap_put(extra, name, p);
+        pa_device_port_ref(p);
+    }
 
-            port = pa_device_port_new(c, s->name, s->description, sizeof(pa_alsa_port_data));
-            port->priority = s->priority;
+    return p;
+}
 
-            data = PA_DEVICE_PORT_DATA(port);
-            data->path = ps->paths;
-            data->setting = s;
+void pa_alsa_path_set_add_ports(
+        pa_alsa_path_set *ps,
+        pa_card_profile *cp,
+        pa_hashmap *ports,
+        pa_hashmap *extra,
+        pa_core *core) {
 
-            pa_hashmap_put(*p, port->name, port);
-        }
+    pa_alsa_path *path;
+    void *state;
 
-    } else {
+    pa_assert(ports);
 
-        /* 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);
+    if (!ps)
+        return;
 
-        PA_LLIST_FOREACH(path, ps->paths) {
+    PA_HASHMAP_FOREACH(path, ps->paths, state) {
+        if (!path->settings || !path->settings->next) {
+            /* If there is no or just one setting we only need a
+             * single entry */
+            pa_device_port *port = device_port_alsa_init(ports, path->name,
+                path->description, path, path->settings, cp, extra, core);
+            port->priority = path->priority * 100;
 
-            if (!path->settings || !path->settings->next) {
+        } else {
+            pa_alsa_setting *s;
+            PA_LLIST_FOREACH(s, path->settings) {
                 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(c, 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;
+                char *n, *d;
 
-                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);
 
-                    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);
 
-                    if (s->description[0])
-                        d = pa_sprintf_malloc(_("%s / %s"), path->description, s->description);
-                    else
-                        d = pa_xstrdup(path->description);
+                port = device_port_alsa_init(ports, n, d, path, s, cp, extra, core);
+                port->priority = path->priority * 100 + s->priority;
 
-                    port = pa_device_port_new(c, n, d, sizeof(pa_alsa_port_data));
-                    port->priority = path->priority * 100 + s->priority;
+                pa_xfree(n);
+                pa_xfree(d);
+            }
+        }
+    }
+}
 
-                    pa_xfree(n);
-                    pa_xfree(d);
+void pa_alsa_add_ports(pa_hashmap **p, pa_alsa_path_set *ps, pa_card *card) {
 
-                    data = PA_DEVICE_PORT_DATA(port);
-                    data->path = path;
-                    data->setting = s;
+    pa_assert(p);
+    pa_assert(!*p);
+    pa_assert(ps);
 
-                    pa_hashmap_put(*p, port->name, port);
-                }
-            }
-        }
+    if (ps->paths && pa_hashmap_size(ps->paths) > 0) {
+        pa_assert(card);
+        *p = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
+        pa_alsa_path_set_add_ports(ps, NULL, card->ports, *p, card->core);
     }
 
-    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 818e88a..c0a746c 100644
--- a/src/modules/alsa/alsa-mixer.h
+++ b/src/modules/alsa/alsa-mixer.h
@@ -158,9 +158,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_alsa_path_set *path_set;
-    PA_LLIST_FIELDS(pa_alsa_path);
-
     pa_alsa_direction_t direction;
 
     char *name;
@@ -192,13 +189,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);
@@ -242,6 +235,8 @@ struct pa_alsa_mapping {
     char **output_path_names;
     char **input_element; /* list of fallbacks */
     char **output_element;
+    pa_alsa_path_set *input_path_set;
+    pa_alsa_path_set *output_path_set;
 
     unsigned supported;
 
@@ -289,8 +284,11 @@ struct pa_alsa_profile_set {
     pa_hashmap *mappings;
     pa_hashmap *profiles;
     pa_hashmap *decibel_fixes;
+    pa_hashmap *input_paths;
+    pa_hashmap *output_paths;
 
     pa_bool_t auto_profiles;
+    pa_bool_t ignore_dB:1;
     pa_bool_t probed:1;
 };
 
@@ -323,6 +321,7 @@ struct pa_alsa_port_data {
     pa_alsa_setting *setting;
 };
 
-void pa_alsa_add_ports(pa_core *c, pa_hashmap **p, pa_alsa_path_set *ps);
+void pa_alsa_add_ports(pa_hashmap **p, pa_alsa_path_set *ps, pa_card *card);
+void pa_alsa_path_set_add_ports(pa_alsa_path_set *ps, pa_card_profile *cp, pa_hashmap *ports, pa_hashmap *extra, pa_core *core);
 
 #endif
diff --git a/src/modules/alsa/alsa-sink.c b/src/modules/alsa/alsa-sink.c
index 786aa20..c4ed760 100644
--- a/src/modules/alsa/alsa-sink.c
+++ b/src/modules/alsa/alsa-sink.c
@@ -1860,22 +1860,14 @@ static void find_mixer(struct userdata *u, pa_alsa_mapping *mapping, const char
 
         pa_log_debug("Probed mixer path %s:", u->mixer_path->name);
         pa_alsa_path_dump(u->mixer_path);
-    } else {
-
-        if (!(u->mixer_path_set = pa_alsa_path_set_new(mapping, PA_ALSA_DIRECTION_OUTPUT, u->paths_dir)))
-            goto fail;
-
-        pa_alsa_path_set_probe(u->mixer_path_set, u->mixer_handle, ignore_dB);
-    }
+    } else if (!(u->mixer_path_set = mapping->output_path_set))
+        goto fail;
 
     return;
 
 fail:
 
-    if (u->mixer_path_set) {
-        pa_alsa_path_set_free(u->mixer_path_set);
-        u->mixer_path_set = NULL;
-    } else if (u->mixer_path) {
+    if (u->mixer_path) {
         pa_alsa_path_free(u->mixer_path);
         u->mixer_path = NULL;
     }
@@ -1912,7 +1904,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 */
@@ -1930,8 +1922,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;
         }
@@ -2224,7 +2217,7 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca
     }
 
     if (u->mixer_path_set)
-        pa_alsa_add_ports(u->core, &data.ports, u->mixer_path_set);
+        pa_alsa_add_ports(&data.ports, u->mixer_path_set, card);
 
     u->sink = pa_sink_new(m->core, &data, PA_SINK_HARDWARE | PA_SINK_LATENCY | (u->use_tsched ? PA_SINK_DYNAMIC_LATENCY : 0) |
                           (set_formats ? PA_SINK_SET_FORMATS : 0));
@@ -2389,9 +2382,7 @@ static void userdata_free(struct userdata *u) {
     if (u->mixer_fdl)
         pa_alsa_fdlist_free(u->mixer_fdl);
 
-    if (u->mixer_path_set)
-        pa_alsa_path_set_free(u->mixer_path_set);
-    else if (u->mixer_path)
+    if (u->mixer_path && !u->mixer_path_set)
         pa_alsa_path_free(u->mixer_path);
 
     if (u->mixer_handle)
diff --git a/src/modules/alsa/alsa-source.c b/src/modules/alsa/alsa-source.c
index e311a34..b95cdd8 100644
--- a/src/modules/alsa/alsa-source.c
+++ b/src/modules/alsa/alsa-source.c
@@ -1598,22 +1598,14 @@ static void find_mixer(struct userdata *u, pa_alsa_mapping *mapping, const char
 
         pa_log_debug("Probed mixer path %s:", u->mixer_path->name);
         pa_alsa_path_dump(u->mixer_path);
-    } else {
-
-        if (!(u->mixer_path_set = pa_alsa_path_set_new(mapping, PA_ALSA_DIRECTION_INPUT, u->paths_dir)))
-            goto fail;
-
-        pa_alsa_path_set_probe(u->mixer_path_set, u->mixer_handle, ignore_dB);
-    }
+    } else if (!(u->mixer_path_set = mapping->input_path_set))
+        goto fail;
 
     return;
 
 fail:
 
-    if (u->mixer_path_set) {
-        pa_alsa_path_set_free(u->mixer_path_set);
-        u->mixer_path_set = NULL;
-    } else if (u->mixer_path) {
+    if (u->mixer_path) {
         pa_alsa_path_free(u->mixer_path);
         u->mixer_path = NULL;
     }
@@ -1649,7 +1641,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 */
@@ -1667,8 +1659,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;
         }
@@ -1950,7 +1943,7 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p
     }
 
     if (u->mixer_path_set)
-        pa_alsa_add_ports(u->core, &data.ports, u->mixer_path_set);
+        pa_alsa_add_ports(&data.ports, u->mixer_path_set, card);
 
     u->source = pa_source_new(m->core, &data, PA_SOURCE_HARDWARE|PA_SOURCE_LATENCY|(u->use_tsched ? PA_SOURCE_DYNAMIC_LATENCY : 0));
     pa_source_new_data_done(&data);
@@ -2089,9 +2082,7 @@ static void userdata_free(struct userdata *u) {
     if (u->mixer_fdl)
         pa_alsa_fdlist_free(u->mixer_fdl);
 
-    if (u->mixer_path_set)
-        pa_alsa_path_set_free(u->mixer_path_set);
-    else if (u->mixer_path)
+    if (u->mixer_path && !u->mixer_path_set)
         pa_alsa_path_free(u->mixer_path);
 
     if (u->mixer_handle)
diff --git a/src/modules/alsa/module-alsa-card.c b/src/modules/alsa/module-alsa-card.c
index 344563f..92483e1 100644
--- a/src/modules/alsa/module-alsa-card.c
+++ b/src/modules/alsa/module-alsa-card.c
@@ -117,7 +117,7 @@ struct profile_data {
     pa_alsa_profile *profile;
 };
 
-static void add_profiles(struct userdata *u, pa_hashmap *h) {
+static void add_profiles(struct userdata *u, pa_hashmap *h, pa_hashmap *ports) {
     pa_alsa_profile *ap;
     void *state;
 
@@ -136,17 +136,21 @@ static void add_profiles(struct userdata *u, pa_hashmap *h) {
         if (ap->output_mappings) {
             cp->n_sinks = pa_idxset_size(ap->output_mappings);
 
-            PA_IDXSET_FOREACH(m, ap->output_mappings, idx)
+            PA_IDXSET_FOREACH(m, ap->output_mappings, idx) {
+                pa_alsa_path_set_add_ports(m->output_path_set, cp, ports, NULL, u->core);
                 if (m->channel_map.channels > cp->max_sink_channels)
                     cp->max_sink_channels = m->channel_map.channels;
+            }
         }
 
         if (ap->input_mappings) {
             cp->n_sources = pa_idxset_size(ap->input_mappings);
 
-            PA_IDXSET_FOREACH(m, ap->input_mappings, idx)
+            PA_IDXSET_FOREACH(m, ap->input_mappings, idx) {
+                pa_alsa_path_set_add_ports(m->input_path_set, cp, ports, NULL, u->core);
                 if (m->channel_map.channels > cp->max_source_channels)
                     cp->max_source_channels = m->channel_map.channels;
+            }
         }
 
         d = PA_CARD_PROFILE_DATA(cp);
@@ -293,6 +297,7 @@ int pa__init(pa_module *m) {
     pa_card_new_data data;
     pa_modargs *ma;
     int alsa_card_index;
+    pa_bool_t ignore_dB = FALSE;
     struct userdata *u;
     pa_reserve_wrapper *reserve = NULL;
     const char *description;
@@ -309,6 +314,11 @@ int pa__init(pa_module *m) {
         goto fail;
     }
 
+    if (pa_modargs_get_value_boolean(ma, "ignore_dB", &ignore_dB) < 0) {
+        pa_log("Failed to parse ignore_dB argument.");
+        goto fail;
+    }
+
     m->userdata = u = pa_xnew0(struct userdata, 1);
     u->core = m->core;
     u->module = m;
@@ -344,6 +354,8 @@ int pa__init(pa_module *m) {
     u->profile_set = pa_alsa_profile_set_new(fn, &u->core->default_channel_map);
     pa_xfree(fn);
 
+    u->profile_set->ignore_dB = ignore_dB;
+
     if (!u->profile_set)
         goto fail;
 
@@ -377,7 +389,7 @@ int pa__init(pa_module *m) {
             pa_reserve_wrapper_set_application_device_name(reserve, description);
 
     data.profiles = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
-    add_profiles(u, data.profiles);
+    add_profiles(u, data.profiles, data.ports);
 
     if (pa_hashmap_isempty(data.profiles)) {
         pa_log("Failed to find a working profile.");



More information about the pulseaudio-commits mailing list