alsactl: add support for recreating enumerated user controls

Signed-off-by: Clemens Ladisch <clemens@ladisch.de>
This commit is contained in:
Clemens Ladisch 2011-10-07 23:16:35 +02:00
parent e80b015689
commit 5a6ca47cb9
2 changed files with 72 additions and 9 deletions

View file

@ -847,6 +847,49 @@ static int get_comment_range(snd_config_t *n, int ctype,
return 0;
}
struct string_array {
unsigned int count;
const char **strings;
};
static int get_comment_items(snd_config_t *n, struct string_array *items)
{
snd_config_iterator_t it, next;
unsigned int i;
int err;
snd_config_for_each(it, next, n) {
snd_config_t *item = snd_config_iterator_entry(it);
const char *id;
unsigned int numid;
if (snd_config_get_id(item, &id) < 0)
return -EINVAL;
numid = atoi(id);
if (numid > 999999)
return -EINVAL;
if (numid >= items->count) {
const char **strings = realloc(items->strings, (numid + 1) * sizeof(char *));
if (!strings)
return -ENOMEM;
for (i = items->count; i < numid + 1; ++i)
strings[i] = NULL;
items->count = numid + 1;
items->strings = strings;
}
err = snd_config_get_string(item, &items->strings[numid]);
if (err < 0)
return err;
}
for (i = 0; i < items->count; ++i)
if (!items->strings[i])
return -EINVAL;
return 0;
}
static int add_user_control(snd_ctl_t *handle, snd_ctl_elem_info_t *info, snd_config_t *conf)
{
snd_ctl_elem_id_t *id;
@ -854,12 +897,15 @@ static int add_user_control(snd_ctl_t *handle, snd_ctl_elem_info_t *info, snd_co
long imin, imax, istep;
snd_ctl_elem_type_t ctype;
unsigned int count;
struct string_array enum_items;
int err;
unsigned int *tlv;
imin = imax = istep = 0;
count = 0;
ctype = SND_CTL_ELEM_TYPE_NONE;
enum_items.count = 0;
enum_items.strings = NULL;
tlv = NULL;
snd_config_for_each(i, next, conf) {
snd_config_t *n = snd_config_iterator_entry(i);
@ -869,31 +915,39 @@ static int add_user_control(snd_ctl_t *handle, snd_ctl_elem_info_t *info, snd_co
if (strcmp(id, "type") == 0) {
err = get_comment_type(n);
if (err < 0)
return err;
goto error;
ctype = err;
continue;
}
if (strcmp(id, "range") == 0) {
err = get_comment_range(n, ctype, &imin, &imax, &istep);
if (err < 0)
return err;
goto error;
continue;
}
if (strcmp(id, "count") == 0) {
long v;
if ((err = snd_config_get_integer(n, &v)) < 0)
return err;
goto error;
count = v;
continue;
}
if (strcmp(id, "item") == 0) {
err = get_comment_items(n, &enum_items);
if (err < 0)
goto error;
continue;
}
if (strcmp(id, "tlv") == 0) {
const char *s;
if ((err = snd_config_get_string(n, &s)) < 0)
return -EINVAL;
goto error;
if (tlv)
free(tlv);
if ((tlv = str_to_tlv(s)) == NULL)
return -EINVAL;
if ((tlv = str_to_tlv(s)) == NULL) {
err = -EINVAL;
goto error;
}
continue;
}
}
@ -904,8 +958,10 @@ static int add_user_control(snd_ctl_t *handle, snd_ctl_elem_info_t *info, snd_co
count = 1;
switch (ctype) {
case SND_CTL_ELEM_TYPE_INTEGER:
if (imin > imax || istep > imax - imin)
return -EINVAL;
if (imin > imax || istep > imax - imin) {
err = -EINVAL;
goto error;
}
err = snd_ctl_elem_add_integer(handle, id, count, imin, imax, istep);
if (err < 0)
goto error;
@ -915,6 +971,10 @@ static int add_user_control(snd_ctl_t *handle, snd_ctl_elem_info_t *info, snd_co
case SND_CTL_ELEM_TYPE_BOOLEAN:
err = snd_ctl_elem_add_boolean(handle, id, count);
break;
case SND_CTL_ELEM_TYPE_ENUMERATED:
err = snd_ctl_elem_add_enumerated(handle, id, count,
enum_items.count, enum_items.strings);
break;
case SND_CTL_ELEM_TYPE_IEC958:
err = snd_ctl_elem_add_iec958(handle, id);
break;
@ -925,6 +985,7 @@ static int add_user_control(snd_ctl_t *handle, snd_ctl_elem_info_t *info, snd_co
error:
free(tlv);
free(enum_items.strings);
if (err < 0)
return err;
return snd_ctl_elem_info(handle, info);

View file

@ -29,7 +29,9 @@ AC_PROG_INSTALL
AC_PROG_MKDIR_P
AC_PROG_LN_S
AC_PROG_SED
AM_PATH_ALSA(1.0.16)
AM_PATH_ALSA(1.0.24)
AC_CHECK_FUNC([snd_ctl_elem_add_enumerated],
, [AC_ERROR([No user enum control support in alsa-lib])])
dnl Check components
AC_CHECK_HEADERS([alsa/pcm.h], [have_pcm="yes"], [have_pcm="no"],