* \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);
#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
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
--- /dev/null
+
+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
+}
*/
#include <stdarg.h>
+#include <wordexp.h>
#include <sys/stat.h>
#include "local.h"
#include "list.h"
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
*/
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
}
+/* 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;
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);
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;
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
#include <sys/ioctl.h>
#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)
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) {
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);
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
{
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;
}
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;
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) {
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);
}
{
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
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
#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)
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);
}
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);
return -ENXIO;
}
err = open_func(inputp, outputp, name, rawmidi_conf, mode);
- _init:
if (err < 0)
return err;
if (inputp) {
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
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);
}
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);
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
*/