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