From be6deb927fff84ee591a9c91758658147f6a856b Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Sun, 3 Nov 2019 19:05:54 +0100 Subject: [PATCH] ucm: extend snd_use_case_mgr_open() to address the sound card directly Some clients like pulseaudio wants to access the multiple instances of sound cards. This patch adds prefixes like "hw:" to the card_name argument to handle this. The card index (value) or card identification (string) can be used for this prefix. Also the prefix "strict:" was added to avoid the driver name and driver long name matching. It might be useable for use case configurations which are not bound to the one sound card. Signed-off-by: Jaroslav Kysela --- include/use-case.h | 19 ++++++- src/ucm/parser.c | 128 ++++++++++++++++++++++++++++----------------- 2 files changed, 99 insertions(+), 48 deletions(-) diff --git a/include/use-case.h b/include/use-case.h index 5cb4f31c..37d0572a 100644 --- a/include/use-case.h +++ b/include/use-case.h @@ -371,8 +371,25 @@ int snd_use_case_set(snd_use_case_mgr_t *uc_mgr, * \param uc_mgr Returned use case manager pointer * \param card_name Sound card name. * \return zero if success, otherwise a negative error code + * + * By default only first card is used when the driver card + * name or long name is passed in the card_name argument. + * + * The "strict:" prefix in the card_name defines that + * there is no driver name / long name matching. The straight + * configuration is used. + * + * The "hw:" prefix in the card_name will load the configuration + * for the ALSA card specified by the card index (value) or + * the card string identificator. + * + * The sound card might be also composed from several physical + * sound cards (for the default and strict card_name). + * The application cannot expect that the device names will refer + * only one ALSA sound card in this case. */ -int snd_use_case_mgr_open(snd_use_case_mgr_t **uc_mgr, const char *card_name); +int snd_use_case_mgr_open(snd_use_case_mgr_t **uc_mgr, + const char *card_name); /** diff --git a/src/ucm/parser.c b/src/ucm/parser.c index 3e1fc24c..34dfe29c 100644 --- a/src/ucm/parser.c +++ b/src/ucm/parser.c @@ -1411,11 +1411,30 @@ static int parse_master_file(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg) return 0; } +/* get the card info */ +static int get_card_info(const char *ctl_name, 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)); + return err; + } + + err = snd_ctl_card_info(handle, info); + if (err < 0) + uc_error("control hardware info (%s): %s", ctl_name, snd_strerror(err)); + + snd_ctl_close(handle); + return err; +} + /* find the card in the local machine and store the card long name */ static int get_card_long_name(snd_use_case_mgr_t *mgr) { const char *card_name = mgr->card_name; - snd_ctl_t *handle; int card, err; snd_ctl_card_info_t *info; const char *_name, *_long_name; @@ -1432,37 +1451,18 @@ static int get_card_long_name(snd_use_case_mgr_t *mgr) char name[32]; sprintf(name, "hw:%d", card); - err = snd_ctl_open(&handle, name, 0); - if (err < 0) { - uc_error("control open (%i): %s", card, - snd_strerror(err)); - goto next_card; + err = get_card_info(name, info); + + if (err == 0) { + _name = snd_ctl_card_info_get_name(info); + _long_name = snd_ctl_card_info_get_longname(info); + if (!strcmp(card_name, _name) || + !strcmp(card_name, _long_name)) { + snd_strlcpy(mgr->card_long_name, _long_name, sizeof(mgr->card_long_name)); + return 0; + } } - err = snd_ctl_card_info(handle, info); - if (err < 0) { - uc_error("control hardware info (%i): %s", card, - snd_strerror(err)); - snd_ctl_close(handle); - goto next_card; - } - - /* Find the local card by comparing the given name with the - * card short name and long name. The given card name may be - * either a short name or long name, because users may open - * the card by either of the two names. - */ - _name = snd_ctl_card_info_get_name(info); - _long_name = snd_ctl_card_info_get_longname(info); - if (!strcmp(card_name, _name) || - !strcmp(card_name, _long_name)) { - strcpy(mgr->card_long_name, _long_name); - snd_ctl_close(handle); - return 0; - } - - snd_ctl_close(handle); -next_card: if (snd_card_next(&card) < 0) { uc_error("snd_card_next"); break; @@ -1472,6 +1472,27 @@ next_card: return -1; } +/* 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_card_info_t *info; + const char *_name, *_long_name; + int err; + + snd_ctl_card_info_alloca(&info); + + err = get_card_info(ctl_name, info); + if (err) + return err; + + _name = snd_ctl_card_info_get_name(info); + _long_name = snd_ctl_card_info_get_longname(info); + + 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; +} + static int load_master_config(snd_use_case_mgr_t *uc_mgr, const char *card_name, snd_config_t **cfg) { @@ -1513,33 +1534,46 @@ static int load_master_config(snd_use_case_mgr_t *uc_mgr, int uc_mgr_import_master_config(snd_use_case_mgr_t *uc_mgr) { snd_config_t *cfg; + const char *name = uc_mgr->card_name; int err; - err = get_card_long_name(uc_mgr); - if (err == 0) /* load file that maches the card long name */ - err = load_master_config(uc_mgr, uc_mgr->card_long_name, &cfg); - - if (err == 0) { - /* got device-specific file that matches the card long name */ - strcpy(uc_mgr->conf_file_name, uc_mgr->card_long_name); - } else { - /* Fall back to the file that maches the given card name, - * either short name or long name (users may open a card by - * its name or long name). - */ - err = load_master_config(uc_mgr, uc_mgr->card_name, &cfg); - if (err < 0) - return err; - strncpy(uc_mgr->conf_file_name, uc_mgr->card_name, MAX_CARD_LONG_NAME); - uc_mgr->conf_file_name[MAX_CARD_LONG_NAME-1] = '\0'; + snd_strlcpy(uc_mgr->conf_file_name, uc_mgr->card_name, sizeof(uc_mgr->conf_file_name)); + + if (strncmp(name, "hw:", 3) == 0) { + err = get_by_card(uc_mgr, name); + if (err == 0) + goto __longname; + uc_error("card '%s' is not valid", name); + goto __error; + } else if (strncmp(name, "strict:", 7)) { + err = get_card_long_name(uc_mgr); +__longname: + if (err == 0) /* load file that matches the card long name */ + err = load_master_config(uc_mgr, uc_mgr->card_long_name, &cfg); + + if (err == 0) { + /* got device-specific file that matches the card long name */ + snd_strlcpy(uc_mgr->conf_file_name, uc_mgr->card_long_name, sizeof(uc_mgr->conf_file_name)); + goto __parse; + } } + /* standard path */ + err = load_master_config(uc_mgr, uc_mgr->conf_file_name, &cfg); + if (err < 0) + goto __error; + +__parse: err = parse_master_file(uc_mgr, cfg); snd_config_delete(cfg); if (err < 0) uc_mgr_free_verb(uc_mgr); return err; + +__error: + uc_mgr->conf_file_name[0] = '\0'; + return err; } static int filename_filter(const struct dirent *dirent) -- 2.47.1