mirror of
https://github.com/alsa-project/alsa-lib.git
synced 2025-10-31 22:25:35 -04:00
Completed parametric configuration and begun to use it
This commit is contained in:
parent
ecfec483a8
commit
f5534c46ed
12 changed files with 617 additions and 256 deletions
|
|
@ -22,7 +22,7 @@ const char *snd_strerror(int errnum);
|
||||||
* \param fmt printf(3) format
|
* \param fmt printf(3) format
|
||||||
* \param ... printf(3) arguments
|
* \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 snd_lib_error_handler_t *snd_lib_error;
|
||||||
extern int snd_lib_error_set_handler(snd_lib_error_handler_t *handler);
|
extern int snd_lib_error_set_handler(snd_lib_error_handler_t *handler);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,10 @@
|
||||||
#ifndef __LOCAL_H
|
#ifndef __LOCAL_H
|
||||||
#define __LOCAL_H
|
#define __LOCAL_H
|
||||||
|
|
||||||
|
#ifndef DATADIR
|
||||||
|
#define DATADIR "/usr/share"
|
||||||
|
#endif
|
||||||
|
|
||||||
#define _snd_config_iterator list_head
|
#define _snd_config_iterator list_head
|
||||||
#define _snd_interval sndrv_interval
|
#define _snd_interval sndrv_interval
|
||||||
#define _snd_pcm_info sndrv_pcm_info
|
#define _snd_pcm_info sndrv_pcm_info
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,11 @@ libasound_la_LIBADD = control/libcontrol.la mixer/libmixer.la pcm/libpcm.la \
|
||||||
|
|
||||||
libasound_la_LDFLAGS = -version-info $(COMPATNUM)
|
libasound_la_LDFLAGS = -version-info $(COMPATNUM)
|
||||||
|
|
||||||
|
EXTRA_DIST = alsa.conf
|
||||||
|
|
||||||
|
alsadir = $(datadir)/alsa
|
||||||
|
alsa_DATA = alsa.conf
|
||||||
|
|
||||||
control/libcontrol.la:
|
control/libcontrol.la:
|
||||||
$(MAKE) -C control libcontrol.la
|
$(MAKE) -C control libcontrol.la
|
||||||
|
|
||||||
|
|
|
||||||
199
src/alsa.conf
Normal file
199
src/alsa.conf
Normal file
|
|
@ -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
|
||||||
|
}
|
||||||
256
src/conf.c
256
src/conf.c
|
|
@ -20,6 +20,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
#include <wordexp.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include "local.h"
|
#include "local.h"
|
||||||
#include "list.h"
|
#include "list.h"
|
||||||
|
|
@ -1194,17 +1195,29 @@ int snd_config_search_alias(snd_config_t *config,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** File used for system wide ALSA configuration */
|
/** Environment variable containing files list for #snd_config_update */
|
||||||
#define SYS_ASOUNDRC "/etc/asound.conf"
|
#define ASOUND_CONFIGS_VAR "ASOUND_CONFIGS"
|
||||||
/** File resident in home directory used for user specific ALSA configuration */
|
|
||||||
#define USR_ASOUNDRC ".asoundrc"
|
/** Default files used by #snd_config_update */
|
||||||
|
#define ASOUND_CONFIGS_DEFAULT DATADIR "/alsa/alsa.conf:/etc/asound.conf:~/.asoundrc"
|
||||||
|
|
||||||
/** \ingroup Config
|
/** \ingroup Config
|
||||||
* Config top node */
|
* Config top node */
|
||||||
snd_config_t *snd_config = NULL;
|
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
|
* \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
|
* 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()
|
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;
|
int err;
|
||||||
char *usr_asoundrc = NULL;
|
char *configs, *c;
|
||||||
char *home = getenv("HOME");
|
unsigned int k;
|
||||||
struct stat usr_st, sys_st;
|
wordexp_t we;
|
||||||
int reload;
|
size_t l;
|
||||||
snd_input_t *in;
|
struct finfo *fi;
|
||||||
if (home) {
|
unsigned int fi_count;
|
||||||
size_t len = strlen(home);
|
configs = getenv(ASOUND_CONFIGS_VAR);
|
||||||
size_t len1 = strlen(USR_ASOUNDRC);
|
if (!configs)
|
||||||
usr_asoundrc = alloca(len + len1 + 2);
|
configs = ASOUND_CONFIGS_DEFAULT;
|
||||||
memcpy(usr_asoundrc, home, len);
|
for (k = 0, c = configs; (l = strcspn(c, ": ")) > 0; ) {
|
||||||
usr_asoundrc[len] = '/';
|
c += l;
|
||||||
memcpy(usr_asoundrc + len + 1, USR_ASOUNDRC, len1);
|
k++;
|
||||||
usr_asoundrc[len + 1 + len1] = '\0';
|
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) {
|
if (snd_config) {
|
||||||
err = snd_config_delete(snd_config);
|
snd_config_delete(snd_config);
|
||||||
if (err < 0)
|
snd_config = NULL;
|
||||||
return err;
|
|
||||||
snd_config = 0;
|
|
||||||
}
|
}
|
||||||
err = snd_config_top(&snd_config);
|
err = snd_config_top(&snd_config);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
goto _end;
|
||||||
err = snd_input_stdio_open(&in, SYS_ASOUNDRC, "r");
|
for (k = 0; k < fi_count; ++k) {
|
||||||
if (err >= 0) {
|
snd_input_t *in;
|
||||||
err = snd_config_load(snd_config, in);
|
err = snd_input_stdio_open(&in, fi[k].name, "r");
|
||||||
snd_input_close(in);
|
if (err >= 0) {
|
||||||
if (err < 0) {
|
err = snd_config_load(snd_config, in);
|
||||||
SNDERR(SYS_ASOUNDRC " may be old or corrupted: consider to remove or fix it");
|
snd_input_close(in);
|
||||||
snd_config_delete(snd_config);
|
if (err < 0) {
|
||||||
snd_config = NULL;
|
SNDERR("%s may be old or corrupted: consider to remove or fix it", fi[k].name);
|
||||||
return err;
|
goto _end;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
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;
|
|
||||||
}
|
|
||||||
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;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Return an iterator pointing to first leaf of a compound config node
|
* \brief Return an iterator pointing to first leaf of a compound config node
|
||||||
* \param node Config node handle
|
* \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)
|
static int parse_args(snd_config_t *subs, const char *str, snd_config_t *defs)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
int arg = 0;
|
int arg = 0;
|
||||||
|
skip_blank(&str);
|
||||||
if (!*str)
|
if (!*str)
|
||||||
return 0;
|
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) {
|
while (1) {
|
||||||
char buf[256];
|
char buf[256];
|
||||||
const char *var = buf;
|
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) {
|
if (err < 0) {
|
||||||
_invalid_type:
|
_invalid_type:
|
||||||
SNDERR("Parameter %s definition is missing a valid type info", var);
|
SNDERR("Parameter %s definition is missing a valid type info", var);
|
||||||
err = -EINVAL;
|
|
||||||
goto _err;
|
goto _err;
|
||||||
}
|
}
|
||||||
err = snd_config_get_string(typ, &tmp);
|
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);
|
err = snd_config_set_string(sub, val);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto _err;
|
goto _err;
|
||||||
} else
|
} else {
|
||||||
|
err = -EINVAL;
|
||||||
goto _invalid_type;
|
goto _invalid_type;
|
||||||
|
}
|
||||||
err = snd_config_set_id(sub, var);
|
err = snd_config_set_id(sub, var);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto _err;
|
goto _err;
|
||||||
|
|
@ -1906,3 +2004,21 @@ int snd_config_expand(snd_config_t *config, const char *args,
|
||||||
return 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
|
||||||
|
|
|
||||||
|
|
@ -28,9 +28,6 @@
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#include "control_local.h"
|
#include "control_local.h"
|
||||||
|
|
||||||
#ifndef DATADIR
|
|
||||||
#define DATADIR "/usr/share"
|
|
||||||
#endif
|
|
||||||
#define ALSA_CARDS_FILE DATADIR "/alsa/cards.conf"
|
#define ALSA_CARDS_FILE DATADIR "/alsa/cards.conf"
|
||||||
|
|
||||||
static int build_config(snd_config_t **r_conf)
|
static int build_config(snd_config_t **r_conf)
|
||||||
|
|
|
||||||
|
|
@ -380,57 +380,38 @@ int snd_ctl_wait(snd_ctl_t *ctl, int timeout)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
int snd_ctl_open_conf(snd_ctl_t **ctlp, const char *name,
|
||||||
* \brief Opens a CTL
|
snd_config_t *ctl_conf, int mode)
|
||||||
* \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)
|
|
||||||
{
|
{
|
||||||
const char *str;
|
const char *str;
|
||||||
char buf[256];
|
char buf[256];
|
||||||
int err;
|
int err;
|
||||||
snd_config_t *ctl_conf, *conf, *type_conf;
|
snd_config_t *conf, *type_conf = NULL;
|
||||||
snd_config_iterator_t i, next;
|
snd_config_iterator_t i, next;
|
||||||
const char *lib = NULL, *open_name = NULL;
|
const char *lib = NULL, *open_name = NULL;
|
||||||
int (*open_func)(snd_ctl_t **, const char *, snd_config_t *, int);
|
int (*open_func)(snd_ctl_t **, const char *, snd_config_t *, int);
|
||||||
void *h;
|
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) {
|
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;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
err = snd_config_search(ctl_conf, "type", &conf);
|
err = snd_config_search(ctl_conf, "type", &conf);
|
||||||
if (err < 0)
|
if (err < 0) {
|
||||||
|
SNDERR("type is not defined");
|
||||||
return err;
|
return err;
|
||||||
|
}
|
||||||
err = snd_config_get_string(conf, &str);
|
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;
|
return err;
|
||||||
|
}
|
||||||
err = snd_config_search_alias(snd_config, "ctl_type", str, &type_conf);
|
err = snd_config_search_alias(snd_config, "ctl_type", str, &type_conf);
|
||||||
if (err >= 0) {
|
if (err >= 0) {
|
||||||
if (snd_config_get_type(type_conf) != SND_CONFIG_TYPE_COMPOUND) {
|
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;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
snd_config_for_each(i, next, type_conf) {
|
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;
|
continue;
|
||||||
if (strcmp(id, "lib") == 0) {
|
if (strcmp(id, "lib") == 0) {
|
||||||
err = snd_config_get_string(n, &lib);
|
err = snd_config_get_string(n, &lib);
|
||||||
if (err < 0)
|
if (err < 0) {
|
||||||
|
SNDERR("Invalid type for %s", id);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (strcmp(id, "open") == 0) {
|
if (strcmp(id, "open") == 0) {
|
||||||
err = snd_config_get_string(n, &open_name);
|
err = snd_config_get_string(n, &open_name);
|
||||||
if (err < 0)
|
if (err < 0) {
|
||||||
|
SNDERR("Invalid type for %s", id);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
SNDERR("Unknown field %s", id);
|
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);
|
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
|
* \brief Set CTL element #SND_CTL_ELEM_TYPE_BYTES value
|
||||||
* \param ctl CTL handle
|
* \param ctl CTL handle
|
||||||
|
|
|
||||||
|
|
@ -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;
|
snd_config_iterator_t i, next;
|
||||||
const char *server = NULL;
|
const char *server = NULL;
|
||||||
const char *sname = NULL;
|
const char *ctl_name = NULL;
|
||||||
snd_config_t *sconfig;
|
snd_config_t *sconfig;
|
||||||
const char *host = NULL;
|
const char *host = NULL;
|
||||||
const char *sockname = 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;
|
continue;
|
||||||
}
|
}
|
||||||
if (strcmp(id, "sname") == 0) {
|
if (strcmp(id, "ctl") == 0) {
|
||||||
err = snd_config_get_string(n, &sname);
|
err = snd_config_get_string(n, &ctl_name);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
SNDERR("Invalid type for %s", id);
|
SNDERR("Invalid type for %s", id);
|
||||||
return -EINVAL;
|
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);
|
SNDERR("Unknown field %s", id);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
if (!sname) {
|
if (!ctl_name) {
|
||||||
SNDERR("sname is not defined");
|
SNDERR("ctl is not defined");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
if (!server) {
|
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);
|
SNDERR("%s is not the local host", host);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
return snd_ctl_shm_open(handlep, name, sockname, sname, mode);
|
return snd_ctl_shm_open(handlep, name, sockname, ctl_name, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
116
src/pcm/pcm.c
116
src/pcm/pcm.c
|
|
@ -995,92 +995,31 @@ static int snd_pcm_open_noupdate(snd_pcm_t **pcmp, const char *name,
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
snd_config_t *pcm_conf;
|
snd_config_t *pcm_conf;
|
||||||
const char *name1;
|
const char *args = strchr(name, ':');
|
||||||
|
char *base;
|
||||||
err = snd_config_search_alias(snd_config, "pcm", name, &pcm_conf);
|
if (args) {
|
||||||
name1 = name;
|
args++;
|
||||||
if (err < 0 || snd_config_get_string(pcm_conf, &name1) >= 0) {
|
base = alloca(args - name);
|
||||||
int card, dev, subdev;
|
memcpy(base, name, args - name - 1);
|
||||||
char socket[256], sname[256];
|
base[args - name - 1] = 0;
|
||||||
char format[16], file[256];
|
} else
|
||||||
err = sscanf(name1, "hw:%d,%d,%d", &card, &dev, &subdev);
|
base = (char *) name;
|
||||||
if (err == 3)
|
err = snd_config_search_alias(snd_config, "pcm", base, &pcm_conf);
|
||||||
return snd_pcm_hw_open(pcmp, name, card, dev, subdev, stream, mode);
|
if (err < 0) {
|
||||||
err = sscanf(name1, "hw:%d,%d", &card, &dev);
|
SNDERR("Unknown PCM %s", name);
|
||||||
if (err == 2)
|
return err;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
return snd_pcm_open_conf(pcmp, name, pcm_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;
|
||||||
}
|
}
|
||||||
|
|
||||||
#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 Opens a PCM
|
* \brief Opens a PCM
|
||||||
* \param pcmp Returned PCM handle
|
* \param pcmp Returned PCM handle
|
||||||
|
|
@ -1100,6 +1039,17 @@ int snd_pcm_open(snd_pcm_t **pcmp, const char *name,
|
||||||
return snd_pcm_open_noupdate(pcmp, name, stream, mode);
|
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
|
* \brief Wait for a PCM to become ready
|
||||||
* \param pcm PCM handle
|
* \param pcm PCM handle
|
||||||
|
|
|
||||||
|
|
@ -36,9 +36,6 @@
|
||||||
#include "pcm_local.h"
|
#include "pcm_local.h"
|
||||||
#include "pcm_plugin.h"
|
#include "pcm_plugin.h"
|
||||||
|
|
||||||
#ifndef DATADIR
|
|
||||||
#define DATADIR "/usr/share"
|
|
||||||
#endif
|
|
||||||
#define ALSA_SURROUND_FILE DATADIR "/alsa/surround.conf"
|
#define ALSA_SURROUND_FILE DATADIR "/alsa/surround.conf"
|
||||||
|
|
||||||
#define SURR_CAP_CAPTURE (1<<0)
|
#define SURR_CAP_CAPTURE (1<<0)
|
||||||
|
|
|
||||||
|
|
@ -60,54 +60,25 @@ static int snd_rawmidi_params_default(snd_rawmidi_t *rawmidi, snd_rawmidi_params
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
int snd_rawmidi_open_conf(snd_rawmidi_t **inputp, snd_rawmidi_t **outputp,
|
||||||
* \brief Opens a new connection to the RawMidi interface.
|
const char *name, snd_config_t *rawmidi_conf,
|
||||||
* \param inputp Returned input handle (NULL if not wanted)
|
int mode)
|
||||||
* \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)
|
|
||||||
{
|
{
|
||||||
const char *str;
|
const char *str;
|
||||||
char buf[256];
|
char buf[256];
|
||||||
int err;
|
int err;
|
||||||
snd_config_t *rawmidi_conf, *conf, *type_conf;
|
snd_config_t *conf, *type_conf;
|
||||||
snd_config_iterator_t i, next;
|
snd_config_iterator_t i, next;
|
||||||
snd_rawmidi_params_t params;
|
snd_rawmidi_params_t params;
|
||||||
const char *lib = NULL, *open_name = NULL;
|
const char *lib = NULL, *open_name = NULL;
|
||||||
int (*open_func)(snd_rawmidi_t **, snd_rawmidi_t **,
|
int (*open_func)(snd_rawmidi_t **, snd_rawmidi_t **,
|
||||||
const char *, snd_config_t *, int);
|
const char *, snd_config_t *, int);
|
||||||
void *h;
|
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) {
|
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;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
err = snd_config_search(rawmidi_conf, "type", &conf);
|
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);
|
err = snd_config_search_alias(snd_config, "rawmidi_type", str, &type_conf);
|
||||||
if (err >= 0) {
|
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_for_each(i, next, type_conf) {
|
||||||
snd_config_t *n = snd_config_iterator_entry(i);
|
snd_config_t *n = snd_config_iterator_entry(i);
|
||||||
const char *id = snd_config_get_id(n);
|
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;
|
return -ENXIO;
|
||||||
}
|
}
|
||||||
err = open_func(inputp, outputp, name, rawmidi_conf, mode);
|
err = open_func(inputp, outputp, name, rawmidi_conf, mode);
|
||||||
_init:
|
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
if (inputp) {
|
if (inputp) {
|
||||||
|
|
@ -181,6 +155,58 @@ int snd_rawmidi_open(snd_rawmidi_t **inputp, snd_rawmidi_t **outputp,
|
||||||
return 0;
|
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
|
* \brief close RawMidi handle
|
||||||
* \param rawmidi RawMidi handle
|
* \param rawmidi RawMidi handle
|
||||||
|
|
|
||||||
|
|
@ -36,33 +36,24 @@ snd_seq_type_t snd_seq_type(snd_seq_t *seq)
|
||||||
return seq->type;
|
return seq->type;
|
||||||
}
|
}
|
||||||
|
|
||||||
int snd_seq_open(snd_seq_t **seqp, const char *name,
|
static int snd_seq_open_conf(snd_seq_t **seqp, const char *name,
|
||||||
int streams, int mode)
|
snd_config_t *seq_conf,
|
||||||
|
int streams, int mode)
|
||||||
{
|
{
|
||||||
const char *str;
|
const char *str;
|
||||||
char buf[256];
|
char buf[256];
|
||||||
int err;
|
int err;
|
||||||
snd_config_t *seq_conf, *conf, *type_conf;
|
snd_config_t *conf, *type_conf = NULL;
|
||||||
snd_config_iterator_t i, next;
|
snd_config_iterator_t i, next;
|
||||||
const char *lib = NULL, *open_name = NULL;
|
const char *lib = NULL, *open_name = NULL;
|
||||||
int (*open_func)(snd_seq_t **, const char *, snd_config_t *,
|
int (*open_func)(snd_seq_t **, const char *, snd_config_t *,
|
||||||
int, int);
|
int, int);
|
||||||
void *h;
|
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) {
|
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;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
err = snd_config_search(seq_conf, "type", &conf);
|
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);
|
err = snd_config_search_alias(snd_config, "seq_type", str, &type_conf);
|
||||||
if (err >= 0) {
|
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_for_each(i, next, type_conf) {
|
||||||
snd_config_t *n = snd_config_iterator_entry(i);
|
snd_config_t *n = snd_config_iterator_entry(i);
|
||||||
const char *id = snd_config_get_id(n);
|
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);
|
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
|
* release sequencer client
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue