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; 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) 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; 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; long imin, imax, istep;
snd_ctl_elem_type_t ctype; snd_ctl_elem_type_t ctype;
unsigned int count; unsigned int count;
struct string_array enum_items;
int err; int err;
unsigned int *tlv; unsigned int *tlv;
imin = imax = istep = 0; imin = imax = istep = 0;
count = 0; count = 0;
ctype = SND_CTL_ELEM_TYPE_NONE; ctype = SND_CTL_ELEM_TYPE_NONE;
enum_items.count = 0;
enum_items.strings = NULL;
tlv = NULL; tlv = NULL;
snd_config_for_each(i, next, conf) { snd_config_for_each(i, next, conf) {
snd_config_t *n = snd_config_iterator_entry(i); 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) { if (strcmp(id, "type") == 0) {
err = get_comment_type(n); err = get_comment_type(n);
if (err < 0) if (err < 0)
return err; goto error;
ctype = err; ctype = err;
continue; continue;
} }
if (strcmp(id, "range") == 0) { if (strcmp(id, "range") == 0) {
err = get_comment_range(n, ctype, &imin, &imax, &istep); err = get_comment_range(n, ctype, &imin, &imax, &istep);
if (err < 0) if (err < 0)
return err; goto error;
continue; continue;
} }
if (strcmp(id, "count") == 0) { if (strcmp(id, "count") == 0) {
long v; long v;
if ((err = snd_config_get_integer(n, &v)) < 0) if ((err = snd_config_get_integer(n, &v)) < 0)
return err; goto error;
count = v; count = v;
continue; continue;
} }
if (strcmp(id, "item") == 0) {
err = get_comment_items(n, &enum_items);
if (err < 0)
goto error;
continue;
}
if (strcmp(id, "tlv") == 0) { if (strcmp(id, "tlv") == 0) {
const char *s; const char *s;
if ((err = snd_config_get_string(n, &s)) < 0) if ((err = snd_config_get_string(n, &s)) < 0)
return -EINVAL; goto error;
if (tlv) if (tlv)
free(tlv); free(tlv);
if ((tlv = str_to_tlv(s)) == NULL) if ((tlv = str_to_tlv(s)) == NULL) {
return -EINVAL; err = -EINVAL;
goto error;
}
continue; continue;
} }
} }
@ -904,8 +958,10 @@ static int add_user_control(snd_ctl_t *handle, snd_ctl_elem_info_t *info, snd_co
count = 1; count = 1;
switch (ctype) { switch (ctype) {
case SND_CTL_ELEM_TYPE_INTEGER: case SND_CTL_ELEM_TYPE_INTEGER:
if (imin > imax || istep > imax - imin) if (imin > imax || istep > imax - imin) {
return -EINVAL; err = -EINVAL;
goto error;
}
err = snd_ctl_elem_add_integer(handle, id, count, imin, imax, istep); err = snd_ctl_elem_add_integer(handle, id, count, imin, imax, istep);
if (err < 0) if (err < 0)
goto error; 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: case SND_CTL_ELEM_TYPE_BOOLEAN:
err = snd_ctl_elem_add_boolean(handle, id, count); err = snd_ctl_elem_add_boolean(handle, id, count);
break; 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: case SND_CTL_ELEM_TYPE_IEC958:
err = snd_ctl_elem_add_iec958(handle, id); err = snd_ctl_elem_add_iec958(handle, id);
break; break;
@ -925,6 +985,7 @@ static int add_user_control(snd_ctl_t *handle, snd_ctl_elem_info_t *info, snd_co
error: error:
free(tlv); free(tlv);
free(enum_items.strings);
if (err < 0) if (err < 0)
return err; return err;
return snd_ctl_elem_info(handle, info); return snd_ctl_elem_info(handle, info);

View file

@ -29,7 +29,9 @@ AC_PROG_INSTALL
AC_PROG_MKDIR_P AC_PROG_MKDIR_P
AC_PROG_LN_S AC_PROG_LN_S
AC_PROG_SED 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 dnl Check components
AC_CHECK_HEADERS([alsa/pcm.h], [have_pcm="yes"], [have_pcm="no"], AC_CHECK_HEADERS([alsa/pcm.h], [have_pcm="yes"], [have_pcm="no"],