[pulseaudio-discuss] [PATCH 09/11] alsa: jack input device implementation

David Henningsson david.henningsson at canonical.com
Tue Aug 30 12:25:02 PDT 2011


Signed-off-by: David Henningsson <david.henningsson at canonical.com>
---
 src/Makefile.am                       |    1 +
 src/modules/alsa/alsa-jack-inputdev.c |  364 +++++++++++++++++++++++++++++++++
 src/modules/alsa/alsa-jack-inputdev.h |   48 +++++
 src/modules/alsa/alsa-mixer.c         |   50 ++---
 src/modules/alsa/alsa-mixer.h         |    6 +-
 src/modules/alsa/alsa-sink.c          |    2 +-
 src/modules/alsa/alsa-source.c        |    2 +-
 src/modules/alsa/module-alsa-card.c   |    8 +-
 8 files changed, 448 insertions(+), 33 deletions(-)
 create mode 100644 src/modules/alsa/alsa-jack-inputdev.c
 create mode 100644 src/modules/alsa/alsa-jack-inputdev.h

diff --git a/src/Makefile.am b/src/Makefile.am
index dd143a1..7f24433 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1543,6 +1543,7 @@ module_coreaudio_device_la_LIBADD = $(MODULE_LIBADD)
 libalsa_util_la_SOURCES = \
 		modules/alsa/alsa-util.c modules/alsa/alsa-util.h \
 		modules/alsa/alsa-mixer.c modules/alsa/alsa-mixer.h \
+		modules/alsa/alsa-jack-inputdev.c modules/alsa/alsa-jack-inputdev.h \
 		modules/alsa/alsa-sink.c modules/alsa/alsa-sink.h \
 		modules/alsa/alsa-source.c modules/alsa/alsa-source.h \
 		modules/reserve-wrap.c modules/reserve-wrap.h
