From c83b34516929214876bd2c46b5f346e53a3adcf7 Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Thu, 24 Jun 2021 09:11:59 +0300 Subject: [PATCH] alsa-ucm: Add enable, disable, status helpers for devices Right now manipulating device status is done inline once while setting a port. However, we will need to reuse this code to disable conflicting devices of a device we want to enable. Split it into enable and disable helper functions. There is another issue with the device enable logic, where trying to disabling an already disabled device sometimes fails. To avoid that, implement a status helper and check if the device we want to enable is already enabled/disabled before trying to do so. Signed-off-by: Alper Nebi Yasak Part-of: --- src/modules/alsa/alsa-ucm.c | 81 ++++++++++++++++++++++++++++--------- 1 file changed, 63 insertions(+), 18 deletions(-) diff --git a/src/modules/alsa/alsa-ucm.c b/src/modules/alsa/alsa-ucm.c index 858aa011a..7b857785d 100644 --- a/src/modules/alsa/alsa-ucm.c +++ b/src/modules/alsa/alsa-ucm.c @@ -631,6 +631,59 @@ static int ucm_get_devices(pa_alsa_ucm_verb *verb, snd_use_case_mgr_t *uc_mgr) { return 0; }; +static long ucm_device_status(pa_alsa_ucm_config *ucm, pa_alsa_ucm_device *dev) { + const char *dev_name = pa_proplist_gets(dev->proplist, PA_ALSA_PROP_UCM_NAME); + char *devstatus; + long status = 0; + + devstatus = pa_sprintf_malloc("_devstatus/%s", dev_name); + if (snd_use_case_geti(ucm->ucm_mgr, devstatus, &status) < 0) { + pa_log_debug("Failed to get status for UCM device %s", dev_name); + status = -1; + } + pa_xfree(devstatus); + + return status; +} + +static int ucm_device_disable(pa_alsa_ucm_config *ucm, pa_alsa_ucm_device *dev) { + const char *dev_name = pa_proplist_gets(dev->proplist, PA_ALSA_PROP_UCM_NAME); + + /* If any of dev's conflicting devices is enabled, trying to disable + * dev gives an error despite the fact that it's already disabled. + * Check that dev is enabled to avoid this error. */ + if (ucm_device_status(ucm, dev) == 0) { + pa_log_debug("UCM device %s is already disabled", dev_name); + return 0; + } + + pa_log_debug("Disabling UCM device %s", dev_name); + if (snd_use_case_set(ucm->ucm_mgr, "_disdev", dev_name) < 0) { + pa_log("Failed to disable UCM device %s", dev_name); + return -1; + } + + return 0; +} + +static int ucm_device_enable(pa_alsa_ucm_config *ucm, pa_alsa_ucm_device *dev) { + const char *dev_name = pa_proplist_gets(dev->proplist, PA_ALSA_PROP_UCM_NAME); + + /* We don't need to enable devices that are already enabled */ + if (ucm_device_status(ucm, dev) > 0) { + pa_log_debug("UCM device %s is already enabled", dev_name); + return 0; + } + + pa_log_debug("Enabling UCM device %s", dev_name); + if (snd_use_case_set(ucm->ucm_mgr, "_enadev", dev_name) < 0) { + pa_log("Failed to enable UCM device %s", dev_name); + return -1; + } + + return 0; +} + static int ucm_get_modifiers(pa_alsa_ucm_verb *verb, snd_use_case_mgr_t *uc_mgr) { const char **mod_list; int num_mod, i; @@ -1417,7 +1470,7 @@ int pa_alsa_ucm_set_port(pa_alsa_ucm_mapping_context *context, pa_device_port *p int i; int ret = 0; pa_alsa_ucm_config *ucm; - const char **enable_devs; + pa_alsa_ucm_device **enable_devs; int enable_num = 0; uint32_t idx; pa_alsa_ucm_device *dev; @@ -1427,31 +1480,23 @@ int pa_alsa_ucm_set_port(pa_alsa_ucm_mapping_context *context, pa_device_port *p ucm = context->ucm; pa_assert(ucm->ucm_mgr); - enable_devs = pa_xnew(const char *, pa_idxset_size(context->ucm_devices)); + enable_devs = pa_xnew(pa_alsa_ucm_device *, pa_idxset_size(context->ucm_devices)); /* first disable then enable */ PA_IDXSET_FOREACH(dev, context->ucm_devices, idx) { const char *dev_name = pa_proplist_gets(dev->proplist, PA_ALSA_PROP_UCM_NAME); if (ucm_port_contains(port->name, dev_name, is_sink)) - enable_devs[enable_num++] = dev_name; - else { - pa_log_debug("Disable ucm device %s", dev_name); - if (snd_use_case_set(ucm->ucm_mgr, "_disdev", dev_name) > 0) { - pa_log("Failed to disable ucm device %s", dev_name); - ret = -1; - break; - } - } + enable_devs[enable_num++] = dev; + else + ret = ucm_device_disable(ucm, dev); + + if (ret < 0) + break; } - for (i = 0; i < enable_num; i++) { - pa_log_debug("Enable ucm device %s", enable_devs[i]); - if (snd_use_case_set(ucm->ucm_mgr, "_enadev", enable_devs[i]) < 0) { - pa_log("Failed to enable ucm device %s", enable_devs[i]); - ret = -1; - break; - } + for (i = 0; i < enable_num && ret == 0; i++) { + ret = ucm_device_enable(ucm, enable_devs[i]); } pa_xfree(enable_devs);