aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXin Li <delphij@google.com>2018-08-06 16:50:46 -0700
committerXin Li <delphij@google.com>2018-08-06 16:50:46 -0700
commitb2ad60dac46080f3c778a50ff2468871b8b07f5e (patch)
tree12b062657b9bff1e8714bf1226ca9819273d55db
parentce0616534e7fcfd9ba4857075a08e54e0c32424e (diff)
parente4b8db0bcfee3fd473b3ece03ee916a0f7bbd600 (diff)
downloadtinyalsa-b2ad60dac46080f3c778a50ff2468871b8b07f5e.tar.gz
Merge Android Pie into master
Bug: 112104996 Change-Id: I2a007561615d5eba4c175116dca80e58b0c8ff1e
-rw-r--r--include/tinyalsa/asoundlib.h1
-rw-r--r--mixer.c108
2 files changed, 81 insertions, 28 deletions
diff --git a/include/tinyalsa/asoundlib.h b/include/tinyalsa/asoundlib.h
index dc71d37..935c8d0 100644
--- a/include/tinyalsa/asoundlib.h
+++ b/include/tinyalsa/asoundlib.h
@@ -316,6 +316,7 @@ int mixer_ctl_get_range_max(struct mixer_ctl *ctl);
int mixer_subscribe_events(struct mixer *mixer, int subscribe);
int mixer_wait_event(struct mixer *mixer, int timeout);
+int mixer_consume_event(struct mixer *mixer);
#if defined(__cplusplus)
} /* extern "C" */
diff --git a/mixer.c b/mixer.c
index 6ea6c0d..f3fdb62 100644
--- a/mixer.c
+++ b/mixer.c
@@ -26,6 +26,7 @@
** DAMAGE.
*/
+#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
@@ -44,12 +45,17 @@
#define __user
#include <sound/asound.h>
+#ifndef SNDRV_CTL_ELEM_ID_NAME_MAXLEN
+#define SNDRV_CTL_ELEM_ID_NAME_MAXLEN 44
+#endif
+
#include <tinyalsa/asoundlib.h>
struct mixer_ctl {
struct mixer *mixer;
struct snd_ctl_elem_info *info;
char **ename;
+ bool info_retrieved;
};
struct mixer {
@@ -93,10 +99,9 @@ void mixer_close(struct mixer *mixer)
struct mixer *mixer_open(unsigned int card)
{
struct snd_ctl_elem_list elist;
- struct snd_ctl_elem_info tmp;
struct snd_ctl_elem_id *eid = NULL;
struct mixer *mixer = NULL;
- unsigned int n, m;
+ unsigned int n;
int fd;
char fn[256];
@@ -133,28 +138,14 @@ struct mixer *mixer_open(unsigned int card)
goto fail;
for (n = 0; n < mixer->count; n++) {
- struct snd_ctl_elem_info *ei = mixer->elem_info + n;
- ei->id.numid = eid[n].numid;
- if (ioctl(fd, SNDRV_CTL_IOCTL_ELEM_INFO, ei) < 0)
- goto fail;
- mixer->ctl[n].info = ei;
- mixer->ctl[n].mixer = mixer;
- if (ei->type == SNDRV_CTL_ELEM_TYPE_ENUMERATED) {
- char **enames = calloc(ei->value.enumerated.items, sizeof(char*));
- if (!enames)
- goto fail;
- mixer->ctl[n].ename = enames;
- for (m = 0; m < ei->value.enumerated.items; m++) {
- memset(&tmp, 0, sizeof(tmp));
- tmp.id.numid = ei->id.numid;
- tmp.value.enumerated.item = m;
- if (ioctl(fd, SNDRV_CTL_IOCTL_ELEM_INFO, &tmp) < 0)
- goto fail;
- enames[m] = strdup(tmp.value.enumerated.name);
- if (!enames[m])
- goto fail;
- }
- }
+ struct mixer_ctl *ctl = mixer->ctl + n;
+
+ ctl->mixer = mixer;
+ ctl->info = mixer->elem_info + n;
+ ctl->info->id.numid = eid[n].numid;
+ strncpy((char *)ctl->info->id.name, (char *)eid[n].name,
+ SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
+ ctl->info->id.name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN - 1] = 0;
}
free(eid);
@@ -171,6 +162,40 @@ fail:
return 0;
}
+static bool mixer_ctl_get_elem_info(struct mixer_ctl* ctl)
+{
+ if (!ctl->info_retrieved) {
+ if (ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_INFO, ctl->info) < 0)
+ return false;
+ ctl->info_retrieved = true;
+ }
+
+ if (ctl->info->type != SNDRV_CTL_ELEM_TYPE_ENUMERATED || ctl->ename)
+ return true;
+
+ struct snd_ctl_elem_info tmp;
+ char** enames = calloc(ctl->info->value.enumerated.items, sizeof(char*));
+ if (!enames)
+ return false;
+
+ for (unsigned int i = 0; i < ctl->info->value.enumerated.items; i++) {
+ memset(&tmp, 0, sizeof(tmp));
+ tmp.id.numid = ctl->info->id.numid;
+ tmp.value.enumerated.item = i;
+ if (ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_INFO, &tmp) < 0)
+ goto fail;
+ enames[i] = strdup(tmp.value.enumerated.name);
+ if (!enames[i])
+ goto fail;
+ }
+ ctl->ename = enames;
+ return true;
+
+fail:
+ free(enames);
+ return false;
+}
+
const char *mixer_get_name(struct mixer *mixer)
{
return (const char *)mixer->card_info.name;
@@ -186,10 +211,16 @@ unsigned int mixer_get_num_ctls(struct mixer *mixer)
struct mixer_ctl *mixer_get_ctl(struct mixer *mixer, unsigned int id)
{
- if (mixer && (id < mixer->count))
- return mixer->ctl + id;
+ struct mixer_ctl *ctl;
- return NULL;
+ if (!mixer || (id >= mixer->count))
+ return NULL;
+
+ ctl = mixer->ctl + id;
+ if (!mixer_ctl_get_elem_info(ctl))
+ return NULL;
+
+ return ctl;
}
struct mixer_ctl *mixer_get_ctl_by_name(struct mixer *mixer, const char *name)
@@ -201,7 +232,7 @@ struct mixer_ctl *mixer_get_ctl_by_name(struct mixer *mixer, const char *name)
for (n = 0; n < mixer->count; n++)
if (!strcmp(name, (char*) mixer->elem_info[n].id.name))
- return mixer->ctl + n;
+ return mixer_get_ctl(mixer, n);
return NULL;
}
@@ -626,3 +657,24 @@ int mixer_wait_event(struct mixer *mixer, int timeout)
return 1;
}
}
+
+/** Consume a mixer event.
+ * If mixer_subscribe_events has been called,
+ * mixer_wait_event will identify when a control value has changed.
+ * This function will clear a single event from the mixer so that
+ * further events can be alerted.
+ *
+ * @param mixer A mixer handle.
+ * @returns 0 on success. -errno on failure.
+ * @ingroup libtinyalsa-mixer
+ */
+int mixer_consume_event(struct mixer *mixer) {
+ struct snd_ctl_event ev;
+ ssize_t count = read(mixer->fd, &ev, sizeof(ev));
+ // Exporting the actual event would require exposing snd_ctl_event
+ // via the header file, and all associated structs.
+ // The events generally tell you exactly which value changed,
+ // but reading values you're interested isn't hard and simplifies
+ // the interface greatly.
+ return (count >= 0) ? 0 : -errno;
+}