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 uc_mgr Returned use case manager pointer
|
||||||
* \param card_name Sound card name.
|
* \param card_name Sound card name.
|
||||||
* \return zero if success, otherwise a negative error code
|
* \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);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
106
src/ucm/parser.c
106
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;
|
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 */
|
/* 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)
|
static int get_card_long_name(snd_use_case_mgr_t *mgr)
|
||||||
{
|
{
|
||||||
const char *card_name = mgr->card_name;
|
const char *card_name = mgr->card_name;
|
||||||
snd_ctl_t *handle;
|
|
||||||
int card, err;
|
int card, err;
|
||||||
snd_ctl_card_info_t *info;
|
snd_ctl_card_info_t *info;
|
||||||
const char *_name, *_long_name;
|
const char *_name, *_long_name;
|
||||||
|
|
@ -1432,37 +1451,18 @@ static int get_card_long_name(snd_use_case_mgr_t *mgr)
|
||||||
char name[32];
|
char name[32];
|
||||||
|
|
||||||
sprintf(name, "hw:%d", card);
|
sprintf(name, "hw:%d", card);
|
||||||
err = snd_ctl_open(&handle, name, 0);
|
err = get_card_info(name, info);
|
||||||
if (err < 0) {
|
|
||||||
uc_error("control open (%i): %s", card,
|
|
||||||
snd_strerror(err));
|
|
||||||
goto next_card;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = snd_ctl_card_info(handle, info);
|
if (err == 0) {
|
||||||
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);
|
_name = snd_ctl_card_info_get_name(info);
|
||||||
_long_name = snd_ctl_card_info_get_longname(info);
|
_long_name = snd_ctl_card_info_get_longname(info);
|
||||||
if (!strcmp(card_name, _name) ||
|
if (!strcmp(card_name, _name) ||
|
||||||
!strcmp(card_name, _long_name)) {
|
!strcmp(card_name, _long_name)) {
|
||||||
strcpy(mgr->card_long_name, _long_name);
|
snd_strlcpy(mgr->card_long_name, _long_name, sizeof(mgr->card_long_name));
|
||||||
snd_ctl_close(handle);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
snd_ctl_close(handle);
|
|
||||||
next_card:
|
|
||||||
if (snd_card_next(&card) < 0) {
|
if (snd_card_next(&card) < 0) {
|
||||||
uc_error("snd_card_next");
|
uc_error("snd_card_next");
|
||||||
break;
|
break;
|
||||||
|
|
@ -1472,6 +1472,27 @@ next_card:
|
||||||
return -1;
|
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,
|
static int load_master_config(snd_use_case_mgr_t *uc_mgr,
|
||||||
const char *card_name, snd_config_t **cfg)
|
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)
|
int uc_mgr_import_master_config(snd_use_case_mgr_t *uc_mgr)
|
||||||
{
|
{
|
||||||
snd_config_t *cfg;
|
snd_config_t *cfg;
|
||||||
|
const char *name = uc_mgr->card_name;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
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);
|
err = get_card_long_name(uc_mgr);
|
||||||
if (err == 0) /* load file that maches the card long name */
|
__longname:
|
||||||
|
if (err == 0) /* load file that matches the card long name */
|
||||||
err = load_master_config(uc_mgr, uc_mgr->card_long_name, &cfg);
|
err = load_master_config(uc_mgr, uc_mgr->card_long_name, &cfg);
|
||||||
|
|
||||||
if (err == 0) {
|
if (err == 0) {
|
||||||
/* got device-specific file that matches the card long name */
|
/* got device-specific file that matches the card long name */
|
||||||
strcpy(uc_mgr->conf_file_name, uc_mgr->card_long_name);
|
snd_strlcpy(uc_mgr->conf_file_name, uc_mgr->card_long_name, sizeof(uc_mgr->conf_file_name));
|
||||||
} else {
|
goto __parse;
|
||||||
/* 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';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 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);
|
err = parse_master_file(uc_mgr, cfg);
|
||||||
snd_config_delete(cfg);
|
snd_config_delete(cfg);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
uc_mgr_free_verb(uc_mgr);
|
uc_mgr_free_verb(uc_mgr);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
|
__error:
|
||||||
|
uc_mgr->conf_file_name[0] = '\0';
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int filename_filter(const struct dirent *dirent)
|
static int filename_filter(const struct dirent *dirent)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue