aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Wilson <ksattic@gmail.com>2011-06-04 00:57:17 -0700
committerSimon Wilson <ksattic@gmail.com>2011-06-04 00:57:17 -0700
commitd2cb5030091760256fcc8e755e686aab746b7697 (patch)
treeff947eba8d70c759185150907d2e77829ad4bcdc
parent98be0055ff47332102cf7b9fc35b962e3b69a22a (diff)
Improve mixer support
- support get/set of multiple values - add parameter checking to functions - add api function to get control type - add tinymix utility to list mixer controls
-rw-r--r--Android.mk9
-rw-r--r--Makefile5
-rw-r--r--include/tinyalsa/asoundlib.h32
-rw-r--r--mixer.c150
-rw-r--r--tinymix.c61
5 files changed, 202 insertions, 55 deletions
diff --git a/Android.mk b/Android.mk
index d812319..9dbef10 100644
--- a/Android.mk
+++ b/Android.mk
@@ -17,3 +17,12 @@ LOCAL_SHARED_LIBRARIES:= libcutils libutils libtinyalsa
LOCAL_MODULE_TAGS := optional
include $(BUILD_EXECUTABLE)
+
+include $(CLEAR_VARS)
+LOCAL_C_INCLUDES:= external/tinyalsa/include
+LOCAL_SRC_FILES:= tinymix.c
+LOCAL_MODULE := tinymix
+LOCAL_SHARED_LIBRARIES:= libcutils libutils libtinyalsa
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_EXECUTABLE)
diff --git a/Makefile b/Makefile
index ac40b6b..2013d59 100644
--- a/Makefile
+++ b/Makefile
@@ -3,11 +3,14 @@ INC = include
OBJECTS = mixer.o pcm.o
LIB = libtinyalsa.so
-all: $(LIB) tinyplay
+all: $(LIB) tinyplay tinymix
tinyplay: $(LIB) tinyplay.o
gcc tinyplay.o -L. -ltinyalsa -o tinyplay
+tinymix: $(LIB) tinymix.o
+ gcc tinymix.o -L. -ltinyalsa -o tinymix
+
$(LIB): $(OBJECTS)
gcc -shared $(OBJECTS) -o $(LIB)
diff --git a/include/tinyalsa/asoundlib.h b/include/tinyalsa/asoundlib.h
index f9920ce..34e5f8c 100644
--- a/include/tinyalsa/asoundlib.h
+++ b/include/tinyalsa/asoundlib.h
@@ -56,6 +56,19 @@ struct pcm_config {
enum pcm_format format;
};
+/* Mixer control types */
+enum mixer_ctl_type {
+ MIXER_CTL_TYPE_BOOL,
+ MIXER_CTL_TYPE_INT,
+ MIXER_CTL_TYPE_ENUM,
+ MIXER_CTL_TYPE_BYTE,
+ MIXER_CTL_TYPE_IEC958,
+ MIXER_CTL_TYPE_INT64,
+ MIXER_CTL_TYPE_UNKNOWN,
+
+ MIXER_CTL_TYPE_MAX,
+};
+
/* Open and close a stream */
struct pcm *pcm_open(unsigned int card, unsigned int device,
unsigned int flags, struct pcm_config *config);
@@ -97,20 +110,25 @@ struct mixer *mixer_open(unsigned int card);
void mixer_close(struct mixer *mixer);
/* Obtain mixer controls */
-int mixer_get_num_ctls(struct mixer *mixer);
+unsigned int mixer_get_num_ctls(struct mixer *mixer);
struct mixer_ctl *mixer_get_ctl(struct mixer *mixer, unsigned int id);
struct mixer_ctl *mixer_get_ctl_by_name(struct mixer *mixer, const char *name);
+/* Get info about mixer controls */
+int mixer_ctl_get_name(struct mixer_ctl *ctl, char *name, unsigned int size);
+enum mixer_ctl_type mixer_ctl_get_type(struct mixer_ctl *ctl);
+const char *mixer_ctl_get_type_string(struct mixer_ctl *ctl);
+unsigned int mixer_ctl_get_num_values(struct mixer_ctl *ctl);
+
/* Set and get mixer controls */
-int mixer_ctl_get_percent(struct mixer_ctl *ctl);
-int mixer_ctl_set_percent(struct mixer_ctl *ctl, int percent);
+int mixer_ctl_get_percent(struct mixer_ctl *ctl, unsigned int id);
+int mixer_ctl_set_percent(struct mixer_ctl *ctl, unsigned int id, int percent);
-int mixer_ctl_get_int(struct mixer_ctl *ctl);
-int mixer_ctl_set_int(struct mixer_ctl *ctl, int);
-int mixer_ctl_get_step(struct mixer_ctl *ctl);
+int mixer_ctl_get_int(struct mixer_ctl *ctl, unsigned int id);
+int mixer_ctl_set_int(struct mixer_ctl *ctl, unsigned int id, int value);
int mixer_ctl_get_enum(struct mixer_ctl *ctl, const char *string, unsigned int size);
-int mixer_ctl_set_enum(struct mixer_ctl *ctl, unsigned int id);
+int mixer_ctl_set_enum(struct mixer_ctl *ctl, unsigned int value);
int mixer_ctl_set_enum_by_name(struct mixer_ctl *ctl, const char *string);
#endif
diff --git a/mixer.c b/mixer.c
index 97f4beb..c2fd78c 100644
--- a/mixer.c
+++ b/mixer.c
@@ -42,35 +42,6 @@
#include <tinyalsa/asoundlib.h>
-static const char *elem_iface_name(snd_ctl_elem_iface_t n)
-{
- switch (n) {
- case SNDRV_CTL_ELEM_IFACE_CARD: return "CARD";
- case SNDRV_CTL_ELEM_IFACE_HWDEP: return "HWDEP";
- case SNDRV_CTL_ELEM_IFACE_MIXER: return "MIXER";
- case SNDRV_CTL_ELEM_IFACE_PCM: return "PCM";
- case SNDRV_CTL_ELEM_IFACE_RAWMIDI: return "MIDI";
- case SNDRV_CTL_ELEM_IFACE_TIMER: return "TIMER";
- case SNDRV_CTL_ELEM_IFACE_SEQUENCER: return "SEQ";
- default: return "???";
- }
-}
-
-static const char *elem_type_name(snd_ctl_elem_type_t n)
-{
- switch (n) {
- case SNDRV_CTL_ELEM_TYPE_NONE: return "NONE";
- case SNDRV_CTL_ELEM_TYPE_BOOLEAN: return "BOOL";
- case SNDRV_CTL_ELEM_TYPE_INTEGER: return "INT32";
- case SNDRV_CTL_ELEM_TYPE_ENUMERATED: return "ENUM";
- case SNDRV_CTL_ELEM_TYPE_BYTES: return "BYTES";
- case SNDRV_CTL_ELEM_TYPE_IEC958: return "IEC958";
- case SNDRV_CTL_ELEM_TYPE_INTEGER64: return "INT64";
- default: return "???";
- }
-}
-
-
struct mixer_ctl {
struct mixer *mixer;
struct snd_ctl_elem_info *info;
@@ -88,6 +59,11 @@ void mixer_close(struct mixer *mixer)
{
unsigned int n,m;
+ if (!mixer) {
+ errno = EINVAL;
+ return;
+ }
+
if (mixer->fd >= 0)
close(mixer->fd);
@@ -189,13 +165,23 @@ fail:
return 0;
}
-int mixer_get_num_ctls(struct mixer *mixer)
+unsigned int mixer_get_num_ctls(struct mixer *mixer)
{
+ if (!mixer) {
+ errno = EINVAL;
+ return -1;
+ }
+
return mixer->count;
}
struct mixer_ctl *mixer_get_ctl(struct mixer *mixer, unsigned int id)
{
+ if (!mixer) {
+ errno = EINVAL;
+ return NULL;
+ }
+
if (id < mixer->count)
return mixer->ctl + id;
@@ -205,6 +191,12 @@ struct mixer_ctl *mixer_get_ctl(struct mixer *mixer, unsigned int id)
struct mixer_ctl *mixer_get_ctl_by_name(struct mixer *mixer, const char *name)
{
unsigned int n;
+
+ if (!mixer) {
+ errno = EINVAL;
+ return NULL;
+ }
+
for (n = 0; n < mixer->count; n++)
if (!strcmp(name, (char*) mixer->info[n].id.name))
return mixer->ctl + n;
@@ -212,6 +204,63 @@ struct mixer_ctl *mixer_get_ctl_by_name(struct mixer *mixer, const char *name)
return NULL;
}
+int mixer_ctl_get_name(struct mixer_ctl *ctl, char *name, unsigned int size)
+{
+ if (!ctl || !name || (size == 0)) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ strncpy(name, (char *)ctl->info->id.name, size);
+ return 0;
+}
+
+enum mixer_ctl_type mixer_ctl_get_type(struct mixer_ctl *ctl)
+{
+ if (!ctl) {
+ errno = EINVAL;
+ return MIXER_CTL_TYPE_UNKNOWN;
+ }
+
+ switch (ctl->info->type) {
+ case SNDRV_CTL_ELEM_TYPE_BOOLEAN: return MIXER_CTL_TYPE_BOOL;
+ case SNDRV_CTL_ELEM_TYPE_INTEGER: return MIXER_CTL_TYPE_INT;
+ case SNDRV_CTL_ELEM_TYPE_ENUMERATED: return MIXER_CTL_TYPE_ENUM;
+ case SNDRV_CTL_ELEM_TYPE_BYTES: return MIXER_CTL_TYPE_BYTE;
+ case SNDRV_CTL_ELEM_TYPE_IEC958: return MIXER_CTL_TYPE_IEC958;
+ case SNDRV_CTL_ELEM_TYPE_INTEGER64: return MIXER_CTL_TYPE_INT64;
+ default: return MIXER_CTL_TYPE_UNKNOWN;
+ };
+}
+
+const char *mixer_ctl_get_type_string(struct mixer_ctl *ctl)
+{
+ if (!ctl) {
+ errno = EINVAL;
+ return "";
+ }
+
+ switch (ctl->info->type) {
+ case SNDRV_CTL_ELEM_TYPE_BOOLEAN: return "BOOL";
+ case SNDRV_CTL_ELEM_TYPE_INTEGER: return "INT";
+ case SNDRV_CTL_ELEM_TYPE_ENUMERATED: return "ENUM";
+ case SNDRV_CTL_ELEM_TYPE_BYTES: return "BYTE";
+ case SNDRV_CTL_ELEM_TYPE_IEC958: return "IEC958";
+ case SNDRV_CTL_ELEM_TYPE_INTEGER64: return "INT64";
+ default: return "Unknown";
+ };
+}
+
+unsigned int mixer_ctl_get_num_values(struct mixer_ctl *ctl)
+{
+ if (!ctl) {
+ errno = EINVAL;
+ return 0;
+ }
+
+ return ctl->info->count;
+}
+
static int percent_to_int(struct snd_ctl_elem_info *ei, int percent)
{
int range;
@@ -236,30 +285,35 @@ static int int_to_percent(struct snd_ctl_elem_info *ei, int value)
return ((value - ei->value.integer.min) / range) * 100;
}
-int mixer_ctl_get_percent(struct mixer_ctl *ctl)
+int mixer_ctl_get_percent(struct mixer_ctl *ctl, unsigned int id)
{
- if (ctl->info->type != SNDRV_CTL_ELEM_TYPE_INTEGER) {
+ if (!ctl || (ctl->info->type != SNDRV_CTL_ELEM_TYPE_INTEGER)) {
errno = EINVAL;
return -1;
}
- return int_to_percent(ctl->info, mixer_ctl_get_int(ctl));
+ return int_to_percent(ctl->info, mixer_ctl_get_int(ctl, id));
}
-int mixer_ctl_set_percent(struct mixer_ctl *ctl, int percent)
+int mixer_ctl_set_percent(struct mixer_ctl *ctl, unsigned int id, int percent)
{
- if (ctl->info->type != SNDRV_CTL_ELEM_TYPE_INTEGER) {
+ if (!ctl || (ctl->info->type != SNDRV_CTL_ELEM_TYPE_INTEGER)) {
errno = EINVAL;
return -1;
}
- return mixer_ctl_set_int(ctl, percent_to_int(ctl->info, percent));
+ return mixer_ctl_set_int(ctl, id, percent_to_int(ctl->info, percent));
}
-int mixer_ctl_get_int(struct mixer_ctl *ctl)
+int mixer_ctl_get_int(struct mixer_ctl *ctl, unsigned int id)
{
struct snd_ctl_elem_value ev;
+ if (!ctl || (id >= ctl->info->count)) {
+ errno = EINVAL;
+ return -1;
+ }
+
memset(&ev, 0, sizeof(ev));
ev.id.numid = ctl->info->id.numid;
if (ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_READ, &ev))
@@ -267,11 +321,11 @@ int mixer_ctl_get_int(struct mixer_ctl *ctl)
switch (ctl->info->type) {
case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
- return !!ev.value.integer.value[0]; /* TODO: handle multiple return values */
+ return !!ev.value.integer.value[id];
break;
case SNDRV_CTL_ELEM_TYPE_INTEGER:
- return ev.value.integer.value[0]; /* TODO: handle multiple return values */
+ return ev.value.integer.value[id];
break;
default:
@@ -282,23 +336,25 @@ int mixer_ctl_get_int(struct mixer_ctl *ctl)
return 0;
}
-int mixer_ctl_set_int(struct mixer_ctl *ctl, int value)
+int mixer_ctl_set_int(struct mixer_ctl *ctl, unsigned int id, int value)
{
struct snd_ctl_elem_value ev;
- unsigned int n;
+
+ if (!ctl || (id >= ctl->info->count)) {
+ errno = EINVAL;
+ return -1;
+ }
memset(&ev, 0, sizeof(ev));
ev.id.numid = ctl->info->id.numid;
switch (ctl->info->type) {
case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
- for (n = 0; n < ctl->info->count; n++)
- ev.value.integer.value[n] = !!value;
+ ev.value.integer.value[id] = !!value;
break;
case SNDRV_CTL_ELEM_TYPE_INTEGER:
- for (n = 0; n < ctl->info->count; n++)
- ev.value.integer.value[n] = value;
+ ev.value.integer.value[id] = value;
break;
default:
@@ -313,7 +369,7 @@ int mixer_ctl_set_enum(struct mixer_ctl *ctl, unsigned int id)
{
struct snd_ctl_elem_value ev;
- if ((ctl->info->type != SNDRV_CTL_ELEM_TYPE_ENUMERATED) ||
+ if (!ctl || (ctl->info->type != SNDRV_CTL_ELEM_TYPE_ENUMERATED) ||
(id >= ctl->info->value.enumerated.items)) {
errno = EINVAL;
return -1;
@@ -332,7 +388,7 @@ int mixer_ctl_set_enum_by_name(struct mixer_ctl *ctl, const char *string)
unsigned int n, max;
struct snd_ctl_elem_value ev;
- if (ctl->info->type != SNDRV_CTL_ELEM_TYPE_ENUMERATED) {
+ if (!ctl || (ctl->info->type != SNDRV_CTL_ELEM_TYPE_ENUMERATED)) {
errno = EINVAL;
return -1;
}
diff --git a/tinymix.c b/tinymix.c
new file mode 100644
index 0000000..73694fd
--- /dev/null
+++ b/tinymix.c
@@ -0,0 +1,61 @@
+/* tinymix.c
+**
+** Copyright 2011, The Android Open Source Project
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** * Neither the name of The Android Open Source Project nor the names of
+** its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY The Android Open Source Project ``AS IS'' AND
+** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+** ARE DISCLAIMED. IN NO EVENT SHALL The Android Open Source Project BE LIABLE
+** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+** DAMAGE.
+*/
+
+#include <tinyalsa/asoundlib.h>
+#include <stdio.h>
+
+int main(int argc, char **argv)
+{
+ struct mixer *mixer;
+ struct mixer_ctl *ctl;
+ const char *type;
+ unsigned int num_ctls, num_values;
+ char buffer[256];
+ unsigned int i;
+
+ mixer = mixer_open(0);
+ num_ctls = mixer_get_num_ctls(mixer);
+
+ printf("Number of controls: %d\n", num_ctls);
+
+ printf("ctl\ttype\tnum\tname\n");
+ for (i = 0; i < num_ctls; i++) {
+ ctl = mixer_get_ctl(mixer, i);
+
+ mixer_ctl_get_name(ctl, buffer, sizeof(buffer));
+ type = mixer_ctl_get_type_string(ctl);
+ num_values = mixer_ctl_get_num_values(ctl);
+
+ printf("%d\t%s\t%d\t%s\n", i, type, num_values, buffer);
+ }
+
+ mixer_close(mixer);
+
+ return 0;
+}
+