diff --git a/src/modules/alsa/alsa-jack-inputdev.c b/src/modules/alsa/alsa-jack-inputdev.c
new file mode 100644
index 0000000..8595ce5
--- /dev/null
+++ b/src/modules/alsa/alsa-jack-inputdev.c
@@ -0,0 +1,364 @@
+/***
+  This file is part of PulseAudio.
+
+  Copyright 2011 Canonical Ltd
+  Copyright 2011 Wolfson Microelectronics PLC
+
+  PulseAudio is free software; you can redistribute it and/or modify
+  it under the terms of the GNU Lesser General Public License as published
+  by the Free Software Foundation; either version 2.1 of the License,
+  or (at your option) any later version.
+
+  PulseAudio is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with PulseAudio; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+  USA.
+***/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <libudev.h>
+#include <linux/input.h>
+
+#include "alsa-jack-inputdev.h"
+
+#include <pulsecore/core-util.h>
+#include <pulsecore/strlist.h>
+#include <pulsecore/core.h>
+#include <pulse/xmalloc.h>
+
+struct pa_alsa_jack_inputdev {
+    int fd;
+    pa_io_event* io_event;
+    pa_core* core;
+    int64_t switches_supported;
+    char *devname;
+    pa_hashmap *links; /* Has struct pa_alsa_jack_inputdev_link pointers in it */
+};
+
+
+/* (mostly) from slimlogic/wolfson start */
+
+static const char *jack_get_input_id(const char *path) {
+    int i;
+
+    for( i = 0; i < (int) strlen(path); i++) {
+        if (pa_startswith(path + i, "/event"))
+            return path + i + 6;
+    }
+
+    return NULL;
+}
+
+static pa_bool_t input_node_belongs_to_device(
+        const char *device,
+        const char *node) {
+
+    char *cd;
+    pa_bool_t b;
+
+    cd = pa_sprintf_malloc("/sys%s", device);
+    b = pa_startswith(node, cd);
+    pa_xfree(cd);
+    return b;
+}
+
+static pa_strlist* alsa_jack_inputdev_udev_detect(struct udev* udev, const char* match_path) {
+    struct udev_enumerate *enumerate;
+    struct udev_list_entry *item, *first;
+    const char *jack_path;
+    const char *jack_input;
+    pa_strlist *result = NULL;
+
+    if (!(enumerate = udev_enumerate_new(udev)))
+        pa_log("Failed to initialize udev enumerator");
+    else {
+        if (udev_enumerate_add_match_subsystem(enumerate, "input"))
+            pa_log_debug("Failed to match to subsystem input");
+
+        if (udev_enumerate_scan_devices(enumerate))
+            pa_log_debug("Failed to scan for devices");
+        first = udev_enumerate_get_list_entry(enumerate);
+        udev_list_entry_foreach(item, first) {
+            jack_path = udev_list_entry_get_name(item);
+            if (input_node_belongs_to_device(match_path, jack_path)) {
+                jack_input = jack_get_input_id(jack_path);
+                if (jack_input) {
+                    pa_log_debug("found jack input device %s\n", jack_input);
+                    result = pa_strlist_prepend(result, jack_input);
+                }
+            }
+        }
+        udev_enumerate_unref(enumerate);
+    }
+    return result;
+}
+
+/* (mostly) from slimlogic/wolfson end */
+
+static char* get_match_path_from_card_idx(struct udev* udev, int card_idx) {
+    char* t;
+    struct udev_device* card;
+
+    t = pa_sprintf_malloc("%s/class/sound/card%i", udev_get_sys_path(udev), card_idx);
+    card = udev_device_new_from_syspath(udev, t);
+    pa_xfree(t);
+    if (!card) {
+        pa_log_error("Udev error getting udev device :-(");
+        return NULL;
+    }
+
+    return pa_xstrdup(udev_device_get_devpath(card));
+}
+
+static void add_inputdev(pa_hashmap* devs, const char* jack_id) {
+    const char *devpath = pa_sprintf_malloc("/dev/input/event%s", jack_id);
+    int fd;
+    char devname[256] = "";
+    int64_t switches = 0;
+
+    pa_assert(SW_MAX <= 63); /* Or switches variable will overflow */
+    pa_assert(devs);
+
+    fd = open(devpath, O_RDONLY);
+    if (fd < 0) {
+        pa_log_info("Could not open %s, error = %s", devpath, strerror(errno));
+        return;
+    }
+
+    if (ioctl(fd, EVIOCGNAME(sizeof(devname)), devname) < 0) {
+        pa_log_warn("Ioctl EVIOCGNAME error %s", strerror(errno));
+        goto finish;
+    }
+    pa_log_debug("Device %s has name \"%s\".", devpath, devname);
+
+    if (ioctl(fd, EVIOCGBIT(EV_SW, SW_MAX), &switches) < 0) {
+        pa_log_warn("Ioctl EVIOCGBIT error %s", strerror(errno));
+        goto finish;
+    }
+
+    if (switches == 0) {
+        pa_log_debug("Device %s does not have any switches.", devname);
+        goto finish;
+    } else {
+        /* Create the new input device */
+        pa_alsa_jack_inputdev *dev = pa_xnew0(pa_alsa_jack_inputdev, 1);
+
+        dev->fd = fd;
+        dev->switches_supported = switches;
+        pa_log_debug("Device %s has switches 0x%x.", devname, (int) switches);
+        dev->devname = pa_xstrdup(devname);
+        dev->links = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
+        pa_hashmap_put(devs, dev, dev);
+        return;
+    }
+
+finish:
+        close(fd);
+}
+
+pa_hashmap* pa_alsa_jack_inputdev_enum(int alsa_card_index) {
+    pa_hashmap *result = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
+    struct udev* udev = NULL;
+    char* match_path = NULL;
+    pa_strlist* jack_names = NULL;
+
+    if (!(udev = udev_new())) {
+        pa_log("Failed to open udev context.");
+        goto finish;
+    }
+
+    /* Step 1: Get a sysfs path to match input devices to */
+    if (!(match_path = get_match_path_from_card_idx(udev, alsa_card_index)))
+        goto finish;
+
+    /* Step 2: Enumerate all input devices */
+    jack_names = alsa_jack_inputdev_udev_detect(udev, match_path);
+
+    /* Step 3: Open input devices and query capabilities */
+    while (jack_names) {
+        char* jack_id;
+        jack_names = pa_strlist_pop(jack_names, &jack_id);
+        add_inputdev(result, jack_id);
+        pa_xfree(jack_id);
+    }
+
+finish:
+    if (match_path)
+        pa_xfree(match_path);
+    if (udev)
+        udev_unref(udev);
+
+    pa_log_debug("Found %d jack input devices.", pa_hashmap_size(result));
+    return result;
+}
+
+const char* swstrings[SW_MAX+1] = {
+    [SW_HEADPHONE_INSERT] = "Headphone",
+    [SW_MICROPHONE_INSERT] = "Microphone",
+    [SW_LINEOUT_INSERT] = "LineOut",
+    [SW_VIDEOOUT_INSERT] = "VideoOut",
+};
+
+/* Match an alsa path against input devices. Returns matched device or NULL */
+pa_alsa_jack_inputdev_link* pa_alsa_jack_inputdev_match(pa_hashmap* devs, pa_alsa_path* path) {
+    void *state;
+    pa_alsa_jack_inputdev *dev;
+    pa_alsa_jack_inputdev_link *jil;
+    char *name = path->jack_inputdev_name;
+    char *code = path->jack_inputdev_code;
+
+    if (!name && !code)
+        return NULL;
+/*    pa_log_debug("Matching against %d devices ", pa_hashmap_size(devs));*/
+    PA_HASHMAP_FOREACH(dev, devs, state) {
+        int64_t switches;
+        int i;
+
+/*        pa_log_debug("Matching against %s ", dev->devname);*/
+        if (name) {
+            if (!strstr(dev->devname, name))
+                continue;
+        }
+
+        for (i = 0; i < SW_MAX; i++) {
+            int64_t bitval = 1LL << i;
+            if ((dev->switches_supported & bitval) == 0)
+                continue;
+            if (!swstrings[i])
+                continue;
+            if ((!code) || strstr(code, swstrings[i]))
+                switches |= bitval;
+        }
+
+        if (!switches)
+            continue;
+
+        /* Found a match, let's add it! */
+        jil = pa_xnew0(pa_alsa_jack_inputdev_link, 1);
+        jil->path = path;
+        jil->dev = dev;
+        jil->switches_enable = switches;
+        pa_hashmap_put(dev->links, jil, jil);
+        pa_log_debug("Matched input device %s to control path %s, jil = %p", dev->devname, pa_strnull(path->name), jil);
+
+        return jil;
+    }
+    return NULL;
+}
+
+static void jack_report(pa_alsa_jack_inputdev *dev, uint64_t bitmask, uint64_t bitvalue) {
+    pa_alsa_jack_inputdev_link *jil;
+    void* state;
+    PA_HASHMAP_FOREACH(jil, dev->links, state) {
+        if (jil->switches_enable & bitmask) {
+            pa_assert(jil->port);
+            pa_device_port_set_available(jil->port, bitmask & bitvalue ? PA_PORT_AVAILABLE_YES : PA_PORT_AVAILABLE_NO, dev->core);
+        }
+    }
+}
+
+static void jack_inputdev_cb(pa_mainloop_api*ea, pa_io_event* e, int fd, pa_io_event_flags_t events, void *userdata) {
+    pa_alsa_jack_inputdev* dev = userdata;
+    struct input_event event;
+
+    pa_assert(dev);
+
+    if (pa_read(dev->fd, &event, sizeof(event), NULL) != sizeof(event)) {
+        pa_log_warn("Failed to read event from dev %s", dev->devname);
+        return;
+    }
+
+    pa_log_debug("jack_report: name %s event type %x code %x value %x", dev->devname, event.type, event.code, event.value);
+    if (event.type == EV_SW)
+        jack_report(dev, 1 << event.code, event.value ? ~0 : 0);
+}
+
+
+static void jack_get_initial_state(pa_alsa_jack_inputdev *dev)
+{
+    uint64_t switches;
+    int err;
+
+    pa_assert(SW_MAX < 63);
+    err = ioctl(dev->fd, EVIOCGSW(sizeof(switches)), &switches);
+    if (err < 0) {
+        pa_log("Failed to read initial %s jack status %s", dev->devname, strerror(errno));
+        return;
+    }
+
+    /* We got all bits, set them correctly */
+    jack_report(dev, (1LL << (SW_MAX+1)) - 1, switches);
+}
+
+static void jack_inputdev_start_listening(pa_alsa_jack_inputdev* dev, pa_core* core) {
+    pa_assert(dev);
+
+    dev->core = core;
+    dev->io_event = core->mainloop->io_new(core->mainloop, dev->fd, PA_IO_EVENT_INPUT, jack_inputdev_cb, dev);
+    if (!dev->io_event) {
+        pa_log_warn("Failed to create io event for dev %s :-(", dev->devname);
+        return;
+    }
+    core->mainloop->io_enable(dev->io_event, PA_IO_EVENT_INPUT);
+    jack_get_initial_state(dev);
+}
+
+static void jack_inputdev_free(pa_alsa_jack_inputdev* dev) {
+
+    if (!dev)
+        return;
+
+    if (dev->links) {
+        pa_alsa_jack_inputdev_link* jil;
+        while ((jil = pa_hashmap_steal_first(dev->links))) {
+            if (jil->port)
+                pa_device_port_unref(jil->port);
+            pa_xfree(jil);
+        }
+        pa_hashmap_free(dev->links, NULL, NULL);
+    }
+
+    if (dev->io_event && dev->core) {
+        dev->core->mainloop->io_free(dev->io_event);
+    }
+
+    if (dev->fd)
+        close(dev->fd);
+
+    pa_xfree(dev);
+}
+
+void pa_alsa_jack_inputdev_free(pa_hashmap* devs) {
+    pa_alsa_jack_inputdev* dev;
+
+    if (!devs)
+        return;
+    while ((dev = pa_hashmap_steal_first(devs)))
+        jack_inputdev_free(dev);
+    pa_hashmap_free(devs, NULL, NULL);
+}
+
+void pa_alsa_jack_inputdev_start(pa_hashmap* devs, pa_core* core) {
+    pa_alsa_jack_inputdev* dev;
+    void* state;
+
+    PA_HASHMAP_FOREACH(dev, devs, state) {
+        if (!dev->links || pa_hashmap_isempty(dev->links)) {
+            pa_hashmap_remove(devs, dev);
+            jack_inputdev_free(dev);
+        }
+        else
+            jack_inputdev_start_listening(dev, core);
+    }
+}
diff --git a/src/modules/alsa/alsa-jack-inputdev.h b/src/modules/alsa/alsa-jack-inputdev.h
new file mode 100644
index 0000000..8ca5238
--- /dev/null
+++ b/src/modules/alsa/alsa-jack-inputdev.h
@@ -0,0 +1,48 @@
+/***
+  This file is part of PulseAudio.
+
+  Copyright 2011 Canonical Ltd
+  FIXME: Some code stolen from earlier patches, from Wolfson Microelectronics PLC
+
+  PulseAudio is free software; you can redistribute it and/or modify
+  it under the terms of the GNU Lesser General Public License as published
+  by the Free Software Foundation; either version 2.1 of the License,
+  or (at your option) any later version.
+
+  PulseAudio is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with PulseAudio; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+  USA.
+***/
+#ifndef fooalsajackinputdevhfoo
+#define fooalsajackinputdevhfoo
+
+#include <pulsecore/idxset.h>
+#include <pulsecore/hashmap.h>
+#include "alsa-mixer.h"
+
+struct pa_alsa_jack_inputdev_link {
+    pa_device_port *port;
+    pa_alsa_path *path;
+    pa_alsa_jack_inputdev *dev;
+    int64_t switches_enable;
+};
+
+/* Return a list of input devices belonging to this card */
+pa_hashmap* pa_alsa_jack_inputdev_enum(int alsa_card_index);
+
+/* Match an alsa path against input devices. Returns NULL if no match.
+   Returned link pointer is owned by input device and does not need to be freed. */
+pa_alsa_jack_inputdev_link* pa_alsa_jack_inputdev_match(pa_hashmap* devs, pa_alsa_path* path);
+
+/* Start listening to input dev change events, and reports initial state */
+void pa_alsa_jack_inputdev_start(pa_hashmap* devs, pa_core* core);
+
+void pa_alsa_jack_inputdev_free(pa_hashmap* devs);
+
+#endif
diff --git a/src/modules/alsa/alsa-mixer.c b/src/modules/alsa/alsa-mixer.c
index e68258d..f248b95 100644
--- a/src/modules/alsa/alsa-mixer.c
+++ b/src/modules/alsa/alsa-mixer.c
@@ -49,6 +49,7 @@
 
 #include "alsa-mixer.h"
 #include "alsa-util.h"
