From f5534c46ed7fb4618c8f970ab035cca1fb11e9cb Mon Sep 17 00:00:00 2001 From: Abramo Bagnara Date: Tue, 22 May 2001 09:19:43 +0000 Subject: [PATCH] Completed parametric configuration and begun to use it --- include/error.h | 2 +- include/local.h | 4 + src/Makefile.am | 5 + src/alsa.conf | 199 +++++++++++++++++++++++++++++ src/conf.c | 256 +++++++++++++++++++++++++++----------- src/control/cards_id.c | 3 - src/control/control.c | 101 +++++++++------ src/control/control_shm.c | 12 +- src/pcm/pcm.c | 116 +++++------------ src/pcm/pcm_surr.c | 3 - src/rawmidi/rawmidi.c | 102 +++++++++------ src/seq/seq.c | 70 ++++++++--- 12 files changed, 617 insertions(+), 256 deletions(-) create mode 100644 src/alsa.conf diff --git a/include/error.h b/include/error.h index 08c7c836..6e6f0446 100644 --- a/include/error.h +++ b/include/error.h @@ -22,7 +22,7 @@ const char *snd_strerror(int errnum); * \param fmt printf(3) format * \param ... printf(3) arguments */ -typedef void (snd_lib_error_handler_t)(const char *file, int line, const char *function, int err, const char *fmt, ...) /* __attribute__ ((weak, format (printf, 5, 6))) */; +typedef void (snd_lib_error_handler_t)(const char *file, int line, const char *function, int err, const char *fmt, ...) /* __attribute__ ((format (printf, 5, 6))) */; extern snd_lib_error_handler_t *snd_lib_error; extern int snd_lib_error_set_handler(snd_lib_error_handler_t *handler); diff --git a/include/local.h b/include/local.h index 903c36a4..3bf29f93 100644 --- a/include/local.h +++ b/include/local.h @@ -22,6 +22,10 @@ #ifndef __LOCAL_H #define __LOCAL_H +#ifndef DATADIR +#define DATADIR "/usr/share" +#endif + #define _snd_config_iterator list_head #define _snd_interval sndrv_interval #define _snd_pcm_info sndrv_pcm_info diff --git a/src/Makefile.am b/src/Makefile.am index 7dc09e37..37076abc 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -10,6 +10,11 @@ libasound_la_LIBADD = control/libcontrol.la mixer/libmixer.la pcm/libpcm.la \ libasound_la_LDFLAGS = -version-info $(COMPATNUM) +EXTRA_DIST = alsa.conf + +alsadir = $(datadir)/alsa +alsa_DATA = alsa.conf + control/libcontrol.la: $(MAKE) -C control libcontrol.la diff --git a/src/alsa.conf b/src/alsa.conf new file mode 100644 index 00000000..b6b6474c --- /dev/null +++ b/src/alsa.conf @@ -0,0 +1,199 @@ + +pcm.default { + type plug + slave.pcm { + type hw + card 0 + device 0 + } +} + +pcm.hw { + $.0 CARD + $.1 DEV + $.2 SUBDEV + $.CARD { + type integer + } + $.DEV { + type integer + } + $.SUBDEV { + type integer + default -1 + } + type hw + card $CARD + device $DEV + subdevice $SUBDEV +} + +pcm.plughw { + $.0 CARD + $.1 DEV + $.2 SUBDEV + $.CARD { + type integer + } + $.DEV { + type integer + } + $.SUBDEV { + type integer + default -1 + } + type plug + slave.pcm { + type hw + card $CARD + device $DEV + subdevice $SUBDEV + } +} + +pcm.plug { + $.0 SLAVE + $.SLAVE { + type string + } + type plug + slave.pcm $SLAVE +} + +pcm.shm { + $.0 SOCKET + $.1 PCM + $.SOCKET { + type string + } + $.PCM { + type string + } + type shm + server $SOCKET + pcm $PCM +} + +pcm.tee { + $.0 SLAVE + $.1 FILE + $.2 FORMAT + $.SLAVE { + type string + } + $.FILE { + type string + } + $.FORMAT { + type string + default raw + } + type file + slave.pcm $SLAVE + file $FILE + format $FORMAT +} + +pcm.file { + $.0 FILE + $.1 FORMAT + $.FILE { + type string + } + $.FORMAT { + type string + default raw + } + type file + slave.pcm null + file $FILE + format $FORMAT +} + +pcm.surround40 { + $.0 CARD + $.1 DEV + $.CARD { + type integer + } + $.DEV { + type integer + default 0 + } + type surround + card $CARD + device $DEVICE + stype 4.0 +} + +pcm.surround51 { + $.0 CARD + $.1 DEV + $.CARD { + type integer + } + $.DEV { + type integer + default 0 + } + type surround + card $CARD + device $DEVICE + stype 5.1 +} + +pcm.null { + type null +} + +ctl.default { + type hw + card 0 +} + +ctl.hw { + $.0 CARD + $.CARD { + type integer + } + type hw + card $CARD +} + +ctl.shm { + $.0 SOCKET + $.1 PCM + $.SOCKET { + type string + } + $.PCM { + type string + } + type shm + server $SOCKET + ctl $PCM +} + +rawmidi.hw { + $.0 CARD + $.1 DEV + $.2 SUBDEV + $.CARD { + type integer + } + $.DEV { + type integer + } + $.SUBDEV { + type integer + default -1 + } + type hw + card $CARD + device $DEV + subdevice $SUBDEV +} + +seq.hw { + type hw +} diff --git a/src/conf.c b/src/conf.c index 2be0e745..8fc889b0 100644 --- a/src/conf.c +++ b/src/conf.c @@ -20,6 +20,7 @@ */ #include +#include #include #include "local.h" #include "list.h" @@ -1194,17 +1195,29 @@ int snd_config_search_alias(snd_config_t *config, return 0; } -/** File used for system wide ALSA configuration */ -#define SYS_ASOUNDRC "/etc/asound.conf" -/** File resident in home directory used for user specific ALSA configuration */ -#define USR_ASOUNDRC ".asoundrc" +/** Environment variable containing files list for #snd_config_update */ +#define ASOUND_CONFIGS_VAR "ASOUND_CONFIGS" + +/** Default files used by #snd_config_update */ +#define ASOUND_CONFIGS_DEFAULT DATADIR "/alsa/alsa.conf:/etc/asound.conf:~/.asoundrc" /** \ingroup Config * Config top node */ snd_config_t *snd_config = NULL; +static struct finfo { + char *name; + dev_t dev; + ino_t ino; + time_t mtime; +} *files_info = NULL; + +static unsigned int files_info_count = 0; + /** - * \brief Update #snd_config rereading if needed #SYS_ASOUNDRC and #USR_ASOUNDRC + * \brief Update #snd_config rereading (if needed) files specified in + * environment variable ASOUND_CONFIGS. If it's not set the default value is + * "/usr/share/alsa/alsa.conf:/etc/asound.conf:~/.asoundrc" * \return 0 if no action is needed, 1 if tree has been rebuilt otherwise a negative error code * * Warning: If config tree is reread all the string pointer and config @@ -1212,80 +1225,120 @@ snd_config_t *snd_config = NULL; */ int snd_config_update() { - 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 err; - char *usr_asoundrc = NULL; - char *home = getenv("HOME"); - struct stat usr_st, sys_st; - int reload; - snd_input_t *in; - 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'; + char *configs, *c; + unsigned int k; + wordexp_t we; + size_t l; + struct finfo *fi; + unsigned int fi_count; + configs = getenv(ASOUND_CONFIGS_VAR); + if (!configs) + configs = ASOUND_CONFIGS_DEFAULT; + for (k = 0, c = configs; (l = strcspn(c, ": ")) > 0; ) { + c += l; + k++; + if (!*c) + break; + c++; + } + fi_count = k; + fi = calloc(fi_count, sizeof(*fi)); + if (!fi) + return -ENOMEM; + for (k = 0, c = configs; (l = strcspn(c, ": ")) > 0; ) { + char name[l + 1]; + memcpy(name, c, l); + name[l] = 0; + err = wordexp(name, &we, WRDE_NOCMD); + switch (err) { + case WRDE_NOSPACE: + err = -ENOMEM; + goto _end; + case 0: + if (we.we_wordc == 1) + break; + /* Fall through */ + default: + err = -EINVAL; + goto _end; + } + fi[k].name = strdup(we.we_wordv[0]); + wordfree(&we); + if (!fi[k].name) { + err = -ENOMEM; + goto _end; + } + c += l; + k++; + if (!*c) + break; + c++; + } + for (k = 0; k < fi_count; ++k) { + struct stat st; + if (stat(fi[k].name, &st) >= 0) { + fi[k].dev = st.st_dev; + fi[k].ino = st.st_ino; + fi[k].mtime = st.st_mtime; + } + } + if (!files_info) + goto _reread; + if (fi_count != files_info_count) + goto _reread; + for (k = 0; k < fi_count; ++k) { + if (strcmp(fi[k].name, files_info[k].name) != 0 || + fi[k].dev != files_info[k].dev || + fi[k].ino != files_info[k].ino || + fi[k].mtime != files_info[k].mtime) + goto _reread; + } + err = 0; + + _end: + if (err < 0 && snd_config) { + snd_config_delete(snd_config); + snd_config = NULL; + } + for (k = 0; k < fi_count; ++k) + free(fi[k].name); + free(fi); + return err; + + _reread: + if (files_info) { + for (k = 0; k < files_info_count; ++k) + free(files_info[k].name); + free(files_info); + files_info = NULL; + files_info_count = 0; } - reload = (snd_config == NULL); - if (stat(SYS_ASOUNDRC, &sys_st) == 0 && - (sys_st.st_dev != sys_asoundrc_device || - sys_st.st_ino != sys_asoundrc_inode || - sys_st.st_mtime != sys_asoundrc_mtime)) - reload = 1; - if (stat(usr_asoundrc, &usr_st) == 0 && - (usr_st.st_dev != usr_asoundrc_device || - usr_st.st_ino != usr_asoundrc_inode || - usr_st.st_mtime != usr_asoundrc_mtime)) - reload = 1; - if (!reload) - return 0; if (snd_config) { - err = snd_config_delete(snd_config); - if (err < 0) - return err; - snd_config = 0; + snd_config_delete(snd_config); + snd_config = NULL; } err = snd_config_top(&snd_config); if (err < 0) - return err; - err = snd_input_stdio_open(&in, SYS_ASOUNDRC, "r"); - if (err >= 0) { - err = snd_config_load(snd_config, in); - snd_input_close(in); - if (err < 0) { - SNDERR(SYS_ASOUNDRC " may be old or corrupted: consider to remove or fix it"); - snd_config_delete(snd_config); - snd_config = NULL; - return err; - } - sys_asoundrc_device = sys_st.st_dev; - sys_asoundrc_inode = sys_st.st_ino; - sys_asoundrc_mtime = sys_st.st_mtime; - } - err = snd_input_stdio_open(&in, usr_asoundrc, "r"); - if (err >= 0) { - err = snd_config_load(snd_config, in); - snd_input_close(in); - if (err < 0) { - SNDERR("%s may be old or corrupted: consider to remove or fix it", usr_asoundrc); - snd_config_delete(snd_config); - snd_config = NULL; - return err; + goto _end; + for (k = 0; k < fi_count; ++k) { + snd_input_t *in; + err = snd_input_stdio_open(&in, fi[k].name, "r"); + if (err >= 0) { + err = snd_config_load(snd_config, in); + snd_input_close(in); + if (err < 0) { + SNDERR("%s may be old or corrupted: consider to remove or fix it", fi[k].name); + goto _end; + } } - usr_asoundrc_device = usr_st.st_dev; - usr_asoundrc_inode = usr_st.st_ino; - usr_asoundrc_mtime = usr_st.st_mtime; } + files_info = fi; + files_info_count = fi_count; return 1; } + /** * \brief Return an iterator pointing to first leaf of a compound config node * \param node Config node handle @@ -1770,12 +1823,56 @@ static int parse_arg(const char **ptr, unsigned int *varlen, char **val) } +/* val1, val2, ... + * var1=val1,var2=val2,... + * { conf syntax } + */ static int parse_args(snd_config_t *subs, const char *str, snd_config_t *defs) { int err; int arg = 0; + skip_blank(&str); if (!*str) return 0; + if (*str == '{') { + int len = strlen(str); + snd_input_t *input; + snd_config_iterator_t i, next; + while (1) { + switch (str[--len]) { + case ' ': + case '\f': + case '\t': + case '\n': + case '\r': + continue; + default: + break; + } + break; + } + if (str[len] != '}') + return -EINVAL; + err = snd_input_buffer_open(&input, str + 1, len - 1); + if (err < 0) + return err; + err = snd_config_load(subs, input); + snd_input_close(input); + if (err < 0) + return err; + snd_config_for_each(i, next, subs) { + snd_config_t *n = snd_config_iterator_entry(i); + snd_config_t *d; + const char *id = snd_config_get_id(n); + err = snd_config_search(defs, id, &d); + if (err < 0) { + SNDERR("Unknown parameter %s", id); + return err; + } + } + return 0; + } + while (1) { char buf[256]; const char *var = buf; @@ -1812,7 +1909,6 @@ static int parse_args(snd_config_t *subs, const char *str, snd_config_t *defs) if (err < 0) { _invalid_type: SNDERR("Parameter %s definition is missing a valid type info", var); - err = -EINVAL; goto _err; } err = snd_config_get_string(typ, &tmp); @@ -1851,8 +1947,10 @@ static int parse_args(snd_config_t *subs, const char *str, snd_config_t *defs) err = snd_config_set_string(sub, val); if (err < 0) goto _err; - } else + } else { + err = -EINVAL; goto _invalid_type; + } err = snd_config_set_id(sub, var); if (err < 0) goto _err; @@ -1906,3 +2004,21 @@ int snd_config_expand(snd_config_t *config, const char *args, return err; } + +#if 0 +/* Not strictly needed, but useful to check for memory leaks */ +void _snd_config_end(void) __attribute__ ((destructor)); + +static void _snd_config_end(void) +{ + int k; + if (snd_config) + snd_config_delete(snd_config); + snd_config = 0; + for (k = 0; k < files_info_count; ++k) + free(files_info[k].name); + free(files_info); + files_info = NULL; + files_info_count = 0; +} +#endif diff --git a/src/control/cards_id.c b/src/control/cards_id.c index 6703cf89..514e76e6 100644 --- a/src/control/cards_id.c +++ b/src/control/cards_id.c @@ -28,9 +28,6 @@ #include #include "control_local.h" -#ifndef DATADIR -#define DATADIR "/usr/share" -#endif #define ALSA_CARDS_FILE DATADIR "/alsa/cards.conf" static int build_config(snd_config_t **r_conf) diff --git a/src/control/control.c b/src/control/control.c index 94d1c1a8..937ae28a 100644 --- a/src/control/control.c +++ b/src/control/control.c @@ -380,57 +380,38 @@ int snd_ctl_wait(snd_ctl_t *ctl, int timeout) return 0; } -/** - * \brief Opens a CTL - * \param ctlp Returned CTL handle - * \param name ASCII identifier of the CTL handle - * \param mode Open mode (see #SND_CTL_NONBLOCK, #SND_CTL_ASYNC) - * \return 0 on success otherwise a negative error code - */ -int snd_ctl_open(snd_ctl_t **ctlp, const char *name, int mode) +int snd_ctl_open_conf(snd_ctl_t **ctlp, const char *name, + snd_config_t *ctl_conf, int mode) { const char *str; char buf[256]; int err; - snd_config_t *ctl_conf, *conf, *type_conf; + snd_config_t *conf, *type_conf = NULL; snd_config_iterator_t i, next; const char *lib = NULL, *open_name = NULL; int (*open_func)(snd_ctl_t **, const char *, snd_config_t *, int); void *h; - const char *name1; - assert(ctlp && name); - err = snd_config_update(); - if (err < 0) - return err; - - err = snd_config_search_alias(snd_config, "ctl", name, &ctl_conf); - name1 = name; - if (err < 0 || snd_config_get_string(ctl_conf, &name1) >= 0) { - int card; - char socket[256], sname[256]; - err = sscanf(name1, "hw:%d", &card); - if (err == 1) - return snd_ctl_hw_open(ctlp, name, card, mode); - err = sscanf(name1, "shm:%256[^,],%256[^,]", socket, sname); - if (err == 2) - return snd_ctl_shm_open(ctlp, name, socket, sname, mode); - SNDERR("Unknown ctl %s", name1); - return -ENOENT; - } if (snd_config_get_type(ctl_conf) != SND_CONFIG_TYPE_COMPOUND) { - SNDERR("Invalid type for %s", snd_config_get_id(ctl_conf)); + if (name) + SNDERR("Invalid type for CTL %s definition", name); + else + SNDERR("Invalid type for CTL definition"); return -EINVAL; } err = snd_config_search(ctl_conf, "type", &conf); - if (err < 0) + if (err < 0) { + SNDERR("type is not defined"); return err; + } err = snd_config_get_string(conf, &str); - if (err < 0) + if (err < 0) { + SNDERR("Invalid type for %s", snd_config_get_id(conf)); return err; + } err = snd_config_search_alias(snd_config, "ctl_type", str, &type_conf); if (err >= 0) { if (snd_config_get_type(type_conf) != SND_CONFIG_TYPE_COMPOUND) { - SNDERR("Invalid type for ctl type %s definition", str); + SNDERR("Invalid type for CTL type %s definition", str); return -EINVAL; } snd_config_for_each(i, next, type_conf) { @@ -440,14 +421,18 @@ int snd_ctl_open(snd_ctl_t **ctlp, const char *name, int mode) continue; if (strcmp(id, "lib") == 0) { err = snd_config_get_string(n, &lib); - if (err < 0) + if (err < 0) { + SNDERR("Invalid type for %s", id); return -EINVAL; + } continue; } if (strcmp(id, "open") == 0) { err = snd_config_get_string(n, &open_name); - if (err < 0) + if (err < 0) { + SNDERR("Invalid type for %s", id); return -EINVAL; + } continue; } SNDERR("Unknown field %s", id); @@ -474,6 +459,52 @@ int snd_ctl_open(snd_ctl_t **ctlp, const char *name, int mode) return open_func(ctlp, name, ctl_conf, mode); } +int snd_ctl_open_noupdate(snd_ctl_t **ctlp, const char *name, int mode) +{ + int err; + snd_config_t *ctl_conf; + const char *args = strchr(name, ':'); + char *base; + if (args) { + args++; + base = alloca(args - name); + memcpy(base, name, args - name - 1); + base[args - name - 1] = 0; + } else + base = (char *) name; + err = snd_config_search_alias(snd_config, "ctl", base, &ctl_conf); + if (err < 0) { + SNDERR("Unknown CTL %s", name); + return err; + } + if (args) { + err = snd_config_expand(ctl_conf, args, &ctl_conf); + if (err < 0) + return err; + } + err = snd_ctl_open_conf(ctlp, name, ctl_conf, mode); + if (args) + snd_config_delete(ctl_conf); + return err; +} + +/** + * \brief Opens a CTL + * \param ctlp Returned CTL handle + * \param name ASCII identifier of the CTL handle + * \param mode Open mode (see #SND_CTL_NONBLOCK, #SND_CTL_ASYNC) + * \return 0 on success otherwise a negative error code + */ +int snd_ctl_open(snd_ctl_t **ctlp, const char *name, int mode) +{ + int err; + assert(ctlp && name); + err = snd_config_update(); + if (err < 0) + return err; + return snd_ctl_open_noupdate(ctlp, name, mode); +} + /** * \brief Set CTL element #SND_CTL_ELEM_TYPE_BYTES value * \param ctl CTL handle diff --git a/src/control/control_shm.c b/src/control/control_shm.c index e2527f02..6554d08a 100644 --- a/src/control/control_shm.c +++ b/src/control/control_shm.c @@ -528,7 +528,7 @@ int _snd_ctl_shm_open(snd_ctl_t **handlep, char *name, snd_config_t *conf, int m { snd_config_iterator_t i, next; const char *server = NULL; - const char *sname = NULL; + const char *ctl_name = NULL; snd_config_t *sconfig; const char *host = NULL; const char *sockname = NULL; @@ -551,8 +551,8 @@ int _snd_ctl_shm_open(snd_ctl_t **handlep, char *name, snd_config_t *conf, int m } continue; } - if (strcmp(id, "sname") == 0) { - err = snd_config_get_string(n, &sname); + if (strcmp(id, "ctl") == 0) { + err = snd_config_get_string(n, &ctl_name); if (err < 0) { SNDERR("Invalid type for %s", id); return -EINVAL; @@ -562,8 +562,8 @@ int _snd_ctl_shm_open(snd_ctl_t **handlep, char *name, snd_config_t *conf, int m SNDERR("Unknown field %s", id); return -EINVAL; } - if (!sname) { - SNDERR("sname is not defined"); + if (!ctl_name) { + SNDERR("ctl is not defined"); return -EINVAL; } if (!server) { @@ -630,6 +630,6 @@ int _snd_ctl_shm_open(snd_ctl_t **handlep, char *name, snd_config_t *conf, int m SNDERR("%s is not the local host", host); return -EINVAL; } - return snd_ctl_shm_open(handlep, name, sockname, sname, mode); + return snd_ctl_shm_open(handlep, name, sockname, ctl_name, mode); } diff --git a/src/pcm/pcm.c b/src/pcm/pcm.c index 9890235a..6095bd65 100644 --- a/src/pcm/pcm.c +++ b/src/pcm/pcm.c @@ -995,91 +995,30 @@ static int snd_pcm_open_noupdate(snd_pcm_t **pcmp, const char *name, { int err; snd_config_t *pcm_conf; - const char *name1; - - err = snd_config_search_alias(snd_config, "pcm", name, &pcm_conf); - name1 = name; - if (err < 0 || snd_config_get_string(pcm_conf, &name1) >= 0) { - int card, dev, subdev; - char socket[256], sname[256]; - char format[16], file[256]; - err = sscanf(name1, "hw:%d,%d,%d", &card, &dev, &subdev); - if (err == 3) - return snd_pcm_hw_open(pcmp, name, card, dev, subdev, stream, mode); - err = sscanf(name1, "hw:%d,%d", &card, &dev); - if (err == 2) - return snd_pcm_hw_open(pcmp, name, card, dev, -1, stream, mode); - err = sscanf(name1, "plug:%d,%d,%d", &card, &dev, &subdev); - if (err == 3) - return snd_pcm_plug_open_hw(pcmp, name, card, dev, subdev, stream, mode); - err = sscanf(name1, "plug:%d,%d", &card, &dev); - if (err == 2) - return snd_pcm_plug_open_hw(pcmp, name, card, dev, -1, stream, mode); - err = sscanf(name1, "plug:%256[^,]", sname); - if (err == 1) { - snd_pcm_t *slave; - err = snd_pcm_open(&slave, sname, stream, mode); - if (err < 0) - return err; - return snd_pcm_plug_open(pcmp, name, NULL, 0, 0, 0, slave, 1); - } - err = sscanf(name1, "shm:%256[^,],%256[^,]", socket, sname); - if (err == 2) - return snd_pcm_shm_open(pcmp, name, socket, sname, stream, mode); - err = sscanf(name1, "file:%256[^,],%16[^,],%256[^,]", file, format, sname); - if (err == 3) { - snd_pcm_t *slave; - err = snd_pcm_open(&slave, sname, stream, mode); - if (err < 0) - return err; - return snd_pcm_file_open(pcmp, name1, file, -1, format, slave, 1); - } - err = sscanf(name1, "file:%256[^,],%16[^,]", file, format); - if (err == 2) { - snd_pcm_t *slave; - err = snd_pcm_null_open(&slave, name, stream, mode); - if (err < 0) - return err; - return snd_pcm_file_open(pcmp, name, file, -1, format, slave, 1); - } - err = sscanf(name1, "file:%256[^,]", file); - if (err == 1) { - snd_pcm_t *slave; - err = snd_pcm_null_open(&slave, name, stream, mode); - if (err < 0) - return err; - return snd_pcm_file_open(pcmp, name, file, -1, "raw", slave, 1); - } - if (strcmp(name1, "null") == 0) - return snd_pcm_null_open(pcmp, name, stream, mode); - err = sscanf(name1, "surround40:%d,%d", &card, &dev); - if (err == 2) - return snd_pcm_surround_open(pcmp, name, card, dev, SND_PCM_SURROUND_40, stream, mode); - err = sscanf(name1, "surround40:%d", &card); - if (err == 1) - return snd_pcm_surround_open(pcmp, name, card, 0, SND_PCM_SURROUND_40, stream, mode); - err = sscanf(name1, "surround51:%d,%d", &card, &dev); - if (err == 2) - return snd_pcm_surround_open(pcmp, name, card, dev, SND_PCM_SURROUND_51, stream, mode); - err = sscanf(name1, "surround51:%d", &card); - if (err == 1) - return snd_pcm_surround_open(pcmp, name, card, 0, SND_PCM_SURROUND_51, stream, mode); - SNDERR("Unknown PCM %s", name1); - return -ENOENT; + const char *args = strchr(name, ':'); + char *base; + if (args) { + args++; + base = alloca(args - name); + memcpy(base, name, args - name - 1); + base[args - name - 1] = 0; + } else + base = (char *) name; + err = snd_config_search_alias(snd_config, "pcm", base, &pcm_conf); + if (err < 0) { + SNDERR("Unknown PCM %s", name); + return err; } - return snd_pcm_open_conf(pcmp, name, pcm_conf, stream, mode); -} - -#ifndef DOC_HIDDEN -int snd_pcm_open_slave(snd_pcm_t **pcmp, snd_config_t *conf, - snd_pcm_stream_t stream, int mode) -{ - const char *str; - if (snd_config_get_string(conf, &str) >= 0) - return snd_pcm_open_noupdate(pcmp, str, stream, mode); - return snd_pcm_open_conf(pcmp, NULL, conf, stream, mode); + if (args) { + err = snd_config_expand(pcm_conf, args, &pcm_conf); + if (err < 0) + return err; + } + err = snd_pcm_open_conf(pcmp, name, pcm_conf, stream, mode); + if (args) + snd_config_delete(pcm_conf); + return err; } -#endif /** * \brief Opens a PCM @@ -1100,6 +1039,17 @@ int snd_pcm_open(snd_pcm_t **pcmp, const char *name, return snd_pcm_open_noupdate(pcmp, name, stream, mode); } +#ifndef DOC_HIDDEN +int snd_pcm_open_slave(snd_pcm_t **pcmp, snd_config_t *conf, + snd_pcm_stream_t stream, int mode) +{ + const char *str; + if (snd_config_get_string(conf, &str) >= 0) + return snd_pcm_open_noupdate(pcmp, str, stream, mode); + return snd_pcm_open_conf(pcmp, NULL, conf, stream, mode); +} +#endif + /** * \brief Wait for a PCM to become ready * \param pcm PCM handle diff --git a/src/pcm/pcm_surr.c b/src/pcm/pcm_surr.c index 327b4ea7..ec94b16d 100644 --- a/src/pcm/pcm_surr.c +++ b/src/pcm/pcm_surr.c @@ -36,9 +36,6 @@ #include "pcm_local.h" #include "pcm_plugin.h" -#ifndef DATADIR -#define DATADIR "/usr/share" -#endif #define ALSA_SURROUND_FILE DATADIR "/alsa/surround.conf" #define SURR_CAP_CAPTURE (1<<0) diff --git a/src/rawmidi/rawmidi.c b/src/rawmidi/rawmidi.c index 90c0fc90..5603176e 100644 --- a/src/rawmidi/rawmidi.c +++ b/src/rawmidi/rawmidi.c @@ -60,54 +60,25 @@ static int snd_rawmidi_params_default(snd_rawmidi_t *rawmidi, snd_rawmidi_params return 0; } -/** - * \brief Opens a new connection to the RawMidi interface. - * \param inputp Returned input handle (NULL if not wanted) - * \param outputp Returned output handle (NULL if not wanted) - * \param name ASCII identifier of the RawMidi handle - * \param mode Open mode - * \return 0 on success otherwise a negative error code - * - * Opens a new connection to the RawMidi interface specified with - * an ASCII identifier and mode. - */ -int snd_rawmidi_open(snd_rawmidi_t **inputp, snd_rawmidi_t **outputp, - const char *name, int mode) +int snd_rawmidi_open_conf(snd_rawmidi_t **inputp, snd_rawmidi_t **outputp, + const char *name, snd_config_t *rawmidi_conf, + int mode) { const char *str; char buf[256]; int err; - snd_config_t *rawmidi_conf, *conf, *type_conf; + snd_config_t *conf, *type_conf; snd_config_iterator_t i, next; snd_rawmidi_params_t params; const char *lib = NULL, *open_name = NULL; int (*open_func)(snd_rawmidi_t **, snd_rawmidi_t **, const char *, snd_config_t *, int); void *h; - const char *name1; - assert((inputp || outputp) && name); - err = snd_config_update(); - if (err < 0) - return err; - err = snd_config_search_alias(snd_config, "rawmidi", name, &rawmidi_conf); - name1 = name; - if (err < 0 || snd_config_get_string(rawmidi_conf, &name1) >= 0) { - int card, dev, subdev; - err = sscanf(name1, "hw:%d,%d,%d", &card, &dev, &subdev); - if (err == 3) { - err = snd_rawmidi_hw_open(inputp, outputp, name, card, dev, subdev, mode); - goto _init; - } - err = sscanf(name1, "hw:%d,%d", &card, &dev); - if (err == 2) { - err = snd_rawmidi_hw_open(inputp, outputp, name, card, dev, -1, mode); - goto _init; - } - SNDERR("Unknown RAWMIDI %s", name1); - return -ENOENT; - } if (snd_config_get_type(rawmidi_conf) != SND_CONFIG_TYPE_COMPOUND) { - SNDERR("Invalid type for RAWMIDI %s definition", name); + if (name) + SNDERR("Invalid type for RAWMIDI %s definition", name); + else + SNDERR("Invalid type for RAWMIDI definition"); return -EINVAL; } err = snd_config_search(rawmidi_conf, "type", &conf); @@ -122,6 +93,10 @@ int snd_rawmidi_open(snd_rawmidi_t **inputp, snd_rawmidi_t **outputp, } err = snd_config_search_alias(snd_config, "rawmidi_type", str, &type_conf); if (err >= 0) { + if (snd_config_get_type(type_conf) != SND_CONFIG_TYPE_COMPOUND) { + SNDERR("Invalid type for RAWMIDI type %s definition", str); + return -EINVAL; + } snd_config_for_each(i, next, type_conf) { snd_config_t *n = snd_config_iterator_entry(i); const char *id = snd_config_get_id(n); @@ -165,7 +140,6 @@ int snd_rawmidi_open(snd_rawmidi_t **inputp, snd_rawmidi_t **outputp, return -ENXIO; } err = open_func(inputp, outputp, name, rawmidi_conf, mode); - _init: if (err < 0) return err; if (inputp) { @@ -181,6 +155,58 @@ int snd_rawmidi_open(snd_rawmidi_t **inputp, snd_rawmidi_t **outputp, return 0; } +int snd_rawmidi_open_noupdate(snd_rawmidi_t **inputp, snd_rawmidi_t **outputp, + const char *name, int mode) +{ + int err; + snd_config_t *rawmidi_conf; + const char *args = strchr(name, ':'); + char *base; + if (args) { + args++; + base = alloca(args - name); + memcpy(base, name, args - name - 1); + base[args - name - 1] = 0; + } else + base = (char *) name; + err = snd_config_search_alias(snd_config, "rawmidi", base, &rawmidi_conf); + if (err < 0) { + SNDERR("Unknown RAWMIDI %s", name); + return err; + } + if (args) { + err = snd_config_expand(rawmidi_conf, args, &rawmidi_conf); + if (err < 0) + return err; + } + err = snd_rawmidi_open_conf(inputp, outputp, name, rawmidi_conf, mode); + if (args) + snd_config_delete(rawmidi_conf); + return err; +} + +/** + * \brief Opens a new connection to the RawMidi interface. + * \param inputp Returned input handle (NULL if not wanted) + * \param outputp Returned output handle (NULL if not wanted) + * \param name ASCII identifier of the RawMidi handle + * \param mode Open mode + * \return 0 on success otherwise a negative error code + * + * Opens a new connection to the RawMidi interface specified with + * an ASCII identifier and mode. + */ +int snd_rawmidi_open(snd_rawmidi_t **inputp, snd_rawmidi_t **outputp, + const char *name, int mode) +{ + int err; + assert((inputp || outputp) && name); + err = snd_config_update(); + if (err < 0) + return err; + return snd_rawmidi_open_noupdate(inputp, outputp, name, mode); +} + /** * \brief close RawMidi handle * \param rawmidi RawMidi handle diff --git a/src/seq/seq.c b/src/seq/seq.c index 8203f536..8de8449f 100644 --- a/src/seq/seq.c +++ b/src/seq/seq.c @@ -36,33 +36,24 @@ snd_seq_type_t snd_seq_type(snd_seq_t *seq) return seq->type; } -int snd_seq_open(snd_seq_t **seqp, const char *name, - int streams, int mode) +static int snd_seq_open_conf(snd_seq_t **seqp, const char *name, + snd_config_t *seq_conf, + int streams, int mode) { const char *str; char buf[256]; int err; - snd_config_t *seq_conf, *conf, *type_conf; + snd_config_t *conf, *type_conf = NULL; snd_config_iterator_t i, next; const char *lib = NULL, *open_name = NULL; int (*open_func)(snd_seq_t **, const char *, snd_config_t *, int, int); void *h; - const char *name1; - assert(seqp && name); - err = snd_config_update(); - if (err < 0) - return err; - err = snd_config_search_alias(snd_config, "seq", name, &seq_conf); - name1 = name; - if (err < 0 || snd_config_get_string(seq_conf, &name1) >= 0) { - if (strcmp(name1, "hw") == 0) - return snd_seq_hw_open(seqp, name, streams, mode); - SNDERR("Unknown SEQ %s", name1); - return -ENOENT; - } if (snd_config_get_type(seq_conf) != SND_CONFIG_TYPE_COMPOUND) { - SNDERR("Invalid type for SEQ %s definition", name); + if (name) + SNDERR("Invalid type for SEQ %s definition", name); + else + SNDERR("Invalid type for SEQ definition"); return -EINVAL; } err = snd_config_search(seq_conf, "type", &conf); @@ -77,6 +68,10 @@ int snd_seq_open(snd_seq_t **seqp, const char *name, } err = snd_config_search_alias(snd_config, "seq_type", str, &type_conf); if (err >= 0) { + if (snd_config_get_type(type_conf) != SND_CONFIG_TYPE_COMPOUND) { + SNDERR("Invalid type for SEQ type %s definition", str); + return -EINVAL; + } snd_config_for_each(i, next, type_conf) { snd_config_t *n = snd_config_iterator_entry(i); const char *id = snd_config_get_id(n); @@ -122,6 +117,47 @@ int snd_seq_open(snd_seq_t **seqp, const char *name, return open_func(seqp, name, seq_conf, streams, mode); } +static int snd_seq_open_noupdate(snd_seq_t **seqp, const char *name, + int streams, int mode) +{ + int err; + snd_config_t *seq_conf; + const char *args = strchr(name, ':'); + char *base; + if (args) { + args++; + base = alloca(args - name); + memcpy(base, name, args - name - 1); + base[args - name - 1] = 0; + } else + base = (char *) name; + err = snd_config_search_alias(snd_config, "seq", base, &seq_conf); + if (err < 0) { + SNDERR("Unknown SEQ %s", name); + return err; + } + if (args) { + err = snd_config_expand(seq_conf, args, &seq_conf); + if (err < 0) + return err; + } + err = snd_seq_open_conf(seqp, name, seq_conf, streams, mode); + if (args) + snd_config_delete(seq_conf); + return err; +} + +int snd_seq_open(snd_seq_t **seqp, const char *name, + int streams, int mode) +{ + int err; + assert(seqp && name); + err = snd_config_update(); + if (err < 0) + return err; + return snd_seq_open_noupdate(seqp, name, streams, mode); +} + /* * release sequencer client */ -- 2.47.1