[PATCH v2 3/6] alsa: Add associations between jacks, UCM devices and UCM ports

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



These associations will be used by subsequent UCM jack detection
refactoring work.
---
 src/modules/alsa/alsa-mixer.c | 11 +++++++
 src/modules/alsa/alsa-mixer.h |  3 ++
 src/modules/alsa/alsa-ucm.c   | 72 +++++++++++++++++++++++++++++++++++++++++--
 src/modules/alsa/alsa-ucm.h   |  6 ++++
 4 files changed, 90 insertions(+), 2 deletions(-)

diff --git a/src/modules/alsa/alsa-mixer.c b/src/modules/alsa/alsa-mixer.c
index 4771a2d..8fc883d 100644
--- a/src/modules/alsa/alsa-mixer.c
+++ b/src/modules/alsa/alsa-mixer.c
@@ -123,6 +123,7 @@ pa_alsa_jack *pa_alsa_jack_new(pa_alsa_path *path, const char *name, const char
 
     jack->state_unplugged = PA_AVAILABLE_NO;
     jack->state_plugged = PA_AVAILABLE_YES;
+    jack->ucm_devices = pa_dynarray_new(NULL);
 
     return jack;
 }
@@ -130,11 +131,21 @@ pa_alsa_jack *pa_alsa_jack_new(pa_alsa_path *path, const char *name, const char
 void pa_alsa_jack_free(pa_alsa_jack *jack) {
     pa_assert(jack);
 
+    if (jack->ucm_devices)
+        pa_dynarray_free(jack->ucm_devices);
+
     pa_xfree(jack->alsa_name);
     pa_xfree(jack->name);
     pa_xfree(jack);
 }
 
+void pa_alsa_jack_add_ucm_device(pa_alsa_jack *jack, pa_alsa_ucm_device *device) {
+    pa_assert(jack);
+    pa_assert(device);
+
+    pa_dynarray_append(jack->ucm_devices, device);
+}
+
 static const char *lookup_description(const char *key, const struct description_map dm[], unsigned n) {
     unsigned i;
 
diff --git a/src/modules/alsa/alsa-mixer.h b/src/modules/alsa/alsa-mixer.h
index 835361b..92a61c2 100644
--- a/src/modules/alsa/alsa-mixer.h
+++ b/src/modules/alsa/alsa-mixer.h
@@ -168,10 +168,13 @@ struct pa_alsa_jack {
     pa_alsa_required_t required;
     pa_alsa_required_t required_any;
     pa_alsa_required_t required_absent;
+
+    pa_dynarray *ucm_devices; /* pa_alsa_ucm_device */
 };
 
 pa_alsa_jack *pa_alsa_jack_new(pa_alsa_path *path, const char *name, const char *alsa_name);
 void pa_alsa_jack_free(pa_alsa_jack *jack);
+void pa_alsa_jack_add_ucm_device(pa_alsa_jack *jack, pa_alsa_ucm_device *device);
 
 /* A path wraps a series of elements into a single entity which can be
  * used to control it as if it had a single volume slider, a single
diff --git a/src/modules/alsa/alsa-ucm.c b/src/modules/alsa/alsa-ucm.c
index 7ddb975..4b0adff 100644
--- a/src/modules/alsa/alsa-ucm.c
+++ b/src/modules/alsa/alsa-ucm.c
@@ -78,6 +78,19 @@ struct ucm_info {
 
 static void device_set_jack(pa_alsa_ucm_device *device, pa_alsa_jack *jack);
 
+struct ucm_port {
+    pa_alsa_ucm_config *ucm;
+    pa_device_port *core_port;
+
+    /* A single port will be associated with multiple devices if it represents
+     * a combination of devices. */
+    pa_dynarray *devices; /* pa_alsa_ucm_device */
+};
+
+static struct ucm_port *ucm_port_new(pa_alsa_ucm_config *ucm, pa_device_port *core_port, pa_alsa_ucm_device **devices,
+                                     unsigned n_devices);
+static void ucm_port_free(struct ucm_port *port);
+
 static struct ucm_items item[] = {
     {"PlaybackPCM", PA_ALSA_PROP_UCM_SINK},
     {"CapturePCM", PA_ALSA_PROP_UCM_SOURCE},
@@ -399,6 +412,7 @@ static int ucm_get_devices(pa_alsa_ucm_verb *verb, snd_use_case_mgr_t *uc_mgr) {
         d->proplist = pa_proplist_new();
         pa_proplist_sets(d->proplist, PA_ALSA_PROP_UCM_NAME, pa_strnull(dev_list[i]));
         pa_proplist_sets(d->proplist, PA_ALSA_PROP_UCM_DESCRIPTION, pa_strna(dev_list[i + 1]));
+        d->ucm_ports = pa_dynarray_new(NULL);
 
         PA_LLIST_PREPEND(pa_alsa_ucm_device, verb->devices, d);
     }
@@ -555,6 +569,8 @@ int pa_alsa_ucm_query_profiles(pa_alsa_ucm_config *ucm, int card_index) {
     const char **verb_list;
     int num_verbs, i, err = 0;
 
+    ucm->ports = pa_dynarray_new((pa_free_cb_t) ucm_port_free);
+
     /* is UCM available for this card ? */
     err = snd_card_get_name(card_index, &card_name);
     if (err < 0) {
@@ -737,6 +753,8 @@ static void ucm_add_port_combination(
 
     port = pa_hashmap_get(ports, name);
     if (!port) {
+        struct ucm_port *ucm_port;
+
         pa_device_port_new_data port_data;
 
         pa_device_port_new_data_init(&port_data);
@@ -744,9 +762,12 @@ static void ucm_add_port_combination(
         pa_device_port_new_data_set_description(&port_data, desc);
         pa_device_port_new_data_set_direction(&port_data, is_sink ? PA_DIRECTION_OUTPUT : PA_DIRECTION_INPUT);
 
-        port = pa_device_port_new(core, &port_data, 0);
+        port = pa_device_port_new(core, &port_data, sizeof(ucm_port));
         pa_device_port_new_data_done(&port_data);
-        pa_assert(port);
+
+        ucm_port = ucm_port_new(context->ucm, port, pdevices, num);
+        pa_dynarray_append(context->ucm->ports, ucm_port);
+        *((struct ucm_port **) PA_DEVICE_PORT_DATA(port)) = ucm_port;
 
         pa_hashmap_put(ports, port->name, port);
         pa_log_debug("Add port %s: %s", port->name, port->description);
@@ -1557,6 +1578,10 @@ static void free_verb(pa_alsa_ucm_verb *verb) {
 
     PA_LLIST_FOREACH_SAFE(di, dn, verb->devices) {
         PA_LLIST_REMOVE(pa_alsa_ucm_device, verb->devices, di);
+
+        if (di->ucm_ports)
+            pa_dynarray_free(di->ucm_ports);
+
         pa_proplist_free(di->proplist);
         if (di->conflicting_devices)
             pa_idxset_free(di->conflicting_devices, NULL);
@@ -1583,6 +1608,9 @@ void pa_alsa_ucm_free(pa_alsa_ucm_config *ucm) {
     pa_alsa_ucm_verb *vi, *vn;
     pa_alsa_jack *ji, *jn;
 
+    if (ucm->ports)
+        pa_dynarray_free(ucm->ports);
+
     PA_LLIST_FOREACH_SAFE(vi, vn, ucm->verbs) {
         PA_LLIST_REMOVE(pa_alsa_ucm_verb, ucm->verbs, vi);
         free_verb(vi);
@@ -1675,10 +1703,50 @@ void pa_alsa_ucm_roled_stream_end(pa_alsa_ucm_config *ucm, const char *role, pa_
     }
 }
 
+static void device_add_ucm_port(pa_alsa_ucm_device *device, struct ucm_port *port) {
+    pa_assert(device);
+    pa_assert(port);
+
+    pa_dynarray_append(device->ucm_ports, port);
+}
+
 static void device_set_jack(pa_alsa_ucm_device *device, pa_alsa_jack *jack) {
     pa_assert(device);
+    pa_assert(jack);
 
     device->jack = jack;
+    pa_alsa_jack_add_ucm_device(jack, device);
+}
+
+static struct ucm_port *ucm_port_new(pa_alsa_ucm_config *ucm, pa_device_port *core_port, pa_alsa_ucm_device **devices,
+                                     unsigned n_devices) {
+    struct ucm_port *port;
+    unsigned i;
+
+    pa_assert(ucm);
+    pa_assert(core_port);
+    pa_assert(devices);
+
+    port = pa_xnew0(struct ucm_port, 1);
+    port->ucm = ucm;
+    port->core_port = core_port;
+    port->devices = pa_dynarray_new(NULL);
+
+    for (i = 0; i < n_devices; i++) {
+        pa_dynarray_append(port->devices, devices[i]);
+        device_add_ucm_port(devices[i], port);
+    }
+
+    return port;
+}
+
+static void ucm_port_free(struct ucm_port *port) {
+    pa_assert(port);
+
+    if (port->devices)
+        pa_dynarray_free(port->devices);
+
+    pa_xfree(port);
 }
 
 #else /* HAVE_ALSA_UCM */
diff --git a/src/modules/alsa/alsa-ucm.h b/src/modules/alsa/alsa-ucm.h
index 8ce9b4b..727d281 100644
--- a/src/modules/alsa/alsa-ucm.h
+++ b/src/modules/alsa/alsa-ucm.h
@@ -142,6 +142,11 @@ struct pa_alsa_ucm_device {
     pa_idxset *conflicting_devices;
     pa_idxset *supported_devices;
 
+    /* One device may be part of multiple ports, since each device has
+     * a dedicated port, and in addition to that we sometimes generate ports
+     * that represent combinations of devices. */
+    pa_dynarray *ucm_ports; /* struct ucm_port */
+
     pa_alsa_jack *jack;
 };
 
@@ -184,6 +189,7 @@ struct pa_alsa_ucm_config {
 
     PA_LLIST_HEAD(pa_alsa_ucm_verb, verbs);
     PA_LLIST_HEAD(pa_alsa_jack, jacks);
+    pa_dynarray *ports; /* struct ucm_port */
 };
 
 struct pa_alsa_ucm_mapping_context {
-- 
1.9.3



[Index of Archives]     [Linux Audio Users]     [AMD Graphics]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux