mirror of
				https://github.com/alsa-project/alsa-lib.git
				synced 2025-11-03 09:01:52 -05:00 
			
		
		
		
	ucm: implemented card list feature
- also added some test files to test/ucm tree Signed-off-by: Jaroslav Kysela <perex@perex.cz>
This commit is contained in:
		
							parent
							
								
									3a34394508
								
							
						
					
					
						commit
						e820866637
					
				
					 6 changed files with 134 additions and 27 deletions
				
			
		| 
						 | 
					@ -561,16 +561,6 @@ int snd_use_case_mgr_reset(snd_use_case_mgr_t *uc_mgr)
 | 
				
			||||||
	return err;
 | 
						return err;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * \brief Get list of cards in pair cardname+comment
 | 
					 | 
				
			||||||
 * \param list Returned list
 | 
					 | 
				
			||||||
 * \return Number of list entries if success, otherwise a negative error code
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
static int get_card_list(const char **list[])
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return -ENXIO;	/* Not Yet Implemented */
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * \brief Get list of verbs in pair verbname+comment
 | 
					 * \brief Get list of verbs in pair verbname+comment
 | 
				
			||||||
 * \param list Returned list
 | 
					 * \param list Returned list
 | 
				
			||||||
| 
						 | 
					@ -780,7 +770,7 @@ int snd_use_case_get_list(snd_use_case_mgr_t *uc_mgr,
 | 
				
			||||||
	int err;
 | 
						int err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (uc_mgr == NULL || identifier == NULL)
 | 
						if (uc_mgr == NULL || identifier == NULL)
 | 
				
			||||||
		return get_card_list(list);
 | 
							return uc_mgr_scan_master_configs(list);
 | 
				
			||||||
	pthread_mutex_lock(&uc_mgr->mutex);
 | 
						pthread_mutex_lock(&uc_mgr->mutex);
 | 
				
			||||||
	if (strcmp(identifier, "_verbs") == 0)
 | 
						if (strcmp(identifier, "_verbs") == 0)
 | 
				
			||||||
		err = get_verb_list(uc_mgr, list);
 | 
							err = get_verb_list(uc_mgr, list);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										142
									
								
								src/ucm/parser.c
									
										
									
									
									
								
							
							
						
						
									
										142
									
								
								src/ucm/parser.c
									
										
									
									
									
								
							| 
						 | 
					@ -31,6 +31,7 @@
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "ucm_local.h"
 | 
					#include "ucm_local.h"
 | 
				
			||||||
 | 
					#include <dirent.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int parse_sequence(snd_use_case_mgr_t *uc_mgr,
 | 
					static int parse_sequence(snd_use_case_mgr_t *uc_mgr,
 | 
				
			||||||
			  struct list_head *base,
 | 
								  struct list_head *base,
 | 
				
			||||||
| 
						 | 
					@ -827,7 +828,7 @@ static int parse_master_section(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * parse and execute controls
 | 
					 * parse controls
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static int parse_controls(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg)
 | 
					static int parse_controls(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -851,6 +852,8 @@ static int parse_controls(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg)
 | 
				
			||||||
 * #Example master file for blah sound card
 | 
					 * #Example master file for blah sound card
 | 
				
			||||||
 * #By Joe Blogs <joe@bloggs.org>
 | 
					 * #By Joe Blogs <joe@bloggs.org>
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 | 
					 * Comment "Nice Abstracted Soundcard"
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 * # The file is divided into Use case sections. One section per use case verb.
 | 
					 * # The file is divided into Use case sections. One section per use case verb.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * SectionUseCase."Voice Call" {
 | 
					 * SectionUseCase."Voice Call" {
 | 
				
			||||||
| 
						 | 
					@ -882,7 +885,8 @@ static int parse_master_file(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	snd_config_iterator_t i, next;
 | 
						snd_config_iterator_t i, next;
 | 
				
			||||||
	snd_config_t *n;
 | 
						snd_config_t *n;
 | 
				
			||||||
	int ret;
 | 
						const char *id;
 | 
				
			||||||
 | 
						int err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
 | 
						if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
 | 
				
			||||||
		uc_error("compound type expected for master file");
 | 
							uc_error("compound type expected for master file");
 | 
				
			||||||
| 
						 | 
					@ -891,26 +895,35 @@ static int parse_master_file(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* parse master config sections */
 | 
						/* parse master config sections */
 | 
				
			||||||
	snd_config_for_each(i, next, cfg) {
 | 
						snd_config_for_each(i, next, cfg) {
 | 
				
			||||||
		const char *id;
 | 
					
 | 
				
			||||||
		n = snd_config_iterator_entry(i);
 | 
							n = snd_config_iterator_entry(i);
 | 
				
			||||||
		if (snd_config_get_id(n, &id) < 0)
 | 
							if (snd_config_get_id(n, &id) < 0)
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (strcmp(id, "Comment") == 0) {
 | 
				
			||||||
 | 
								err = parse_string(n, &uc_mgr->comment);
 | 
				
			||||||
 | 
								if (err < 0) {
 | 
				
			||||||
 | 
									uc_error("error: failed to get master comment");
 | 
				
			||||||
 | 
									return err;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* find use case section and parse it */
 | 
							/* find use case section and parse it */
 | 
				
			||||||
		if (strcmp(id, "SectionUseCase") == 0) {
 | 
							if (strcmp(id, "SectionUseCase") == 0) {
 | 
				
			||||||
			ret = parse_compound(uc_mgr, n,
 | 
								err = parse_compound(uc_mgr, n,
 | 
				
			||||||
					     parse_master_section,
 | 
										     parse_master_section,
 | 
				
			||||||
					     NULL, NULL);
 | 
										     NULL, NULL);
 | 
				
			||||||
			if (ret < 0)
 | 
								if (err < 0)
 | 
				
			||||||
				return ret;
 | 
									return err;
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* find default control values section and parse it */
 | 
							/* find default control values section and parse it */
 | 
				
			||||||
		if (strcmp(id, "SectionDefaults") == 0) {
 | 
							if (strcmp(id, "SectionDefaults") == 0) {
 | 
				
			||||||
			ret = parse_controls(uc_mgr, n);
 | 
								err = parse_controls(uc_mgr, n);
 | 
				
			||||||
			if (ret < 0)
 | 
								if (err < 0)
 | 
				
			||||||
				return ret;
 | 
									return err;
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		uc_error("uknown master file field %s", id);
 | 
							uc_error("uknown master file field %s", id);
 | 
				
			||||||
| 
						 | 
					@ -918,25 +931,39 @@ static int parse_master_file(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg)
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* load master use case file for sound card */
 | 
					/** The name of the environment variable containing the UCM directory */
 | 
				
			||||||
int uc_mgr_import_master_config(snd_use_case_mgr_t *uc_mgr)
 | 
					#define ALSA_CONFIG_UCM_VAR "ALSA_CONFIG_UCM"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int load_master_config(const char *card_name, snd_config_t **cfg)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	char filename[MAX_FILE];
 | 
						char filename[MAX_FILE];
 | 
				
			||||||
	snd_config_t *cfg;
 | 
						char *env = getenv(ALSA_CONFIG_UCM_VAR);
 | 
				
			||||||
	int err;
 | 
						int err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	snprintf(filename, sizeof(filename)-1,
 | 
						snprintf(filename, sizeof(filename)-1,
 | 
				
			||||||
		"%s/%s/%s.conf", ALSA_USE_CASE_DIR,
 | 
							"%s/%s/%s.conf", env ? env : ALSA_USE_CASE_DIR,
 | 
				
			||||||
		uc_mgr->card_name, uc_mgr->card_name);
 | 
							card_name, card_name);
 | 
				
			||||||
	filename[MAX_FILE-1] = '\0';
 | 
						filename[MAX_FILE-1] = '\0';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = uc_mgr_config_load(filename, &cfg);
 | 
						err = uc_mgr_config_load(filename, cfg);
 | 
				
			||||||
	if (err < 0) {
 | 
						if (err < 0) {
 | 
				
			||||||
		uc_error("error: could not parse configuration for card %s",
 | 
							uc_error("error: could not parse configuration for card %s",
 | 
				
			||||||
				uc_mgr->card_name);
 | 
									card_name);
 | 
				
			||||||
		return err;
 | 
							return err;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* load master use case file for sound card */
 | 
				
			||||||
 | 
					int uc_mgr_import_master_config(snd_use_case_mgr_t *uc_mgr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						snd_config_t *cfg;
 | 
				
			||||||
 | 
						int err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = load_master_config(uc_mgr->card_name, &cfg);
 | 
				
			||||||
 | 
						if (err < 0)
 | 
				
			||||||
 | 
							return err;
 | 
				
			||||||
	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)
 | 
				
			||||||
| 
						 | 
					@ -944,3 +971,86 @@ int uc_mgr_import_master_config(snd_use_case_mgr_t *uc_mgr)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return err;
 | 
						return err;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int filename_filter(const struct dirent *dirent)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (dirent == NULL)
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						if (dirent->d_type == DT_DIR) {
 | 
				
			||||||
 | 
							if (dirent->d_name[0] == '.') {
 | 
				
			||||||
 | 
								if (dirent->d_name[1] == '\0')
 | 
				
			||||||
 | 
									return 0;
 | 
				
			||||||
 | 
								if (dirent->d_name[1] == '.' &&
 | 
				
			||||||
 | 
								    dirent->d_name[2] == '\0')
 | 
				
			||||||
 | 
									return 0;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return 1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* scan all cards and comments */
 | 
				
			||||||
 | 
					int uc_mgr_scan_master_configs(const char **_list[])
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						char filename[MAX_FILE];
 | 
				
			||||||
 | 
						char *env = getenv(ALSA_CONFIG_UCM_VAR);
 | 
				
			||||||
 | 
						const char **list;
 | 
				
			||||||
 | 
						snd_config_t *cfg, *c;
 | 
				
			||||||
 | 
						int i, cnt, err;
 | 
				
			||||||
 | 
						struct dirent **namelist;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						snprintf(filename, sizeof(filename)-1,
 | 
				
			||||||
 | 
							"%s", env ? env : ALSA_USE_CASE_DIR);
 | 
				
			||||||
 | 
						filename[MAX_FILE-1] = '\0';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = scandir(filename, &namelist, filename_filter, alphasort);
 | 
				
			||||||
 | 
						if (err < 0) {
 | 
				
			||||||
 | 
							err = -errno;
 | 
				
			||||||
 | 
							uc_error("error: could not scan directory %s: %s",
 | 
				
			||||||
 | 
									filename, strerror(-err));
 | 
				
			||||||
 | 
							return err;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						cnt = err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						list = calloc(1, cnt * 2 * sizeof(char *));
 | 
				
			||||||
 | 
						if (list == NULL) {
 | 
				
			||||||
 | 
							err = -ENOMEM;
 | 
				
			||||||
 | 
							goto __err;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < cnt; i++) {
 | 
				
			||||||
 | 
							err = load_master_config(namelist[i]->d_name, &cfg);
 | 
				
			||||||
 | 
							if (err < 0)
 | 
				
			||||||
 | 
								goto __err;
 | 
				
			||||||
 | 
							err = snd_config_search(cfg, "Comment", &c);
 | 
				
			||||||
 | 
							if (err >= 0) {
 | 
				
			||||||
 | 
								err = parse_string(c, (char **)&list[i*2+1]);
 | 
				
			||||||
 | 
								if (err < 0) {
 | 
				
			||||||
 | 
									snd_config_delete(cfg);
 | 
				
			||||||
 | 
									goto __err;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							snd_config_delete(cfg);
 | 
				
			||||||
 | 
							list[i * 2] = strdup(namelist[i]->d_name);
 | 
				
			||||||
 | 
							if (list[i * 2] == NULL) {
 | 
				
			||||||
 | 
								err = -ENOMEM;
 | 
				
			||||||
 | 
								goto __err;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						err = cnt * 2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      __err:
 | 
				
			||||||
 | 
						for (i = 0; i < cnt; i++) {
 | 
				
			||||||
 | 
							free(namelist[i]);
 | 
				
			||||||
 | 
							if (err < 0) {
 | 
				
			||||||
 | 
								free((void *)list[i * 2]);
 | 
				
			||||||
 | 
								free((void *)list[i * 2 + 1]);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						free(namelist);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (err >= 0)
 | 
				
			||||||
 | 
							*_list = list;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return err;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -193,6 +193,7 @@ void uc_mgr_stdout(const char *fmt, ...);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int uc_mgr_config_load(const char *file, snd_config_t **cfg);
 | 
					int uc_mgr_config_load(const char *file, snd_config_t **cfg);
 | 
				
			||||||
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);
 | 
				
			||||||
 | 
					int uc_mgr_scan_master_configs(const char **_list[]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void uc_mgr_free_sequence_element(struct sequence_element *seq);
 | 
					void uc_mgr_free_sequence_element(struct sequence_element *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);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -57,8 +57,13 @@ int uc_mgr_config_load(const char *file, snd_config_t **cfg)
 | 
				
			||||||
	int err;
 | 
						int err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	fp = fopen(file, "r");
 | 
						fp = fopen(file, "r");
 | 
				
			||||||
 | 
						if (fp == NULL) {
 | 
				
			||||||
 | 
							err = -errno;
 | 
				
			||||||
 | 
							goto __err;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	err = snd_input_stdio_attach(&in, fp, 1);
 | 
						err = snd_input_stdio_attach(&in, fp, 1);
 | 
				
			||||||
	if (err < 0) {
 | 
						if (err < 0) {
 | 
				
			||||||
 | 
						      __err:
 | 
				
			||||||
		uc_error("could not open configuration file %s", file);
 | 
							uc_error("could not open configuration file %s", file);
 | 
				
			||||||
		return err;
 | 
							return err;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										1
									
								
								test/ucm/anothercard/anothercard.conf
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								test/ucm/anothercard/anothercard.conf
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1 @@
 | 
				
			||||||
 | 
					Comment "Another Card"
 | 
				
			||||||
							
								
								
									
										0
									
								
								test/ucm/testcard1/testcard1.conf
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								test/ucm/testcard1/testcard1.conf
									
										
									
									
									
										Normal file
									
								
							
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue