mirror of
https://github.com/alsa-project/alsa-lib.git
synced 2025-10-28 05:40:23 -04:00
Added snd_config_load_override().
Fixed problem with EOF detection in freestring parser. Fixed problem with run-time argument parsing (snd_config_load()->snd_config_load_override() replace). Added more documentation for configuration run-time arguments and hooks. Fixed the behaviour of snd_config_search_definition() - implicit and explicit base.
This commit is contained in:
parent
b642a7c11e
commit
d10bcbf76d
6 changed files with 146 additions and 34 deletions
1
TODO
1
TODO
|
|
@ -1,4 +1,3 @@
|
||||||
H make snd_config_update thread safe
|
|
||||||
H add serious PCM test application to test various period/buffer size
|
H add serious PCM test application to test various period/buffer size
|
||||||
combinations to determine possible problems in the lowlevel drivers
|
combinations to determine possible problems in the lowlevel drivers
|
||||||
M think about xrun recovery helpers
|
M think about xrun recovery helpers
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@ may be placed in the library code instead of the kernel driver.</P>
|
||||||
<LI>Page \ref conf explains the syntax of library configuration files.
|
<LI>Page \ref conf explains the syntax of library configuration files.
|
||||||
<LI>Page \ref confarg explains the run-time argument syntax.
|
<LI>Page \ref confarg explains the run-time argument syntax.
|
||||||
<LI>Page \ref conffunc explains the run-time function definition and usage.
|
<LI>Page \ref conffunc explains the run-time function definition and usage.
|
||||||
|
<LI>Page \ref confhooks explains the run-time hooks definition and usage.
|
||||||
</UL>
|
</UL>
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -69,6 +69,7 @@ extern snd_config_t *snd_config;
|
||||||
int snd_config_top(snd_config_t **config);
|
int snd_config_top(snd_config_t **config);
|
||||||
|
|
||||||
int snd_config_load(snd_config_t *config, snd_input_t *in);
|
int snd_config_load(snd_config_t *config, snd_input_t *in);
|
||||||
|
int snd_config_load_override(snd_config_t *config, snd_input_t *in);
|
||||||
int snd_config_save(snd_config_t *config, snd_output_t *out);
|
int snd_config_save(snd_config_t *config, snd_output_t *out);
|
||||||
int snd_config_update(void);
|
int snd_config_update(void);
|
||||||
int snd_config_update_r(snd_config_t **top, snd_config_update_t **update, const char *path);
|
int snd_config_update_r(snd_config_t **top, snd_config_update_t **update, const char *path);
|
||||||
|
|
|
||||||
|
|
@ -405,8 +405,8 @@ typedef struct snd_seq_result {
|
||||||
|
|
||||||
/** Queue skew values */
|
/** Queue skew values */
|
||||||
typedef struct snd_seq_queue_skew {
|
typedef struct snd_seq_queue_skew {
|
||||||
unsigned int value;
|
unsigned int value; /**< skew value */
|
||||||
unsigned int base;
|
unsigned int base; /**< skew base */
|
||||||
} snd_seq_queue_skew_t;
|
} snd_seq_queue_skew_t;
|
||||||
|
|
||||||
/** queue timer control */
|
/** queue timer control */
|
||||||
|
|
|
||||||
171
src/conf.c
171
src/conf.c
|
|
@ -219,6 +219,29 @@ a.0 "first"
|
||||||
a.1 "second"
|
a.1 "second"
|
||||||
\endcode
|
\endcode
|
||||||
|
|
||||||
|
\section conf_mode Parsed node operation mode
|
||||||
|
|
||||||
|
By default, the node operation node is 'merge+create'. It means, if
|
||||||
|
a configuration node is not present a new one is created, otherwise
|
||||||
|
the latest assignment is merged (if possible - type checking). The
|
||||||
|
'merge+create' operation mode is specified with a prefix char plus (+).
|
||||||
|
|
||||||
|
The operation mode 'merge' merges the node with old one (which must
|
||||||
|
exists). Type checking is done, so string cannot be assigned to integer
|
||||||
|
and so on. This mode is specified with a prefix char minus (-).
|
||||||
|
|
||||||
|
The operation mode 'do not override' ignores a new configuration node
|
||||||
|
if a configuration node with same name exists. This mode is specified with
|
||||||
|
a prefix char note of interrogation (?).
|
||||||
|
|
||||||
|
The operation mode 'override' always overrides the old configuration node
|
||||||
|
with new contents. This mode is specified with a prefix char note of
|
||||||
|
exclamation (!).
|
||||||
|
|
||||||
|
\code
|
||||||
|
!defaults.pcm.device 1
|
||||||
|
\endcode
|
||||||
|
|
||||||
\section conf_syntax_summary Syntax summary
|
\section conf_syntax_summary Syntax summary
|
||||||
|
|
||||||
\code
|
\code
|
||||||
|
|
@ -251,7 +274,11 @@ name.0 [=] value0 [,|;]
|
||||||
name.1 [=] value1 [,|;]
|
name.1 [=] value1 [,|;]
|
||||||
\endcode
|
\endcode
|
||||||
|
|
||||||
|
\section conf_syntax_ref References
|
||||||
|
|
||||||
|
\ref confarg
|
||||||
|
\ref conffunc
|
||||||
|
\ref confhooks
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
@ -291,6 +318,23 @@ Arguments are refered by dollar-sign ($) and name of argument:
|
||||||
card $CARD
|
card $CARD
|
||||||
\endcode
|
\endcode
|
||||||
|
|
||||||
|
\section confarg_usage Usage
|
||||||
|
|
||||||
|
Arguments are replaced with real values when the key contains part after
|
||||||
|
colon (:). For example, all these names for PCM interface gives same result:
|
||||||
|
|
||||||
|
\code
|
||||||
|
hw:0,1
|
||||||
|
hw:CARD=0,DEV=1
|
||||||
|
hw:{CARD 0 DEV 1}
|
||||||
|
plug:"hw:0,1"
|
||||||
|
plug:{SLAVE="hw:{CARD 0 DEV 1}"}
|
||||||
|
\endcode
|
||||||
|
|
||||||
|
As you see, the argument can be specified by order or by name. Note that
|
||||||
|
arguments closed into braces are parsed in same way like configuration files,
|
||||||
|
but with the override method by default.
|
||||||
|
|
||||||
\section confarg_example Example
|
\section confarg_example Example
|
||||||
|
|
||||||
\code
|
\code
|
||||||
|
|
@ -333,6 +377,40 @@ func.remove_first_char {
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*! \page confhooks Configuration - hooks
|
||||||
|
|
||||||
|
<P>The hook extension in the ALSA library allows expanding of configuration
|
||||||
|
nodes at run-time lookup. The presence of a hook is determined with a @hooks
|
||||||
|
compound node.</P>
|
||||||
|
|
||||||
|
<P>The example definition a hook which loads two configuration files at beginning:</P>
|
||||||
|
|
||||||
|
\code
|
||||||
|
@hooks [
|
||||||
|
{
|
||||||
|
func load
|
||||||
|
files [
|
||||||
|
"/etc/asound.conf"
|
||||||
|
"~/.asoundrc"
|
||||||
|
]
|
||||||
|
errors false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
\endcode
|
||||||
|
|
||||||
|
\section confhooks_ref Function reference
|
||||||
|
|
||||||
|
<UL>
|
||||||
|
<LI>The function load - snd_config_hook_load() - loads and parses the given
|
||||||
|
configuration files.
|
||||||
|
<LI>The function load_for_all_cards - snd_config_hook_load_for_all_cards() -
|
||||||
|
loads and parses the given configuration files for all installed soundcards.
|
||||||
|
The driver name (type of soundcard) is passed in the private configuration
|
||||||
|
node.
|
||||||
|
</UL>
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <wordexp.h>
|
#include <wordexp.h>
|
||||||
|
|
@ -500,8 +578,8 @@ static int get_char_skip_comments(input_t *input)
|
||||||
break;
|
break;
|
||||||
while (1) {
|
while (1) {
|
||||||
c = get_char(input);
|
c = get_char(input);
|
||||||
if (c == EOF)
|
if (c < 0)
|
||||||
return LOCAL_UNEXPECTED_EOF;
|
return c;
|
||||||
if (c == '\n')
|
if (c == '\n')
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -577,7 +655,16 @@ static int get_freestring(char **string, int id, input_t *input)
|
||||||
while (1) {
|
while (1) {
|
||||||
c = get_char(input);
|
c = get_char(input);
|
||||||
if (c < 0) {
|
if (c < 0) {
|
||||||
if (buf != _buf)
|
if (c == LOCAL_UNEXPECTED_EOF) {
|
||||||
|
char *s = malloc(idx + 1);
|
||||||
|
if (!s)
|
||||||
|
return -ENOMEM;
|
||||||
|
memcpy(s, buf, idx);
|
||||||
|
s[idx] = '\0';
|
||||||
|
*string = s;
|
||||||
|
c = 0;
|
||||||
|
}
|
||||||
|
if (alloc > bufsize)
|
||||||
free(buf);
|
free(buf);
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
@ -852,10 +939,10 @@ static int parse_value(snd_config_t **_n, snd_config_t *father, input_t *input,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int parse_defs(snd_config_t *father, input_t *input, int skip);
|
static int parse_defs(snd_config_t *father, input_t *input, int skip, int override);
|
||||||
static int parse_array_defs(snd_config_t *farther, input_t *input, int skip);
|
static int parse_array_defs(snd_config_t *farther, input_t *input, int skip, int override);
|
||||||
|
|
||||||
static int parse_array_def(snd_config_t *father, input_t *input, int idx, int skip)
|
static int parse_array_def(snd_config_t *father, input_t *input, int idx, int skip, int override)
|
||||||
{
|
{
|
||||||
char static_id[12], *id = NULL;
|
char static_id[12], *id = NULL;
|
||||||
int c;
|
int c;
|
||||||
|
|
@ -893,10 +980,10 @@ static int parse_array_def(snd_config_t *father, input_t *input, int idx, int sk
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (c == '{') {
|
if (c == '{') {
|
||||||
err = parse_defs(n, input, skip);
|
err = parse_defs(n, input, skip, override);
|
||||||
endchr = '}';
|
endchr = '}';
|
||||||
} else {
|
} else {
|
||||||
err = parse_array_defs(n, input, skip);
|
err = parse_array_defs(n, input, skip, override);
|
||||||
endchr = ']';
|
endchr = ']';
|
||||||
}
|
}
|
||||||
c = get_nonwhite(input);
|
c = get_nonwhite(input);
|
||||||
|
|
@ -926,7 +1013,7 @@ static int parse_array_def(snd_config_t *father, input_t *input, int idx, int sk
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int parse_array_defs(snd_config_t *father, input_t *input, int skip)
|
static int parse_array_defs(snd_config_t *father, input_t *input, int skip, int override)
|
||||||
{
|
{
|
||||||
int idx = 0;
|
int idx = 0;
|
||||||
while (1) {
|
while (1) {
|
||||||
|
|
@ -936,14 +1023,14 @@ static int parse_array_defs(snd_config_t *father, input_t *input, int skip)
|
||||||
unget_char(c, input);
|
unget_char(c, input);
|
||||||
if (c == ']')
|
if (c == ']')
|
||||||
return 0;
|
return 0;
|
||||||
err = parse_array_def(father, input, idx++, skip);
|
err = parse_array_def(father, input, idx++, skip, override);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int parse_def(snd_config_t *father, input_t *input, int skip)
|
static int parse_def(snd_config_t *father, input_t *input, int skip, int override)
|
||||||
{
|
{
|
||||||
char *id = NULL;
|
char *id = NULL;
|
||||||
int c;
|
int c;
|
||||||
|
|
@ -955,6 +1042,12 @@ static int parse_def(snd_config_t *father, input_t *input, int skip)
|
||||||
if (c < 0)
|
if (c < 0)
|
||||||
return c;
|
return c;
|
||||||
switch (c) {
|
switch (c) {
|
||||||
|
case '+':
|
||||||
|
mode = MERGE_CREATE;
|
||||||
|
break;
|
||||||
|
case '-':
|
||||||
|
mode = MERGE;
|
||||||
|
break;
|
||||||
case '?':
|
case '?':
|
||||||
mode = DONT_OVERRIDE;
|
mode = DONT_OVERRIDE;
|
||||||
break;
|
break;
|
||||||
|
|
@ -962,7 +1055,7 @@ static int parse_def(snd_config_t *father, input_t *input, int skip)
|
||||||
mode = OVERRIDE;
|
mode = OVERRIDE;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
mode = MERGE_CREATE;
|
mode = !override ? MERGE_CREATE : OVERRIDE;
|
||||||
unget_char(c, input);
|
unget_char(c, input);
|
||||||
}
|
}
|
||||||
err = get_string(&id, 1, input);
|
err = get_string(&id, 1, input);
|
||||||
|
|
@ -1046,10 +1139,10 @@ static int parse_def(snd_config_t *father, input_t *input, int skip)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (c == '{') {
|
if (c == '{') {
|
||||||
err = parse_defs(n, input, skip);
|
err = parse_defs(n, input, skip, override);
|
||||||
endchr = '}';
|
endchr = '}';
|
||||||
} else {
|
} else {
|
||||||
err = parse_array_defs(n, input, skip);
|
err = parse_array_defs(n, input, skip, override);
|
||||||
endchr = ']';
|
endchr = ']';
|
||||||
}
|
}
|
||||||
c = get_nonwhite(input);
|
c = get_nonwhite(input);
|
||||||
|
|
@ -1082,7 +1175,7 @@ static int parse_def(snd_config_t *father, input_t *input, int skip)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int parse_defs(snd_config_t *father, input_t *input, int skip)
|
static int parse_defs(snd_config_t *father, input_t *input, int skip, int override)
|
||||||
{
|
{
|
||||||
int c, err;
|
int c, err;
|
||||||
while (1) {
|
while (1) {
|
||||||
|
|
@ -1092,7 +1185,7 @@ static int parse_defs(snd_config_t *father, input_t *input, int skip)
|
||||||
unget_char(c, input);
|
unget_char(c, input);
|
||||||
if (c == '}')
|
if (c == '}')
|
||||||
return 0;
|
return 0;
|
||||||
err = parse_def(father, input, skip);
|
err = parse_def(father, input, skip, override);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
@ -1387,13 +1480,7 @@ int snd_config_top(snd_config_t **config)
|
||||||
return _snd_config_make(config, 0, SND_CONFIG_TYPE_COMPOUND);
|
return _snd_config_make(config, 0, SND_CONFIG_TYPE_COMPOUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
static int snd_config_load1(snd_config_t *config, snd_input_t *in, int override)
|
||||||
* \brief Load a config tree
|
|
||||||
* \param config Config top node handle
|
|
||||||
* \param in Input handle
|
|
||||||
* \return 0 on success otherwise a negative error code
|
|
||||||
*/
|
|
||||||
int snd_config_load(snd_config_t *config, snd_input_t *in)
|
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
input_t input;
|
input_t input;
|
||||||
|
|
@ -1409,7 +1496,7 @@ int snd_config_load(snd_config_t *config, snd_input_t *in)
|
||||||
fd->next = NULL;
|
fd->next = NULL;
|
||||||
input.current = fd;
|
input.current = fd;
|
||||||
input.unget = 0;
|
input.unget = 0;
|
||||||
err = parse_defs(config, &input, 0);
|
err = parse_defs(config, &input, 0, override);
|
||||||
fd = input.current;
|
fd = input.current;
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
const char *str;
|
const char *str;
|
||||||
|
|
@ -1450,6 +1537,28 @@ int snd_config_load(snd_config_t *config, snd_input_t *in)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Load a config tree
|
||||||
|
* \param config Config top node handle
|
||||||
|
* \param in Input handle
|
||||||
|
* \return 0 on success otherwise a negative error code
|
||||||
|
*/
|
||||||
|
int snd_config_load(snd_config_t *config, snd_input_t *in)
|
||||||
|
{
|
||||||
|
return snd_config_load1(config, in, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Load a config tree and override existing configuration nodes
|
||||||
|
* \param config Config top node handle
|
||||||
|
* \param in Input handle
|
||||||
|
* \return 0 on success otherwise a negative error code
|
||||||
|
*/
|
||||||
|
int snd_config_load_override(snd_config_t *config, snd_input_t *in)
|
||||||
|
{
|
||||||
|
return snd_config_load1(config, in, 1);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Add a leaf to a config compound node
|
* \brief Add a leaf to a config compound node
|
||||||
* \param father Config compound node handle
|
* \param father Config compound node handle
|
||||||
|
|
@ -3433,7 +3542,7 @@ static int parse_args(snd_config_t *subs, const char *str, snd_config_t *defs)
|
||||||
err = snd_input_buffer_open(&input, str + 1, len - 1);
|
err = snd_input_buffer_open(&input, str + 1, len - 1);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
err = snd_config_load(subs, input);
|
err = snd_config_load_override(subs, input);
|
||||||
snd_input_close(input);
|
snd_input_close(input);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
|
|
@ -3609,7 +3718,7 @@ int snd_config_expand(snd_config_t *config, snd_config_t *root, const char *args
|
||||||
/**
|
/**
|
||||||
* \brief Search a definition inside a config tree using alias and expand hooks and arguments
|
* \brief Search a definition inside a config tree using alias and expand hooks and arguments
|
||||||
* \param config Config node handle
|
* \param config Config node handle
|
||||||
* \param base Key base (or NULL)
|
* \param base Implicit key base (or NULL - none)
|
||||||
* \param key Key suffix
|
* \param key Key suffix
|
||||||
* \param result Pointer to expanded found node
|
* \param result Pointer to expanded found node
|
||||||
* \return 0 on success otherwise a negative error code
|
* \return 0 on success otherwise a negative error code
|
||||||
|
|
@ -3633,10 +3742,12 @@ int snd_config_search_definition(snd_config_t *config,
|
||||||
key[args - name - 1] = '\0';
|
key[args - name - 1] = '\0';
|
||||||
} else {
|
} else {
|
||||||
key = (char *) name;
|
key = (char *) name;
|
||||||
}
|
}
|
||||||
err = snd_config_search_alias_hooks(config, NULL, key, &conf);
|
/*
|
||||||
if (err < 0)
|
* if key contains dot (.), the implicit base is ignored
|
||||||
err = snd_config_search_alias_hooks(config, base, key, &conf);
|
* and the key starts from root given by the 'config' parameter
|
||||||
|
*/
|
||||||
|
err = snd_config_search_alias_hooks(config, strchr(key, '.') ? NULL : base, key, &conf);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
return snd_config_expand(conf, config, args, NULL, result);
|
return snd_config_expand(conf, config, args, NULL, result);
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@
|
||||||
|
|
||||||
/*! \page conffunc
|
/*! \page conffunc
|
||||||
|
|
||||||
\section Function reference
|
\section conffunc_ref Function reference
|
||||||
|
|
||||||
<UL>
|
<UL>
|
||||||
<LI>The getenv function - snd_func_getenv() - allows to obtain
|
<LI>The getenv function - snd_func_getenv() - allows to obtain
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue