]> code.delx.au - pulseaudio/commitdiff
alsa: Add UCM jack detection
authorFeng Wei <b34248@freescale.com>
Thu, 5 Jul 2012 05:03:45 +0000 (13:03 +0800)
committerArun Raghavan <arun.raghavan@collabora.co.uk>
Mon, 16 Jul 2012 11:38:28 +0000 (17:08 +0530)
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>
src/modules/alsa/alsa-ucm.c
src/modules/alsa/alsa-ucm.h
src/modules/alsa/module-alsa-card.c

index 7b08b1b1a1c49d4b6af50f1b3d8169f2f097bba6..0a63bff296e079cfa1067f38cad08981c01f2f0a 100644 (file)
@@ -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;
index db21d251ed71aeee95205b3f544faa402aceb90a..38fb2625a657995f32817a17265c1f5e9e8606cf 100644 (file)
@@ -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 {
index 517c8f88a806627316e16a921bd84f0558a5f715..d9c0596696c569676353492b3e2f9e58e6200f70 100644 (file)
@@ -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->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->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);
+    }
 
     pa_log_debug("Found %d jacks.", pa_hashmap_size(u->jacks));