mirror of
https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
synced 2025-10-29 05:40:23 -04:00
alsa: Add UCM jack detection
Jack in UCM is decided by UCM device name, although in fact not all UCM devices have "jacks". Because port is also mapped to UCM device, we can always find target port when some jack event happens. Signed-off-by: Feng Wei <wei.feng@freescale.com>
This commit is contained in:
parent
c19d108219
commit
dae4b83dd0
3 changed files with 105 additions and 16 deletions
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue