OSDN Git Service

ucm: extend snd_use_case_mgr_open() to address the sound card directly
authorJaroslav Kysela <perex@perex.cz>
Sun, 3 Nov 2019 18:05:54 +0000 (19:05 +0100)
committerJaroslav Kysela <perex@perex.cz>
Sun, 10 Nov 2019 12:10:43 +0000 (13:10 +0100)
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 <perex@perex.cz>
include/use-case.h
src/ucm/parser.c

index 5cb4f31..37d0572 100644 (file)
@@ -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);
 
 
 /**
index 3e1fc24..34dfe29 100644 (file)
@@ -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)