Now also UCM ports are created before any device prototypes or card profiles are created. There is some code duplication: alsa-ucm.c already had functions ucm_add_ports_combination() and ucm_add_port_combination(), and now this patch adds add_port_combination() that is very similar to ucm_add_port_combination(), and pa_alsa_profile_set_create_ports() is similar to ucm_add_ports_combination() (the recursion was replaced with a loop, though, so it looks different, but it still does essentially the same thing). The old ucm_* functions will be removed later, so the duplication isn't permanenet. Port creation is now done in the new functions, but the old ucm_* variants are still kept, because they link profiles to ports and ports to sinks/sources, which the new functions don't do (those things will be done later by the core). --- src/modules/alsa/alsa-mixer.c | 18 ++-- src/modules/alsa/alsa-mixer.h | 1 + src/modules/alsa/alsa-ucm.c | 190 +++++++++++++++++++++++++++++------------- src/modules/alsa/alsa-ucm.h | 2 + 4 files changed, 146 insertions(+), 65 deletions(-) diff --git a/src/modules/alsa/alsa-mixer.c b/src/modules/alsa/alsa-mixer.c index bd243ba..14bfd88 100644 --- a/src/modules/alsa/alsa-mixer.c +++ b/src/modules/alsa/alsa-mixer.c @@ -4639,16 +4639,24 @@ static void path_create_ports(pa_core *core, pa_alsa_path *path, pa_hashmap *por } void pa_alsa_profile_set_create_ports(pa_core *core, pa_alsa_profile_set *profile_set, pa_hashmap *ports) { - pa_alsa_path *path; void *state; pa_assert(core); pa_assert(profile_set); pa_assert(ports); - PA_HASHMAP_FOREACH(path, profile_set->output_paths, state) - path_create_ports(core, path, ports); + if (profile_set->use_ucm) { + pa_alsa_mapping *mapping; + + PA_HASHMAP_FOREACH(mapping, profile_set->mappings, state) + pa_alsa_ucm_mapping_create_ports(core, mapping, ports); + } else { + pa_alsa_path *path; - PA_HASHMAP_FOREACH(path, profile_set->input_paths, state) - path_create_ports(core, path, ports); + PA_HASHMAP_FOREACH(path, profile_set->output_paths, state) + path_create_ports(core, path, ports); + + PA_HASHMAP_FOREACH(path, profile_set->input_paths, state) + path_create_ports(core, path, ports); + } } diff --git a/src/modules/alsa/alsa-mixer.h b/src/modules/alsa/alsa-mixer.h index a39befe..6869261 100644 --- a/src/modules/alsa/alsa-mixer.h +++ b/src/modules/alsa/alsa-mixer.h @@ -318,6 +318,7 @@ struct pa_alsa_profile_set { pa_hashmap *input_paths; pa_hashmap *output_paths; + bool use_ucm; bool auto_profiles; bool ignore_dB:1; bool probed:1; diff --git a/src/modules/alsa/alsa-ucm.c b/src/modules/alsa/alsa-ucm.c index 302c8fc..2924506 100644 --- a/src/modules/alsa/alsa-ucm.c +++ b/src/modules/alsa/alsa-ucm.c @@ -676,23 +676,14 @@ static void ucm_add_port_combination( pa_device_port *port; int i; - unsigned priority; - double prio2; char *name = NULL; - char *desc = NULL; const char *dev_name; - const char *direction; pa_alsa_ucm_device *dev; dev = pdevices[0]; dev_name = pa_proplist_gets(dev->proplist, PA_ALSA_PROP_UCM_NAME); name = pa_sprintf_malloc("%s%s", is_sink ? PA_UCM_PRE_TAG_OUTPUT : PA_UCM_PRE_TAG_INPUT, dev_name); - desc = num == 1 ? pa_xstrdup(pa_proplist_gets(dev->proplist, PA_ALSA_PROP_UCM_DESCRIPTION)) - : pa_sprintf_malloc("Combination port for %s", dev_name); - - priority = is_sink ? dev->playback_priority : dev->capture_priority; - prio2 = (priority == 0 ? 0 : 1.0/priority); for (i = 1; i < num; i++) { char *tmp; @@ -703,57 +694,11 @@ static void ucm_add_port_combination( tmp = pa_sprintf_malloc("%s+%s", name, dev_name); pa_xfree(name); name = tmp; - - tmp = pa_sprintf_malloc("%s,%s", desc, dev_name); - pa_xfree(desc); - desc = tmp; - - priority = is_sink ? dev->playback_priority : dev->capture_priority; - if (priority != 0 && prio2 > 0) - prio2 += 1.0/priority; } - /* Make combination ports always have lower priority, and use the formula - 1/p = 1/p1 + 1/p2 + ... 1/pn. - This way, the result will always be less than the individual components, - yet higher components will lead to higher result. */ - - if (num > 1) - priority = prio2 > 0 ? 1.0/prio2 : 0; - port = pa_hashmap_get(ports, name); - if (!port) { - pa_device_port_new_data port_data; - - pa_device_port_new_data_init(&port_data); - pa_device_port_new_data_set_name(&port_data, name); - 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); - pa_node_new_data_set_fallback_name_prefix(&port_data.node_data, "alsa"); - - port = pa_device_port_new(core, &port_data, 0); - pa_device_port_new_data_done(&port_data); - - if (!port) { - pa_log("Failed to create port %s.", name); - goto fail; - } - - pa_hashmap_put(ports, port->name, port); - pa_dynarray_append(context->ports, port); - pa_log_debug("Add port %s: %s", port->name, port->description); - port->profiles = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); - } - - port->priority = priority; - + pa_assert(port); pa_xfree(name); - name = NULL; - pa_xfree(desc); - desc = NULL; - - direction = is_sink ? "output" : "input"; - pa_log_debug("Port %s direction %s, priority %d", port->name, direction, priority); if (cp) { pa_log_debug("Adding profile %s to port %s.", cp->name, port->name); @@ -766,10 +711,6 @@ static void ucm_add_port_combination( } return; - -fail: - pa_xfree(name); - pa_xfree(desc); } static int ucm_port_contains(const char *port_name, const char *dev_name, bool is_sink) { @@ -1522,6 +1463,7 @@ pa_alsa_profile_set* pa_alsa_ucm_add_profile_set(pa_alsa_ucm_config *ucm, pa_cha pa_alsa_profile_set *ps; ps = pa_xnew0(pa_alsa_profile_set, 1); + ps->use_ucm = true; ps->mappings = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); ps->profiles = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); ps->decibel_fixes = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); @@ -1678,6 +1620,131 @@ void pa_alsa_ucm_roled_stream_end(pa_alsa_ucm_config *ucm, const char *role, pa_ } } +static void add_port_combination( + pa_alsa_ucm_mapping_context *context, + bool is_sink, + pa_alsa_ucm_device **pdevices, + int num, + pa_hashmap *ports, + pa_core *core) { + + pa_device_port *port; + int i; + unsigned priority; + double prio2; + char *name = NULL; + char *desc = NULL; + const char *dev_name; + const char *direction; + pa_alsa_ucm_device *dev; + + dev = pdevices[0]; + dev_name = pa_proplist_gets(dev->proplist, PA_ALSA_PROP_UCM_NAME); + + name = pa_sprintf_malloc("%s%s", is_sink ? PA_UCM_PRE_TAG_OUTPUT : PA_UCM_PRE_TAG_INPUT, dev_name); + desc = num == 1 ? pa_xstrdup(pa_proplist_gets(dev->proplist, PA_ALSA_PROP_UCM_DESCRIPTION)) + : pa_sprintf_malloc("Combination port for %s", dev_name); + + priority = is_sink ? dev->playback_priority : dev->capture_priority; + prio2 = (priority == 0 ? 0 : 1.0/priority); + + for (i = 1; i < num; i++) { + char *tmp; + + dev = pdevices[i]; + dev_name = pa_proplist_gets(dev->proplist, PA_ALSA_PROP_UCM_NAME); + + tmp = pa_sprintf_malloc("%s+%s", name, dev_name); + pa_xfree(name); + name = tmp; + + tmp = pa_sprintf_malloc("%s,%s", desc, dev_name); + pa_xfree(desc); + desc = tmp; + + priority = is_sink ? dev->playback_priority : dev->capture_priority; + if (priority != 0 && prio2 > 0) + prio2 += 1.0/priority; + } + + /* Make combination ports always have lower priority, and use the formula + 1/p = 1/p1 + 1/p2 + ... 1/pn. + This way, the result will always be less than the individual components, + yet higher components will lead to higher result. */ + + if (num > 1) + priority = prio2 > 0 ? 1.0/prio2 : 0; + + port = pa_hashmap_get(ports, name); + if (!port) { + pa_device_port_new_data port_data; + + pa_device_port_new_data_init(&port_data); + pa_device_port_new_data_set_name(&port_data, name); + 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); + pa_node_new_data_set_fallback_name_prefix(&port_data.node_data, "alsa"); + + port = pa_device_port_new(core, &port_data, 0); + pa_device_port_new_data_done(&port_data); + + if (!port) { + pa_log("Failed to create port %s.", name); + goto fail; + } + + pa_hashmap_put(ports, port->name, port); + pa_dynarray_append(context->ports, port); + pa_log_debug("Add port %s: %s", port->name, port->description); + } + + port->priority = priority; + + pa_xfree(name); + name = NULL; + pa_xfree(desc); + desc = NULL; + + direction = is_sink ? "output" : "input"; + pa_log_debug("Port %s direction %s, priority %d", port->name, direction, priority); + + return; + +fail: + pa_xfree(name); + pa_xfree(desc); +} + +void pa_alsa_ucm_mapping_create_ports(pa_core *core, pa_alsa_mapping *mapping, pa_hashmap *ports) { + pa_alsa_ucm_mapping_context *context; + bool is_sink; + pa_alsa_ucm_device **combination_devices; + pa_alsa_ucm_device *device; + uint32_t idx; + unsigned dev_num = 0; + + pa_assert(core); + pa_assert(mapping); + pa_assert(ports); + + context = &mapping->ucm_context; + is_sink = context->direction == PA_DIRECTION_OUTPUT; + + if (pa_idxset_isempty(context->ucm_devices)) + return; + + combination_devices = pa_xnew0(pa_alsa_ucm_device *, pa_idxset_size(context->ucm_devices)); + + PA_IDXSET_FOREACH(device, context->ucm_devices, idx) { + if (ucm_check_conformance(combination_devices, dev_num, device)) { + combination_devices[dev_num++] = device; + add_port_combination(context, is_sink, combination_devices, dev_num, ports, core); + } + } + + pa_xfree(combination_devices); +} + #else /* HAVE_ALSA_UCM */ /* Dummy functions for systems without UCM support */ @@ -1732,4 +1799,7 @@ void pa_alsa_ucm_roled_stream_begin(pa_alsa_ucm_config *ucm, const char *role, p void pa_alsa_ucm_roled_stream_end(pa_alsa_ucm_config *ucm, const char *role, pa_direction_t dir) { } +void pa_alsa_ucm_mapping_create_ports(pa_core *core, pa_alsa_mapping *mapping, pa_hashmap *ports) { +} + #endif diff --git a/src/modules/alsa/alsa-ucm.h b/src/modules/alsa/alsa-ucm.h index 66b27a0..605b1a3 100644 --- a/src/modules/alsa/alsa-ucm.h +++ b/src/modules/alsa/alsa-ucm.h @@ -195,4 +195,6 @@ struct pa_alsa_ucm_mapping_context { pa_dynarray *ports; }; +void pa_alsa_ucm_mapping_create_ports(pa_core *core, pa_alsa_mapping *mapping, pa_hashmap *ports); + #endif -- 1.8.3.1