mirror of
https://github.com/alsa-project/alsa-lib.git
synced 2025-11-07 13:30:07 -05:00
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 <perex@perex.cz>
This commit is contained in:
parent
aba2260ae7
commit
be6deb927f
2 changed files with 98 additions and 47 deletions
|
|
@ -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);
|
||||
|
||||
|
||||
/**
|
||||
|
|
|
|||
126
src/ucm/parser.c
126
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);
|
||||
snd_strlcpy(uc_mgr->conf_file_name, uc_mgr->card_name, sizeof(uc_mgr->conf_file_name));
|
||||
|
||||
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';
|
||||
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)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue