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