Added back modified snd_config_refer_load function.
Added snd_func_private_pcm_subdevice function.
Removed the callback from the snd_sctl_build function (no more required).
Modified alsa.conf to use refer {} blocks again.
Modified card specific conf files to use new snd_func_private_pcm_subdevice function.
typedef int (snd_config_string_replace_callback_t)(const char *what, char **dst, void *private_data);
-int snd_config_string_replace(const char *src, char idchr,
- snd_config_string_replace_callback_t *callback,
- void *private_data,
- char **dst);
+int snd_config_refer_load(snd_config_t **dst, char **name,
+ snd_config_t *root, snd_config_t *config);
#ifdef __cplusplus
}
int snd_card_type_enum_to_string(snd_card_type_t enumid, char **strid);
int snd_sctl_build(snd_sctl_t **ctl, snd_ctl_t *handle, snd_config_t *config,
- snd_config_string_replace_callback_t *callback,
void *private_data, int mode);
int snd_sctl_free(snd_sctl_t *handle);
int snd_sctl_install(snd_sctl_t *handle);
default 0
}
}
- @func refer
- file {
- @func concat
- strings [
- {
- @func datadir
- }
- "/cards/"
- {
- @func card_strtype
- card $CARD
- }
- ".conf"
- ]
- }
- name {
- @func concat
- strings [
- "pcm.front_" $DEV ":CARD=" $CARD
- ]
+ refer {
+ file {
+ @func concat
+ strings [
+ {
+ @func datadir
+ }
+ "/cards/"
+ {
+ @func card_strtype
+ card $CARD
+ }
+ ".conf"
+ ]
+ }
+ name {
+ @func concat
+ strings [
+ "pcm.front_" $DEV ":CARD=" $CARD
+ ]
+ }
}
}
default 0
}
}
- @func refer
- file {
- @func concat
- strings [
- {
- @func datadir
- }
- "/cards/"
- {
- @func card_strtype
- card $CARD
- }
- ".conf"
- ]
- }
- name {
- @func concat
- strings [
- "pcm.rear_" $DEV ":CARD=" $CARD
- ]
+ refer {
+ file {
+ @func concat
+ strings [
+ {
+ @func datadir
+ }
+ "/cards/"
+ {
+ @func card_strtype
+ card $CARD
+ }
+ ".conf"
+ ]
+ }
+ name {
+ @func concat
+ strings [
+ "pcm.rear_" $DEV ":CARD=" $CARD
+ ]
+ }
}
}
default 0
}
}
- @func refer
- file {
- @func concat
- strings [
- {
- @func datadir
- }
- "/cards/"
- {
- @func card_strtype
- card $CARD
- }
- ".conf"
- ]
- }
- name {
- @func concat
- strings [
- "pcm.center_lfe_" $DEV ":CARD=" $CARD
- ]
+ refer {
+ file {
+ @func concat
+ strings [
+ {
+ @func datadir
+ }
+ "/cards/"
+ {
+ @func card_strtype
+ card $CARD
+ }
+ ".conf"
+ ]
+ }
+ name {
+ @func concat
+ strings [
+ "pcm.center_lfe_" $DEV ":CARD=" $CARD
+ ]
+ }
}
}
default 0
}
}
- @func refer
- file {
- @func concat
- strings [
- {
- @func datadir
- }
- "/cards/"
- {
- @func card_strtype
- card $CARD
- }
- ".conf"
- ]
- }
- name {
- @func concat
- strings [
- "pcm.surround40_" $DEV ":CARD=" $CARD
- ]
+ refer {
+ file {
+ @func concat
+ strings [
+ {
+ @func datadir
+ }
+ "/cards/"
+ {
+ @func card_strtype
+ card $CARD
+ }
+ ".conf"
+ ]
+ }
+ name {
+ @func concat
+ strings [
+ "pcm.surround40_" $DEV ":CARD=" $CARD
+ ]
+ }
}
}
default 0
}
}
- @func refer
- file {
- @func concat
- strings [
- {
- @func datadir
- }
- "/cards/"
- {
- @func card_strtype
- card $CARD
- }
- ".conf"
- ]
- }
- name {
- @func concat
- strings [
- "pcm.surround51_" $DEV ":CARD=" $CARD
- ]
+ refer {
+ file {
+ @func concat
+ strings [
+ {
+ @func datadir
+ }
+ "/cards/"
+ {
+ @func card_strtype
+ card $CARD
+ }
+ ".conf"
+ ]
+ }
+ name {
+ @func concat
+ strings [
+ "pcm.surround51_" $DEV ":CARD=" $CARD
+ ]
+ }
}
}
# fs=48000Hz, clock accuracy=1000ppm
default 0x02
}
- @func refer
- file {
- @func concat
- strings [
- {
- @func datadir
- }
- "/cards/"
- {
- @func card_strtype
- card $CARD
- }
- ".conf"
- ]
- }
- name {
- @func concat
- strings [
- "pcm.iec958_" $DEV ":"
- "CARD=" $CARD ","
- "AES0=" $AES0 ","
- "AES1=" $AES1 ","
- "AES2=" $AES2 ","
- "AES3=" $AES3
- ]
+ refer {
+ file {
+ @func concat
+ strings [
+ {
+ @func datadir
+ }
+ "/cards/"
+ {
+ @func card_strtype
+ card $CARD
+ }
+ ".conf"
+ ]
+ }
+ name {
+ @func concat
+ strings [
+ "pcm.iec958_" $DEV ":"
+ "CARD=" $CARD ","
+ "AES0=" $AES0 ","
+ "AES1=" $AES1 ","
+ "AES2=" $AES2 ","
+ "AES3=" $AES3
+ ]
+ }
}
}
}
{
name "EMU10K1 PCM Send Volume"
- index = &(subdevice)
+ index { @func private_pcm_subdevice }
lock true
value [ 0 0 0 0 0 0 255 0 0 0 0 255 ]
}
}
{
name "EMU10K1 PCM Send Volume"
- index = &(subdevice)
+ index { @func private_pcm_subdevice }
lock true
value [ 0 0 0 0 255 0 0 0 0 255 0 0 ]
}
{
name "EMU10K1 PCM Send Routing"
- index = &(subdevice)
+ index { @func private_pcm_subdevice }
lock true
value [ 0 1 2 3 6 7 0 1 6 7 0 1 ]
}
name "PCM Playback Volume"
preserve true
lock true
+ index { @func private_pcm_subdevice }
value [ 24 24 ]
}
]
hook_args [
{
name "Rear Path"
- index &(subdevice)
+ index { @func private_pcm_subdevice }
lock true
preserve true
value true
}
{
name "PCM Front Playback Volume"
- index &(subdevice)
+ index { @func private_pcm_subdevice }
lock true
preserve true
value [ 0 0 ]
}
{
name "PCM Reverb Playback Volume"
- index &(subdevice)
+ index { @func private_pcm_subdevice }
lock true
preserve true
value [ 127 127 ]
}
/**
- * \brief Expand the dynamic contents
- * \param src Source string
- * \param idchr Identification character
- * \param callback Callback function
- * \param private_data Private data for the given callback function
- * \param dst Destination string
+ * \brief Refer the configuration block to another
+ * \param dst new configuration block (if *dst != root -> dst needs to be deleted)
+ * \param name the identifier of new configuration block
+ * \param root the root of all configurations
+ * \param config redirect configuration
*/
-int snd_config_string_replace(const char *src, char idchr,
- snd_config_string_replace_callback_t *callback,
- void *private_data,
- char **dst)
+int snd_config_refer_load(snd_config_t **dst,
+ char **name,
+ snd_config_t *root,
+ snd_config_t *config)
{
- int len = 0, len1, err;
- const char *ptr, *end;
- char *tmp, *what, *fptr, *rdst = NULL;
+ int err;
+ snd_config_t *result, *c;
+ char *rname;
- assert(src && idchr && dst);
- while (*src != '\0') {
- ptr = strchr(src, idchr);
- end = NULL;
- if (ptr == src && *(ptr + 1) == '(' && (end = strchr(ptr + 2, ')')) != NULL) {
- src = end + 1;
- if (callback == NULL)
- continue;
- len1 = end - (ptr + 2);
- if (len1 == 0) /* empty */
- continue;
- what = malloc(len1 + 1);
- memcpy(what, ptr + 2, len1);
- what[len1] = '\0';
- fptr = NULL;
- err = callback(what, &fptr, private_data);
- free(what);
- if (err < 0) {
- if (*dst != NULL)
- free(*dst);
- return err;
- }
- if (fptr == NULL) /* empty */
- continue;
- len1 = strlen(ptr = fptr);
+ assert(dst);
+ assert(name);
+ assert(root);
+ assert(config);
+ if (snd_config_get_type(config) == SND_CONFIG_TYPE_STRING) {
+ const char *str;
+ snd_config_get_string(config, &str);
+ *name = strdup(str);
+ if (*name == NULL)
+ return -ENOMEM;
+ *dst = root;
+ return 0;
+ }
+ if (snd_config_get_type(config) != SND_CONFIG_TYPE_COMPOUND)
+ return -EINVAL;
+ result = root;
+ rname = NULL;
+ if (snd_config_search(config, "file", &c) >= 0) {
+ snd_config_t *rconfig;
+ const char *filename;
+ snd_input_t *input;
+ err = snd_config_copy(&rconfig, root);
+ if (err < 0)
+ return err;
+ if (snd_config_get_type(c) == SND_CONFIG_TYPE_STRING) {
+ snd_config_get_string(c, &filename);
} else {
- if (ptr == NULL) {
- len1 = strlen(ptr = src);
- } else {
- len1 = ptr - src;
- ptr = src;
- }
- src += len1;
- fptr = NULL;
+ err = -EINVAL;
+ __filename_error:
+ snd_config_delete(rconfig);
+ return err;
}
- tmp = realloc(rdst, len + len1 + 1);
- if (tmp == NULL) {
- if (*dst != NULL)
- free(*dst);
- return -ENOMEM;
+ err = snd_input_stdio_open(&input, filename, "r");
+ if (err < 0) {
+ SNDERR("Unable to open filename %s: %s", filename, snd_strerror(err));
+ goto __filename_error;
+ }
+ err = snd_config_load(rconfig, input);
+ if (err < 0) {
+ snd_input_close(input);
+ goto __filename_error;
}
- memcpy(tmp + len, ptr, len1);
- tmp[len+=len1] = '\0';
- if (fptr)
- free(fptr);
- rdst = tmp;
+ snd_input_close(input);
+ result = rconfig;
}
- *dst = rdst;
+ if (snd_config_search(config, "name", &c) >= 0) {
+ const char *ptr;
+ if ((err = snd_config_get_string(c, &ptr)) < 0)
+ goto __error;
+ rname = strdup(ptr);
+ if (rname == NULL) {
+ err = -ENOMEM;
+ goto __error;
+ }
+ }
+ if (rname == NULL) {
+ err = -EINVAL;
+ goto __error;
+ }
+ *dst = result;
+ *name = rname;
return 0;
+ __error:
+ if (rname)
+ free(rname);
+ if (result != root)
+ snd_config_delete(result);
+ return err;
}
/*
}
-
int snd_func_concat(snd_config_t **dst, snd_config_t *root, snd_config_t *src, void *private_data)
{
snd_config_t *n;
int snd_func_pcm_id(snd_config_t **dst, snd_config_t *root, snd_config_t *src, void *private_data)
{
snd_config_t *n;
- char *res = NULL;
snd_ctl_t *ctl = NULL;
snd_pcm_info_t *info;
long card, device, subdevice = 0;
SNDERR("snd_ctl_pcm_info error: %s", snd_strerror(err));
goto __error;
}
- res = strdup(snd_pcm_info_get_id(info));
- if (res == NULL) {
- err = -ENOMEM;
- goto __error;
- }
err = snd_config_make_string(dst, snd_config_get_id(src));
if (err >= 0)
- err = snd_config_set_string(*dst, res);
- free(res);
+ err = snd_config_set_string(*dst, snd_pcm_info_get_id(info));
__error:
if (ctl)
snd_ctl_close(ctl);
return err;
}
+int snd_func_private_pcm_subdevice(snd_config_t **dst, snd_config_t *root ATTRIBUTE_UNUSED, snd_config_t *src, void *private_data)
+{
+ char *res = NULL;
+ snd_pcm_info_t *info;
+ int err;
+
+ if (private_data == NULL)
+ return snd_config_copy(dst, src);
+ snd_pcm_info_alloca(&info);
+ err = snd_pcm_info((snd_pcm_t *)private_data, info);
+ if (err < 0) {
+ SNDERR("snd_ctl_pcm_info error: %s", snd_strerror(err));
+ return err;
+ }
+ res = strdup(snd_pcm_info_get_id(info));
+ if (res == NULL)
+ return -ENOMEM;
+ err = snd_config_make_integer(dst, snd_config_get_id(src));
+ if (err >= 0)
+ err = snd_config_set_integer(*dst, snd_pcm_info_get_subdevice(info));
+ free(res);
+ return err;
+}
+
int snd_func_refer(snd_config_t **dst, snd_config_t *_root, snd_config_t *src, void *private_data)
{
snd_config_t *n;
return 0;
}
-static int config_replace(snd_config_t *conf,
- snd_config_string_replace_callback_t *callback,
- void *private_data, char **res)
-{
- int err;
- char *replace, *tmp;
-
- err = snd_config_get_ascii(conf, &tmp);
- if (err < 0)
- return err;
- err = snd_config_string_replace(tmp, '&', callback, private_data, &replace);
- free(tmp);
- if (err < 0)
- return err;
- if (replace == NULL) {
- SNDERR("Invalid value for '%s'", snd_config_get_id(conf));
- return err;
- }
- *res = replace;
- return 0;
-}
-
-static int config_replace_integer(snd_config_t *conf,
- snd_config_string_replace_callback_t *callback,
- void *private_data, long *res)
-{
- char *tmp;
- int err;
-
- err = config_replace(conf, callback, private_data, &tmp);
- if (err < 0)
- return err;
- err = safe_strtol(tmp, res);
- if (err < 0) {
- SNDERR("Invalid value for '%s'", snd_config_get_id(conf));
- return err;
- }
- return 0;
-}
-
-static int config_replace_bool(snd_config_t *conf,
- snd_config_string_replace_callback_t *callback,
- void *private_data, int *res)
-{
- char *tmp;
- int err;
-
- err = config_replace(conf, callback, private_data, &tmp);
- if (err < 0)
- return err;
- err = snd_config_get_bool_ascii(tmp);
- free(tmp);
- if (err < 0) {
- SNDERR("Invalid value for '%s'", snd_config_get_id(conf));
- return err;
- }
- *res = err;
- return 0;
-}
-
-static int add_elem(snd_sctl_t *h, snd_config_t *conf,
- snd_config_string_replace_callback_t *callback,
- void *private_data)
+static int add_elem(snd_sctl_t *h, snd_config_t *_conf, void *private_data)
{
+ snd_config_t *conf;
snd_config_iterator_t i, next;
char *tmp;
int iface = SND_CTL_ELEM_IFACE_MIXER;
- char *name = NULL;
+ const char *name = NULL;
long index = 0;
long device = -1;
long subdevice = -1;
snd_config_t *value = NULL, *mask = NULL;
snd_sctl_elem_t *elem = NULL;
int err;
+ err = snd_config_expand(_conf, _conf, NULL, private_data, &conf);
+ if (err < 0)
+ return err;
snd_config_for_each(i, next, conf) {
snd_config_t *n = snd_config_iterator_entry(i);
const char *id = snd_config_get_id(n);
if (strcmp(id, "comment") == 0)
continue;
if (strcmp(id, "iface") == 0 || strcmp(id, "interface") == 0) {
- if ((err = config_replace(n, callback, private_data, &tmp)) < 0)
+ const char *ptr;
+ if ((err = snd_config_get_string(n, &ptr)) < 0) {
+ SNDERR("field %s is not a string", id);
goto _err;
- if ((err = snd_config_get_ctl_iface_ascii(tmp)) < 0) {
+ }
+ if ((err = snd_config_get_ctl_iface_ascii(ptr)) < 0) {
SNDERR("Invalid value for '%s'", id);
free(tmp);
goto _err;
}
iface = err;
- free(tmp);
continue;
}
if (strcmp(id, "name") == 0) {
- if ((err = config_replace(n, callback, private_data, &name)) < 0)
+ if ((err = snd_config_get_string(n, &name)) < 0) {
+ SNDERR("field %s is not a string", id);
goto _err;
+ }
continue;
}
if (strcmp(id, "index") == 0) {
- if ((err = config_replace_integer(n, callback, private_data, &index)) < 0)
+ if ((err = snd_config_get_integer(n, &index)) < 0) {
+ SNDERR("field %s is not an integer", id);
goto _err;
+ }
continue;
}
if (strcmp(id, "device") == 0) {
- if ((err = config_replace_integer(n, callback, private_data, &device)) < 0)
+ if ((err = snd_config_get_integer(n, &device)) < 0) {
+ SNDERR("field %s is not an integer", id);
goto _err;
+ }
continue;
}
if (strcmp(id, "subdevice") == 0) {
- if ((err = config_replace_integer(n, callback, private_data, &subdevice)) < 0)
+ if ((err = snd_config_get_integer(n, &subdevice)) < 0) {
+ SNDERR("field %s is not an integer", id);
goto _err;
+ }
+ continue;
}
if (strcmp(id, "lock") == 0) {
- if ((err = config_replace_bool(n, callback, private_data, &lock)) < 0)
+ if ((err = snd_config_get_ascii(n, &tmp)) < 0) {
+ SNDERR("field %s has an invalid type", id);
+ goto _err;
+ }
+ err = snd_config_get_bool_ascii(tmp);
+ if (err < 0) {
+ SNDERR("field %s is not a boolean", id);
goto _err;
+ }
+ lock = err;
continue;
}
if (strcmp(id, "preserve") == 0) {
- if ((err = config_replace_bool(n, callback, private_data, &preserve)) < 0)
+ if ((err = snd_config_get_ascii(n, &tmp)) < 0) {
+ SNDERR("field %s has an invalid type", id);
+ goto _err;
+ }
+ err = snd_config_get_bool_ascii(tmp);
+ if (err < 0) {
+ SNDERR("field %s is not a boolean", id);
goto _err;
+ }
+ preserve = err;
continue;
}
if (strcmp(id, "value") == 0) {
if (err < 0)
goto _err;
list_add_tail(&elem->list, &h->elems);
- return 0;
_err:
- if (name)
- free(name);
- if (elem) {
+ if (err < 0 && elem) {
if (elem->id)
snd_ctl_elem_id_free(elem->id);
if (elem->info)
snd_ctl_elem_value_free(elem->old);
free(elem);
}
+ if (conf)
+ snd_config_delete(conf);
return err;
}
-int snd_sctl_build(snd_sctl_t **sctl, snd_ctl_t *handle, snd_config_t *conf,
- snd_config_string_replace_callback_t *callback,
- void *private_data,
- int mode)
+int snd_sctl_build(snd_sctl_t **sctl, snd_ctl_t *handle, snd_config_t *conf, void *private_data, int mode)
{
snd_sctl_t *h;
snd_config_iterator_t i, next;
INIT_LIST_HEAD(&h->elems);
snd_config_for_each(i, next, conf) {
snd_config_t *n = snd_config_iterator_entry(i);
- err = add_elem(h, n, callback, private_data);
+ err = add_elem(h, n, private_data);
if (err < 0) {
free_elems(h);
return err;
const char *name, snd_pcm_stream_t stream, int mode)
{
int err;
- snd_config_t *pcm_conf;
+ snd_config_t *pcm_conf, *n;
err = snd_config_search_definition(root, "pcm", name, &pcm_conf);
if (err < 0) {
SNDERR("Unknown PCM %s", name);
return err;
}
+ if (snd_config_search(pcm_conf, "refer", &n) >= 0) {
+ snd_config_t *refer;
+ char *new_name;
+ err = snd_config_refer_load(&refer, &new_name, root, n);
+ if (err < 0) {
+ SNDERR("Unable to load refered block in PCM %s: %s", name, snd_strerror(err));
+ return err;
+ }
+ err = snd_pcm_open_noupdate(pcmp, refer, new_name, stream, mode);
+ if (refer != root)
+ snd_config_delete(refer);
+ return err;
+ }
err = snd_pcm_open_conf(pcmp, name, root, pcm_conf, stream, mode);
snd_config_delete(pcm_conf);
return err;
return err;
}
-static int snd_pcm_hook_ctl_elems_replace(const char *what, char **dst, void *private_data)
-{
- snd_pcm_t *pcm = private_data;
- snd_pcm_info_t *info;
- char str[12];
- long val;
- int err;
-
- snd_pcm_info_alloca(&info);
- err = snd_pcm_info(pcm, info);
- if (err < 0)
- return err;
- if (!strcmp(what, "card")) {
- val = snd_pcm_info_get_card(info);
- } else if (!strcmp(what, "device")) {
- val = snd_pcm_info_get_device(info);
- } else if (!strcmp(what, "subdevice")) {
- val = snd_pcm_info_get_subdevice(info);
- } else
- return 0; /* empty string */
- snprintf(str, sizeof(str), "%li", val);
- str[sizeof(str)-1] = '\0';
- *dst = strdup(str);
- return 0;
-}
-
int _snd_pcm_hook_ctl_elems_install(snd_pcm_t *pcm, snd_config_t *conf)
{
int err;
SNDERR("Cannot open CTL %s", ctl_name);
return err;
}
- err = snd_sctl_build(&sctl, ctl, conf, snd_pcm_hook_ctl_elems_replace, pcm, 0);
+ err = snd_sctl_build(&sctl, ctl, conf, pcm, 0);
if (err < 0)
return -ENOMEM;
err = snd_pcm_hook_add(&h_hw_params, pcm, SND_PCM_HOOK_TYPE_HW_PARAMS,