[pulseaudio-discuss] [PATCH 1/3] alsa-util: Add functions for accessing mixer elements through mixer class

David Henningsson david.henningsson at canonical.com
Mon Sep 1 07:08:51 PDT 2014


Instead of using the hctl interface, we can find controls belonging
to other iface types than "mixer". We do this by introducing a new
mixer class "SND_MIXER_ELEM_PULSEAUDIO" and create snd_mixer_elem's
for all PCM and CARD iface types (as Jacks are of the CARD type and
ELD controls are of the PCM type).

Signed-off-by: David Henningsson <david.henningsson at canonical.com>
---
 src/modules/alsa/alsa-util.c | 77 ++++++++++++++++++++++++++++++++++++++++++++
 src/modules/alsa/alsa-util.h |  2 ++
 2 files changed, 79 insertions(+)

diff --git a/src/modules/alsa/alsa-util.c b/src/modules/alsa/alsa-util.c
index 1ce2e16..97edb67 100644
--- a/src/modules/alsa/alsa-util.c
+++ b/src/modules/alsa/alsa-util.c
@@ -1457,6 +1457,25 @@ bool pa_alsa_may_tsched(bool want) {
     return true;
 }
 
+#define SND_MIXER_ELEM_PULSEAUDIO (SND_MIXER_ELEM_LAST + 10)
+
+snd_mixer_elem_t *pa_alsa_mixer_find(snd_mixer_t *mixer, const char *name, unsigned int device) {
+    snd_mixer_elem_t *elem;
+
+    for (elem = snd_mixer_first_elem(mixer); elem; elem = snd_mixer_elem_next(elem)) {
+        snd_hctl_elem_t *helem;
+        if (snd_mixer_elem_get_type(elem) != SND_MIXER_ELEM_PULSEAUDIO)
+            continue;
+        helem = snd_mixer_elem_get_private(elem);
+        if (!pa_streq(snd_hctl_elem_get_name(helem), name))
+            continue;
+        if (snd_hctl_elem_get_device(helem) != device)
+            continue;
+        return elem;
+    }
+    return NULL;
+}
+
 snd_hctl_elem_t* pa_alsa_find_jack(snd_hctl_t *hctl, const char* jack_name) {
     snd_ctl_elem_id_t *id;
 
@@ -1481,8 +1500,53 @@ snd_hctl_elem_t* pa_alsa_find_eld_ctl(snd_hctl_t *hctl, int device) {
     return snd_hctl_find_elem(hctl, id);
 }
 
+static int mixer_class_compare(const snd_mixer_elem_t *c1, const snd_mixer_elem_t *c2)
+{
+    /* Dummy compare function */
+    return c1 == c2 ? 0 : (c1 > c2 ? 1 : -1);
+}
+
+static int mixer_class_event(snd_mixer_class_t *class, unsigned int mask,
+			snd_hctl_elem_t *helem, snd_mixer_elem_t *melem)
+{
+    int err;
+    const char *name = snd_hctl_elem_get_name(helem);
+    if (mask & SND_CTL_EVENT_MASK_ADD) {
+        snd_ctl_elem_iface_t iface = snd_hctl_elem_get_interface(helem);
+        if (iface == SND_CTL_ELEM_IFACE_CARD || iface == SND_CTL_ELEM_IFACE_PCM) {
+            snd_mixer_elem_t *new_melem;
+
+            /* Put the hctl pointer as our private data - it will be useful for callbacks */
+            if ((err = snd_mixer_elem_new(&new_melem, SND_MIXER_ELEM_PULSEAUDIO, 0, helem, NULL)) < 0) {
+                pa_log_warn("snd_mixer_elem_new failed: %s", pa_alsa_strerror(err));
+                return 0;
+            }
+
+            if ((err = snd_mixer_elem_attach(new_melem, helem)) < 0) {
+                pa_log_warn("snd_mixer_elem_attach failed: %s", pa_alsa_strerror(err));
+		snd_mixer_elem_free(melem);
+                return 0;
+            }
+
+            if ((err = snd_mixer_elem_add(new_melem, class)) < 0) {
+                pa_log_warn("snd_mixer_elem_add failed: %s", pa_alsa_strerror(err));
+                return 0;
+            }
+        }
+    }
+    else if (mask & SND_CTL_EVENT_MASK_VALUE) {
+        snd_mixer_elem_value(melem); /* Calls the element callback */
+        return 0;
+    }
+    else
+        pa_log_info("Got an unknown mixer class event for %s: mask 0x%x\n", name, mask);
+
+    return 0;
+}
+
 static int prepare_mixer(snd_mixer_t *mixer, const char *dev, snd_hctl_t **hctl) {
     int err;
+    snd_mixer_class_t *class;
 
     pa_assert(mixer);
     pa_assert(dev);
@@ -1499,6 +1563,19 @@ static int prepare_mixer(snd_mixer_t *mixer, const char *dev, snd_hctl_t **hctl)
         return -1;
     }
 
+    if (snd_mixer_class_malloc(&class)) {
+        pa_log_info("Failed to allocate mixer class for %s", dev);
+        return -1;
+    }
+    snd_mixer_class_set_event(class, mixer_class_event);
+    snd_mixer_class_set_compare(class, mixer_class_compare);
+    if ((err = snd_mixer_class_register(class, mixer)) < 0) {
+        pa_log_info("Unable register mixer class for %s: %s", dev, pa_alsa_strerror(err));
+        snd_mixer_class_free(class);
+        return -1;
+    }
+    /* From here on, the mixer class is deallocated by alsa on snd_mixer_close/free. */
+
     if ((err = snd_mixer_selem_register(mixer, NULL, NULL)) < 0) {
         pa_log_warn("Unable to register mixer: %s", pa_alsa_strerror(err));
         return -1;
diff --git a/src/modules/alsa/alsa-util.h b/src/modules/alsa/alsa-util.h
index bb2ad4e..50b0aaf 100644
--- a/src/modules/alsa/alsa-util.h
+++ b/src/modules/alsa/alsa-util.h
@@ -145,6 +145,8 @@ bool pa_alsa_may_tsched(bool want);
 snd_hctl_elem_t* pa_alsa_find_jack(snd_hctl_t *hctl, const char* jack_name);
 snd_hctl_elem_t* pa_alsa_find_eld_ctl(snd_hctl_t *hctl, int device);
 
+snd_mixer_elem_t *pa_alsa_mixer_find(snd_mixer_t *mixer, const char *name, unsigned int device);
+
 snd_mixer_t *pa_alsa_open_mixer(int alsa_card_index, char **ctl_device, snd_hctl_t **hctl);
 
 typedef struct pa_hdmi_eld pa_hdmi_eld;
-- 
1.9.1



More information about the pulseaudio-discuss mailing list