[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