mirror of
				https://github.com/alsa-project/alsa-lib.git
				synced 2025-11-03 09:01:52 -05:00 
			
		
		
		
	ucm: configuration - allow to define the configuration variables
It may be useful for the library files to use the runtime configuration
variables.
Example:
 Define.Var1 "hw:${CardId},2"
 Value.PlaybackPCM "${var:Var1}"
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
			
			
This commit is contained in:
		
							parent
							
								
									6cc6024ac5
								
							
						
					
					
						commit
						ed4567d1c9
					
				
					 5 changed files with 130 additions and 5 deletions
				
			
		| 
						 | 
					@ -966,6 +966,7 @@ int snd_use_case_mgr_open(snd_use_case_mgr_t **uc_mgr,
 | 
				
			||||||
	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);
 | 
						INIT_LIST_HEAD(&mgr->ctl_list);
 | 
				
			||||||
 | 
						INIT_LIST_HEAD(&mgr->variable_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);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -193,6 +193,49 @@ int parse_get_safe_id(snd_config_t *n, const char **id)
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Evaluate variable definitions (in-place delete)
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static int evaluate_define(snd_use_case_mgr_t *uc_mgr,
 | 
				
			||||||
 | 
								   snd_config_t *cfg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						snd_config_iterator_t i, next;
 | 
				
			||||||
 | 
						snd_config_t *d, *n;
 | 
				
			||||||
 | 
						const char *id;
 | 
				
			||||||
 | 
						char *var, *s;
 | 
				
			||||||
 | 
						int err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = snd_config_search(cfg, "Define", &d);
 | 
				
			||||||
 | 
						if (err == -ENOENT)
 | 
				
			||||||
 | 
							return 1;
 | 
				
			||||||
 | 
						if (err < 0)
 | 
				
			||||||
 | 
							return err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (snd_config_get_type(d) != SND_CONFIG_TYPE_COMPOUND) {
 | 
				
			||||||
 | 
							uc_error("compound type expected for Define");
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						snd_config_for_each(i, next, d) {
 | 
				
			||||||
 | 
							n = snd_config_iterator_entry(i);
 | 
				
			||||||
 | 
							err = snd_config_get_id(n, &id);
 | 
				
			||||||
 | 
							if (err < 0)
 | 
				
			||||||
 | 
								return err;
 | 
				
			||||||
 | 
							err = snd_config_get_ascii(n, &var);
 | 
				
			||||||
 | 
							if (err < 0)
 | 
				
			||||||
 | 
								return err;
 | 
				
			||||||
 | 
							err = uc_mgr_get_substituted_value(uc_mgr, &s, var);
 | 
				
			||||||
 | 
							free(var);
 | 
				
			||||||
 | 
							if (err < 0)
 | 
				
			||||||
 | 
								return err;
 | 
				
			||||||
 | 
							uc_mgr_set_variable(uc_mgr, id, s);
 | 
				
			||||||
 | 
							free(s);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						snd_config_delete(d);
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Evaluate include (in-place)
 | 
					 * Evaluate include (in-place)
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
| 
						 | 
					@ -239,16 +282,20 @@ static int evaluate_condition(snd_use_case_mgr_t *uc_mgr,
 | 
				
			||||||
int uc_mgr_evaluate_inplace(snd_use_case_mgr_t *uc_mgr,
 | 
					int uc_mgr_evaluate_inplace(snd_use_case_mgr_t *uc_mgr,
 | 
				
			||||||
			    snd_config_t *cfg)
 | 
								    snd_config_t *cfg)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int err1 = 0, err2 = 0;
 | 
						int err1 = 0, err2 = 0, err3 = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	while (err1 == 0 || err2 == 0) {
 | 
						while (err1 == 0 || err2 == 0 || err3 == 0) {
 | 
				
			||||||
		/* include at first */
 | 
							/* variables at first */
 | 
				
			||||||
		err1 = evaluate_include(uc_mgr, cfg);
 | 
							err1 = evaluate_define(uc_mgr, cfg);
 | 
				
			||||||
		if (err1 < 0)
 | 
							if (err1 < 0)
 | 
				
			||||||
			return err1;
 | 
								return err1;
 | 
				
			||||||
		err2 = evaluate_condition(uc_mgr, cfg);
 | 
							/* include at second */
 | 
				
			||||||
 | 
							err2 = evaluate_include(uc_mgr, cfg);
 | 
				
			||||||
		if (err2 < 0)
 | 
							if (err2 < 0)
 | 
				
			||||||
			return err2;
 | 
								return err2;
 | 
				
			||||||
 | 
							err3 = evaluate_condition(uc_mgr, cfg);
 | 
				
			||||||
 | 
							if (err3 < 0)
 | 
				
			||||||
 | 
								return err3;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -239,6 +239,9 @@ struct snd_use_case_mgr {
 | 
				
			||||||
	/* locking */
 | 
						/* locking */
 | 
				
			||||||
	pthread_mutex_t mutex;
 | 
						pthread_mutex_t mutex;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* UCM internal variables defined in configuration files */
 | 
				
			||||||
 | 
						struct list_head variable_list;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* list of opened control devices */
 | 
						/* list of opened control devices */
 | 
				
			||||||
	struct list_head ctl_list;
 | 
						struct list_head ctl_list;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -289,6 +292,13 @@ void uc_mgr_free_ctl_list(snd_use_case_mgr_t *uc_mgr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int uc_mgr_add_value(struct list_head *base, const char *key, char *val);
 | 
					int uc_mgr_add_value(struct list_head *base, const char *key, char *val);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const char *uc_mgr_get_variable(snd_use_case_mgr_t *uc_mgr,
 | 
				
			||||||
 | 
									const char *name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int uc_mgr_set_variable(snd_use_case_mgr_t *uc_mgr,
 | 
				
			||||||
 | 
								const char *name,
 | 
				
			||||||
 | 
								const char *val);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int uc_mgr_get_substituted_value(snd_use_case_mgr_t *uc_mgr,
 | 
					int uc_mgr_get_substituted_value(snd_use_case_mgr_t *uc_mgr,
 | 
				
			||||||
				 char **_rvalue,
 | 
									 char **_rvalue,
 | 
				
			||||||
				 const char *value);
 | 
									 const char *value);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -167,6 +167,21 @@ static char *rval_sysfs(snd_use_case_mgr_t *uc_mgr ATTRIBUTE_UNUSED, const char
 | 
				
			||||||
	return strdup(path);
 | 
						return strdup(path);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static char *rval_var(snd_use_case_mgr_t *uc_mgr, const char *id)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						const char *v;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (uc_mgr->conf_format < 3) {
 | 
				
			||||||
 | 
							uc_error("variable substitution is supported in v3+ syntax");
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						v = uc_mgr_get_variable(uc_mgr, id);
 | 
				
			||||||
 | 
						if (v)
 | 
				
			||||||
 | 
							return strdup(v);
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MATCH_VARIABLE(name, id, fcn, empty_ok)				\
 | 
					#define MATCH_VARIABLE(name, id, fcn, empty_ok)				\
 | 
				
			||||||
	if (strncmp((name), (id), sizeof(id) - 1) == 0) { 		\
 | 
						if (strncmp((name), (id), sizeof(id) - 1) == 0) { 		\
 | 
				
			||||||
		rval = fcn(uc_mgr);					\
 | 
							rval = fcn(uc_mgr);					\
 | 
				
			||||||
| 
						 | 
					@ -224,6 +239,7 @@ int uc_mgr_get_substituted_value(snd_use_case_mgr_t *uc_mgr,
 | 
				
			||||||
			MATCH_VARIABLE(value, "${CardComponents}", rval_card_components, true);
 | 
								MATCH_VARIABLE(value, "${CardComponents}", rval_card_components, true);
 | 
				
			||||||
			MATCH_VARIABLE2(value, "${env:", rval_env);
 | 
								MATCH_VARIABLE2(value, "${env:", rval_env);
 | 
				
			||||||
			MATCH_VARIABLE2(value, "${sys:", rval_sysfs);
 | 
								MATCH_VARIABLE2(value, "${sys:", rval_sysfs);
 | 
				
			||||||
 | 
								MATCH_VARIABLE2(value, "${var:", rval_var);
 | 
				
			||||||
			err = -EINVAL;
 | 
								err = -EINVAL;
 | 
				
			||||||
			tmp = strchr(value, '}');
 | 
								tmp = strchr(value, '}');
 | 
				
			||||||
			if (tmp) {
 | 
								if (tmp) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -552,6 +552,56 @@ int uc_mgr_remove_device(struct use_case_verb *verb, const char *name)
 | 
				
			||||||
	return found == 0 ? -ENODEV : 0;
 | 
						return found == 0 ? -ENODEV : 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const char *uc_mgr_get_variable(snd_use_case_mgr_t *uc_mgr, const char *name)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct list_head *pos;
 | 
				
			||||||
 | 
						struct ucm_value *value;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						list_for_each(pos, &uc_mgr->variable_list) {
 | 
				
			||||||
 | 
							value = list_entry(pos, struct ucm_value, list);
 | 
				
			||||||
 | 
							if (strcmp(value->name, name) == 0)
 | 
				
			||||||
 | 
								return value->data;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int uc_mgr_set_variable(snd_use_case_mgr_t *uc_mgr, const char *name,
 | 
				
			||||||
 | 
								const char *val)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct list_head *pos;
 | 
				
			||||||
 | 
						struct ucm_value *curr;
 | 
				
			||||||
 | 
						char *val2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						list_for_each(pos, &uc_mgr->variable_list) {
 | 
				
			||||||
 | 
							curr = list_entry(pos, struct ucm_value, list);
 | 
				
			||||||
 | 
							if (strcmp(curr->name, name) == 0) {
 | 
				
			||||||
 | 
								val2 = strdup(val);
 | 
				
			||||||
 | 
								if (val2 == NULL)
 | 
				
			||||||
 | 
									return -ENOMEM;
 | 
				
			||||||
 | 
								free(curr->data);
 | 
				
			||||||
 | 
								curr->data = val2;
 | 
				
			||||||
 | 
								return 0;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						curr = calloc(1, sizeof(struct ucm_value));
 | 
				
			||||||
 | 
						if (curr == NULL)
 | 
				
			||||||
 | 
							return -ENOMEM;
 | 
				
			||||||
 | 
						curr->name = strdup(name);
 | 
				
			||||||
 | 
						if (curr->name == NULL) {
 | 
				
			||||||
 | 
							free(curr);
 | 
				
			||||||
 | 
							return -ENOMEM;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						curr->data = strdup(val);
 | 
				
			||||||
 | 
						if (curr->data == NULL) {
 | 
				
			||||||
 | 
							free(curr->name);
 | 
				
			||||||
 | 
							free(curr);
 | 
				
			||||||
 | 
							return -ENOMEM;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						list_add_tail(&curr->list, &uc_mgr->variable_list);
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void uc_mgr_free_verb(snd_use_case_mgr_t *uc_mgr)
 | 
					void uc_mgr_free_verb(snd_use_case_mgr_t *uc_mgr)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct list_head *pos, *npos;
 | 
						struct list_head *pos, *npos;
 | 
				
			||||||
| 
						 | 
					@ -576,6 +626,7 @@ void uc_mgr_free_verb(snd_use_case_mgr_t *uc_mgr)
 | 
				
			||||||
	uc_mgr_free_sequence(&uc_mgr->once_list);
 | 
						uc_mgr_free_sequence(&uc_mgr->once_list);
 | 
				
			||||||
	uc_mgr_free_sequence(&uc_mgr->default_list);
 | 
						uc_mgr_free_sequence(&uc_mgr->default_list);
 | 
				
			||||||
	uc_mgr_free_value(&uc_mgr->value_list);
 | 
						uc_mgr_free_value(&uc_mgr->value_list);
 | 
				
			||||||
 | 
						uc_mgr_free_value(&uc_mgr->variable_list);
 | 
				
			||||||
	free(uc_mgr->comment);
 | 
						free(uc_mgr->comment);
 | 
				
			||||||
	free(uc_mgr->conf_dir_name);
 | 
						free(uc_mgr->conf_dir_name);
 | 
				
			||||||
	free(uc_mgr->conf_file_name);
 | 
						free(uc_mgr->conf_file_name);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue