[alsa-devel] [alsa-lib][PATCH 0/6] control: add APIs for control element set
This patchset adds some APIs for control element set, according to design of ALSA control core. Additionally, for the APIs, some API documentation is improved.
In ALSA control core, each sound card can have control elements. The elements are managed according to below design.
* element set * A set of elements with the same attribute (i.e. name, get/put operations). Some element sets can be added to a sound card. [0] * element * An element can be identified by userspace applications. * channel * An element has channels which can be changed by userspace applications or hardware device itself. * value * Each channel has its own value. The place to kept the value depends on design of each device driver (i.e. in hardware register or kernel space).
There're two ways to identify the element; by identification number(numid), or by a combination of name of the element set and index from the first element in the element set [1].
Both of device drivers in kernel land and ALSA control applications in user land can add the element set. When userspace applications add them, ALSA control core works as Inter Process Communication mechanism between event-listening applications and usual control applications. Such element is referred as 'user-defined control elements' in alsa-lib.
Typically, device drivers in kernel land adds one element set for a single element. So users and userspace developers are hard to realize that an existence of the element set.
There are more items to describe the design. But here I focus on what relates to this patchset.
Well, current alsa-lib implementation includes small bugs, some misleadings, a lack of feature related to user-defined control elements. This patchset is my attempt to improves them.
[0] In kernel, the element set is represented by 'struct snd_kcontrol'. Some developers call it as 'kernel control'. The others call it as 'control group'. Here, I suggest 'element set', because from userspace the 'struct snd_kcontrol' is not visible and any elements are just visible. Furthermore, I'd like to use unique name against Linux control groups.
[1] Actually, when identifying an element according to name/index pair, the other members of 'struct snd_ctl_elem_id' such as iface, device and subdevice are required. They're required to seek element set, then index is used to find an element.
Regards
Takashi Sakamoto (6): control: rename variables so that it represents the number of channels which an element has control: improve API documentation for functions to add elements control: improve API documentation for functions to set/get channel values for an element control: rename variables so that it represents a channel in element control: add a function to add an element of bytes type control: add functions to add element set
include/control.h | 55 +++-- src/control/control.c | 589 ++++++++++++++++++++++++++++++++++++++------------ 2 files changed, 487 insertions(+), 157 deletions(-)
An element has some channels which can be changed in a single operation from userspace. In control API, variables to represents the number of channels is described as 'count'. On the other hand, in ALSA control core, the number of elements in an element set is also described as 'count'. They're a bit confusing.
This commit renames 'count' with 'channels'. The 'count' is reserved for future commit to describe the number of elements in an element set.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- src/control/control.c | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-)
diff --git a/src/control/control.c b/src/control/control.c index 8a5d530..e02727a 100644 --- a/src/control/control.c +++ b/src/control/control.c @@ -264,14 +264,15 @@ int snd_ctl_elem_info(snd_ctl_t *ctl, snd_ctl_elem_info_t *info) * \brief Create and add an user INTEGER CTL element * \param ctl CTL handle * \param id CTL element id to add - * \param count number of elements + * \param channels number of elements * \param min minimum value * \param max maximum value * \param step value step * \return 0 on success otherwise a negative error code */ int snd_ctl_elem_add_integer(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, - unsigned int count, long min, long max, long step) + unsigned int channels, long min, long max, + long step) { snd_ctl_elem_info_t *info; snd_ctl_elem_value_t *val; @@ -284,7 +285,7 @@ int snd_ctl_elem_add_integer(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, info->type = SND_CTL_ELEM_TYPE_INTEGER; info->access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE; - info->count = count; + info->count = channels; info->value.integer.min = min; info->value.integer.max = max; info->value.integer.step = step; @@ -293,7 +294,7 @@ int snd_ctl_elem_add_integer(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, return err; snd_ctl_elem_value_alloca(&val); val->id = info->id; - for (i = 0; i < count; i++) + for (i = 0; i < channels; i++) val->value.integer.value[i] = min; err = ctl->ops->element_write(ctl, val); return err; @@ -303,15 +304,15 @@ int snd_ctl_elem_add_integer(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, * \brief Create and add an user INTEGER64 CTL element * \param ctl CTL handle * \param id CTL element id to add - * \param count number of elements + * \param channels number of elements * \param min minimum value * \param max maximum value * \param step value step * \return 0 on success otherwise a negative error code */ int snd_ctl_elem_add_integer64(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, - unsigned int count, long long min, long long max, - long long step) + unsigned int channels, long long min, + long long max, long long step) { snd_ctl_elem_info_t *info; snd_ctl_elem_value_t *val; @@ -322,7 +323,7 @@ int snd_ctl_elem_add_integer64(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, snd_ctl_elem_info_alloca(&info); info->id = *id; info->type = SND_CTL_ELEM_TYPE_INTEGER64; - info->count = count; + info->count = channels; info->value.integer64.min = min; info->value.integer64.max = max; info->value.integer64.step = step; @@ -331,7 +332,7 @@ int snd_ctl_elem_add_integer64(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, return err; snd_ctl_elem_value_alloca(&val); val->id = info->id; - for (i = 0; i < count; i++) + for (i = 0; i < channels; i++) val->value.integer64.value[i] = min; err = ctl->ops->element_write(ctl, val); return err; @@ -341,11 +342,11 @@ int snd_ctl_elem_add_integer64(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, * \brief Create and add an user BOOLEAN CTL element * \param ctl CTL handle * \param id CTL element id to add - * \param count number of elements + * \param channels number of elements * \return 0 on success otherwise a negative error code */ int snd_ctl_elem_add_boolean(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, - unsigned int count) + unsigned int channels) { snd_ctl_elem_info_t *info;
@@ -353,7 +354,7 @@ int snd_ctl_elem_add_boolean(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, snd_ctl_elem_info_alloca(&info); info->id = *id; info->type = SND_CTL_ELEM_TYPE_BOOLEAN; - info->count = count; + info->count = channels; info->value.integer.min = 0; info->value.integer.max = 1; return ctl->ops->element_add(ctl, info); @@ -363,7 +364,7 @@ int snd_ctl_elem_add_boolean(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, * \brief Create and add a user-defined control element of type enumerated. * \param[in] ctl Control device handle. * \param[in] id ID of the new control element. - * \param[in] count Number of element values. + * \param[in] channels Number of element values. * \param[in] items Range of possible values (0 ... \a items - 1). * \param[in] names An array containing \a items strings. * \return Zero on success, otherwise a negative error code. @@ -380,9 +381,10 @@ int snd_ctl_elem_add_boolean(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, * \par Errors: * <dl> * <dt>-EBUSY<dd>A control element with ID \a id already exists. - * <dt>-EINVAL<dd>\a count is not at least one or greater than 128, or \a items - * is not at least one, or a string in \a names is empty or longer than 63 - * bytes, or the strings in \a names require more than 64 KB storage. + * <dt>-EINVAL<dd>\a channels is not at least one or greater than 128, or \a + * items is not at least one, or a string in \a names is empty or longer + * than 63 bytes, or the strings in \a names require more than 64 KB + * storage. * <dt>-ENOMEM<dd>Out of memory, or there are too many user control elements. * <dt>-ENXIO<dd>This driver does not support (enumerated) user controls. * <dt>-ENODEV<dd>Device unplugged. @@ -392,7 +394,7 @@ int snd_ctl_elem_add_boolean(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, * snd_ctl_elem_add_enumerated() was introduced in ALSA 1.0.25. */ int snd_ctl_elem_add_enumerated(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, - unsigned int count, unsigned int items, + unsigned int channels, unsigned int items, const char *const names[]) { snd_ctl_elem_info_t *info; @@ -405,7 +407,7 @@ int snd_ctl_elem_add_enumerated(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, snd_ctl_elem_info_alloca(&info); info->id = *id; info->type = SND_CTL_ELEM_TYPE_ENUMERATED; - info->count = count; + info->count = channels; info->value.enumerated.items = items;
bytes = 0;
On Feb 23 2016 09:48, Takashi Sakamoto wrote:
An element has some channels which can be changed in a single operation from userspace. In control API, variables to represents the number of channels is described as 'count'. On the other hand, in ALSA control core, the number of elements in an element set is also described as 'count'. They're a bit confusing.
This commit renames 'count' with 'channels'. The 'count' is reserved for future commit to describe the number of elements in an element set.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp
src/control/control.c | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-)
diff --git a/src/control/control.c b/src/control/control.c index 8a5d530..e02727a 100644 --- a/src/control/control.c +++ b/src/control/control.c @@ -264,14 +264,15 @@ int snd_ctl_elem_info(snd_ctl_t *ctl, snd_ctl_elem_info_t *info)
- \brief Create and add an user INTEGER CTL element
- \param ctl CTL handle
- \param id CTL element id to add
- \param count number of elements
- \param channels number of elements
Oops. This is incomplete because in my intension the description of this argument represents the number of 'channels', not 'elements'.
- \param min minimum value
- \param max maximum value
- \param step value step
- \return 0 on success otherwise a negative error code
*/ int snd_ctl_elem_add_integer(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id,
unsigned int count, long min, long max, long step)
unsigned int channels, long min, long max,
{ snd_ctl_elem_info_t *info; snd_ctl_elem_value_t *val;long step)
@@ -284,7 +285,7 @@ int snd_ctl_elem_add_integer(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, info->type = SND_CTL_ELEM_TYPE_INTEGER; info->access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE;
- info->count = count;
- info->count = channels; info->value.integer.min = min; info->value.integer.max = max; info->value.integer.step = step;
@@ -293,7 +294,7 @@ int snd_ctl_elem_add_integer(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, return err; snd_ctl_elem_value_alloca(&val); val->id = info->id;
- for (i = 0; i < count; i++)
- for (i = 0; i < channels; i++) val->value.integer.value[i] = min; err = ctl->ops->element_write(ctl, val); return err;
@@ -303,15 +304,15 @@ int snd_ctl_elem_add_integer(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id,
- \brief Create and add an user INTEGER64 CTL element
- \param ctl CTL handle
- \param id CTL element id to add
- \param count number of elements
- \param channels number of elements
Ditto.
- \param min minimum value
- \param max maximum value
- \param step value step
- \return 0 on success otherwise a negative error code
*/ int snd_ctl_elem_add_integer64(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id,
unsigned int count, long long min, long long max,
long long step)
unsigned int channels, long long min,
{ snd_ctl_elem_info_t *info; snd_ctl_elem_value_t *val;long long max, long long step)
@@ -322,7 +323,7 @@ int snd_ctl_elem_add_integer64(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, snd_ctl_elem_info_alloca(&info); info->id = *id; info->type = SND_CTL_ELEM_TYPE_INTEGER64;
- info->count = count;
- info->count = channels; info->value.integer64.min = min; info->value.integer64.max = max; info->value.integer64.step = step;
@@ -331,7 +332,7 @@ int snd_ctl_elem_add_integer64(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, return err; snd_ctl_elem_value_alloca(&val); val->id = info->id;
- for (i = 0; i < count; i++)
- for (i = 0; i < channels; i++) val->value.integer64.value[i] = min; err = ctl->ops->element_write(ctl, val); return err;
@@ -341,11 +342,11 @@ int snd_ctl_elem_add_integer64(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id,
- \brief Create and add an user BOOLEAN CTL element
- \param ctl CTL handle
- \param id CTL element id to add
- \param count number of elements
- \param channels number of elements
Ditto.
- \return 0 on success otherwise a negative error code
*/ int snd_ctl_elem_add_boolean(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id,
unsigned int count)
{ snd_ctl_elem_info_t *info;unsigned int channels)
@@ -353,7 +354,7 @@ int snd_ctl_elem_add_boolean(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, snd_ctl_elem_info_alloca(&info); info->id = *id; info->type = SND_CTL_ELEM_TYPE_BOOLEAN;
- info->count = count;
- info->count = channels; info->value.integer.min = 0; info->value.integer.max = 1; return ctl->ops->element_add(ctl, info);
@@ -363,7 +364,7 @@ int snd_ctl_elem_add_boolean(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id,
- \brief Create and add a user-defined control element of type enumerated.
- \param[in] ctl Control device handle.
- \param[in] id ID of the new control element.
- \param[in] count Number of element values.
- \param[in] channels Number of element values.
Ditto.
- \param[in] items Range of possible values (0 ... \a items - 1).
- \param[in] names An array containing \a items strings.
- \return Zero on success, otherwise a negative error code.
@@ -380,9 +381,10 @@ int snd_ctl_elem_add_boolean(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id,
- \par Errors:
<dl>
<dt>-EBUSY<dd>A control element with ID \a id already exists.
<dt>-EINVAL<dd>\a count is not at least one or greater than 128, or \a items
- is not at least one, or a string in \a names is empty or longer than 63
- bytes, or the strings in \a names require more than 64 KB storage.
<dt>-EINVAL<dd>\a channels is not at least one or greater than 128, or \a
- items is not at least one, or a string in \a names is empty or longer
- than 63 bytes, or the strings in \a names require more than 64 KB
- storage.
<dt>-ENOMEM<dd>Out of memory, or there are too many user control elements.
<dt>-ENXIO<dd>This driver does not support (enumerated) user controls.
<dt>-ENODEV<dd>Device unplugged.
@@ -392,7 +394,7 @@ int snd_ctl_elem_add_boolean(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id,
- snd_ctl_elem_add_enumerated() was introduced in ALSA 1.0.25.
*/ int snd_ctl_elem_add_enumerated(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id,
unsigned int count, unsigned int items,
{ snd_ctl_elem_info_t *info;unsigned int channels, unsigned int items, const char *const names[])
@@ -405,7 +407,7 @@ int snd_ctl_elem_add_enumerated(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, snd_ctl_elem_info_alloca(&info); info->id = *id; info->type = SND_CTL_ELEM_TYPE_ENUMERATED;
- info->count = count;
info->count = channels; info->value.enumerated.items = items;
bytes = 0;
Regards
Takashi Sakamoto
Current API documentation has a lack of details for functions to add elements. This commit fulfils them.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- src/control/control.c | 150 +++++++++++++++++++++++++++++++++++++------------- 1 file changed, 111 insertions(+), 39 deletions(-)
diff --git a/src/control/control.c b/src/control/control.c index e02727a..fe9e557 100644 --- a/src/control/control.c +++ b/src/control/control.c @@ -261,14 +261,33 @@ int snd_ctl_elem_info(snd_ctl_t *ctl, snd_ctl_elem_info_t *info) }
/** - * \brief Create and add an user INTEGER CTL element - * \param ctl CTL handle - * \param id CTL element id to add - * \param channels number of elements - * \param min minimum value - * \param max maximum value - * \param step value step - * \return 0 on success otherwise a negative error code + * \brief Create and add an user-defined control element of integer type. + * \param[in] ctl CTL handle + * \param[in,out] id ID of the new control element. + * \param[in] channels The number of channels which a control element includes. + * \param[in] min Minimum value for the value of each channel. + * \param[in] max Maximum value for the value of each channel. + * \param[in] step The step of value for the value of each channel. + * \return Zero on success, otherwise a negative error code. + * + * This function creates a user control element. This control element is not + * controlled by device drivers in kernel, but can be handled by the same way as + * usual control elements added by the device drivers. + * + * The fields of \a id, except for numid, must be set with unique values to + * identify the new element. After returning, all fields of \a id are filled. + * + * All of channels in the new element are locked. The value of each channel is + * initialized with the minimum value. + * + * \par Errors: + * <dl> + * <dt>-EBUSY<dd>A control element with ID \a id already exists. + * <dt>-EINVAL<dd>ID has no name, or \a channels is not between 1 to 127. + * <dt>-ENOMEM<dd>Out of memory, or there are too many user control elements. + * <dt>-ENXIO<dd>This driver does not support (integer) user controls. + * <dt>-ENODEV<dd>Device unplugged. + * </dl> */ int snd_ctl_elem_add_integer(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, unsigned int channels, long min, long max, @@ -301,14 +320,33 @@ int snd_ctl_elem_add_integer(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, }
/** - * \brief Create and add an user INTEGER64 CTL element - * \param ctl CTL handle - * \param id CTL element id to add - * \param channels number of elements - * \param min minimum value - * \param max maximum value - * \param step value step - * \return 0 on success otherwise a negative error code + * \brief Create and add an user-defined control element of integer64 type. + * \param[in] ctl CTL handle + * \param[in,out] id ID of the new control element. + * \param[in] channels The number of channels which a control element includes. + * \param[in] min Minimum value for the value of each channel + * \param[in] max Maximum value for the value of each channel + * \param[in] step Step of value for the value of each channel + * \return Zero on success, otherwise a negative error code. + * + * This function creates a user control element. This control element is not + * controlled by device drivers in kernel, but can be handled by the same way as + * usual control elements added by the device drivers. + * + * The fields of \a id, except for numid, must be set with unique values to + * identify the new element. After returning, all fields of \a id are filled. + * + * All of channels in the new element are locked. The value of each channel is + * initialized with the minimum value. + * + * \par Errors: + * <dl> + * <dt>-EBUSY<dd>A control element with ID \a id already exists. + * <dt>-EINVAL<dd>ID has no name, or \a channels is not between 1 to 63. + * <dt>-ENOMEM<dd>Out of memory, or there are too many user control elements. + * <dt>-ENXIO<dd>This driver does not support (integer64) user controls. + * <dt>-ENODEV<dd>Device unplugged. + * </dl> */ int snd_ctl_elem_add_integer64(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, unsigned int channels, long long min, @@ -339,11 +377,29 @@ int snd_ctl_elem_add_integer64(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, }
/** - * \brief Create and add an user BOOLEAN CTL element - * \param ctl CTL handle - * \param id CTL element id to add - * \param channels number of elements - * \return 0 on success otherwise a negative error code + * \brief Create and add an user-defined control element of boolean type. + * \param[in] ctl CTL handle + * \param[in,out] id ID of the new control element. + * \param[in] channels The number of channels which a control element includes. + * + * This function creates a user control element. This control element is not + * controlled by device drivers in kernel, but can be handled by the same way as + * usual control elements added by the device drivers. + * + * The fields of \a id, except for numid, must be set with unique values to + * identify the new element. After returning, all fields of \a id are filled. + * + * All of channels in the new element are locked. The value of each channel is + * initialized with false. + * + * \par Errors: + * <dl> + * <dt>-EBUSY<dd>A control element with ID \a id already exists. + * <dt>-EINVAL<dd>ID has no name, or \a channels is not between 1 to 127. + * <dt>-ENOMEM<dd>Out of memory, or there are too many user control elements. + * <dt>-ENXIO<dd>This driver does not support (boolean) user controls. + * <dt>-ENODEV<dd>Device unplugged. + * </dl> */ int snd_ctl_elem_add_boolean(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, unsigned int channels) @@ -361,37 +417,37 @@ int snd_ctl_elem_add_boolean(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, }
/** - * \brief Create and add a user-defined control element of type enumerated. - * \param[in] ctl Control device handle. - * \param[in] id ID of the new control element. - * \param[in] channels Number of element values. + * \brief Create and add a user-defined control element of enumerated type. + * \param[in] ctl CTL handle + * \param[in,out] id ID of the new control element. + * \param[in] channels The number of channels which a control element includes. * \param[in] items Range of possible values (0 ... \a items - 1). * \param[in] names An array containing \a items strings. * \return Zero on success, otherwise a negative error code. * - * This function creates a user element, i.e., a control element that is not - * controlled by the control device's driver but that is just stored together - * with the other elements of \a ctl. + * This function creates a user control element. This control element is not + * controlled by device drivers in kernel, but can be handled by the same way as + * usual control elements added by the device drivers. * - * The fields of \a id, except numid, must be set to unique values that + * The fields of \a id, except for numid, must be set to unique values that * identify the new element. * - * The new element is locked; its value is initialized as zero. + * All of channels in the new element are locked. The value of each channel is + * initialized with the first entry of names. * * \par Errors: * <dl> * <dt>-EBUSY<dd>A control element with ID \a id already exists. - * <dt>-EINVAL<dd>\a channels is not at least one or greater than 128, or \a - * items is not at least one, or a string in \a names is empty or longer - * than 63 bytes, or the strings in \a names require more than 64 KB - * storage. + * <dt>-EINVAL<dd>\a channels is not between 1 to 127, or \a items is not at + * least one, or a string in \a names is empty or longer than 63 + * bytes, or the strings in \a names require more than 64 KB storage. * <dt>-ENOMEM<dd>Out of memory, or there are too many user control elements. * <dt>-ENXIO<dd>This driver does not support (enumerated) user controls. * <dt>-ENODEV<dd>Device unplugged. * </dl> * * \par Compatibility: - * snd_ctl_elem_add_enumerated() was introduced in ALSA 1.0.25. + * This function is added in ALSA 1.0.25. */ int snd_ctl_elem_add_enumerated(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, unsigned int channels, unsigned int items, @@ -432,10 +488,26 @@ int snd_ctl_elem_add_enumerated(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, }
/** - * \brief Create and add an user IEC958 CTL element - * \param ctl CTL handle - * \param id CTL element info to add - * \return 0 on success otherwise a negative error code + * \brief Create and add a user-defined control element of IEC958 type. + * \param[in] ctl CTL handle + * \param[in,out] id ID of the new control element. + * + * This function creates a user control element, This control element is not + * controlled by device drivers in kernel but that is handled by the same way as + * the control elements added by the device drivers. + * + * The fields of \a id, except numid, must be set with unique values to identify + * the new element. After returning, all fields of \a id are filled. + * + * The channel in the new element is locked; the value is initialized with zero. + * + * \par Errors: + * <dl> + * <dt>-EBUSY<dd>A control element with ID \a id already exists. + * <dt>-ENOMEM<dd>Out of memory, or there are too many user control elements. + * <dt>-ENXIO<dd>This driver does not support (IEC958) user controls. + * <dt>-ENODEV<dd>Device unplugged. + * </dl> */ int snd_ctl_elem_add_iec958(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id) {
Current API documentation about functions to set/get element value includes unfriendry texts for userspace developers. This commit improves them.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- src/control/control.c | 117 +++++++++++++++++++++++++++----------------------- 1 file changed, 64 insertions(+), 53 deletions(-)
diff --git a/src/control/control.c b/src/control/control.c index fe9e557..3ce14c2 100644 --- a/src/control/control.c +++ b/src/control/control.c @@ -2563,10 +2563,11 @@ void snd_ctl_elem_value_set_index(snd_ctl_elem_value_t *obj, unsigned int val) }
/** - * \brief Get value for an entry of a #SND_CTL_ELEM_TYPE_BOOLEAN CTL element id/value - * \param obj CTL element id/value - * \param idx Entry index - * \return value for the entry + * \brief Get value from given data for a specified channel as an element of + * boolean type. + * \param[in] obj Data of an element. + * \param[in] idx index of channel in the control element + * \return Value for the channel. */ int snd_ctl_elem_value_get_boolean(const snd_ctl_elem_value_t *obj, unsigned int idx) { @@ -2576,10 +2577,11 @@ int snd_ctl_elem_value_get_boolean(const snd_ctl_elem_value_t *obj, unsigned int }
/** - * \brief Get value for an entry of a #SND_CTL_ELEM_TYPE_INTEGER CTL element id/value - * \param obj CTL element id/value - * \param idx Entry index - * \return value for the entry + * \brief Get value from given data for a specified channel as an element of + * integer type. + * \param[in] obj Data of an element. + * \param[in] idx index of channel in the control element + * \return Value for the channel. */ long snd_ctl_elem_value_get_integer(const snd_ctl_elem_value_t *obj, unsigned int idx) { @@ -2589,10 +2591,11 @@ long snd_ctl_elem_value_get_integer(const snd_ctl_elem_value_t *obj, unsigned in }
/** - * \brief Get value for an entry of a #SND_CTL_ELEM_TYPE_INTEGER64 CTL element id/value - * \param obj CTL element id/value - * \param idx Entry index - * \return value for the entry + * \brief Get value from given data for a specified channel as an element of + * integer64 type. + * \param[in] obj Data of an element. + * \param[in] idx index of channel in the control element + * \return Value for the channel. */ long long snd_ctl_elem_value_get_integer64(const snd_ctl_elem_value_t *obj, unsigned int idx) { @@ -2602,10 +2605,11 @@ long long snd_ctl_elem_value_get_integer64(const snd_ctl_elem_value_t *obj, unsi }
/** - * \brief Get value for an entry of a #SND_CTL_ELEM_TYPE_ENUMERATED CTL element id/value - * \param obj CTL element id/value - * \param idx Entry index - * \return value for the entry + * \brief Get value from given data for a specified channel as an element of + * enumerated type. + * \param[in] obj Data of an element. + * \param[in] idx index of channel in the control element + * \return Value for the channel. This is an index of name set in the element. */ unsigned int snd_ctl_elem_value_get_enumerated(const snd_ctl_elem_value_t *obj, unsigned int idx) { @@ -2615,10 +2619,11 @@ unsigned int snd_ctl_elem_value_get_enumerated(const snd_ctl_elem_value_t *obj, }
/** - * \brief Get value for an entry of a #SND_CTL_ELEM_TYPE_BYTES CTL element id/value - * \param obj CTL element id/value - * \param idx Entry index - * \return value for the entry + * \brief Get value from given data for a specified channel as an element of + * bytes type. + * \param[in] obj Data of an element. + * \param[in] idx index of channel in the control element + * \return Value for the channel. */ unsigned char snd_ctl_elem_value_get_byte(const snd_ctl_elem_value_t *obj, unsigned int idx) { @@ -2628,10 +2633,11 @@ unsigned char snd_ctl_elem_value_get_byte(const snd_ctl_elem_value_t *obj, unsig }
/** - * \brief Set value for an entry of a #SND_CTL_ELEM_TYPE_BOOLEAN CTL element id/value - * \param obj CTL element id/value - * \param idx Entry index - * \param val value for the entry + * \brief Set value to given data for a specified channel as an element of + * boolean type. + * \param[in] obj Data of an element. + * \param[in] idx index of channel in the control element + * \param[in] val Value for the channel. */ void snd_ctl_elem_value_set_boolean(snd_ctl_elem_value_t *obj, unsigned int idx, long val) { @@ -2641,10 +2647,11 @@ void snd_ctl_elem_value_set_boolean(snd_ctl_elem_value_t *obj, unsigned int idx, }
/** - * \brief Set value for an entry of a #SND_CTL_ELEM_TYPE_INTEGER CTL element id/value - * \param obj CTL element id/value - * \param idx Entry index - * \param val value for the entry + * \brief Set value to given data for a specified channel as an element of + * integer type. + * \param[in] obj Data of an element. + * \param[in] idx index of channel in the control element + * \param[in] val Value for the channel. */ void snd_ctl_elem_value_set_integer(snd_ctl_elem_value_t *obj, unsigned int idx, long val) { @@ -2654,10 +2661,11 @@ void snd_ctl_elem_value_set_integer(snd_ctl_elem_value_t *obj, unsigned int idx, }
/** - * \brief Set value for an entry of a #SND_CTL_ELEM_TYPE_INTEGER64 CTL element id/value - * \param obj CTL element id/value - * \param idx Entry index - * \param val value for the entry + * \brief Set value to given data for a specified channel as an element of + * integer64 type. + * \param[in] obj Data of an element. + * \param[in] idx index of channel in the control element + * \param[in] val Value for the channel. */ void snd_ctl_elem_value_set_integer64(snd_ctl_elem_value_t *obj, unsigned int idx, long long val) { @@ -2667,10 +2675,12 @@ void snd_ctl_elem_value_set_integer64(snd_ctl_elem_value_t *obj, unsigned int id }
/** - * \brief Set value for an entry of a #SND_CTL_ELEM_TYPE_ENUMERATED CTL element id/value - * \param obj CTL element id/value - * \param idx Entry index - * \param val value for the entry + * \brief Set value to given data for a specified channel as an element of + * enumerated type. + * \param[in] obj Data of an element. + * \param[in] idx index of channel in the control element + * \param[in] val Value for the channel. This is an index of name set in the + * element. */ void snd_ctl_elem_value_set_enumerated(snd_ctl_elem_value_t *obj, unsigned int idx, unsigned int val) { @@ -2680,10 +2690,11 @@ void snd_ctl_elem_value_set_enumerated(snd_ctl_elem_value_t *obj, unsigned int i }
/** - * \brief Set value for an entry of a #SND_CTL_ELEM_TYPE_BYTES CTL element id/value - * \param obj CTL element id/value - * \param idx Entry index - * \param val value for the entry + * \brief Set value to given data for a specified channel as an element of + * bytes type. + * \param[in] obj Data of the element. + * \param[in] idx index of channel in the control element + * \param[in] val Value for the channel. */ void snd_ctl_elem_value_set_byte(snd_ctl_elem_value_t *obj, unsigned int idx, unsigned char val) { @@ -2693,10 +2704,10 @@ void snd_ctl_elem_value_set_byte(snd_ctl_elem_value_t *obj, unsigned int idx, un }
/** - * \brief Set CTL element #SND_CTL_ELEM_TYPE_BYTES value - * \param obj CTL handle - * \param data Bytes value - * \param size Size in bytes + * \brief Set values to given data as an element of bytes type. + * \param[in] obj Data of the element. + * \param[in] data Pointer to memory block for values. + * \param[in] size The number of bytes included in the memory block. */ void snd_ctl_elem_set_bytes(snd_ctl_elem_value_t *obj, void *data, size_t size) { @@ -2706,9 +2717,9 @@ void snd_ctl_elem_set_bytes(snd_ctl_elem_value_t *obj, void *data, size_t size) }
/** - * \brief Get value for a #SND_CTL_ELEM_TYPE_BYTES CTL element id/value - * \param obj CTL element id/value - * \return Pointer to CTL element value + * \brief Get memory block from given data as an element of bytes type. + * \param[in] obj Data of an element. + * \return Pointer to a memory block for values. */ const void * snd_ctl_elem_value_get_bytes(const snd_ctl_elem_value_t *obj) { @@ -2717,9 +2728,9 @@ const void * snd_ctl_elem_value_get_bytes(const snd_ctl_elem_value_t *obj) }
/** - * \brief Get value for a #SND_CTL_ELEM_TYPE_IEC958 CTL element id/value - * \param obj CTL element id/value - * \param ptr Pointer to returned CTL element value + * Get value from given data to given pointer as an element of IEC958 type. + * \param[in] obj Data of an element. + * \param[out] ptr Pointer to an IEC958 data. */ void snd_ctl_elem_value_get_iec958(const snd_ctl_elem_value_t *obj, snd_aes_iec958_t *ptr) { @@ -2728,9 +2739,9 @@ void snd_ctl_elem_value_get_iec958(const snd_ctl_elem_value_t *obj, snd_aes_iec9 }
/** - * \brief Set value for a #SND_CTL_ELEM_TYPE_IEC958 CTL element id/value - * \param obj CTL element id/value - * \param ptr Pointer to CTL element value + * Set value from given pointer to given data as an element of IEC958 type. + * \param obj Data of an element. + * \param ptr Pointer to an IEC958 data. */ void snd_ctl_elem_value_set_iec958(snd_ctl_elem_value_t *obj, const snd_aes_iec958_t *ptr) {
In ALSA control core, an element has some channels which can be changed by a single operation from userspace. Currently, control API uses 'idx' to indicate the position of channel, while 'index' is also used to identify an element in an element set. The usage of 'idx' for channel is a bit confusing.
This commit replaces 'idx' with 'channel' to help userspace developers to understand ALSA control interface.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- include/control.h | 21 ++++++------ src/control/control.c | 90 ++++++++++++++++++++++++++++----------------------- 2 files changed, 61 insertions(+), 50 deletions(-)
diff --git a/include/control.h b/include/control.h index 5fdf379..12859f0 100644 --- a/include/control.h +++ b/include/control.h @@ -455,16 +455,17 @@ void snd_ctl_elem_value_set_device(snd_ctl_elem_value_t *obj, unsigned int val); void snd_ctl_elem_value_set_subdevice(snd_ctl_elem_value_t *obj, unsigned int val); void snd_ctl_elem_value_set_name(snd_ctl_elem_value_t *obj, const char *val); void snd_ctl_elem_value_set_index(snd_ctl_elem_value_t *obj, unsigned int val); -int snd_ctl_elem_value_get_boolean(const snd_ctl_elem_value_t *obj, unsigned int idx); -long snd_ctl_elem_value_get_integer(const snd_ctl_elem_value_t *obj, unsigned int idx); -long long snd_ctl_elem_value_get_integer64(const snd_ctl_elem_value_t *obj, unsigned int idx); -unsigned int snd_ctl_elem_value_get_enumerated(const snd_ctl_elem_value_t *obj, unsigned int idx); -unsigned char snd_ctl_elem_value_get_byte(const snd_ctl_elem_value_t *obj, unsigned int idx); -void snd_ctl_elem_value_set_boolean(snd_ctl_elem_value_t *obj, unsigned int idx, long val); -void snd_ctl_elem_value_set_integer(snd_ctl_elem_value_t *obj, unsigned int idx, long val); -void snd_ctl_elem_value_set_integer64(snd_ctl_elem_value_t *obj, unsigned int idx, long long val); -void snd_ctl_elem_value_set_enumerated(snd_ctl_elem_value_t *obj, unsigned int idx, unsigned int val); -void snd_ctl_elem_value_set_byte(snd_ctl_elem_value_t *obj, unsigned int idx, unsigned char val); + +int snd_ctl_elem_value_get_boolean(const snd_ctl_elem_value_t *obj, unsigned int channel); +long snd_ctl_elem_value_get_integer(const snd_ctl_elem_value_t *obj, unsigned int channel); +long long snd_ctl_elem_value_get_integer64(const snd_ctl_elem_value_t *obj, unsigned int channel); +unsigned int snd_ctl_elem_value_get_enumerated(const snd_ctl_elem_value_t *obj, unsigned int channel); +unsigned char snd_ctl_elem_value_get_byte(const snd_ctl_elem_value_t *obj, unsigned int channel); +void snd_ctl_elem_value_set_boolean(snd_ctl_elem_value_t *obj, unsigned int channel, long val); +void snd_ctl_elem_value_set_integer(snd_ctl_elem_value_t *obj, unsigned int channel, long val); +void snd_ctl_elem_value_set_integer64(snd_ctl_elem_value_t *obj, unsigned int channel, long long val); +void snd_ctl_elem_value_set_enumerated(snd_ctl_elem_value_t *obj, unsigned int channel, unsigned int val); +void snd_ctl_elem_value_set_byte(snd_ctl_elem_value_t *obj, unsigned int channel, unsigned char val); void snd_ctl_elem_set_bytes(snd_ctl_elem_value_t *obj, void *data, size_t size); const void * snd_ctl_elem_value_get_bytes(const snd_ctl_elem_value_t *obj); void snd_ctl_elem_value_get_iec958(const snd_ctl_elem_value_t *obj, snd_aes_iec958_t *ptr); diff --git a/src/control/control.c b/src/control/control.c index 3ce14c2..69dbdc2 100644 --- a/src/control/control.c +++ b/src/control/control.c @@ -2566,141 +2566,151 @@ void snd_ctl_elem_value_set_index(snd_ctl_elem_value_t *obj, unsigned int val) * \brief Get value from given data for a specified channel as an element of * boolean type. * \param[in] obj Data of an element. - * \param[in] idx index of channel in the control element + * \param[in] channel Channel in the element. * \return Value for the channel. */ -int snd_ctl_elem_value_get_boolean(const snd_ctl_elem_value_t *obj, unsigned int idx) +int snd_ctl_elem_value_get_boolean(const snd_ctl_elem_value_t *obj, + unsigned int channel) { assert(obj); - assert(idx < ARRAY_SIZE(obj->value.integer.value)); - return obj->value.integer.value[idx]; + assert(channel < ARRAY_SIZE(obj->value.integer.value)); + return obj->value.integer.value[channel]; }
/** * \brief Get value from given data for a specified channel as an element of * integer type. * \param[in] obj Data of an element. - * \param[in] idx index of channel in the control element + * \param[in] channel Channel in the element. * \return Value for the channel. */ -long snd_ctl_elem_value_get_integer(const snd_ctl_elem_value_t *obj, unsigned int idx) +long snd_ctl_elem_value_get_integer(const snd_ctl_elem_value_t *obj, + unsigned int channel) { assert(obj); - assert(idx < ARRAY_SIZE(obj->value.integer.value)); - return obj->value.integer.value[idx]; + assert(channel < ARRAY_SIZE(obj->value.integer.value)); + return obj->value.integer.value[channel]; }
/** * \brief Get value from given data for a specified channel as an element of * integer64 type. * \param[in] obj Data of an element. - * \param[in] idx index of channel in the control element + * \param[in] channel Channel in the element. * \return Value for the channel. */ -long long snd_ctl_elem_value_get_integer64(const snd_ctl_elem_value_t *obj, unsigned int idx) +long long snd_ctl_elem_value_get_integer64(const snd_ctl_elem_value_t *obj, + unsigned int channel) { assert(obj); - assert(idx < ARRAY_SIZE(obj->value.integer64.value)); - return obj->value.integer64.value[idx]; + assert(channel < ARRAY_SIZE(obj->value.integer64.value)); + return obj->value.integer64.value[channel]; }
/** * \brief Get value from given data for a specified channel as an element of * enumerated type. * \param[in] obj Data of an element. - * \param[in] idx index of channel in the control element + * \param[in] channel Channel in the element. * \return Value for the channel. This is an index of name set in the element. */ -unsigned int snd_ctl_elem_value_get_enumerated(const snd_ctl_elem_value_t *obj, unsigned int idx) +unsigned int snd_ctl_elem_value_get_enumerated(const snd_ctl_elem_value_t *obj, + unsigned int channel) { assert(obj); - assert(idx < ARRAY_SIZE(obj->value.enumerated.item)); - return obj->value.enumerated.item[idx]; + assert(channel < ARRAY_SIZE(obj->value.enumerated.item)); + return obj->value.enumerated.item[channel]; }
/** * \brief Get value from given data for a specified channel as an element of * bytes type. * \param[in] obj Data of an element. - * \param[in] idx index of channel in the control element + * \param[in] channel Channel in the element. * \return Value for the channel. */ -unsigned char snd_ctl_elem_value_get_byte(const snd_ctl_elem_value_t *obj, unsigned int idx) +unsigned char snd_ctl_elem_value_get_byte(const snd_ctl_elem_value_t *obj, + unsigned int channel) { assert(obj); - assert(idx < ARRAY_SIZE(obj->value.bytes.data)); - return obj->value.bytes.data[idx]; + assert(channel < ARRAY_SIZE(obj->value.bytes.data)); + return obj->value.bytes.data[channel]; }
/** * \brief Set value to given data for a specified channel as an element of * boolean type. * \param[in] obj Data of an element. - * \param[in] idx index of channel in the control element + * \param[in] channel Channel in the element. * \param[in] val Value for the channel. */ -void snd_ctl_elem_value_set_boolean(snd_ctl_elem_value_t *obj, unsigned int idx, long val) +void snd_ctl_elem_value_set_boolean(snd_ctl_elem_value_t *obj, + unsigned int channel, long val) { assert(obj); - assert(idx < ARRAY_SIZE(obj->value.integer.value)); - obj->value.integer.value[idx] = val; + assert(channel < ARRAY_SIZE(obj->value.integer.value)); + obj->value.integer.value[channel] = val; }
/** * \brief Set value to given data for a specified channel as an element of * integer type. * \param[in] obj Data of an element. - * \param[in] idx index of channel in the control element + * \param[in] channel Channel in the element. * \param[in] val Value for the channel. */ -void snd_ctl_elem_value_set_integer(snd_ctl_elem_value_t *obj, unsigned int idx, long val) +void snd_ctl_elem_value_set_integer(snd_ctl_elem_value_t *obj, + unsigned int channel, long val) { assert(obj); - assert(idx < ARRAY_SIZE(obj->value.integer.value)); - obj->value.integer.value[idx] = val; + assert(channel < ARRAY_SIZE(obj->value.integer.value)); + obj->value.integer.value[channel] = val; }
/** * \brief Set value to given data for a specified channel as an element of * integer64 type. * \param[in] obj Data of an element. - * \param[in] idx index of channel in the control element + * \param[in] channel Channel in the element. * \param[in] val Value for the channel. */ -void snd_ctl_elem_value_set_integer64(snd_ctl_elem_value_t *obj, unsigned int idx, long long val) +void snd_ctl_elem_value_set_integer64(snd_ctl_elem_value_t *obj, + unsigned int channel, long long val) { assert(obj); - assert(idx < ARRAY_SIZE(obj->value.integer64.value)); - obj->value.integer64.value[idx] = val; + assert(channel < ARRAY_SIZE(obj->value.integer64.value)); + obj->value.integer64.value[channel] = val; }
/** * \brief Set value to given data for a specified channel as an element of * enumerated type. * \param[in] obj Data of an element. - * \param[in] idx index of channel in the control element + * \param[in] channel Channel in the element. * \param[in] val Value for the channel. This is an index of name set in the * element. */ -void snd_ctl_elem_value_set_enumerated(snd_ctl_elem_value_t *obj, unsigned int idx, unsigned int val) +void snd_ctl_elem_value_set_enumerated(snd_ctl_elem_value_t *obj, + unsigned int channel, unsigned int val) { assert(obj); - assert(idx < ARRAY_SIZE(obj->value.enumerated.item)); - obj->value.enumerated.item[idx] = val; + assert(channel < ARRAY_SIZE(obj->value.enumerated.item)); + obj->value.enumerated.item[channel] = val; }
/** * \brief Set value to given data for a specified channel as an element of * bytes type. * \param[in] obj Data of the element. - * \param[in] idx index of channel in the control element + * \param[in] channel Channel in the element. * \param[in] val Value for the channel. */ -void snd_ctl_elem_value_set_byte(snd_ctl_elem_value_t *obj, unsigned int idx, unsigned char val) +void snd_ctl_elem_value_set_byte(snd_ctl_elem_value_t *obj, + unsigned int channel, unsigned char val) { assert(obj); - assert(idx < ARRAY_SIZE(obj->value.bytes.data)); - obj->value.bytes.data[idx] = val; + assert(channel < ARRAY_SIZE(obj->value.bytes.data)); + obj->value.bytes.data[channel] = val; }
/**
ALSA Ctl core allows userspace applications to add elements of bytes type, while there's no APIs for this purpose in alsa-lib.
This commit adds the missing function.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- src/control/control.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+)
diff --git a/src/control/control.c b/src/control/control.c index 69dbdc2..17a2620 100644 --- a/src/control/control.c +++ b/src/control/control.c @@ -488,6 +488,51 @@ int snd_ctl_elem_add_enumerated(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, }
/** + * \brief Create and add an user-defined control element of bytes type. + * \param[in] ctl CTL handle. + * \param[in,out] id ID of the new control element. + * \param[in] channels The number of channels which a control element includes. + * \return Zero on success, otherwise a negative error code. + * + * This function creates an user control element, This control element is not + * controlled by device drivers in kernel but that is handled by the same way as + * the control elements added by the device drivers. + * + * The fields of \a id, except for numid, must be set with unique values to + * identify the new element. After returning, all fields of \a id are filled. + * + * All of channels in the new element are locked. The value of each channel is + * initialized with zero. + * + * \par Errors: + * <dl> + * <dt>-EBUSY<dd>A control element with ID \a id already exists. + * <dt>-EINVAL<dd>\a channels is not between 1 to 511. + * <dt>-ENOMEM<dd>Out of memory, or there are too many user control elements. + * <dt>-ENXIO<dd>This driver does not support (bytes) user controls. + * <dt>-ENODEV<dd>Device unplugged. + * </dl> + * + * \par Compatibility: + * This function is added in version 1.1.1. + */ +int snd_ctl_elem_add_bytes(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, + unsigned int channels) +{ + snd_ctl_elem_info_t *info; + + assert(ctl && id && id->name[0]); + + snd_ctl_elem_info_alloca(&info); + info->id = *id; + info->type = SND_CTL_ELEM_TYPE_BYTES; + info->owner = 1; + info->count = channels; + + return ctl->ops->element_add(ctl, info); +} + +/** * \brief Create and add a user-defined control element of IEC958 type. * \param[in] ctl CTL handle * \param[in,out] id ID of the new control element.
Takashi Sakamoto wrote:
ALSA Ctl core allows userspace applications to add elements of bytes type, while there's no APIs for this purpose in alsa-lib.
This commit adds the missing function.
/**
- \brief Create and add an user-defined control element of bytes type.
- \param[in] ctl CTL handle.
- \param[in,out] id ID of the new control element.
- \param[in] channels The number of channels which a control element includes.
For this control type, "count" might be a better name. Or at least say in the description that this is the number of bytes.
Regards, Clemens
Hi,
On Feb 23 2016 17:31, Clemens Ladisch wrote:
Takashi Sakamoto wrote:
ALSA Ctl core allows userspace applications to add elements of bytes type, while there's no APIs for this purpose in alsa-lib.
This commit adds the missing function.
/**
- \brief Create and add an user-defined control element of bytes type.
- \param[in] ctl CTL handle.
- \param[in,out] id ID of the new control element.
- \param[in] channels The number of channels which a control element includes.
For this control type, "count" might be a better name. Or at least say in the description that this is the number of bytes.
For the name of this variable, I don't mind using 'count'. But then, in next commit, snd_ctl_elem_add_bytes_set() has two arguments named 'count'. And the consistency of API design is lost a bit.
I think that naming the variables depends on interpretation of 'struct snd_ctl_elem_value', therefore it mostly depends on taste of each developers. For example, to 'bytes' type element set, we can interpret 'struct snd_ctl_elem_value.bytes' as either 'byte array in an element' or 'data for each channels with int8_t (=char) value for an element'.
So I propose the design of ALSA control core. If possible, I'd like to follow the design when adding new APIs for a consistent representation. If the proposed design is not propper, we can change the design for better shape. (but it will sometimes be a dull work depending on taste of each developers.)
And, I note that the name of 'channel' is picked up from Mixer APIs in alsa-lib. It doesn't come from my brain ;)
Thanks
Takashi Sakamoto
On Tue, 23 Feb 2016 10:22:50 +0100, Takashi Sakamoto wrote:
Hi,
On Feb 23 2016 17:31, Clemens Ladisch wrote:
Takashi Sakamoto wrote:
ALSA Ctl core allows userspace applications to add elements of bytes type, while there's no APIs for this purpose in alsa-lib.
This commit adds the missing function.
/**
- \brief Create and add an user-defined control element of bytes type.
- \param[in] ctl CTL handle.
- \param[in,out] id ID of the new control element.
- \param[in] channels The number of channels which a control element includes.
For this control type, "count" might be a better name. Or at least say in the description that this is the number of bytes.
For the name of this variable, I don't mind using 'count'. But then, in next commit, snd_ctl_elem_add_bytes_set() has two arguments named 'count'. And the consistency of API design is lost a bit.
How about naming it a bit more descriptive way, e.g. count_xxx? "channel" isn't clearer than "count", IMO.
I think that naming the variables depends on interpretation of 'struct snd_ctl_elem_value', therefore it mostly depends on taste of each developers. For example, to 'bytes' type element set, we can interpret 'struct snd_ctl_elem_value.bytes' as either 'byte array in an element' or 'data for each channels with int8_t (=char) value for an element'.
So I propose the design of ALSA control core. If possible, I'd like to follow the design when adding new APIs for a consistent representation. If the proposed design is not propper, we can change the design for better shape. (but it will sometimes be a dull work depending on taste of each developers.)
And, I note that the name of 'channel' is picked up from Mixer APIs in alsa-lib. It doesn't come from my brain ;)
The mixer API is indeed focused on the mixer element, thus the concept of channel would match in most cases (but not all, sure). But control API is designed a bit more generically, so I understand Clemens' concern, too.
thanks,
Takashi
ALSA Ctl core allows userspace applications to add element sets. Currently, some APIs use the functionality to add a single element.
This commit adds functions to add element set for each type. Some existed functions are simple wrappers of the new ones to add one elements.
I note that some old APIs get static id variables, although Linux kernel 4.1 or later fills id field with all parameters. In this commit, old APIs are what they're to keep signature, while new APIs get non-static id parameters.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- include/control.h | 34 ++++++- src/control/control.c | 267 ++++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 245 insertions(+), 56 deletions(-)
diff --git a/include/control.h b/include/control.h index 12859f0..cf3ff1b 100644 --- a/include/control.h +++ b/include/control.h @@ -423,11 +423,37 @@ void snd_ctl_elem_info_set_subdevice(snd_ctl_elem_info_t *obj, unsigned int val) void snd_ctl_elem_info_set_name(snd_ctl_elem_info_t *obj, const char *val); void snd_ctl_elem_info_set_index(snd_ctl_elem_info_t *obj, unsigned int val);
-int snd_ctl_elem_add_integer(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, unsigned int count, long imin, long imax, long istep); -int snd_ctl_elem_add_integer64(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, unsigned int count, long long imin, long long imax, long long istep); -int snd_ctl_elem_add_boolean(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, unsigned int count); -int snd_ctl_elem_add_enumerated(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, unsigned int count, unsigned int items, const char *const names[]); +int snd_ctl_elem_add_integer_set(snd_ctl_t *ctl, snd_ctl_elem_id_t *id, + unsigned int count, unsigned int channels, + long min, long max, long step); +int snd_ctl_elem_add_integer64_set(snd_ctl_t *ctl, snd_ctl_elem_id_t *id, + unsigned int count, unsigned int channels, + long long min, long long max, + long long step); +int snd_ctl_elem_add_boolean_set(snd_ctl_t *ctl, snd_ctl_elem_id_t *id, + unsigned int count, unsigned int channels); +int snd_ctl_elem_add_enumerated_set(snd_ctl_t *ctl, snd_ctl_elem_id_t *id, + unsigned int count, unsigned int channels, + unsigned int items, + const char *const names[]); +int snd_ctl_elem_add_bytes_set(snd_ctl_t *ctl, snd_ctl_elem_id_t *id, + unsigned int count, unsigned int channels); + +int snd_ctl_elem_add_integer(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, + unsigned int channels, + long min, long max, long step); +int snd_ctl_elem_add_integer64(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, + unsigned int channels, + long long min, long long max, long long step); +int snd_ctl_elem_add_boolean(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, + unsigned int channels); +int snd_ctl_elem_add_enumerated(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, + unsigned int channels, unsigned int items, + const char *const names[]); +int snd_ctl_elem_add_bytes(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, + unsigned int channels); int snd_ctl_elem_add_iec958(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id); + int snd_ctl_elem_remove(snd_ctl_t *ctl, snd_ctl_elem_id_t *id);
size_t snd_ctl_elem_value_sizeof(void); diff --git a/src/control/control.c b/src/control/control.c index 17a2620..a752972 100644 --- a/src/control/control.c +++ b/src/control/control.c @@ -261,23 +261,25 @@ int snd_ctl_elem_info(snd_ctl_t *ctl, snd_ctl_elem_info_t *info) }
/** - * \brief Create and add an user-defined control element of integer type. + * \brief Create and add some user-defined control elements of integer type. * \param[in] ctl CTL handle * \param[in,out] id ID of the new control element. + * \param[in] count The number of control elements added by this operation. * \param[in] channels The number of channels which a control element includes. * \param[in] min Minimum value for the value of each channel. * \param[in] max Maximum value for the value of each channel. * \param[in] step The step of value for the value of each channel. * \return Zero on success, otherwise a negative error code. * - * This function creates a user control element. This control element is not - * controlled by device drivers in kernel, but can be handled by the same way as - * usual control elements added by the device drivers. + * This function creates some user control elements. These control elements are + * not controlled by device drivers in kernel, but can be handled by the same + * way as usual control elements added by the device drivers. * * The fields of \a id, except for numid, must be set with unique values to - * identify the new element. After returning, all fields of \a id are filled. + * identify the first new element. After returning, all fields of \a id are + * filled. * - * All of channels in the new element are locked. The value of each channel is + * All of channels in the new elements are locked. The value of each channel is * initialized with the minimum value. * * \par Errors: @@ -288,103 +290,145 @@ int snd_ctl_elem_info(snd_ctl_t *ctl, snd_ctl_elem_info_t *info) * <dt>-ENXIO<dd>This driver does not support (integer) user controls. * <dt>-ENODEV<dd>Device unplugged. * </dl> + * + * \par Compatibility: + * This function is added in version 1.1.1. */ -int snd_ctl_elem_add_integer(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, - unsigned int channels, long min, long max, - long step) +int snd_ctl_elem_add_integer_set(snd_ctl_t *ctl, snd_ctl_elem_id_t *id, + unsigned int count, unsigned int channels, + long min, long max, long step) { snd_ctl_elem_info_t *info; snd_ctl_elem_value_t *val; unsigned int i; + unsigned int j; + unsigned int numid; int err;
assert(ctl && id && id->name[0]); + snd_ctl_elem_info_alloca(&info); info->id = *id; info->type = SND_CTL_ELEM_TYPE_INTEGER; info->access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE; + info->owner = count; info->count = channels; info->value.integer.min = min; info->value.integer.max = max; info->value.integer.step = step; + err = ctl->ops->element_add(ctl, info); if (err < 0) return err; + numid = snd_ctl_elem_id_get_numid(&info->id); + + /* Set initial value to all of chanenls in all of elements. */ snd_ctl_elem_value_alloca(&val); val->id = info->id; - for (i = 0; i < channels; i++) - val->value.integer.value[i] = min; - err = ctl->ops->element_write(ctl, val); - return err; + for (i = 0; i < count; i++) { + snd_ctl_elem_id_set_numid(&val->id, numid + i); + + for (j = 0; j < channels; j++) + val->value.integer.value[j] = min; + + err = ctl->ops->element_write(ctl, val); + if (err < 0) + return err; + } + + *id = info->id; + return 0; }
/** - * \brief Create and add an user-defined control element of integer64 type. + * \brief Create and add some user-defined control elements of integer64 type. * \param[in] ctl CTL handle * \param[in,out] id ID of the new control element. + * \param[in] count The number of control elements added by this operation. * \param[in] channels The number of channels which a control element includes. * \param[in] min Minimum value for the value of each channel * \param[in] max Maximum value for the value of each channel * \param[in] step Step of value for the value of each channel * \return Zero on success, otherwise a negative error code. * - * This function creates a user control element. This control element is not - * controlled by device drivers in kernel, but can be handled by the same way as - * usual control elements added by the device drivers. + * This function creates some user control element. These control elements are + * not controlled by device drivers in kernel, but can be handled by the same + * way as usual control elements added by the device drivers. * * The fields of \a id, except for numid, must be set with unique values to * identify the new element. After returning, all fields of \a id are filled. * - * All of channels in the new element are locked. The value of each channel is + * All of channels in the new elements are locked. The value of each channel is * initialized with the minimum value. * * \par Errors: * <dl> * <dt>-EBUSY<dd>A control element with ID \a id already exists. - * <dt>-EINVAL<dd>ID has no name, or \a channels is not between 1 to 63. + * <dt>-EINVAL<dd>ID has no name, or \a channels is not between 1 to 127. * <dt>-ENOMEM<dd>Out of memory, or there are too many user control elements. - * <dt>-ENXIO<dd>This driver does not support (integer64) user controls. + * <dt>-ENXIO<dd>This driver does not support (integer) user controls. * <dt>-ENODEV<dd>Device unplugged. * </dl> + * + * \par Compatibility: + * This function is added in version 1.1.1. */ -int snd_ctl_elem_add_integer64(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, - unsigned int channels, long long min, - long long max, long long step) +int snd_ctl_elem_add_integer64_set(snd_ctl_t *ctl, snd_ctl_elem_id_t *id, + unsigned int count, unsigned int channels, + long long min, long long max, long long step) { snd_ctl_elem_info_t *info; snd_ctl_elem_value_t *val; unsigned int i; + unsigned int j; + unsigned int numid; int err;
assert(ctl && id && id->name[0]); + snd_ctl_elem_info_alloca(&info); info->id = *id; info->type = SND_CTL_ELEM_TYPE_INTEGER64; + info->owner = count; info->count = channels; info->value.integer64.min = min; info->value.integer64.max = max; info->value.integer64.step = step; + err = ctl->ops->element_add(ctl, info); if (err < 0) return err; + numid = snd_ctl_elem_id_get_numid(&info->id); + + /* Set initial value to all of chanenls in all of elements. */ snd_ctl_elem_value_alloca(&val); val->id = info->id; - for (i = 0; i < channels; i++) - val->value.integer64.value[i] = min; - err = ctl->ops->element_write(ctl, val); - return err; + for (i = 0; i < count; i++) { + snd_ctl_elem_id_set_numid(&val->id, numid + i); + + for (j = 0; j < channels; j++) + val->value.integer64.value[i] = min; + + err = ctl->ops->element_write(ctl, val); + if (err < 0) + return err; + } + + *id = info->id; + return 0; }
/** - * \brief Create and add an user-defined control element of boolean type. + * \brief Create and add some user-defined control elements of boolean type. * \param[in] ctl CTL handle * \param[in,out] id ID of the new control element. + * \param[in] count The number of control elements added by this operation. * \param[in] channels The number of channels which a control element includes. * - * This function creates a user control element. This control element is not - * controlled by device drivers in kernel, but can be handled by the same way as - * usual control elements added by the device drivers. + * This function creates some user control elements. These control elements are + * not controlled by device drivers in kernel, but can be handled by the same + * way as usual control elements added by the device drivers. * * The fields of \a id, except for numid, must be set with unique values to * identify the new element. After returning, all fields of \a id are filled. @@ -400,34 +444,46 @@ int snd_ctl_elem_add_integer64(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, * <dt>-ENXIO<dd>This driver does not support (boolean) user controls. * <dt>-ENODEV<dd>Device unplugged. * </dl> + * + * \par Compatibility: + * This function is added in version 1.1.1. */ -int snd_ctl_elem_add_boolean(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, - unsigned int channels) +int snd_ctl_elem_add_boolean_set(snd_ctl_t *ctl, snd_ctl_elem_id_t *id, + unsigned int count, unsigned int channels) { snd_ctl_elem_info_t *info; + int err;
assert(ctl && id && id->name[0]); + snd_ctl_elem_info_alloca(&info); info->id = *id; info->type = SND_CTL_ELEM_TYPE_BOOLEAN; + info->owner = count; info->count = channels; info->value.integer.min = 0; info->value.integer.max = 1; - return ctl->ops->element_add(ctl, info); + + err = ctl->ops->element_add(ctl, info); + if (err >= 0) + *id = info->id; + + return err; }
/** - * \brief Create and add a user-defined control element of enumerated type. + * \brief Create and add some user-defined control elements of enumerated type. * \param[in] ctl CTL handle * \param[in,out] id ID of the new control element. + * \param[in] count The number of control elements added by this operation. * \param[in] channels The number of channels which a control element includes. * \param[in] items Range of possible values (0 ... \a items - 1). * \param[in] names An array containing \a items strings. * \return Zero on success, otherwise a negative error code. * - * This function creates a user control element. This control element is not - * controlled by device drivers in kernel, but can be handled by the same way as - * usual control elements added by the device drivers. + * This function creates some user control elements. These control elements are + * not controlled by device drivers in kernel, but can be handled by the same + * way as usual control elements added by the device drivers. * * The fields of \a id, except for numid, must be set to unique values that * identify the new element. @@ -447,11 +503,12 @@ int snd_ctl_elem_add_boolean(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, * </dl> * * \par Compatibility: - * This function is added in ALSA 1.0.25. + * This function is added in version 1.1.1. */ -int snd_ctl_elem_add_enumerated(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, - unsigned int channels, unsigned int items, - const char *const names[]) +int snd_ctl_elem_add_enumerated_set(snd_ctl_t *ctl, snd_ctl_elem_id_t *id, + unsigned int count, unsigned int channels, + unsigned int items, + const char *const names[]) { snd_ctl_elem_info_t *info; unsigned int i, bytes; @@ -463,6 +520,7 @@ int snd_ctl_elem_add_enumerated(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, snd_ctl_elem_info_alloca(&info); info->id = *id; info->type = SND_CTL_ELEM_TYPE_ENUMERATED; + info->owner = count; info->count = channels; info->value.enumerated.items = items;
@@ -481,6 +539,8 @@ int snd_ctl_elem_add_enumerated(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, }
err = ctl->ops->element_add(ctl, info); + if (err >= 0) + *id = info->id;
free(buf);
@@ -488,20 +548,22 @@ int snd_ctl_elem_add_enumerated(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, }
/** - * \brief Create and add an user-defined control element of bytes type. + * \brief Create and add some user-defined control elements of bytes type. * \param[in] ctl CTL handle. * \param[in,out] id ID of the new control element. + * \param[in] count The number of control elements added by this operation. * \param[in] channels The number of channels which a control element includes. * \return Zero on success, otherwise a negative error code. * - * This function creates an user control element, This control element is not - * controlled by device drivers in kernel but that is handled by the same way as - * the control elements added by the device drivers. + * This function creates some user control element, This control elements are + * not controlled by device drivers in kernel but that is handled by the same + * way as usual control elements added by the device drivers. * * The fields of \a id, except for numid, must be set with unique values to - * identify the new element. After returning, all fields of \a id are filled. + * identify the first new element. After returning, all fields of \a id are + * filled. * - * All of channels in the new element are locked. The value of each channel is + * All of channels in the new elements are locked. The value of each channel is * initialized with zero. * * \par Errors: @@ -516,20 +578,121 @@ int snd_ctl_elem_add_enumerated(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, * \par Compatibility: * This function is added in version 1.1.1. */ -int snd_ctl_elem_add_bytes(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, - unsigned int channels) +int snd_ctl_elem_add_bytes_set(snd_ctl_t *ctl, snd_ctl_elem_id_t *id, + unsigned int count, unsigned int channels) { snd_ctl_elem_info_t *info; + int err;
assert(ctl && id && id->name[0]);
snd_ctl_elem_info_alloca(&info); info->id = *id; info->type = SND_CTL_ELEM_TYPE_BYTES; - info->owner = 1; + info->owner = count; info->count = channels;
- return ctl->ops->element_add(ctl, info); + err = ctl->ops->element_add(ctl, info); + if (err >= 0) + *id = info->id; + + return err; +} + +/** + * \brief Create and add an user-defined control element of integer type. + * + * This function is a wrapper function to snd_ctl_elem_add_integer_set() for + * single control element. + */ +int snd_ctl_elem_add_integer(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, + unsigned int channels, + long min, long max, long step) +{ + snd_ctl_elem_id_t *local_id; + + snd_ctl_elem_id_alloca(&local_id); + *local_id = *id; + + return snd_ctl_elem_add_integer_set(ctl, local_id, 1, channels, + min, max, step); +} + +/** + * \brief Create and add an user-defined control element of integer64 type. + * + * This function is a wrapper function to snd_ctl_elem_add_integer64_set() for + * single control element. + */ +int snd_ctl_elem_add_integer64(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, + unsigned int channels, + long long min, long long max, long long step) +{ + snd_ctl_elem_id_t *local_id; + + snd_ctl_elem_id_alloca(&local_id); + *local_id = *id; + + return snd_ctl_elem_add_integer64_set(ctl, local_id, 1, channels, + min, max, step); +} + +/** + * \brief Create and add an user-defined control element of boolean type. + * + * This function is a wrapper function to snd_ctl_elem_add_boolean_set() for + * single control element. + */ +int snd_ctl_elem_add_boolean(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, + unsigned int channels) +{ + snd_ctl_elem_id_t *local_id; + + snd_ctl_elem_id_alloca(&local_id); + *local_id = *id; + + return snd_ctl_elem_add_boolean_set(ctl, local_id, 1, channels); +} + +/** + * \brief Create and add a user-defined control element of enumerated type. + * + * This function is a wrapper function to snd_ctl_elem_add_enumerated_set() for + * single control element. + * + * This function is added in version 1.0.25. + */ +int snd_ctl_elem_add_enumerated(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, + unsigned int channels, unsigned int items, + const char *const names[]) +{ + snd_ctl_elem_id_t *local_id; + + snd_ctl_elem_id_alloca(&local_id); + *local_id = *id; + + return snd_ctl_elem_add_enumerated_set(ctl, local_id, 1, channels, + items, names); +} + +/** + * \brief Create and add a user-defined control element of bytes type. + * + * This function is a wrapper function to snd_ctl_elem_add_bytes_set() for + * single control element. + * + * \par Compatibility: + * This function is added in version 1.1.1. + */ +int snd_ctl_elem_add_bytes(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, + unsigned int channels) +{ + snd_ctl_elem_id_t *local_id; + + snd_ctl_elem_id_alloca(&local_id); + *local_id = *id; + + return snd_ctl_elem_add_bytes_set(ctl, local_id, 1, channels); }
/**
participants (3)
-
Clemens Ladisch
-
Takashi Iwai
-
Takashi Sakamoto