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