From 32ff0ba7a36e1fbe41b6334b219bdee14502d425 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Mon, 4 Nov 2019 14:42:45 +0100 Subject: [PATCH] ucm: add support for multiple control devices, more aggresive caching Signed-off-by: Jaroslav Kysela --- src/ucm/main.c | 34 +-------- src/ucm/parser.c | 27 ++++--- src/ucm/ucm_local.h | 23 +++++- src/ucm/utils.c | 178 ++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 212 insertions(+), 50 deletions(-) diff --git a/src/ucm/main.c b/src/ucm/main.c index 99b1cd08..0c4e2dc3 100644 --- a/src/ucm/main.c +++ b/src/ucm/main.c @@ -138,37 +138,6 @@ int snd_use_case_free_list(const char *list[], int items) return 0; } -static int open_ctl(snd_use_case_mgr_t *uc_mgr, - snd_ctl_t **ctl, - const char *ctl_dev) -{ - int err; - - /* FIXME: add a list of ctl devices to uc_mgr structure and - cache accesses for multiple opened ctl devices */ - if (uc_mgr->ctl_dev != NULL && strcmp(ctl_dev, uc_mgr->ctl_dev) == 0) { - *ctl = uc_mgr->ctl; - return 0; - } - if (uc_mgr->ctl_dev) { - free(uc_mgr->ctl_dev); - uc_mgr->ctl_dev = NULL; - snd_ctl_close(uc_mgr->ctl); - uc_mgr->ctl = NULL; - - } - err = snd_ctl_open(ctl, ctl_dev, 0); - if (err < 0) - return err; - uc_mgr->ctl_dev = strdup(ctl_dev); - if (uc_mgr->ctl_dev == NULL) { - snd_ctl_close(*ctl); - return -ENOMEM; - } - uc_mgr->ctl = *ctl; - return 0; -} - static int read_tlv_file(unsigned int **res, const char *filepath) { @@ -427,7 +396,7 @@ static int execute_sequence(snd_use_case_mgr_t *uc_mgr, cdev = capture_ctl; } if (ctl == NULL) { - err = open_ctl(uc_mgr, &ctl, cdev); + err = uc_mgr_open_ctl(uc_mgr, &ctl, cdev); if (err < 0) { uc_error("unable to open ctl device '%s'", cdev); goto __fail; @@ -932,6 +901,7 @@ int snd_use_case_mgr_open(snd_use_case_mgr_t **uc_mgr, INIT_LIST_HEAD(&mgr->value_list); INIT_LIST_HEAD(&mgr->active_modifiers); INIT_LIST_HEAD(&mgr->active_devices); + INIT_LIST_HEAD(&mgr->ctl_list); pthread_mutex_init(&mgr->mutex, NULL); mgr->card_name = strdup(card_name); diff --git a/src/ucm/parser.c b/src/ucm/parser.c index 34dfe29c..97b25013 100644 --- a/src/ucm/parser.c +++ b/src/ucm/parser.c @@ -1412,22 +1412,27 @@ static int parse_master_file(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg) } /* get the card info */ -static int get_card_info(const char *ctl_name, snd_ctl_card_info_t *info) +static int get_card_info(snd_use_case_mgr_t *mgr, + const char *ctl_name, + snd_ctl_t **_handle, + snd_ctl_card_info_t *info) { snd_ctl_t *handle; int err; - err = snd_ctl_open(&handle, ctl_name, 0); - if (err < 0) { - uc_error("control open (%s): %s", ctl_name, snd_strerror(err)); + *_handle = NULL; + + err = uc_mgr_open_ctl(mgr, &handle, ctl_name); + if (err < 0) return err; - } err = snd_ctl_card_info(handle, info); - if (err < 0) + if (err < 0) { uc_error("control hardware info (%s): %s", ctl_name, snd_strerror(err)); + } else { + *_handle = handle; + } - snd_ctl_close(handle); return err; } @@ -1436,6 +1441,7 @@ static int get_card_long_name(snd_use_case_mgr_t *mgr) { const char *card_name = mgr->card_name; int card, err; + snd_ctl_t *ctl; snd_ctl_card_info_t *info; const char *_name, *_long_name; @@ -1451,7 +1457,7 @@ static int get_card_long_name(snd_use_case_mgr_t *mgr) char name[32]; sprintf(name, "hw:%d", card); - err = get_card_info(name, info); + err = get_card_info(mgr, name, &ctl, info); if (err == 0) { _name = snd_ctl_card_info_get_name(info); @@ -1475,13 +1481,14 @@ static int get_card_long_name(snd_use_case_mgr_t *mgr) /* set the driver name and long name by the card ctl name */ static int get_by_card(snd_use_case_mgr_t *mgr, const char *ctl_name) { + snd_ctl_t *ctl; snd_ctl_card_info_t *info; const char *_name, *_long_name; int err; snd_ctl_card_info_alloca(&info); - err = get_card_info(ctl_name, info); + err = get_card_info(mgr, ctl_name, &ctl, info); if (err) return err; @@ -1490,6 +1497,7 @@ static int get_by_card(snd_use_case_mgr_t *mgr, const char *ctl_name) snd_strlcpy(mgr->card_long_name, _long_name, sizeof(mgr->card_long_name)); snd_strlcpy(mgr->conf_file_name, _name, sizeof(mgr->conf_file_name)); + return 0; } @@ -1572,6 +1580,7 @@ __parse: return err; __error: + uc_mgr_free_ctl_list(uc_mgr); uc_mgr->conf_file_name[0] = '\0'; return err; } diff --git a/src/ucm/ucm_local.h b/src/ucm/ucm_local.h index ee15d385..3da747e9 100644 --- a/src/ucm/ucm_local.h +++ b/src/ucm/ucm_local.h @@ -105,6 +105,18 @@ struct dev_list { struct list_head list; }; +struct ctl_dev { + struct list_head list; + char *device; +}; + +struct ctl_list { + struct list_head list; + struct list_head dev_list; + char *ctl_id; + snd_ctl_t *ctl; +}; + /* * Describes a Use Case Modifier and it's enable and disable sequences. * A use case verb can have N modifiers. @@ -214,9 +226,8 @@ struct snd_use_case_mgr { /* locking */ pthread_mutex_t mutex; - /* change to list of ctl handles */ - snd_ctl_t *ctl; - char *ctl_dev; + /* list of opened control devices */ + struct list_head ctl_list; /* Components don't define cdev, the card device. When executing * a sequence of a component device, ucm manager enters component @@ -247,6 +258,12 @@ void uc_mgr_free_transition_element(struct transition_sequence *seq); void uc_mgr_free_verb(snd_use_case_mgr_t *uc_mgr); void uc_mgr_free(snd_use_case_mgr_t *uc_mgr); +int uc_mgr_open_ctl(snd_use_case_mgr_t *uc_mgr, + snd_ctl_t **ctl, + const char *device); + +void uc_mgr_free_ctl_list(snd_use_case_mgr_t *uc_mgr); + /** The name of the environment variable containing the UCM directory */ #define ALSA_CONFIG_UCM_VAR "ALSA_CONFIG_UCM" diff --git a/src/ucm/utils.c b/src/ucm/utils.c index 84ad5ac8..e81f8751 100644 --- a/src/ucm/utils.c +++ b/src/ucm/utils.c @@ -49,6 +49,177 @@ void uc_mgr_stdout(const char *fmt,...) va_end(va); } +static void uc_mgr_free_ctl(struct ctl_list *ctl_list) +{ + struct list_head *pos, *npos; + struct ctl_dev *ctl_dev; + + list_for_each_safe(pos, npos, &ctl_list->dev_list) { + ctl_dev = list_entry(pos, struct ctl_dev, list); + free(ctl_dev->device); + free(ctl_dev); + } + free(ctl_list->ctl_id); + free(ctl_list); +} + +void uc_mgr_free_ctl_list(snd_use_case_mgr_t *uc_mgr) +{ + struct list_head *pos, *npos; + struct ctl_list *ctl_list; + + list_for_each_safe(pos, npos, &uc_mgr->ctl_list) { + ctl_list = list_entry(pos, struct ctl_list, list); + snd_ctl_close(ctl_list->ctl); + list_del(&ctl_list->list); + uc_mgr_free_ctl(ctl_list); + } +} + +static int uc_mgr_ctl_add_dev(struct ctl_list *ctl_list, const char *device) +{ + struct list_head *pos; + struct ctl_dev *ctl_dev; + + /* skip duplicates */ + list_for_each(pos, &ctl_list->dev_list) { + ctl_dev = list_entry(pos, struct ctl_dev, list); + if (strcmp(ctl_dev->device, device) == 0) + return 0; + } + + /* allocate new device name */ + ctl_dev = malloc(sizeof(*ctl_dev)); + if (ctl_dev == NULL) + return -ENOMEM; + ctl_dev->device = strdup(device); + if (ctl_dev->device == NULL) { + free(ctl_dev); + return -ENOMEM; + } + list_add_tail(&ctl_dev->list, &ctl_list->dev_list); + return 0; +} + +static int uc_mgr_ctl_add(snd_use_case_mgr_t *uc_mgr, + struct ctl_list *ctl_list, + snd_ctl_t *ctl, int card, snd_ctl_card_info_t *info, + const char *device) +{ + struct ctl_list *cl = NULL; + const char *id = snd_ctl_card_info_get_id(info); + char dev[MAX_CARD_LONG_NAME]; + int err, hit = 0; + + if (id == NULL || id[0] == '\0') + return -ENOENT; + if (!ctl_list) { + cl = malloc(sizeof(*cl)); + if (cl == NULL) + return -ENOMEM; + INIT_LIST_HEAD(&cl->dev_list); + cl->ctl = ctl; + cl->ctl_id = strdup(id); + if (cl->ctl_id == NULL) { + free(cl); + return -ENOMEM; + } + ctl_list = cl; + } + if (card >= 0) { + snprintf(dev, sizeof(dev), "hw:%d", card); + hit |= !!(device && (strcmp(dev, device) == 0)); + err = uc_mgr_ctl_add_dev(ctl_list, dev); + if (err < 0) + goto __nomem; + } + snprintf(dev, sizeof(dev), "hw:%s", id); + hit |= !!(device && (strcmp(dev, device) == 0)); + err = uc_mgr_ctl_add_dev(ctl_list, dev); + if (err < 0) + goto __nomem; + /* the UCM name not based on the card name / id */ + if (!hit && device) { + err = uc_mgr_ctl_add_dev(ctl_list, device); + if (err < 0) + goto __nomem; + } + + list_add_tail(&ctl_list->list, &uc_mgr->ctl_list); + return 0; + +__nomem: + if (ctl_list == cl) + uc_mgr_free_ctl(cl); + return -ENOMEM; +} + +int uc_mgr_open_ctl(snd_use_case_mgr_t *uc_mgr, + snd_ctl_t **ctl, + const char *device) +{ + struct list_head *pos1, *pos2; + struct ctl_list *ctl_list; + struct ctl_dev *ctl_dev; + snd_ctl_card_info_t *info; + const char *id; + int err, card; + + snd_ctl_card_info_alloca(&info); + + /* cache lookup */ + list_for_each(pos1, &uc_mgr->ctl_list) { + ctl_list = list_entry(pos1, struct ctl_list, list); + list_for_each(pos2, &ctl_list->dev_list) { + ctl_dev = list_entry(pos2, struct ctl_dev, list); + if (strcmp(ctl_dev->device, device) == 0) { + *ctl = ctl_list->ctl; + return 0; + } + } + } + + err = snd_ctl_open(ctl, device, 0); + if (err < 0) + return err; + + id = NULL; + err = snd_ctl_card_info(*ctl, info); + if (err == 0) + id = snd_ctl_card_info_get_id(info); + if (err < 0 || id == NULL || id[0] == '\0') { + uc_error("control hardware info (%s): %s", device, snd_strerror(err)); + snd_ctl_close(*ctl); + *ctl = NULL; + return err; + } + + /* insert to cache, if just name differs */ + list_for_each(pos1, &uc_mgr->ctl_list) { + ctl_list = list_entry(pos1, struct ctl_list, list); + if (strcmp(id, ctl_list->ctl_id) == 0) { + card = snd_card_get_index(id); + err = uc_mgr_ctl_add(uc_mgr, ctl_list, *ctl, card, info, device); + if (err < 0) + goto __nomem; + snd_ctl_close(*ctl); + *ctl = ctl_list->ctl; + return 0; + } + } + + err = uc_mgr_ctl_add(uc_mgr, NULL, *ctl, -1, info, device); + if (err < 0) + goto __nomem; + + return 0; + +__nomem: + snd_ctl_close(*ctl); + *ctl = NULL; + return -ENOMEM; +} + int uc_mgr_config_load(int format, const char *file, snd_config_t **cfg) { FILE *fp; @@ -241,17 +412,12 @@ void uc_mgr_free_verb(snd_use_case_mgr_t *uc_mgr) uc_mgr->active_verb = NULL; INIT_LIST_HEAD(&uc_mgr->active_devices); INIT_LIST_HEAD(&uc_mgr->active_modifiers); - if (uc_mgr->ctl != NULL) { - snd_ctl_close(uc_mgr->ctl); - uc_mgr->ctl = NULL; - } - free(uc_mgr->ctl_dev); - uc_mgr->ctl_dev = NULL; } void uc_mgr_free(snd_use_case_mgr_t *uc_mgr) { uc_mgr_free_verb(uc_mgr); + uc_mgr_free_ctl_list(uc_mgr); free(uc_mgr->card_name); free(uc_mgr); } -- 2.47.1