mirror of
https://github.com/alsa-project/alsa-lib.git
synced 2025-10-31 22:25:35 -04:00
Fix infinite parse of recursive definitions
Fixed the infinite parse (and eventually segfault) of recursive definitions. Also fixed the parse of a string slave PCM of direct plugins.
This commit is contained in:
parent
bf174b7046
commit
eccc92a34d
29 changed files with 127 additions and 36 deletions
|
|
@ -249,4 +249,9 @@ void *snd_dlobj_cache_lookup(const char *name);
|
||||||
int snd_dlobj_cache_add(const char *name, void *dlobj, void *open_func);
|
int snd_dlobj_cache_add(const char *name, void *dlobj, void *open_func);
|
||||||
void snd_dlobj_cache_cleanup(void);
|
void snd_dlobj_cache_cleanup(void);
|
||||||
|
|
||||||
|
/* for recursive checks */
|
||||||
|
void snd_config_set_hop(snd_config_t *conf, int hop);
|
||||||
|
int snd_config_check_hop(snd_config_t *conf);
|
||||||
|
#define SND_CONF_MAX_HOPS 64
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
19
src/conf.c
19
src/conf.c
|
|
@ -440,6 +440,7 @@ struct _snd_config {
|
||||||
} u;
|
} u;
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
snd_config_t *father;
|
snd_config_t *father;
|
||||||
|
int hop;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct filedesc {
|
struct filedesc {
|
||||||
|
|
@ -4011,6 +4012,24 @@ int snd_config_search_definition(snd_config_t *config,
|
||||||
return snd_config_expand(conf, config, args, NULL, result);
|
return snd_config_expand(conf, config, args, NULL, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef DOC_HIDDEN
|
||||||
|
void snd_config_set_hop(snd_config_t *conf, int hop)
|
||||||
|
{
|
||||||
|
conf->hop = hop;
|
||||||
|
}
|
||||||
|
|
||||||
|
int snd_config_check_hop(snd_config_t *conf)
|
||||||
|
{
|
||||||
|
if (conf) {
|
||||||
|
if (conf->hop >= SND_CONF_MAX_HOPS) {
|
||||||
|
SYSERR("Too many definition levels (looped?)\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
return conf->hop;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
/* Not strictly needed, but useful to check for memory leaks */
|
/* Not strictly needed, but useful to check for memory leaks */
|
||||||
|
|
|
||||||
|
|
@ -2098,7 +2098,8 @@ static int snd_pcm_open_conf(snd_pcm_t **pcmp, const char *name,
|
||||||
}
|
}
|
||||||
|
|
||||||
static int snd_pcm_open_noupdate(snd_pcm_t **pcmp, snd_config_t *root,
|
static int snd_pcm_open_noupdate(snd_pcm_t **pcmp, snd_config_t *root,
|
||||||
const char *name, snd_pcm_stream_t stream, int mode)
|
const char *name, snd_pcm_stream_t stream,
|
||||||
|
int mode, int hop)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
snd_config_t *pcm_conf;
|
snd_config_t *pcm_conf;
|
||||||
|
|
@ -2107,6 +2108,7 @@ static int snd_pcm_open_noupdate(snd_pcm_t **pcmp, snd_config_t *root,
|
||||||
SNDERR("Unknown PCM %s", name);
|
SNDERR("Unknown PCM %s", name);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
snd_config_set_hop(pcm_conf, hop);
|
||||||
err = snd_pcm_open_conf(pcmp, name, root, pcm_conf, stream, mode);
|
err = snd_pcm_open_conf(pcmp, name, root, pcm_conf, stream, mode);
|
||||||
snd_config_delete(pcm_conf);
|
snd_config_delete(pcm_conf);
|
||||||
return err;
|
return err;
|
||||||
|
|
@ -2128,7 +2130,7 @@ int snd_pcm_open(snd_pcm_t **pcmp, const char *name,
|
||||||
err = snd_config_update();
|
err = snd_config_update();
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
return snd_pcm_open_noupdate(pcmp, snd_config, name, stream, mode);
|
return snd_pcm_open_noupdate(pcmp, snd_config, name, stream, mode, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -2145,7 +2147,7 @@ int snd_pcm_open_lconf(snd_pcm_t **pcmp, const char *name,
|
||||||
snd_config_t *lconf)
|
snd_config_t *lconf)
|
||||||
{
|
{
|
||||||
assert(pcmp && name && lconf);
|
assert(pcmp && name && lconf);
|
||||||
return snd_pcm_open_noupdate(pcmp, lconf, name, stream, mode);
|
return snd_pcm_open_noupdate(pcmp, lconf, name, stream, mode, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef DOC_HIDDEN
|
#ifndef DOC_HIDDEN
|
||||||
|
|
@ -2187,11 +2189,16 @@ int snd_pcm_free(snd_pcm_t *pcm)
|
||||||
|
|
||||||
int snd_pcm_open_slave(snd_pcm_t **pcmp, snd_config_t *root,
|
int snd_pcm_open_slave(snd_pcm_t **pcmp, snd_config_t *root,
|
||||||
snd_config_t *conf, snd_pcm_stream_t stream,
|
snd_config_t *conf, snd_pcm_stream_t stream,
|
||||||
int mode)
|
int mode, snd_config_t *parent_conf)
|
||||||
{
|
{
|
||||||
const char *str;
|
const char *str;
|
||||||
|
int hop;
|
||||||
|
|
||||||
|
if ((hop = snd_config_check_hop(parent_conf)) < 0)
|
||||||
|
return hop;
|
||||||
if (snd_config_get_string(conf, &str) >= 0)
|
if (snd_config_get_string(conf, &str) >= 0)
|
||||||
return snd_pcm_open_noupdate(pcmp, root, str, stream, mode);
|
return snd_pcm_open_noupdate(pcmp, root, str, stream, mode,
|
||||||
|
hop + 1);
|
||||||
return snd_pcm_open_conf(pcmp, NULL, root, conf, stream, mode);
|
return snd_pcm_open_conf(pcmp, NULL, root, conf, stream, mode);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -666,7 +666,7 @@ int _snd_pcm_adpcm_open(snd_pcm_t **pcmp, const char *name,
|
||||||
SNDERR("invalid slave format");
|
SNDERR("invalid slave format");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode);
|
err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf);
|
||||||
snd_config_delete(sconf);
|
snd_config_delete(sconf);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
|
|
|
||||||
|
|
@ -538,7 +538,7 @@ int _snd_pcm_alaw_open(snd_pcm_t **pcmp, const char *name,
|
||||||
SNDERR("invalid slave format");
|
SNDERR("invalid slave format");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode);
|
err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf);
|
||||||
snd_config_delete(sconf);
|
snd_config_delete(sconf);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
|
|
|
||||||
|
|
@ -109,7 +109,7 @@ int _snd_pcm_asym_open(snd_pcm_t **pcmp, const char *name ATTRIBUTE_UNUSED,
|
||||||
err = snd_pcm_slave_conf(root, slave, &sconf, 0);
|
err = snd_pcm_slave_conf(root, slave, &sconf, 0);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
err = snd_pcm_open_slave(pcmp, root, sconf, stream, mode);
|
err = snd_pcm_open_slave(pcmp, root, sconf, stream, mode, conf);
|
||||||
snd_config_delete(sconf);
|
snd_config_delete(sconf);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -284,7 +284,7 @@ int _snd_pcm_copy_open(snd_pcm_t **pcmp, const char *name,
|
||||||
err = snd_pcm_slave_conf(root, slave, &sconf, 0);
|
err = snd_pcm_slave_conf(root, slave, &sconf, 0);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode);
|
err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf);
|
||||||
snd_config_delete(sconf);
|
snd_config_delete(sconf);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
|
|
|
||||||
|
|
@ -1260,11 +1260,34 @@ int snd_pcm_direct_parse_bindings(snd_pcm_direct_t *dmix, snd_config_t *cfg)
|
||||||
/*
|
/*
|
||||||
* parse slave config and calculate the ipc_key offset
|
* parse slave config and calculate the ipc_key offset
|
||||||
*/
|
*/
|
||||||
int snd_pcm_direct_get_slave_ipc_offset(snd_config_t *sconf, int direction)
|
|
||||||
|
static int _snd_pcm_direct_get_slave_ipc_offset(snd_config_t *root,
|
||||||
|
snd_config_t *sconf,
|
||||||
|
int direction,
|
||||||
|
int hop)
|
||||||
{
|
{
|
||||||
snd_config_iterator_t i, next;
|
snd_config_iterator_t i, next;
|
||||||
int err;
|
int err;
|
||||||
long card = 0, device = 0, subdevice = 0;
|
long card = 0, device = 0, subdevice = 0;
|
||||||
|
const char *str;
|
||||||
|
|
||||||
|
if (snd_config_get_string(sconf, &str) >= 0) {
|
||||||
|
snd_config_t *pcm_conf;
|
||||||
|
if (hop > SND_CONF_MAX_HOPS) {
|
||||||
|
SNDERR("Too many definition levels (looped?)");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
err = snd_config_search_definition(root, "pcm", str, &pcm_conf);
|
||||||
|
if (err < 0) {
|
||||||
|
SNDERR("Unknown slave PCM %s", str);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
err = _snd_pcm_direct_get_slave_ipc_offset(root, pcm_conf,
|
||||||
|
direction,
|
||||||
|
hop + 1);
|
||||||
|
snd_config_delete(pcm_conf);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
snd_config_for_each(i, next, sconf) {
|
snd_config_for_each(i, next, sconf) {
|
||||||
snd_config_t *n = snd_config_iterator_entry(i);
|
snd_config_t *n = snd_config_iterator_entry(i);
|
||||||
|
|
@ -1325,6 +1348,12 @@ int snd_pcm_direct_get_slave_ipc_offset(snd_config_t *sconf, int direction)
|
||||||
return direction + (card << 1) + (device << 4) + (subdevice << 8);
|
return direction + (card << 1) + (device << 4) + (subdevice << 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int snd_pcm_direct_get_slave_ipc_offset(snd_config_t *root,
|
||||||
|
snd_config_t *sconf,
|
||||||
|
int direction)
|
||||||
|
{
|
||||||
|
return _snd_pcm_direct_get_slave_ipc_offset(root, sconf, direction, 0);
|
||||||
|
}
|
||||||
|
|
||||||
int snd_pcm_direct_parse_open_conf(snd_config_t *conf, struct snd_pcm_direct_open_conf *rec)
|
int snd_pcm_direct_parse_open_conf(snd_config_t *conf, struct snd_pcm_direct_open_conf *rec)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -186,7 +186,7 @@ int snd_pcm_direct_timer_stop(snd_pcm_direct_t *dmix);
|
||||||
void snd_pcm_direct_clear_timer_queue(snd_pcm_direct_t *dmix);
|
void snd_pcm_direct_clear_timer_queue(snd_pcm_direct_t *dmix);
|
||||||
int snd_pcm_direct_set_timer_params(snd_pcm_direct_t *dmix);
|
int snd_pcm_direct_set_timer_params(snd_pcm_direct_t *dmix);
|
||||||
int snd_pcm_direct_open_secondary_client(snd_pcm_t **spcmp, snd_pcm_direct_t *dmix, const char *client_name);
|
int snd_pcm_direct_open_secondary_client(snd_pcm_t **spcmp, snd_pcm_direct_t *dmix, const char *client_name);
|
||||||
int snd_pcm_direct_get_slave_ipc_offset(snd_config_t *sconf, int direction);
|
int snd_pcm_direct_get_slave_ipc_offset(snd_config_t *root, snd_config_t *sconf, int direction);
|
||||||
|
|
||||||
int snd_timer_async(snd_timer_t *timer, int sig, pid_t pid);
|
int snd_timer_async(snd_timer_t *timer, int sig, pid_t pid);
|
||||||
struct timespec snd_pcm_hw_fast_tstamp(snd_pcm_t *pcm);
|
struct timespec snd_pcm_hw_fast_tstamp(snd_pcm_t *pcm);
|
||||||
|
|
|
||||||
|
|
@ -847,7 +847,10 @@ int snd_pcm_dmix_open(snd_pcm_t **pcmp, const char *name,
|
||||||
dmix->sync_ptr = snd_pcm_dmix_sync_ptr;
|
dmix->sync_ptr = snd_pcm_dmix_sync_ptr;
|
||||||
|
|
||||||
if (first_instance) {
|
if (first_instance) {
|
||||||
ret = snd_pcm_open_slave(&spcm, root, sconf, stream, mode | SND_PCM_NONBLOCK);
|
/* recursion is already checked in
|
||||||
|
snd_pcm_direct_get_slave_ipc_offset() */
|
||||||
|
ret = snd_pcm_open_slave(&spcm, root, sconf, stream,
|
||||||
|
mode | SND_PCM_NONBLOCK, NULL);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
SNDERR("unable to open slave");
|
SNDERR("unable to open slave");
|
||||||
goto _err;
|
goto _err;
|
||||||
|
|
@ -1124,7 +1127,7 @@ int _snd_pcm_dmix_open(snd_pcm_t **pcmp, const char *name,
|
||||||
params.period_size = psize;
|
params.period_size = psize;
|
||||||
params.buffer_size = bsize;
|
params.buffer_size = bsize;
|
||||||
|
|
||||||
ipc_offset = snd_pcm_direct_get_slave_ipc_offset(sconf, stream);
|
ipc_offset = snd_pcm_direct_get_slave_ipc_offset(root, sconf, stream);
|
||||||
if (ipc_offset < 0) {
|
if (ipc_offset < 0) {
|
||||||
snd_config_delete(sconf);
|
snd_config_delete(sconf);
|
||||||
return ipc_offset;
|
return ipc_offset;
|
||||||
|
|
|
||||||
|
|
@ -672,7 +672,10 @@ int snd_pcm_dshare_open(snd_pcm_t **pcmp, const char *name,
|
||||||
dshare->sync_ptr = snd_pcm_dshare_sync_ptr;
|
dshare->sync_ptr = snd_pcm_dshare_sync_ptr;
|
||||||
|
|
||||||
if (first_instance) {
|
if (first_instance) {
|
||||||
ret = snd_pcm_open_slave(&spcm, root, sconf, stream, mode | SND_PCM_NONBLOCK);
|
/* recursion is already checked in
|
||||||
|
snd_pcm_direct_get_slave_ipc_offset() */
|
||||||
|
ret = snd_pcm_open_slave(&spcm, root, sconf, stream,
|
||||||
|
mode | SND_PCM_NONBLOCK, NULL);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
SNDERR("unable to open slave");
|
SNDERR("unable to open slave");
|
||||||
goto _err;
|
goto _err;
|
||||||
|
|
@ -873,7 +876,7 @@ int _snd_pcm_dshare_open(snd_pcm_t **pcmp, const char *name,
|
||||||
params.period_size = psize;
|
params.period_size = psize;
|
||||||
params.buffer_size = bsize;
|
params.buffer_size = bsize;
|
||||||
|
|
||||||
ipc_offset = snd_pcm_direct_get_slave_ipc_offset(sconf, stream);
|
ipc_offset = snd_pcm_direct_get_slave_ipc_offset(root, sconf, stream);
|
||||||
if (ipc_offset < 0) {
|
if (ipc_offset < 0) {
|
||||||
snd_config_delete(sconf);
|
snd_config_delete(sconf);
|
||||||
return ipc_offset;
|
return ipc_offset;
|
||||||
|
|
|
||||||
|
|
@ -554,7 +554,10 @@ int snd_pcm_dsnoop_open(snd_pcm_t **pcmp, const char *name,
|
||||||
dsnoop->sync_ptr = snd_pcm_dsnoop_sync_ptr;
|
dsnoop->sync_ptr = snd_pcm_dsnoop_sync_ptr;
|
||||||
|
|
||||||
if (first_instance) {
|
if (first_instance) {
|
||||||
ret = snd_pcm_open_slave(&spcm, root, sconf, stream, mode | SND_PCM_NONBLOCK);
|
/* recursion is already checked in
|
||||||
|
snd_pcm_direct_get_slave_ipc_offset() */
|
||||||
|
ret = snd_pcm_open_slave(&spcm, root, sconf, stream,
|
||||||
|
mode | SND_PCM_NONBLOCK, NULL);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
SNDERR("unable to open slave");
|
SNDERR("unable to open slave");
|
||||||
goto _err;
|
goto _err;
|
||||||
|
|
@ -745,7 +748,7 @@ int _snd_pcm_dsnoop_open(snd_pcm_t **pcmp, const char *name,
|
||||||
params.period_size = psize;
|
params.period_size = psize;
|
||||||
params.buffer_size = bsize;
|
params.buffer_size = bsize;
|
||||||
|
|
||||||
ipc_offset = snd_pcm_direct_get_slave_ipc_offset(sconf, stream);
|
ipc_offset = snd_pcm_direct_get_slave_ipc_offset(root, sconf, stream);
|
||||||
if (ipc_offset < 0) {
|
if (ipc_offset < 0) {
|
||||||
snd_config_delete(sconf);
|
snd_config_delete(sconf);
|
||||||
return ipc_offset;
|
return ipc_offset;
|
||||||
|
|
|
||||||
|
|
@ -622,7 +622,7 @@ int snd_pcm_extplug_create(snd_pcm_extplug_t *extplug, const char *name,
|
||||||
err = snd_pcm_slave_conf(root, slave_conf, &sconf, 0);
|
err = snd_pcm_slave_conf(root, slave_conf, &sconf, 0);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode);
|
err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, NULL);
|
||||||
snd_config_delete(sconf);
|
snd_config_delete(sconf);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
|
|
|
||||||
|
|
@ -556,7 +556,7 @@ int _snd_pcm_file_open(snd_pcm_t **pcmp, const char *name,
|
||||||
SNDERR("file is not defined");
|
SNDERR("file is not defined");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode);
|
err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf);
|
||||||
snd_config_delete(sconf);
|
snd_config_delete(sconf);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
|
|
|
||||||
|
|
@ -460,7 +460,7 @@ int _snd_pcm_hooks_open(snd_pcm_t **pcmp, const char *name,
|
||||||
err = snd_pcm_slave_conf(root, slave, &sconf, 0);
|
err = snd_pcm_slave_conf(root, slave, &sconf, 0);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode);
|
err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf);
|
||||||
snd_config_delete(sconf);
|
snd_config_delete(sconf);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
|
|
|
||||||
|
|
@ -662,7 +662,7 @@ int _snd_pcm_iec958_open(snd_pcm_t **pcmp, const char *name,
|
||||||
SNDERR("invalid slave format");
|
SNDERR("invalid slave format");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode);
|
err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf);
|
||||||
snd_config_delete(sconf);
|
snd_config_delete(sconf);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
|
|
|
||||||
|
|
@ -1782,7 +1782,7 @@ int _snd_pcm_ladspa_open(snd_pcm_t **pcmp, const char *name,
|
||||||
err = snd_pcm_slave_conf(root, slave, &sconf, 0);
|
err = snd_pcm_slave_conf(root, slave, &sconf, 0);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode);
|
err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf);
|
||||||
snd_config_delete(sconf);
|
snd_config_delete(sconf);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
|
|
|
||||||
|
|
@ -497,7 +497,7 @@ int _snd_pcm_lfloat_open(snd_pcm_t **pcmp, const char *name,
|
||||||
SNDERR("slave format is not linear integer or linear float");
|
SNDERR("slave format is not linear integer or linear float");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode);
|
err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf);
|
||||||
snd_config_delete(sconf);
|
snd_config_delete(sconf);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
|
|
|
||||||
|
|
@ -552,7 +552,7 @@ int _snd_pcm_linear_open(snd_pcm_t **pcmp, const char *name,
|
||||||
SNDERR("slave format is not linear");
|
SNDERR("slave format is not linear");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode);
|
err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf);
|
||||||
snd_config_delete(sconf);
|
snd_config_delete(sconf);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
|
|
|
||||||
|
|
@ -748,7 +748,7 @@ int snd_pcm_slave_conf(snd_config_t *root, snd_config_t *conf,
|
||||||
|
|
||||||
int snd_pcm_open_slave(snd_pcm_t **pcmp, snd_config_t *root,
|
int snd_pcm_open_slave(snd_pcm_t **pcmp, snd_config_t *root,
|
||||||
snd_config_t *conf, snd_pcm_stream_t stream,
|
snd_config_t *conf, snd_pcm_stream_t stream,
|
||||||
int mode);
|
int mode, snd_config_t *parent_conf);
|
||||||
int snd_pcm_conf_generic_id(const char *id);
|
int snd_pcm_conf_generic_id(const char *id);
|
||||||
|
|
||||||
int snd_pcm_hw_open_fd(snd_pcm_t **pcmp, const char *name, int fd, int mmap_emulation, int sync_ptr_ioctl);
|
int snd_pcm_hw_open_fd(snd_pcm_t **pcmp, const char *name, int fd, int mmap_emulation, int sync_ptr_ioctl);
|
||||||
|
|
|
||||||
|
|
@ -779,7 +779,7 @@ int _snd_pcm_meter_open(snd_pcm_t **pcmp, const char *name,
|
||||||
err = snd_pcm_slave_conf(root, slave, &sconf, 0);
|
err = snd_pcm_slave_conf(root, slave, &sconf, 0);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode);
|
err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf);
|
||||||
snd_config_delete(sconf);
|
snd_config_delete(sconf);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
|
|
|
||||||
|
|
@ -553,7 +553,7 @@ int _snd_pcm_mulaw_open(snd_pcm_t **pcmp, const char *name,
|
||||||
SNDERR("invalid slave format");
|
SNDERR("invalid slave format");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode);
|
err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf);
|
||||||
snd_config_delete(sconf);
|
snd_config_delete(sconf);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
|
|
|
||||||
|
|
@ -1103,7 +1103,9 @@ int _snd_pcm_multi_open(snd_pcm_t **pcmp, const char *name,
|
||||||
}
|
}
|
||||||
|
|
||||||
for (idx = 0; idx < slaves_count; ++idx) {
|
for (idx = 0; idx < slaves_count; ++idx) {
|
||||||
err = snd_pcm_open_slave(&slaves_pcm[idx], root, slaves_conf[idx], stream, mode);
|
err = snd_pcm_open_slave(&slaves_pcm[idx], root,
|
||||||
|
slaves_conf[idx], stream, mode,
|
||||||
|
conf);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto _free;
|
goto _free;
|
||||||
snd_config_delete(slaves_conf[idx]);
|
snd_config_delete(slaves_conf[idx]);
|
||||||
|
|
|
||||||
|
|
@ -1215,7 +1215,7 @@ int _snd_pcm_plug_open(snd_pcm_t **pcmp, const char *name,
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode);
|
err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf);
|
||||||
snd_config_delete(sconf);
|
snd_config_delete(sconf);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
|
|
|
||||||
|
|
@ -1532,7 +1532,7 @@ int _snd_pcm_rate_open(snd_pcm_t **pcmp, const char *name,
|
||||||
SNDERR("slave format is not linear");
|
SNDERR("slave format is not linear");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode);
|
err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf);
|
||||||
snd_config_delete(sconf);
|
snd_config_delete(sconf);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
|
|
|
||||||
|
|
@ -1152,7 +1152,7 @@ int _snd_pcm_route_open(snd_pcm_t **pcmp, const char *name,
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode);
|
err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf);
|
||||||
snd_config_delete(sconf);
|
snd_config_delete(sconf);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
free(ttable);
|
free(ttable);
|
||||||
|
|
|
||||||
|
|
@ -814,7 +814,7 @@ int _snd_pcm_softvol_open(snd_pcm_t **pcmp, const char *name,
|
||||||
snd_config_delete(sconf);
|
snd_config_delete(sconf);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode);
|
err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf);
|
||||||
snd_config_delete(sconf);
|
snd_config_delete(sconf);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
|
|
|
||||||
|
|
@ -53,6 +53,10 @@ typedef struct {
|
||||||
snd_seq_event_t out_event;
|
snd_seq_event_t out_event;
|
||||||
int pending;
|
int pending;
|
||||||
} snd_rawmidi_virtual_t;
|
} snd_rawmidi_virtual_t;
|
||||||
|
|
||||||
|
int _snd_seq_open_lconf(snd_seq_t **seqp, const char *name,
|
||||||
|
int streams, int mode, snd_config_t *lconf,
|
||||||
|
snd_config_t *parent_conf);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int snd_rawmidi_virtual_close(snd_rawmidi_t *rmidi)
|
static int snd_rawmidi_virtual_close(snd_rawmidi_t *rmidi)
|
||||||
|
|
@ -439,7 +443,8 @@ int _snd_rawmidi_virtual_open(snd_rawmidi_t **inputp, snd_rawmidi_t **outputp,
|
||||||
|
|
||||||
if (! slave_str)
|
if (! slave_str)
|
||||||
slave_str = "default";
|
slave_str = "default";
|
||||||
err = snd_seq_open_lconf(&seq_handle, slave_str, streams, seq_mode, root);
|
err = _snd_seq_open_lconf(&seq_handle, slave_str, streams, seq_mode,
|
||||||
|
root, conf);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -919,7 +919,8 @@ static int snd_seq_open_conf(snd_seq_t **seqp, const char *name,
|
||||||
}
|
}
|
||||||
|
|
||||||
static int snd_seq_open_noupdate(snd_seq_t **seqp, snd_config_t *root,
|
static int snd_seq_open_noupdate(snd_seq_t **seqp, snd_config_t *root,
|
||||||
const char *name, int streams, int mode)
|
const char *name, int streams, int mode,
|
||||||
|
int hop)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
snd_config_t *seq_conf;
|
snd_config_t *seq_conf;
|
||||||
|
|
@ -928,6 +929,7 @@ static int snd_seq_open_noupdate(snd_seq_t **seqp, snd_config_t *root,
|
||||||
SNDERR("Unknown SEQ %s", name);
|
SNDERR("Unknown SEQ %s", name);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
snd_config_set_hop(seq_conf, hop);
|
||||||
err = snd_seq_open_conf(seqp, name, root, seq_conf, streams, mode);
|
err = snd_seq_open_conf(seqp, name, root, seq_conf, streams, mode);
|
||||||
snd_config_delete(seq_conf);
|
snd_config_delete(seq_conf);
|
||||||
return err;
|
return err;
|
||||||
|
|
@ -971,7 +973,7 @@ int snd_seq_open(snd_seq_t **seqp, const char *name,
|
||||||
err = snd_config_update();
|
err = snd_config_update();
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
return snd_seq_open_noupdate(seqp, snd_config, name, streams, mode);
|
return snd_seq_open_noupdate(seqp, snd_config, name, streams, mode, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -993,9 +995,22 @@ int snd_seq_open_lconf(snd_seq_t **seqp, const char *name,
|
||||||
int streams, int mode, snd_config_t *lconf)
|
int streams, int mode, snd_config_t *lconf)
|
||||||
{
|
{
|
||||||
assert(seqp && name && lconf);
|
assert(seqp && name && lconf);
|
||||||
return snd_seq_open_noupdate(seqp, lconf, name, streams, mode);
|
return snd_seq_open_noupdate(seqp, lconf, name, streams, mode, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef DOC_HIDDEN
|
||||||
|
int _snd_seq_open_lconf(snd_seq_t **seqp, const char *name,
|
||||||
|
int streams, int mode, snd_config_t *lconf,
|
||||||
|
snd_config_t *parent_conf)
|
||||||
|
{
|
||||||
|
int hop;
|
||||||
|
assert(seqp && name && lconf);
|
||||||
|
if ((hop = snd_config_check_hop(parent_conf)) < 0)
|
||||||
|
return hop;
|
||||||
|
return snd_seq_open_noupdate(seqp, lconf, name, streams, mode, hop + 1);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Close the sequencer
|
* \brief Close the sequencer
|
||||||
* \param seq Handle returned from #snd_seq_open()
|
* \param seq Handle returned from #snd_seq_open()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue