From c25879f9d90a0b1d619383dec96a3449a5c64d32 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 9 Sep 2002 14:24:56 +0000 Subject: [PATCH] added the handling of enum controls to simple mixer API. the following functions are added: int snd_mixer_selem_is_enumerated() int snd_mixer_selem_get_enum_items() int snd_mixer_selem_get_enum_item_name() int snd_mixer_selem_get_enum_item() int snd_mixer_selem_set_enum_item() --- include/mixer.h | 6 ++ src/mixer/simple.c | 180 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 183 insertions(+), 3 deletions(-) diff --git a/include/mixer.h b/include/mixer.h index 6c4f47fe..f0dc49b3 100644 --- a/include/mixer.h +++ b/include/mixer.h @@ -192,6 +192,12 @@ void snd_mixer_selem_get_capture_volume_range(snd_mixer_elem_t *elem, void snd_mixer_selem_set_capture_volume_range(snd_mixer_elem_t *elem, long min, long max); +int snd_mixer_selem_is_enumerated(snd_mixer_elem_t *elem); +int snd_mixer_selem_get_enum_items(snd_mixer_elem_t *elem); +int snd_mixer_selem_get_enum_item_name(snd_mixer_elem_t *elem, unsigned int idx, size_t maxlen, char *str); +int snd_mixer_selem_get_enum_item(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, unsigned int *idxp); +int snd_mixer_selem_set_enum_item(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, unsigned int idx); + size_t snd_mixer_selem_id_sizeof(void); /** \hideinitializer * \brief allocate an invalid #snd_mixer_selem_id_t using standard alloca diff --git a/src/mixer/simple.c b/src/mixer/simple.c index 0f8ceba2..2164d29a 100644 --- a/src/mixer/simple.c +++ b/src/mixer/simple.c @@ -51,6 +51,7 @@ #define CAP_CSWITCH (1<<9) #define CAP_CSWITCH_JOIN (1<<10) #define CAP_CSWITCH_EXCL (1<<11) +#define CAP_ENUM (1<<12) typedef struct _mixer_simple mixer_simple_t; @@ -59,6 +60,7 @@ typedef struct _mixer_simple mixer_simple_t; typedef enum _selem_ctl_type { CTL_SINGLE, + CTL_ENUMLIST, CTL_GLOBAL_SWITCH, CTL_GLOBAL_VOLUME, CTL_GLOBAL_ROUTE, @@ -289,6 +291,24 @@ static int elem_read_route(selem_t *s, int dir, selem_ctl_type_t type) return 0; } +static int elem_read_enum(selem_t *s) +{ + snd_ctl_elem_value_t ctl; + unsigned int idx; + int err; + selem_ctl_t *c = &s->ctls[CTL_ENUMLIST]; + memset(&ctl, 0, sizeof(ctl)); + if ((err = snd_hctl_elem_read(c->elem, &ctl)) < 0) + return err; + for (idx = 0; idx < s->str[0].channels; idx++) { + unsigned int idx1 = idx; + if (idx >= c->values) + idx1 = 0; + s->str[0].vol[idx] = ctl.value.enumerated.item[idx1]; + } + return 0; +} + static int selem_read(snd_mixer_elem_t *elem) { selem_t *s; @@ -309,6 +329,9 @@ static int selem_read(snd_mixer_elem_t *elem) csw = s->str[CAPT].sw; s->str[CAPT].sw = ~0U; + if (s->ctls[CTL_ENUMLIST].elem) + return elem_read_enum(s); + if (s->ctls[CTL_PLAYBACK_VOLUME].elem) err = elem_read_volume(s, PLAY, CTL_PLAYBACK_VOLUME); else if (s->ctls[CTL_GLOBAL_VOLUME].elem) @@ -482,6 +505,22 @@ static int elem_write_route(selem_t *s, int dir, selem_ctl_type_t type) return 0; } +static int elem_write_enum(selem_t *s) +{ + snd_ctl_elem_value_t ctl; + unsigned int idx; + int err; + selem_ctl_t *c = &s->ctls[CTL_ENUMLIST]; + memset(&ctl, 0, sizeof(ctl)); + if ((err = snd_hctl_elem_read(c->elem, &ctl)) < 0) + return err; + for (idx = 0; idx < c->values; idx++) + ctl.value.enumerated.item[idx] = (unsigned int)s->str[0].vol[idx]; + if ((err = snd_hctl_elem_write(c->elem, &ctl)) < 0) + return err; + return 0; +} + static int selem_write(snd_mixer_elem_t *elem) { selem_t *s; @@ -491,6 +530,9 @@ static int selem_write(snd_mixer_elem_t *elem) assert(elem->type == SND_MIXER_ELEM_SIMPLE); s = elem->private_data; + if (s->ctls[CTL_ENUMLIST].elem) + return elem_write_enum(s); + if (s->ctls[CTL_SINGLE].elem) { if (s->ctls[CTL_SINGLE].type == SND_CTL_ELEM_TYPE_INTEGER) err = elem_write_volume(s, PLAY, CTL_SINGLE); @@ -682,6 +724,12 @@ static int simple_update(snd_mixer_elem_t *melem) caps |= CAP_CSWITCH | CAP_CSWITCH_EXCL; caps &= ~CAP_GSWITCH; } + ctl = &simple->ctls[CTL_ENUMLIST]; + if (ctl->elem) { + if (pchannels < ctl->values) + pchannels = ctl->values; + caps |= CAP_ENUM; + } if (pchannels > 32) pchannels = 32; if (cchannels > 32) @@ -813,7 +861,9 @@ static int simple_add1(snd_mixer_class_t *class, const char *name, return err; switch (type) { case CTL_SINGLE: - if (info.type != SND_CTL_ELEM_TYPE_BOOLEAN && + if (info.type == SND_CTL_ELEM_TYPE_ENUMERATED) + type = CTL_ENUMLIST; + else if (info.type != SND_CTL_ELEM_TYPE_BOOLEAN && info.type != SND_CTL_ELEM_TYPE_INTEGER) return 0; break; @@ -886,8 +936,13 @@ static int simple_add1(snd_mixer_class_t *class, const char *name, simple->ctls[type].type = info.type; simple->ctls[type].access = info.access; simple->ctls[type].values = info.count; - simple->ctls[type].min = info.value.integer.min; - simple->ctls[type].max = info.value.integer.max; + if (type == CTL_ENUMLIST) { + simple->ctls[type].min = 0; + simple->ctls[type].max = info.value.enumerated.items; + } else { + simple->ctls[type].min = info.value.integer.min; + simple->ctls[type].max = info.value.integer.max; + } switch (type) { case CTL_CAPTURE_SOURCE: simple->capture_item = value; @@ -1811,6 +1866,125 @@ int snd_mixer_selem_set_capture_switch_all(snd_mixer_elem_t *elem, int value) return 0; } +/** + * \brief Return true if mixer simple element is an enumerated control + * \param elem Mixer simple element handle + * \return 0 normal volume/switch control, 1 enumerated control + */ +int snd_mixer_selem_is_enumerated(snd_mixer_elem_t *elem) +{ + selem_t *s; + assert(elem); + assert(elem->type == SND_MIXER_ELEM_SIMPLE); + s = elem->private_data; + return s->ctls[CTL_ENUMLIST].elem != 0; +} + +/** + * \brief Return the number of enumerated items of the given mixer simple element + * \param elem Mixer simple element handle + * \return the number of enumerated items, otherwise a negative error code + */ +int snd_mixer_selem_get_enum_items(snd_mixer_elem_t *elem) +{ + selem_t *s; + assert(elem); + assert(elem->type == SND_MIXER_ELEM_SIMPLE); + s = elem->private_data; + if (! s->ctls[CTL_ENUMLIST].elem) + return -EINVAL; + return s->ctls[CTL_ENUMLIST].max; +} + +/** + * \brief get the enumerated item string for the given mixer simple element + * \param elem Mixer simple element handle + * \param item the index of the enumerated item to query + * \param maxlen the maximal length to be stored + * \param buf the buffer to store the name string + * \return 0 if successful, otherwise a negative error code + */ +int snd_mixer_selem_get_enum_item_name(snd_mixer_elem_t *elem, + unsigned int item, + size_t maxlen, char *buf) +{ + selem_t *s; + snd_ctl_elem_info_t *info; + snd_hctl_elem_t *helem; + assert(elem); + assert(elem->type == SND_MIXER_ELEM_SIMPLE); + s = elem->private_data; + helem = s->ctls[CTL_ENUMLIST].elem; + assert(helem); + if (item >= (unsigned int)s->ctls[CTL_ENUMLIST].max) + return -EINVAL; + snd_ctl_elem_info_alloca(&info); + snd_hctl_elem_info(helem, info); + snd_ctl_elem_info_set_item(info, item); + snd_hctl_elem_info(helem, info); + strncpy(buf, snd_ctl_elem_info_get_item_name(info), maxlen); + return 0; +} + +/** + * \brief get the current selected enumerated item for the given mixer simple element + * \param elem Mixer simple element handle + * \param channel mixer simple element channel identifier + * \param itemp the pointer to store the index of the enumerated item + * \return 0 if successful, otherwise a negative error code + */ +int snd_mixer_selem_get_enum_item(snd_mixer_elem_t *elem, + snd_mixer_selem_channel_id_t channel, + unsigned int *itemp) +{ + selem_t *s; + snd_ctl_elem_value_t ctl; + snd_hctl_elem_t *helem; + int err; + assert(elem); + assert(elem->type == SND_MIXER_ELEM_SIMPLE); + s = elem->private_data; + if ((unsigned int) channel >= s->str[0].channels) + return -EINVAL; + helem = s->ctls[CTL_ENUMLIST].elem; + assert(helem); + memset(&ctl, 0, sizeof(ctl)); + err = snd_hctl_elem_read(helem, &ctl); + if (! err) + *itemp = ctl.value.enumerated.item[channel]; + return err; +} + +/** + * \brief set the current selected enumerated item for the given mixer simple element + * \param elem Mixer simple element handle + * \param channel mixer simple element channel identifier + * \param item the enumerated item index + * \return 0 if successful, otherwise a negative error code + */ +int snd_mixer_selem_set_enum_item(snd_mixer_elem_t *elem, + snd_mixer_selem_channel_id_t channel, + unsigned int item) +{ + selem_t *s; + snd_ctl_elem_value_t ctl; + snd_hctl_elem_t *helem; + int err; + assert(elem); + assert(elem->type == SND_MIXER_ELEM_SIMPLE); + s = elem->private_data; + if ((unsigned int) channel >= s->str[0].channels) + return -EINVAL; + helem = s->ctls[CTL_ENUMLIST].elem; + assert(helem); + if (item >= (unsigned int)s->ctls[CTL_ENUMLIST].max) + return -EINVAL; + memset(&ctl, 0, sizeof(ctl)); + err = snd_hctl_elem_read(helem, &ctl); + ctl.value.enumerated.item[channel] = item; + return snd_hctl_elem_write(helem, &ctl); +} + /** * \brief get size of #snd_mixer_selem_id_t * \return size in bytes -- 2.47.1