ucm: add support for multiple control devices, more aggresive caching

Signed-off-by: Jaroslav Kysela <perex@perex.cz>
This commit is contained in:
Jaroslav Kysela 2019-11-04 14:42:45 +01:00
parent be6deb927f
commit 32ff0ba7a3
4 changed files with 212 additions and 50 deletions

View file

@ -138,37 +138,6 @@ int snd_use_case_free_list(const char *list[], int items)
return 0; 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, static int read_tlv_file(unsigned int **res,
const char *filepath) const char *filepath)
{ {
@ -427,7 +396,7 @@ static int execute_sequence(snd_use_case_mgr_t *uc_mgr,
cdev = capture_ctl; cdev = capture_ctl;
} }
if (ctl == NULL) { if (ctl == NULL) {
err = open_ctl(uc_mgr, &ctl, cdev); err = uc_mgr_open_ctl(uc_mgr, &ctl, cdev);
if (err < 0) { if (err < 0) {
uc_error("unable to open ctl device '%s'", cdev); uc_error("unable to open ctl device '%s'", cdev);
goto __fail; 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->value_list);
INIT_LIST_HEAD(&mgr->active_modifiers); INIT_LIST_HEAD(&mgr->active_modifiers);
INIT_LIST_HEAD(&mgr->active_devices); INIT_LIST_HEAD(&mgr->active_devices);
INIT_LIST_HEAD(&mgr->ctl_list);
pthread_mutex_init(&mgr->mutex, NULL); pthread_mutex_init(&mgr->mutex, NULL);
mgr->card_name = strdup(card_name); mgr->card_name = strdup(card_name);

View file

@ -1412,22 +1412,27 @@ static int parse_master_file(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg)
} }
/* get the card info */ /* 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; snd_ctl_t *handle;
int err; int err;
err = snd_ctl_open(&handle, ctl_name, 0); *_handle = NULL;
if (err < 0) {
uc_error("control open (%s): %s", ctl_name, snd_strerror(err)); err = uc_mgr_open_ctl(mgr, &handle, ctl_name);
if (err < 0)
return err; return err;
}
err = snd_ctl_card_info(handle, info); 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)); uc_error("control hardware info (%s): %s", ctl_name, snd_strerror(err));
} else {
*_handle = handle;
}
snd_ctl_close(handle);
return err; 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; const char *card_name = mgr->card_name;
int card, err; int card, err;
snd_ctl_t *ctl;
snd_ctl_card_info_t *info; snd_ctl_card_info_t *info;
const char *_name, *_long_name; const char *_name, *_long_name;
@ -1451,7 +1457,7 @@ 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 = get_card_info(name, info); err = get_card_info(mgr, name, &ctl, info);
if (err == 0) { if (err == 0) {
_name = snd_ctl_card_info_get_name(info); _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 */ /* 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) 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; snd_ctl_card_info_t *info;
const char *_name, *_long_name; const char *_name, *_long_name;
int err; int err;
snd_ctl_card_info_alloca(&info); snd_ctl_card_info_alloca(&info);
err = get_card_info(ctl_name, info); err = get_card_info(mgr, ctl_name, &ctl, info);
if (err) if (err)
return 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->card_long_name, _long_name, sizeof(mgr->card_long_name));
snd_strlcpy(mgr->conf_file_name, _name, sizeof(mgr->conf_file_name)); snd_strlcpy(mgr->conf_file_name, _name, sizeof(mgr->conf_file_name));
return 0; return 0;
} }
@ -1572,6 +1580,7 @@ __parse:
return err; return err;
__error: __error:
uc_mgr_free_ctl_list(uc_mgr);
uc_mgr->conf_file_name[0] = '\0'; uc_mgr->conf_file_name[0] = '\0';
return err; return err;
} }

View file

@ -105,6 +105,18 @@ struct dev_list {
struct list_head 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. * Describes a Use Case Modifier and it's enable and disable sequences.
* A use case verb can have N modifiers. * A use case verb can have N modifiers.
@ -214,9 +226,8 @@ struct snd_use_case_mgr {
/* locking */ /* locking */
pthread_mutex_t mutex; pthread_mutex_t mutex;
/* change to list of ctl handles */ /* list of opened control devices */
snd_ctl_t *ctl; struct list_head ctl_list;
char *ctl_dev;
/* Components don't define cdev, the card device. When executing /* Components don't define cdev, the card device. When executing
* a sequence of a component device, ucm manager enters component * 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_verb(snd_use_case_mgr_t *uc_mgr);
void uc_mgr_free(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 */ /** The name of the environment variable containing the UCM directory */
#define ALSA_CONFIG_UCM_VAR "ALSA_CONFIG_UCM" #define ALSA_CONFIG_UCM_VAR "ALSA_CONFIG_UCM"

View file

@ -49,6 +49,177 @@ void uc_mgr_stdout(const char *fmt,...)
va_end(va); 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) int uc_mgr_config_load(int format, const char *file, snd_config_t **cfg)
{ {
FILE *fp; FILE *fp;
@ -241,17 +412,12 @@ void uc_mgr_free_verb(snd_use_case_mgr_t *uc_mgr)
uc_mgr->active_verb = NULL; uc_mgr->active_verb = NULL;
INIT_LIST_HEAD(&uc_mgr->active_devices); INIT_LIST_HEAD(&uc_mgr->active_devices);
INIT_LIST_HEAD(&uc_mgr->active_modifiers); 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) void uc_mgr_free(snd_use_case_mgr_t *uc_mgr)
{ {
uc_mgr_free_verb(uc_mgr); uc_mgr_free_verb(uc_mgr);
uc_mgr_free_ctl_list(uc_mgr);
free(uc_mgr->card_name); free(uc_mgr->card_name);
free(uc_mgr); free(uc_mgr);
} }