+#include "alsa-jack-inputdev.h"
 
 struct description_map {
     const char *name;
@@ -2539,7 +2540,7 @@ static void path_create_settings(pa_alsa_path *p) {
     element_create_settings(p->elements, NULL);
 }
 
-int pa_alsa_path_probe(pa_alsa_path *p, snd_mixer_t *m, pa_bool_t ignore_dB) {
+int pa_alsa_path_probe(pa_alsa_path *p, snd_mixer_t *m, pa_bool_t ignore_dB, pa_alsa_profile_set *profile_set) {
     pa_alsa_element *e;
     double min_dB[PA_CHANNEL_POSITION_MAX], max_dB[PA_CHANNEL_POSITION_MAX];
     pa_channel_position_t t;
@@ -2621,6 +2622,9 @@ int pa_alsa_path_probe(pa_alsa_path *p, snd_mixer_t *m, pa_bool_t ignore_dB) {
         return -1;
     }
 
+    if (profile_set)
+        p->jack_inputdev_link = pa_alsa_jack_inputdev_match(profile_set->jack_inputdevs, p);
+
     path_drop_unsupported(p);
     path_make_options_unique(p);
     path_create_settings(p);
@@ -3054,7 +3058,10 @@ static void path_set_condense(pa_alsa_path_set *ps, snd_mixer_t *m) {
             if (p == p2)
                 continue;
 
-            /* FIXME: a is not a subset of b if a has a matched port and b has not. */
+            /* a is not a subset of b if a has a matched input device and b has not. */
+            if (p->jack_inputdev_link && ((!p2->jack_inputdev_link) ||
+                p->jack_inputdev_link->dev != p2->jack_inputdev_link->dev))
+                is_subset = FALSE;
 
             /* Compare the elements of each set... */
             pa_assert_se(ea = p->elements);
@@ -3126,31 +3133,7 @@ static void path_set_make_paths_unique(pa_alsa_path_set *ps) {
 
 /* This function is no longer used. */
 void pa_alsa_path_set_probe(pa_alsa_path_set *ps, snd_mixer_t *m, pa_bool_t ignore_dB) {
-    pa_alsa_path *p, *n;
-
-    pa_assert(ps);
-
-    if (ps->probed)
-        return;
-
-    for (p = ps->paths; p; p = n) {
-        n = p->next;
-
-        if (pa_alsa_path_probe(p, m, ignore_dB) < 0) {
-            PA_LLIST_REMOVE(pa_alsa_path, ps->paths, p);
-            /* pa_alsa_path_free(p); Paths are now owned by the profile set */
-        }
-    }
-
-    pa_log_debug("Found mixer paths (before tidying):");
-    pa_alsa_path_set_dump(ps);
-
-    path_set_condense(ps, m);
-    path_set_make_paths_unique(ps);
-    ps->probed = TRUE;
-
-    pa_log_debug("Available mixer paths (after tidying):");
-    pa_alsa_path_set_dump(ps);
+    return;
 }
 
 static void mapping_free(pa_alsa_mapping *m) {
@@ -3724,7 +3707,7 @@ static void mapping_paths_probe(pa_alsa_mapping *m, pa_alsa_profile *profile, pa
 
     for (p = ps->paths; p; p = np) {
         np = p->next;
-        if (pa_alsa_path_probe(p, mixer_handle, m->profile_set->ignore_dB) < 0) {
+        if (pa_alsa_path_probe(p, mixer_handle, m->profile_set->ignore_dB, m->profile_set) < 0) {
             PA_LLIST_REMOVE(pa_alsa_path, ps->paths, p);
         }
     }
@@ -4372,7 +4355,13 @@ static pa_device_port* device_port_alsa_init(pa_hashmap *ports,
         data = PA_DEVICE_PORT_DATA(p);
         data->path = path;
         data->setting = setting;
+        pa_log_debug("Adding port: path = %s, link-dev = %p", path->name, path->jack_inputdev_link);
+        if (path->jack_inputdev_link) {
+            path->jack_inputdev_link->port = p;
+            pa_device_port_ref(p);
+        }
     }
+    pa_log_debug("Adding port %s to profile %s", p->name, cp->name);
     pa_hashmap_put(p->profiles, cp->name, cp);
 
     return p;
@@ -4385,10 +4374,13 @@ void pa_alsa_path_set_add_ports(pa_alsa_path_set *ps, pa_card_profile *cp, pa_ha
     pa_assert(cp);
     pa_assert(ports);
 
+    pa_log_debug("pa_alsa_path_set_add_ports: ps = %p, profile = %s", ps, cp->name);
+
     if (!ps)
         return;
 
     PA_LLIST_FOREACH(path, ps->paths) {
+        pa_log_debug("pa_alsa_path_set_add_ports: path = %p, %s", path, path->name);
         if (!path->settings || !path->settings->next) {
             /* If there is no or just one setting we only need a
              * single entry */
@@ -4429,6 +4421,8 @@ void pa_alsa_add_ports(pa_hashmap **p, pa_alsa_path_set *ps) {
     pa_assert(!*p);
     pa_assert(ps);
 
+    *p = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
+
     /* if there is no path, we don't want a port list */
     if (!ps->paths)
         return;
diff --git a/src/modules/alsa/alsa-mixer.h b/src/modules/alsa/alsa-mixer.h
index 1d99b13..75edc02 100644
--- a/src/modules/alsa/alsa-mixer.h
+++ b/src/modules/alsa/alsa-mixer.h
@@ -45,6 +45,8 @@ typedef struct pa_alsa_profile pa_alsa_profile;
 typedef struct pa_alsa_decibel_fix pa_alsa_decibel_fix;
 typedef struct pa_alsa_profile_set pa_alsa_profile_set;
 typedef struct pa_alsa_port_data pa_alsa_port_data;
+typedef struct pa_alsa_jack_inputdev_link pa_alsa_jack_inputdev_link;
+typedef struct pa_alsa_jack_inputdev pa_alsa_jack_inputdev;
 
 #include "alsa-util.h"
 
@@ -168,6 +170,7 @@ struct pa_alsa_path {
 
     char *jack_inputdev_name;
     char *jack_inputdev_code;
+    pa_alsa_jack_inputdev_link *jack_inputdev_link;
 
     pa_bool_t probed:1;
     pa_bool_t supported:1;
@@ -212,7 +215,7 @@ void pa_alsa_element_dump(pa_alsa_element *e);
 
 pa_alsa_path *pa_alsa_path_new(const char *fname, pa_alsa_direction_t direction);
 pa_alsa_path *pa_alsa_path_synthesize(const char *element, pa_alsa_direction_t direction);
-int pa_alsa_path_probe(pa_alsa_path *p, snd_mixer_t *m, pa_bool_t ignore_dB);
+int pa_alsa_path_probe(pa_alsa_path *p, snd_mixer_t *m, pa_bool_t ignore_dB, pa_alsa_profile_set *profile_set);
 void pa_alsa_path_dump(pa_alsa_path *p);
 int pa_alsa_path_get_volume(pa_alsa_path *p, snd_mixer_t *m, const pa_channel_map *cm, pa_cvolume *v);
 int pa_alsa_path_get_mute(pa_alsa_path *path, snd_mixer_t *m, pa_bool_t *muted);
@@ -295,6 +298,7 @@ struct pa_alsa_profile_set {
     pa_hashmap *decibel_fixes;
     pa_hashmap *input_paths;
     pa_hashmap *output_paths;
+    pa_hashmap *jack_inputdevs;
 
     pa_bool_t auto_profiles;
     pa_bool_t ignore_dB:1;
diff --git a/src/modules/alsa/alsa-sink.c b/src/modules/alsa/alsa-sink.c
index 612ad5b..850e07b 100644
--- a/src/modules/alsa/alsa-sink.c
+++ b/src/modules/alsa/alsa-sink.c
@@ -1796,7 +1796,7 @@ static void find_mixer(struct userdata *u, pa_alsa_mapping *mapping, const char
         if (!(u->mixer_path = pa_alsa_path_synthesize(element, PA_ALSA_DIRECTION_OUTPUT)))
             goto fail;
 
-        if (pa_alsa_path_probe(u->mixer_path, u->mixer_handle, ignore_dB) < 0)
+        if (pa_alsa_path_probe(u->mixer_path, u->mixer_handle, ignore_dB, NULL) < 0)
             goto fail;
 
         pa_log_debug("Probed mixer path %s:", u->mixer_path->name);
diff --git a/src/modules/alsa/alsa-source.c b/src/modules/alsa/alsa-source.c
index 8318498..e34e51f 100644
--- a/src/modules/alsa/alsa-source.c
+++ b/src/modules/alsa/alsa-source.c
@@ -1508,7 +1508,7 @@ static void find_mixer(struct userdata *u, pa_alsa_mapping *mapping, const char
         if (!(u->mixer_path = pa_alsa_path_synthesize(element, PA_ALSA_DIRECTION_INPUT)))
             goto fail;
 
-        if (pa_alsa_path_probe(u->mixer_path, u->mixer_handle, ignore_dB) < 0)
+        if (pa_alsa_path_probe(u->mixer_path, u->mixer_handle, ignore_dB, NULL) < 0)
             goto fail;
 
         pa_log_debug("Probed mixer path %s:", u->mixer_path->name);
diff --git a/src/modules/alsa/module-alsa-card.c b/src/modules/alsa/module-alsa-card.c
index 7b120be..3eea300 100644
--- a/src/modules/alsa/module-alsa-card.c
+++ b/src/modules/alsa/module-alsa-card.c
@@ -40,6 +40,7 @@
 #include "alsa-sink.h"
 #include "alsa-source.h"
 #include "module-alsa-card-symdef.h"
+#include "alsa-jack-inputdev.h"
 
 PA_MODULE_AUTHOR("Lennart Poettering");
 PA_MODULE_DESCRIPTION("ALSA Card");
@@ -348,11 +349,11 @@ int pa__init(pa_module *m) {
     u->profile_set = pa_alsa_profile_set_new(fn, &u->core->default_channel_map);
     pa_xfree(fn);
 
-    u->profile_set->ignore_dB = ignore_dB;
-
     if (!u->profile_set)
         goto fail;
 
+    u->profile_set->ignore_dB = ignore_dB;
+    u->profile_set->jack_inputdevs = pa_alsa_jack_inputdev_enum(alsa_card_index);
     pa_alsa_profile_set_probe(u->profile_set, u->device_id, &m->core->default_sample_spec, m->core->default_n_fragments, m->core->default_fragment_size_msec);
     pa_alsa_profile_set_dump(u->profile_set);
 
@@ -409,6 +410,7 @@ int pa__init(pa_module *m) {
     u->card->set_profile = card_set_profile;
 
     init_profile(u);
+    pa_alsa_jack_inputdev_start(u->profile_set->jack_inputdevs, m->core);
 
     if (reserve)
         pa_reserve_wrapper_unref(reserve);
@@ -474,6 +476,8 @@ void pa__done(pa_module*m) {
             pa_alsa_source_free(s);
     }
 
+    pa_alsa_jack_inputdev_free(u->profile_set->jack_inputdevs);
+
     if (u->card)
         pa_card_free(u->card);
 
-- 
1.7.5.4



More information about the pulseaudio-discuss mailing list