From: Abramo Bagnara Date: Thu, 24 Aug 2000 17:07:44 +0000 (+0000) Subject: Continued config implementation. Added incomplete support for pcm X-Git-Tag: v1.0.3~1171 X-Git-Url: https://git.alsa-project.org/?a=commitdiff_plain;h=244653df61ddad375e61a43aad0b936f16a6a2fa;p=alsa-lib.git Continued config implementation. Added incomplete support for pcm --- diff --git a/include/conf.h b/include/conf.h index be686a1a..a3eb6508 100644 --- a/include/conf.h +++ b/include/conf.h @@ -24,11 +24,14 @@ struct snd_config { snd_config_t *father; }; +int snd_config_top(snd_config_t **config); -int snd_config_load(snd_config_t **config, FILE *fp); +int snd_config_load(snd_config_t *config, FILE *fp); int snd_config_save(snd_config_t *config, FILE *fp); int snd_config_search(snd_config_t *config, char *key, snd_config_t **result); +int snd_config_searchv(snd_config_t *config, + snd_config_t **result, ...); int snd_config_add(snd_config_t *config, snd_config_t *leaf); int snd_config_delete(snd_config_t *config); @@ -55,3 +58,15 @@ typedef struct list_head *snd_config_iterator_t; #define snd_config_entry(iterator) list_entry(iterator, snd_config_t, list) +static inline snd_config_type_t snd_config_type(snd_config_t *config) +{ + return config->type; +} + +static inline char *snd_config_id(snd_config_t *config) +{ + return config->id; +} + +snd_config_t *snd_config; +int snd_config_update(); diff --git a/include/pcm.h b/include/pcm.h index 69e1e2ca..a4b2d36d 100644 --- a/include/pcm.h +++ b/include/pcm.h @@ -122,6 +122,9 @@ int snd_pcm_synchro(snd_pcm_synchro_cmd_t cmd, #endif +int snd_pcm_open(snd_pcm_t **handle, char *name, + int stream, int mode); + int snd_pcm_hw_open_subdevice(snd_pcm_t **handle, int card, int device, int subdevice, int stream, int mode); int snd_pcm_hw_open(snd_pcm_t **handle, int card, int device, int stream, int mode); diff --git a/src/Makefile.am b/src/Makefile.am index c0eb0020..4286ea43 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -6,7 +6,7 @@ libasound_la_SOURCES = error.c libasound_la_LIBADD = control/libcontrol.la mixer/libmixer.la pcm/libpcm.la \ rawmidi/librawmidi.la timer/libtimer.la \ hwdep/libhwdep.la seq/libseq.la instr/libinstr.la \ - compat/libcompat.la + compat/libcompat.la conf/libconf.la libasound_la_LDFLAGS = -version-info $(COMPATNUM) @@ -37,4 +37,7 @@ instr/libinstr.la: compat/libcompat.la: $(MAKE) -C compat libcompat.la +conf/libconf.la: + $(MAKE) -C conf libconf.la + INCLUDES=-I$(top_srcdir)/include diff --git a/src/conf/conf.c b/src/conf/conf.c index 3d5e488f..ec277ac0 100644 --- a/src/conf/conf.c +++ b/src/conf/conf.c @@ -22,9 +22,13 @@ #include #include #include +#include #include "asoundlib.h" #include "list.h" +#define SYS_ASOUNDRC "/etc/asound.conf" +#define USR_ASOUNDRC ".asoundrc" + typedef struct { FILE *fp; unsigned int line, column; @@ -183,7 +187,7 @@ static int get_freestring(char **string, input_t *input) } if (idx >= alloc) { size_t old_alloc = alloc; - alloc *= 2; + alloc += bufsize; if (old_alloc == bufsize) { buf = malloc(alloc); memcpy(buf, _buf, old_alloc); @@ -227,7 +231,7 @@ static int get_delimstring(char **string, int delim, input_t *input) } if (idx >= alloc) { size_t old_alloc = alloc; - alloc *= 2; + alloc += bufsize; if (old_alloc == bufsize) { buf = malloc(alloc); memcpy(buf, _buf, old_alloc); @@ -507,30 +511,30 @@ static int parse_defs(snd_config_t *father, input_t *input) return 0; } +int snd_config_top(snd_config_t **config) +{ + assert(config); + return _snd_config_make(config, 0, SND_CONFIG_TYPE_COMPOUND); +} -int snd_config_load(snd_config_t **config, FILE *fp) +int snd_config_load(snd_config_t *config, FILE *fp) { int err; input_t input; - snd_config_t *c; assert(config && fp); - err = _snd_config_make(&c, 0, SND_CONFIG_TYPE_COMPOUND); - if (err < 0) - return err; input.fp = fp; input.line = 1; input.column = 0; input.unget = 0; - err = parse_defs(c, &input); + err = parse_defs(config, &input); if (err < 0) { - snd_config_delete(c); + snd_config_delete(config); return err; } if (get_char(&input) != EOF) { - snd_config_delete(c); + snd_config_delete(config); return -1; } - *config = c; return 0; } @@ -595,14 +599,18 @@ int snd_config_make(snd_config_t **config, char *id, int snd_config_integer_set(snd_config_t *config, long value) { - assert(config->type == SND_CONFIG_TYPE_INTEGER); + assert(config); + if (config->type != SND_CONFIG_TYPE_INTEGER) + return -EINVAL; config->u.integer = value; return 0; } int snd_config_real_set(snd_config_t *config, double value) { - assert(config->type == SND_CONFIG_TYPE_REAL); + assert(config); + if (config->type != SND_CONFIG_TYPE_REAL) + return -EINVAL; config->u.real = value; return 0; } @@ -610,7 +618,8 @@ int snd_config_real_set(snd_config_t *config, double value) int snd_config_string_set(snd_config_t *config, char *value) { assert(config); - assert(config->type == SND_CONFIG_TYPE_INTEGER); + if (config->type != SND_CONFIG_TYPE_STRING) + return -EINVAL; if (config->u.string) free(config->u.string); config->u.string = strdup(value); @@ -645,7 +654,8 @@ int snd_config_set(snd_config_t *config, ...) int snd_config_integer_get(snd_config_t *config, long *ptr) { assert(config && ptr); - assert(config->type == SND_CONFIG_TYPE_INTEGER); + if (config->type != SND_CONFIG_TYPE_INTEGER) + return -EINVAL; *ptr = config->u.integer; return 0; } @@ -653,7 +663,8 @@ int snd_config_integer_get(snd_config_t *config, long *ptr) int snd_config_real_get(snd_config_t *config, double *ptr) { assert(config && ptr); - assert(config->type == SND_CONFIG_TYPE_REAL); + if (config->type != SND_CONFIG_TYPE_REAL) + return -EINVAL; *ptr = config->u.real; return 0; } @@ -661,7 +672,8 @@ int snd_config_real_get(snd_config_t *config, double *ptr) int snd_config_string_get(snd_config_t *config, char **ptr) { assert(config && ptr); - assert(config->type == SND_CONFIG_TYPE_INTEGER); + if (config->type != SND_CONFIG_TYPE_STRING) + return -EINVAL; *ptr = config->u.string; return 0; } @@ -860,4 +872,110 @@ int snd_config_search(snd_config_t *config, char *key, snd_config_t **result) return _snd_config_search(config, key, -1, result); } } + +int snd_config_searchv(snd_config_t *config, + snd_config_t **result, ...) +{ + va_list arg; + const size_t bufsize = 256; + char _buf[bufsize]; + char *buf = _buf; + size_t alloc = bufsize; + size_t idx = 0; + size_t dot = 0; + assert(config && result); + va_start(arg, result); + while (1) { + char *k = va_arg(arg, char *); + size_t len; + if (!k) + break; + len = strlen(k); + if (idx + len + dot>= alloc) { + size_t old_alloc = alloc; + alloc = idx + len + dot; + alloc += bufsize - alloc % bufsize; + if (old_alloc == bufsize) { + buf = malloc(alloc); + memcpy(buf, _buf, old_alloc); + } else + buf = realloc(buf, alloc); + } + if (dot) + buf[idx] = '.'; + memcpy(buf + idx + dot, k, len); + idx += len + dot; + if (dot == 0) + dot = 1; + } + buf[idx] = '\0'; + return snd_config_search(config, buf, result); +} + +snd_config_t *snd_config = 0; +static dev_t sys_asoundrc_device; +static ino_t sys_asoundrc_inode; +static time_t sys_asoundrc_mtime; +static dev_t usr_asoundrc_device; +static ino_t usr_asoundrc_inode; +static time_t usr_asoundrc_mtime; +int snd_config_update() +{ + int err; + char *usr_asoundrc = NULL; + char *home = getenv("HOME"); + struct stat st; + int reload; + FILE *fp; + if (home) { + size_t len = strlen(home); + size_t len1 = strlen(USR_ASOUNDRC); + usr_asoundrc = alloca(len + len1 + 2); + memcpy(usr_asoundrc, home, len); + usr_asoundrc[len] = '/'; + memcpy(usr_asoundrc + len + 1, USR_ASOUNDRC, len1); + usr_asoundrc[len + 1 + len1] = '\0'; + } + reload = (snd_config == NULL); + if (!reload && + stat(usr_asoundrc, &st) == 0 && + (st.st_dev != usr_asoundrc_device || + st.st_ino != usr_asoundrc_inode || + st.st_mtime != usr_asoundrc_mtime)) + reload = 1; + if (!reload && + stat(SYS_ASOUNDRC, &st) == 0 && + (st.st_dev != sys_asoundrc_device || + st.st_ino != sys_asoundrc_inode || + st.st_mtime != sys_asoundrc_mtime)) + reload = 1; + if (!reload) + return 0; + if (snd_config == NULL) { + err = snd_config_top(&snd_config); + if (err < 0) + return err; + } + fp = fopen(SYS_ASOUNDRC, "r"); + if (fp) { + err = snd_config_load(snd_config, fp); + if (err < 0) { + snd_config = NULL; + fclose(fp); + return err; + } + fclose(fp); + } + fp = fopen(usr_asoundrc, "r"); + if (fp) { + err = snd_config_load(snd_config, fp); + if (err < 0) { + snd_config = NULL; + fclose(fp); + return err; + } + fclose(fp); + } + return 0; +} diff --git a/src/pcm/pcm.c b/src/pcm/pcm.c index 658f0f03..948046c8 100644 --- a/src/pcm/pcm.c +++ b/src/pcm/pcm.c @@ -27,6 +27,7 @@ #include #include #include "pcm_local.h" +#include "list.h" snd_pcm_type_t snd_pcm_type(snd_pcm_t *handle) { @@ -501,3 +502,170 @@ ssize_t snd_pcm_samples_to_bytes(snd_pcm_t *handle, ssize_t samples) return samples * handle->bits_per_sample / 8; } +static int _snd_pcm_open_hw(snd_pcm_t **handlep, snd_config_t *conf, + int stream, int mode) +{ + snd_config_iterator_t i; + long card = -1, device = -1, subdevice = -1; + char *str; + int err; + snd_config_foreach(i, conf) { + snd_config_t *n = snd_config_entry(i); + if (strcmp(n->id, "comment") == 0) + continue; + if (strcmp(n->id, "type") == 0) + continue; + if (strcmp(n->id, "stream") == 0) + continue; + if (strcmp(n->id, "card") == 0) { + err = snd_config_integer_get(n, &card); + if (err < 0) { + err = snd_config_string_get(n, &str); + if (err < 0) + return -EINVAL; + card = snd_card_name(str); + if (card < 0) + return card; + } + continue; + } + if (strcmp(n->id, "device") == 0) { + err = snd_config_integer_get(n, &device); + if (err < 0) + return err; + continue; + } + if (strcmp(n->id, "subdevice") == 0) { + err = snd_config_integer_get(n, &subdevice); + if (err < 0) + return err; + continue; + } + return -EINVAL; + } + if (card < 0 || device < 0) + return -EINVAL; + return snd_pcm_hw_open_subdevice(handlep, card, device, subdevice, stream, mode); +} + +static int _snd_pcm_open_plug(snd_pcm_t **handlep, snd_config_t *conf, + int stream, int mode) +{ + snd_config_iterator_t i; + long card = -1, device = -1, subdevice = -1; + char *str; + int err; + snd_config_foreach(i, conf) { + snd_config_t *n = snd_config_entry(i); + if (strcmp(n->id, "comment") == 0) + continue; + if (strcmp(n->id, "type") == 0) + continue; + if (strcmp(n->id, "stream") == 0) + continue; + if (strcmp(n->id, "card") == 0) { + err = snd_config_integer_get(n, &card); + if (err < 0) { + err = snd_config_string_get(n, &str); + if (err < 0) + return -EINVAL; + card = snd_card_name(str); + if (card < 0) + return card; + } + continue; + } + if (strcmp(n->id, "device") == 0) { + err = snd_config_integer_get(n, &device); + if (err < 0) + return err; + continue; + } + if (strcmp(n->id, "subdevice") == 0) { + err = snd_config_integer_get(n, &subdevice); + if (err < 0) + return err; + continue; + } + return -EINVAL; + } + if (card < 0 || device < 0) + return -EINVAL; + return snd_pcm_plug_open_subdevice(handlep, card, device, subdevice, stream, mode); +} + +static int _snd_pcm_open_multi(snd_pcm_t **handle, snd_config_t *conf, + int stream, int mode) +{ + snd_config_iterator_t i; + char *str; + int err; + snd_config_foreach(i, conf) { + snd_config_t *n = snd_config_entry(i); + if (strcmp(n->id, "comment") == 0) + continue; + if (strcmp(n->id, "type") == 0) + continue; + if (strcmp(n->id, "stream") == 0) + continue; + if (strcmp(n->id, "slave") == 0) { + if (snd_config_type(n) != SND_CONFIG_TYPE_COMPOUND) + return -EINVAL; + /* Not yet implemented */ + continue; + } + if (strcmp(n->id, "binding") == 0) { + if (snd_config_type(n) != SND_CONFIG_TYPE_COMPOUND) + return -EINVAL; + /* Not yet implemented */ + continue; + } + return -EINVAL; + } + return -ENOSYS; +} + +int snd_pcm_open(snd_pcm_t **handlep, char *name, + int stream, int mode) +{ + char *str; + int err; + snd_config_t *pcm_conf, *conf; + assert(handlep && name); + err = snd_config_update(); + if (err < 0) + return err; + err = snd_config_searchv(snd_config, &pcm_conf, "pcm", name, 0); + if (err < 0) + return err; + if (snd_config_type(pcm_conf) != SND_CONFIG_TYPE_COMPOUND) + return -EINVAL; + err = snd_config_search(pcm_conf, "stream", &conf); + if (err >= 0) { + err = snd_config_string_get(conf, &str); + if (err < 0) + return err; + if (strcmp(str, "playback") == 0) { + if (stream != SND_PCM_STREAM_PLAYBACK) + return -EINVAL; + } else if (strcmp(str, "capture") == 0) { + if (stream != SND_PCM_STREAM_CAPTURE) + return -EINVAL; + } else + return -EINVAL; + } + err = snd_config_search(pcm_conf, "type", &conf); + if (err < 0) + return err; + err = snd_config_string_get(conf, &str); + if (err < 0) + return err; + if (strcmp(str, "hw") == 0) + return _snd_pcm_open_hw(handlep, pcm_conf, stream, mode); + else if (strcmp(str, "plug") == 0) + return _snd_pcm_open_plug(handlep, pcm_conf, stream, mode); + else if (strcmp(str, "multi") == 0) + return _snd_pcm_open_multi(handlep, pcm_conf, stream, mode); + else + return -EINVAL; +} diff --git a/src/pcm/pcm_hw.c b/src/pcm/pcm_hw.c index 531dea57..80f7fad1 100644 --- a/src/pcm/pcm_hw.c +++ b/src/pcm/pcm_hw.c @@ -406,6 +406,7 @@ int snd_pcm_hw_open_subdevice(snd_pcm_t **handlep, int card, int device, int sub snd_pcm_t *handle; snd_pcm_hw_t *hw; + assert(handlep); *handlep = 0; if ((ret = snd_ctl_open(&ctl, card)) < 0) diff --git a/src/pcm/pcm_multi.c b/src/pcm/pcm_multi.c index 7abec1e2..172aaf46 100644 --- a/src/pcm/pcm_multi.c +++ b/src/pcm/pcm_multi.c @@ -737,6 +737,7 @@ int snd_pcm_multi_create(snd_pcm_t **handlep, size_t slaves_count, char client_map[32] = { 0 }; char slave_map[32][32] = { { 0 } }; + assert(handlep); assert(slaves_count > 0 && slaves_handle && slaves_channels_count); assert(binds_count > 0 && binds_slave && binds_client_channel && binds_slave_channel); diff --git a/src/pcm/pcm_plug.c b/src/pcm/pcm_plug.c index 6feda185..d65e63c2 100644 --- a/src/pcm/pcm_plug.c +++ b/src/pcm/pcm_plug.c @@ -789,6 +789,7 @@ int snd_pcm_plug_create(snd_pcm_t **handlep, snd_pcm_t *slave, int close_slave) { snd_pcm_t *handle; snd_pcm_plug_t *plug; + assert(handlep && slave); handle = calloc(1, sizeof(snd_pcm_t)); if (!handle) return -ENOMEM;