diff --git a/src/modules/alsa/alsa-ucm.c b/src/modules/alsa/alsa-ucm.c index 7b08b1b1a..0a63bff29 100644 --- a/src/modules/alsa/alsa-ucm.c +++ b/src/modules/alsa/alsa-ucm.c @@ -1112,6 +1112,27 @@ static int ucm_create_mapping( return ret; } +static pa_alsa_jack* ucm_get_jack(pa_alsa_ucm_config *ucm, const char *dev_name, const char *pre_tag) { + pa_alsa_jack *j; + char *name = pa_sprintf_malloc("%s%s", pre_tag, dev_name); + + PA_LLIST_FOREACH(j, ucm->jacks) + if (pa_streq(j->name, name)) + goto out; + + j = pa_xnew0(pa_alsa_jack, 1); + j->state_unplugged = PA_PORT_AVAILABLE_NO; + j->state_plugged = PA_PORT_AVAILABLE_YES; + j->name = pa_xstrdup(name); + j->alsa_name = pa_sprintf_malloc("%s Jack", dev_name); + + PA_LLIST_PREPEND(pa_alsa_jack, ucm->jacks, j); + +out: + pa_xfree(name); + return j; +} + static int ucm_create_profile( pa_alsa_ucm_config *ucm, pa_alsa_profile_set *ps, @@ -1169,6 +1190,11 @@ static int ucm_create_profile( source = pa_proplist_gets(dev->proplist, PA_ALSA_PROP_UCM_SOURCE); ucm_create_mapping(ucm, ps, p, dev, verb_name, name, sink, source); + + if (sink) + dev->output_jack = ucm_get_jack(ucm, name, PA_UCM_PRE_TAG_OUTPUT); + if (source) + dev->input_jack = ucm_get_jack(ucm, name, PA_UCM_PRE_TAG_INPUT); } pa_alsa_profile_dump(p); @@ -1230,6 +1256,30 @@ static void profile_finalize_probing(pa_alsa_profile *p) { } } +static void ucm_mapping_jack_probe(pa_alsa_mapping *m) { + snd_pcm_t *pcm_handle; + snd_mixer_t *mixer_handle; + snd_hctl_t *hctl_handle; + pa_alsa_ucm_mapping_context *context = &m->ucm_context; + pa_alsa_ucm_device *dev; + uint32_t idx; + + pcm_handle = m->direction == PA_ALSA_DIRECTION_OUTPUT ? m->output_pcm : m->input_pcm; + mixer_handle = pa_alsa_open_mixer_for_pcm(pcm_handle, NULL, &hctl_handle); + if (!mixer_handle || !hctl_handle) + return; + + PA_IDXSET_FOREACH(dev, context->ucm_devices, idx) { + pa_alsa_jack *jack; + jack = m->direction == PA_ALSA_DIRECTION_OUTPUT ? dev->output_jack : dev->input_jack; + pa_assert (jack); + jack->has_control = pa_alsa_find_jack(hctl_handle, jack->alsa_name) != NULL; + pa_log_info("UCM jack %s has_control=%d", jack->name, jack->has_control); + } + + snd_mixer_close(mixer_handle); +} + static void ucm_probe_profile_set(pa_alsa_ucm_config *ucm, pa_alsa_profile_set *ps) { void *state; pa_alsa_profile *p; @@ -1268,6 +1318,12 @@ static void ucm_probe_profile_set(pa_alsa_ucm_config *ucm, pa_alsa_profile_set * pa_log_debug("Profile %s supported.", p->name); + PA_IDXSET_FOREACH(m, p->output_mappings, idx) + ucm_mapping_jack_probe(m); + + PA_IDXSET_FOREACH(m, p->input_mappings, idx) + ucm_mapping_jack_probe(m); + profile_finalize_probing(p); } @@ -1337,11 +1393,18 @@ static void free_verb(pa_alsa_ucm_verb *verb) { void pa_alsa_ucm_free(pa_alsa_ucm_config *ucm) { pa_alsa_ucm_verb *vi, *vn; + pa_alsa_jack *ji, *jn; PA_LLIST_FOREACH_SAFE(vi, vn, ucm->verbs) { PA_LLIST_REMOVE(pa_alsa_ucm_verb, ucm->verbs, vi); free_verb(vi); } + PA_LLIST_FOREACH_SAFE(ji, jn, ucm->jacks) { + PA_LLIST_REMOVE(pa_alsa_jack, ucm->jacks, ji); + pa_xfree(ji->alsa_name); + pa_xfree(ji->name); + pa_xfree(ji); + } if (ucm->ucm_mgr) { snd_use_case_mgr_close(ucm->ucm_mgr); ucm->ucm_mgr = NULL; diff --git a/src/modules/alsa/alsa-ucm.h b/src/modules/alsa/alsa-ucm.h index db21d251e..38fb2625a 100644 --- a/src/modules/alsa/alsa-ucm.h +++ b/src/modules/alsa/alsa-ucm.h @@ -121,6 +121,9 @@ struct pa_alsa_ucm_device { pa_idxset *conflicting_devices; pa_idxset *supported_devices; + + pa_alsa_jack *input_jack; + pa_alsa_jack *output_jack; }; struct pa_alsa_ucm_modifier { @@ -154,6 +157,7 @@ struct pa_alsa_ucm_config { pa_alsa_ucm_verb *active_verb; PA_LLIST_HEAD(pa_alsa_ucm_verb, verbs); + PA_LLIST_HEAD(pa_alsa_jack, jacks); }; struct pa_alsa_ucm_mapping_context { diff --git a/src/modules/alsa/module-alsa-card.c b/src/modules/alsa/module-alsa-card.c index 517c8f88a..d9c059669 100644 --- a/src/modules/alsa/module-alsa-card.c +++ b/src/modules/alsa/module-alsa-card.c @@ -307,14 +307,21 @@ static void report_port_state(pa_device_port *p, struct userdata *u) void *state; pa_alsa_jack *jack; pa_port_available_t pa = PA_PORT_AVAILABLE_UNKNOWN; + pa_device_port *port; PA_HASHMAP_FOREACH(jack, u->jacks, state) { pa_port_available_t cpa; - if (!jack->path) - continue; + if (u->use_ucm) + port = pa_hashmap_get(u->card->ports, jack->name); + else { + if (jack->path) + port = jack->path->port; + else + continue; + } - if (p != jack->path->port) + if (p != port) continue; cpa = jack->plugged_in ? jack->state_plugged : jack->state_unplugged; @@ -340,6 +347,7 @@ static int report_jack_state(snd_hctl_elem_t *elem, unsigned int mask) pa_bool_t plugged_in; void *state; pa_alsa_jack *jack; + pa_device_port *port; pa_assert(u); @@ -359,8 +367,16 @@ static int report_jack_state(snd_hctl_elem_t *elem, unsigned int mask) PA_HASHMAP_FOREACH(jack, u->jacks, state) if (jack->hctl_elem == elem) { jack->plugged_in = plugged_in; - pa_assert(jack->path && jack->path->port); - report_port_state(jack->path->port, u); + if (u->use_ucm) { + pa_assert(u->card->ports); + port = pa_hashmap_get(u->card->ports, jack->name); + pa_assert(port); + } + else { + pa_assert(jack->path && jack->path->port); + port = jack->path->port; + } + report_port_state(port, u); } return 0; } @@ -372,18 +388,24 @@ static void init_jacks(struct userdata *u) { u->jacks = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func); - /* See if we have any jacks */ - if (u->profile_set->output_paths) - PA_HASHMAP_FOREACH(path, u->profile_set->output_paths, state) - PA_LLIST_FOREACH(jack, path->jacks) - if (jack->has_control) - pa_hashmap_put(u->jacks, jack, jack); + if (u->use_ucm) { + PA_LLIST_FOREACH(jack, u->ucm.jacks) + if (jack->has_control) + pa_hashmap_put(u->jacks, jack, jack); + } else { + /* See if we have any jacks */ + if (u->profile_set->output_paths) + PA_HASHMAP_FOREACH(path, u->profile_set->output_paths, state) + PA_LLIST_FOREACH(jack, path->jacks) + if (jack->has_control) + pa_hashmap_put(u->jacks, jack, jack); - if (u->profile_set->input_paths) - PA_HASHMAP_FOREACH(path, u->profile_set->input_paths, state) - PA_LLIST_FOREACH(jack, path->jacks) - if (jack->has_control) - pa_hashmap_put(u->jacks, jack, jack); + if (u->profile_set->input_paths) + PA_HASHMAP_FOREACH(path, u->profile_set->input_paths, state) + PA_LLIST_FOREACH(jack, path->jacks) + if (jack->has_control) + pa_hashmap_put(u->jacks, jack, jack); + } pa_log_debug("Found %d jacks.", pa_hashmap_size(u->jacks));