[pulseaudio-commits] [Git][pulseaudio/pulseaudio][master] 5 commits: alsa: rewrite mixer open/close, cache mixer accesses in probe

Arun Raghavan gitlab at gitlab.freedesktop.org
Mon Dec 23 14:04:01 UTC 2019



Arun Raghavan pushed to branch master at PulseAudio / pulseaudio


Commits:
3bd7c70c by Jaroslav Kysela at 2019-12-23T11:10:44+00:00
alsa: rewrite mixer open/close, cache mixer accesses in probe

The ALSA mixer can be opened multiple times (especially for UCM
in the probe). This adds a simple mixer cache to prevent
multiple open calls.

Signed-off-by: Jaroslav Kysela <perex at perex.cz>

- - - - -
3ceff8bb by Jaroslav Kysela at 2019-12-23T11:10:44+00:00
alsa-ucm: add support for HDMI ELD

Signed-off-by: Jaroslav Kysela <perex at perex.cz>

- - - - -
8837c90b by Jaroslav Kysela at 2019-12-23T11:10:44+00:00
alsa-mixer: do the quick card number lookup to save mixer instances

Signed-off-by: Jaroslav Kysela <perex at perex.cz>

- - - - -
d7dbd0cb by Jaroslav Kysela at 2019-12-23T11:10:44+00:00
alsa-mixer: improve check for the empty path set for sink/source

The unused mixer instances are created without this code.

Signed-off-by: Jaroslav Kysela <perex at perex.cz>

- - - - -
cd4a6937 by Jaroslav Kysela at 2019-12-23T11:10:44+00:00
alsa-ucm: allow to set profile priority from UCM value

Signed-off-by: Jaroslav Kysela <perex at perex.cz>

- - - - -


9 changed files:

- src/modules/alsa/alsa-mixer.c
- src/modules/alsa/alsa-mixer.h
- src/modules/alsa/alsa-sink.c
- src/modules/alsa/alsa-source.c
- src/modules/alsa/alsa-ucm.c
- src/modules/alsa/alsa-ucm.h
- src/modules/alsa/alsa-util.c
- src/modules/alsa/alsa-util.h
- src/modules/alsa/module-alsa-card.c


Changes:

=====================================
src/modules/alsa/alsa-mixer.c
=====================================
@@ -147,13 +147,14 @@ static int alsa_id_decode(const char *src, char *name, int *index) {
     return 0;
 }
 
-pa_alsa_jack *pa_alsa_jack_new(pa_alsa_path *path, const char *name) {
+pa_alsa_jack *pa_alsa_jack_new(pa_alsa_path *path, const char *mixer_device_name, const char *name) {
     pa_alsa_jack *jack;
 
     pa_assert(name);
 
     jack = pa_xnew0(pa_alsa_jack, 1);
     jack->path = path;
+    jack->mixer_device_name = pa_xstrdup(mixer_device_name);
     jack->name = pa_xstrdup(name);
     jack->alsa_name = pa_sprintf_malloc("%s Jack", name);
     jack->state_unplugged = PA_AVAILABLE_NO;
@@ -172,6 +173,7 @@ void pa_alsa_jack_free(pa_alsa_jack *jack) {
 
     pa_xfree(jack->alsa_name);
     pa_xfree(jack->name);
+    pa_xfree(jack->mixer_device_name);
     pa_xfree(jack);
 }
 
@@ -739,6 +741,12 @@ void pa_alsa_path_set_free(pa_alsa_path_set *ps) {
     pa_xfree(ps);
 }
 
+int pa_alsa_path_set_is_empty(pa_alsa_path_set *ps) {
+    if (ps && !pa_hashmap_isempty(ps->paths))
+        return 0;
+    return 1;
+}
+
 static long to_alsa_dB(pa_volume_t v) {
     return lround(pa_sw_volume_to_dB(v) * 100.0);
 }
@@ -1982,7 +1990,7 @@ static pa_alsa_jack* jack_get(pa_alsa_path *p, const char *section) {
         if (pa_streq(j->name, section))
             goto finish;
 
-    j = pa_alsa_jack_new(p, section);
+    j = pa_alsa_jack_new(p, NULL, section);
     PA_LLIST_INSERT_AFTER(pa_alsa_jack, p->jacks, p->last_jack, j);
 
 finish:
@@ -4160,7 +4168,8 @@ fail:
 }
 
 static void mapping_paths_probe(pa_alsa_mapping *m, pa_alsa_profile *profile,
-                                pa_alsa_direction_t direction, pa_hashmap *used_paths) {
+                                pa_alsa_direction_t direction, pa_hashmap *used_paths,
+                                pa_hashmap *mixers) {
 
     pa_alsa_path *p;
     void *state;
@@ -4185,7 +4194,7 @@ static void mapping_paths_probe(pa_alsa_mapping *m, pa_alsa_profile *profile,
 
     pa_assert(pcm_handle);
 
-    mixer_handle = pa_alsa_open_mixer_for_pcm(pcm_handle, NULL);
+    mixer_handle = pa_alsa_open_mixer_for_pcm(mixers, pcm_handle, true);
     if (!mixer_handle) {
         /* Cannot open mixer, remove all entries */
         pa_hashmap_remove_all(ps->paths);
@@ -4203,9 +4212,6 @@ static void mapping_paths_probe(pa_alsa_mapping *m, pa_alsa_profile *profile,
     path_set_condense(ps, mixer_handle);
     path_set_make_path_descriptions_unique(ps);
 
-    if (mixer_handle)
-        snd_mixer_close(mixer_handle);
-
     PA_HASHMAP_FOREACH(p, ps->paths, state)
         pa_hashmap_put(used_paths, p, p);
 
@@ -4785,6 +4791,7 @@ static void mapping_query_hw_device(pa_alsa_mapping *mapping, snd_pcm_t *pcm) {
 
 void pa_alsa_profile_set_probe(
         pa_alsa_profile_set *ps,
+        pa_hashmap *mixers,
         const char *dev_id,
         const pa_sample_spec *ss,
         unsigned default_n_fragments,
@@ -4914,14 +4921,14 @@ void pa_alsa_profile_set_probe(
             PA_IDXSET_FOREACH(m, p->output_mappings, idx)
                 if (m->output_pcm) {
                     found_output |= !p->fallback_output;
-                    mapping_paths_probe(m, p, PA_ALSA_DIRECTION_OUTPUT, used_paths);
+                    mapping_paths_probe(m, p, PA_ALSA_DIRECTION_OUTPUT, used_paths, mixers);
                 }
 
         if (p->input_mappings)
             PA_IDXSET_FOREACH(m, p->input_mappings, idx)
                 if (m->input_pcm) {
                     found_input |= !p->fallback_input;
-                    mapping_paths_probe(m, p, PA_ALSA_DIRECTION_INPUT, used_paths);
+                    mapping_paths_probe(m, p, PA_ALSA_DIRECTION_INPUT, used_paths, mixers);
                 }
     }
 


=====================================
src/modules/alsa/alsa-mixer.h
=====================================
@@ -32,6 +32,7 @@
 #include <pulsecore/rtpoll.h>
 
 typedef struct pa_alsa_fdlist pa_alsa_fdlist;
+typedef struct pa_alsa_mixer pa_alsa_mixer;
 typedef struct pa_alsa_mixer_pdata pa_alsa_mixer_pdata;
 typedef struct pa_alsa_setting pa_alsa_setting;
 typedef struct pa_alsa_mixer_id pa_alsa_mixer_id;
@@ -98,6 +99,14 @@ struct pa_alsa_setting {
     unsigned priority;
 };
 
+/* An entry for one ALSA mixer */
+struct pa_alsa_mixer {
+    snd_mixer_t *mixer_handle;
+    int card_index;
+    pa_alsa_fdlist *fdl;
+    bool used_for_probe_only:1;
+};
+
 /* ALSA mixer element identifier */
 struct pa_alsa_mixer_id {
     char *name;
@@ -165,6 +174,9 @@ struct pa_alsa_jack {
     pa_alsa_path *path;
     PA_LLIST_FIELDS(pa_alsa_jack);
 
+    snd_mixer_t *mixer_handle;
+    char *mixer_device_name;
+
     char *name; /* E g "Headphone" */
     char *alsa_name; /* E g "Headphone Jack" */
     bool has_control; /* is the jack itself present? */
@@ -182,7 +194,7 @@ struct pa_alsa_jack {
     bool append_pcm_to_name;
 };
 
-pa_alsa_jack *pa_alsa_jack_new(pa_alsa_path *path, const char *name);
+pa_alsa_jack *pa_alsa_jack_new(pa_alsa_path *path, const char *mixer_device_name, const char *name);
 void pa_alsa_jack_free(pa_alsa_jack *jack);
 void pa_alsa_jack_set_has_control(pa_alsa_jack *jack, bool has_control);
 void pa_alsa_jack_set_plugged_in(pa_alsa_jack *jack, bool plugged_in);
@@ -201,6 +213,7 @@ struct pa_alsa_path {
     char *description;
     unsigned priority;
     bool autodetect_eld_device;
+    pa_alsa_mixer *eld_mixer_handle;
     int eld_device;
     pa_proplist *proplist;
 
@@ -259,6 +272,7 @@ pa_alsa_path_set *pa_alsa_path_set_new(pa_alsa_mapping *m, pa_alsa_direction_t d
 void pa_alsa_path_set_dump(pa_alsa_path_set *s);
 void pa_alsa_path_set_set_callback(pa_alsa_path_set *ps, snd_mixer_t *m, snd_mixer_elem_callback_t cb, void *userdata);
 void pa_alsa_path_set_free(pa_alsa_path_set *s);
+int pa_alsa_path_set_is_empty(pa_alsa_path_set *s);
 
 struct pa_alsa_mapping {
     pa_alsa_profile_set *profile_set;
@@ -359,14 +373,11 @@ void pa_alsa_decibel_fix_dump(pa_alsa_decibel_fix *db_fix);
 pa_alsa_mapping *pa_alsa_mapping_get(pa_alsa_profile_set *ps, const char *name);
 
 pa_alsa_profile_set* pa_alsa_profile_set_new(const char *fname, const pa_channel_map *bonus);
-void pa_alsa_profile_set_probe(pa_alsa_profile_set *ps, const char *dev_id, const pa_sample_spec *ss, unsigned default_n_fragments, unsigned default_fragment_size_msec);
+void pa_alsa_profile_set_probe(pa_alsa_profile_set *ps, pa_hashmap *mixers, const char *dev_id, const pa_sample_spec *ss, unsigned default_n_fragments, unsigned default_fragment_size_msec);
 void pa_alsa_profile_set_free(pa_alsa_profile_set *s);
 void pa_alsa_profile_set_dump(pa_alsa_profile_set *s);
 void pa_alsa_profile_set_drop_unsupported(pa_alsa_profile_set *s);
 
-snd_mixer_t *pa_alsa_open_mixer_by_name(const char *dev);
-snd_mixer_t *pa_alsa_open_mixer_for_pcm(snd_pcm_t *pcm, char **ctl_device);
-
 pa_alsa_fdlist *pa_alsa_fdlist_new(void);
 void pa_alsa_fdlist_free(pa_alsa_fdlist *fdl);
 int pa_alsa_fdlist_set_handle(pa_alsa_fdlist *fdl, snd_mixer_t *mixer_handle, snd_hctl_t *hctl_handle, pa_mainloop_api* m);


=====================================
src/modules/alsa/alsa-sink.c
=====================================
@@ -105,6 +105,7 @@ struct userdata {
     char *paths_dir;
     pa_alsa_fdlist *mixer_fdl;
     pa_alsa_mixer_pdata *mixer_pd;
+    pa_hashmap *mixers;
     snd_mixer_t *mixer_handle;
     pa_alsa_path_set *mixer_path_set;
     pa_alsa_path *mixer_path;
@@ -1650,7 +1651,6 @@ static int sink_set_port_ucm_cb(pa_sink *s, pa_device_port *p) {
 
     pa_assert(u);
     pa_assert(p);
-    pa_assert(u->mixer_handle);
     pa_assert(u->ucm_context);
 
     data = PA_DEVICE_PORT_DATA(p);
@@ -2088,13 +2088,19 @@ static void find_mixer(struct userdata *u, pa_alsa_mapping *mapping, const char
     if (!mapping && !element)
         return;
 
+    if (!element && mapping && pa_alsa_path_set_is_empty(mapping->output_path_set))
+        return;
+
+    u->mixers = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func,
+                                    NULL, (pa_free_cb_t) pa_alsa_mixer_free);
+
     mdev = pa_proplist_gets(mapping->proplist, "alsa.mixer_device");
     if (mdev) {
-        u->mixer_handle = pa_alsa_open_mixer_by_name(mdev);
+        u->mixer_handle = pa_alsa_open_mixer_by_name(u->mixers, mdev, true);
     } else {
-        u->mixer_handle = pa_alsa_open_mixer_for_pcm(u->pcm_handle, &u->control_device);
+        u->mixer_handle = pa_alsa_open_mixer_for_pcm(u->mixers, u->pcm_handle, true);
     }
-    if (!mdev) {
+    if (!u->mixer_handle) {
         pa_log_info("Failed to find a working mixer device.");
         return;
     }
@@ -2109,8 +2115,9 @@ static void find_mixer(struct userdata *u, pa_alsa_mapping *mapping, const char
 
         pa_log_debug("Probed mixer path %s:", u->mixer_path->name);
         pa_alsa_path_dump(u->mixer_path);
-    } else if (!(u->mixer_path_set = mapping->output_path_set))
-        goto fail;
+    } else {
+        u->mixer_path_set = mapping->output_path_set;
+    }
 
     return;
 
@@ -2121,10 +2128,9 @@ fail:
         u->mixer_path = NULL;
     }
 
-    if (u->mixer_handle) {
-        snd_mixer_close(u->mixer_handle);
-        u->mixer_handle = NULL;
-    }
+    u->mixer_handle = NULL;
+    pa_hashmap_free(u->mixers);
+    u->mixers = NULL;
 }
 
 static int setup_mixer(struct userdata *u, bool ignore_dB) {
@@ -2556,10 +2562,14 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca
         goto fail;
     }
 
-    if (u->ucm_context)
+    if (u->ucm_context) {
         pa_alsa_ucm_add_ports(&data.ports, data.proplist, u->ucm_context, true, card, u->pcm_handle, ignore_dB);
-    else if (u->mixer_path_set)
-        pa_alsa_add_ports(&data, u->mixer_path_set, card);
+        find_mixer(u, mapping, pa_modargs_get_value(ma, "control", NULL), ignore_dB);
+    } else {
+        find_mixer(u, mapping, pa_modargs_get_value(ma, "control", NULL), ignore_dB);
+        if (u->mixer_path_set)
+            pa_alsa_add_ports(&data, u->mixer_path_set, card);
+    }
 
     u->sink = pa_sink_new(m->core, &data, PA_SINK_HARDWARE | PA_SINK_LATENCY | (u->use_tsched ? PA_SINK_DYNAMIC_LATENCY : 0) |
                           (set_formats ? PA_SINK_SET_FORMATS : 0));
@@ -2759,8 +2769,8 @@ static void userdata_free(struct userdata *u) {
     if (u->mixer_path && !u->mixer_path_set && !u->ucm_context)
         pa_alsa_path_free(u->mixer_path);
 
-    if (u->mixer_handle)
-        snd_mixer_close(u->mixer_handle);
+    if (u->mixers)
+        pa_hashmap_free(u->mixers);
 
     if (u->smoother)
         pa_smoother_free(u->smoother);


=====================================
src/modules/alsa/alsa-source.c
=====================================
@@ -93,6 +93,7 @@ struct userdata {
     char *paths_dir;
     pa_alsa_fdlist *mixer_fdl;
     pa_alsa_mixer_pdata *mixer_pd;
+    pa_hashmap *mixers;
     snd_mixer_t *mixer_handle;
     pa_alsa_path_set *mixer_path_set;
     pa_alsa_path *mixer_path;
@@ -1521,7 +1522,6 @@ static int source_set_port_ucm_cb(pa_source *s, pa_device_port *p) {
 
     pa_assert(u);
     pa_assert(p);
-    pa_assert(u->mixer_handle);
     pa_assert(u->ucm_context);
 
     data = PA_DEVICE_PORT_DATA(p);
@@ -1794,13 +1794,19 @@ static void find_mixer(struct userdata *u, pa_alsa_mapping *mapping, const char
     if (!mapping && !element)
         return;
 
+    if (!element && mapping && pa_alsa_path_set_is_empty(mapping->input_path_set))
+        return;
+
+    u->mixers = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func,
+                                    NULL, (pa_free_cb_t) pa_alsa_mixer_free);
+
     mdev = pa_proplist_gets(mapping->proplist, "alsa.mixer_device");
     if (mdev) {
-        u->mixer_handle = pa_alsa_open_mixer_by_name(mdev);
+        u->mixer_handle = pa_alsa_open_mixer_by_name(u->mixers, mdev, false);
     } else {
-        u->mixer_handle = pa_alsa_open_mixer_for_pcm(u->pcm_handle, &u->control_device);
+        u->mixer_handle = pa_alsa_open_mixer_for_pcm(u->mixers, u->pcm_handle, false);
     }
-    if (!mdev) {
+    if (!u->mixer_handle) {
         pa_log_info("Failed to find a working mixer device.");
         return;
     }
@@ -1815,8 +1821,9 @@ static void find_mixer(struct userdata *u, pa_alsa_mapping *mapping, const char
 
         pa_log_debug("Probed mixer path %s:", u->mixer_path->name);
         pa_alsa_path_dump(u->mixer_path);
-    } else if (!(u->mixer_path_set = mapping->input_path_set))
-        goto fail;
+    } else {
+        u->mixer_path_set = mapping->input_path_set;
+    }
 
     return;
 
@@ -1827,10 +1834,9 @@ fail:
         u->mixer_path = NULL;
     }
 
-    if (u->mixer_handle) {
-        snd_mixer_close(u->mixer_handle);
-        u->mixer_handle = NULL;
-    }
+    u->mixer_handle = NULL;
+    pa_hashmap_free(u->mixers);
+    u->mixers = NULL;
 }
 
 static int setup_mixer(struct userdata *u, bool ignore_dB) {
@@ -2403,8 +2409,8 @@ static void userdata_free(struct userdata *u) {
     if (u->mixer_path && !u->mixer_path_set && !u->ucm_context)
         pa_alsa_path_free(u->mixer_path);
 
-    if (u->mixer_handle)
-        snd_mixer_close(u->mixer_handle);
+    if (u->mixers)
+        pa_hashmap_free(u->mixers);
 
     if (u->smoother)
         pa_smoother_free(u->smoother);


=====================================
src/modules/alsa/alsa-ucm.c
=====================================
@@ -146,6 +146,26 @@ static struct ucm_info dev_info[] = {
     {NULL, 0}
 };
 
+
+static char *ucm_verb_value(
+    snd_use_case_mgr_t *uc_mgr,
+    const char *verb_name,
+    const char *id) {
+
+    const char *value;
+    char *_id = pa_sprintf_malloc("=%s//%s", id, verb_name);
+    int err = snd_use_case_get(uc_mgr, _id, &value);
+    pa_xfree(_id);
+    if (err < 0)
+         return NULL;
+    pa_log_debug("Got %s for verb %s: %s", id, verb_name, value);
+    /* Use the cast here to allow free() call without casting for callers.
+     * The snd_use_case_get() returns mallocated string.
+     * See the Note: in use-case.h for snd_use_case_get().
+     */
+    return (char *)value;
+}
+
 static int ucm_device_exists(pa_idxset *idxset, pa_alsa_ucm_device *dev) {
     pa_alsa_ucm_device *d;
     uint32_t idx;
@@ -766,6 +786,8 @@ int pa_alsa_ucm_get_verb(snd_use_case_mgr_t *uc_mgr, const char *verb_name, cons
     pa_alsa_ucm_device *d;
     pa_alsa_ucm_modifier *mod;
     pa_alsa_ucm_verb *verb;
+    char *value;
+    unsigned ui;
     int err = 0;
 
     *p_verb = NULL;
@@ -780,6 +802,11 @@ int pa_alsa_ucm_get_verb(snd_use_case_mgr_t *uc_mgr, const char *verb_name, cons
     pa_proplist_sets(verb->proplist, PA_ALSA_PROP_UCM_NAME, pa_strnull(verb_name));
     pa_proplist_sets(verb->proplist, PA_ALSA_PROP_UCM_DESCRIPTION, pa_strna(verb_desc));
 
+    value = ucm_verb_value(uc_mgr, verb_name, "Priority");
+    if (value && !pa_atou(value, &ui))
+        verb->priority = ui > 10000 ? 10000 : ui;
+    free(value);
+
     err = ucm_get_devices(verb, uc_mgr);
     if (err < 0)
         pa_log("No UCM devices for verb %s", verb_name);
@@ -820,13 +847,43 @@ static int pa_alsa_ucm_device_cmp(const void *a, const void *b) {
     return strcmp(pa_proplist_gets(d1->proplist, PA_ALSA_PROP_UCM_NAME), pa_proplist_gets(d2->proplist, PA_ALSA_PROP_UCM_NAME));
 }
 
-static void probe_volumes(pa_hashmap *hash, bool is_sink, snd_pcm_t *pcm_handle, bool ignore_dB) {
+static void set_eld_devices(pa_hashmap *hash)
+{
+    pa_device_port *port;
+    pa_alsa_ucm_port_data *data;
+    pa_alsa_ucm_device *dev;
+    const char *eld_mixer_device_name;
+    void *state;
+    int idx, eld_device;
+
+    PA_HASHMAP_FOREACH(port, hash, state) {
+        data = PA_DEVICE_PORT_DATA(port);
+        eld_mixer_device_name = NULL;
+        eld_device = -1;
+        PA_DYNARRAY_FOREACH(dev, data->devices, idx) {
+            if (dev->eld_device >= 0 && dev->eld_mixer_device_name) {
+                if (eld_device >= 0 && eld_device != dev->eld_device) {
+                    pa_log_error("The ELD device is already set!");
+                } else if (eld_mixer_device_name && pa_streq(dev->eld_mixer_device_name, eld_mixer_device_name)) {
+                    pa_log_error("The ELD mixer device is already set (%s, %s)!", dev->eld_mixer_device_name, dev->eld_mixer_device_name);
+                } else {
+                    eld_mixer_device_name = dev->eld_mixer_device_name;
+                    eld_device = dev->eld_device;
+                }
+            }
+        }
+        data->eld_device = eld_device;
+        data->eld_mixer_device_name = pa_xstrdup(eld_mixer_device_name);
+    }
+}
+
+static void probe_volumes(pa_hashmap *hash, bool is_sink, snd_pcm_t *pcm_handle, pa_hashmap *mixers, bool ignore_dB) {
     pa_device_port *port;
     pa_alsa_path *path;
     pa_alsa_ucm_port_data *data;
     pa_alsa_ucm_device *dev;
-    snd_mixer_t *mixer_handle = NULL;
-    const char *profile, *mdev_opened = NULL, *mdev, *mdev2;
+    snd_mixer_t *mixer_handle;
+    const char *profile, *mdev, *mdev2;
     void *state, *state2;
     int idx;
 
@@ -843,16 +900,9 @@ static void probe_volumes(pa_hashmap *hash, bool is_sink, snd_pcm_t *pcm_handle,
             mdev = mdev2;
         }
 
-        if (!mdev_opened || !pa_streq(mdev_opened, mdev)) {
-            if (mixer_handle) {
-                snd_mixer_close(mixer_handle);
-                mdev_opened = NULL;
-            }
-            if (!(mixer_handle = pa_alsa_open_mixer_by_name(mdev))) {
-                pa_log_error("Failed to find a working mixer device (%s).", mdev);
-                goto fail;
-            }
-            mdev_opened = mdev;
+        if (!(mixer_handle = pa_alsa_open_mixer_by_name(mixers, mdev, true))) {
+            pa_log_error("Failed to find a working mixer device (%s).", mdev);
+            goto fail;
         }
 
         PA_HASHMAP_FOREACH_KV(profile, path, data->paths, state2) {
@@ -867,9 +917,6 @@ static void probe_volumes(pa_hashmap *hash, bool is_sink, snd_pcm_t *pcm_handle,
         }
     }
 
-    if (mixer_handle)
-        snd_mixer_close(mixer_handle);
-
     return;
 
 fail:
@@ -1169,6 +1216,9 @@ void pa_alsa_ucm_add_ports_combination(
         ucm_add_ports_combination(p, context, is_sink, pdevices, 0, PA_IDXSET_INVALID, ports, cp, core);
         pa_xfree(pdevices);
     }
+
+    /* ELD devices */
+    set_eld_devices(ports);
 }
 
 void pa_alsa_ucm_add_ports(
@@ -1194,7 +1244,7 @@ void pa_alsa_ucm_add_ports(
     pa_alsa_ucm_add_ports_combination(*p, context, is_sink, card->ports, NULL, card->core);
 
     /* now set up volume paths if any */
-    probe_volumes(*p, is_sink, pcm_handle, ignore_dB);
+    probe_volumes(*p, is_sink, pcm_handle, context->ucm->mixers, ignore_dB);
 
     /* then set property PA_PROP_DEVICE_INTENDED_ROLES */
     merged_roles = pa_xstrdup(pa_proplist_gets(proplist, PA_PROP_DEVICE_INTENDED_ROLES));
@@ -1543,6 +1593,7 @@ static pa_alsa_jack* ucm_get_jack(pa_alsa_ucm_config *ucm, pa_alsa_ucm_device *d
     pa_alsa_jack *j;
     const char *device_name;
     const char *jack_control;
+    const char *mixer_device_name;
     char *name;
 
     pa_assert(ucm);
@@ -1585,7 +1636,14 @@ static pa_alsa_jack* ucm_get_jack(pa_alsa_ucm_config *ucm, pa_alsa_ucm_device *d
         if (pa_streq(j->name, name))
             goto finish;
 
-    j = pa_alsa_jack_new(NULL, name);
+    mixer_device_name = get_jack_mixer_device(device, true);
+    if (!mixer_device_name)
+        mixer_device_name = get_jack_mixer_device(device, false);
+    if (!mixer_device_name) {
+        pa_log("[%s] No mixer device name for JackControl \"%s\"", device_name, jack_control);
+        return NULL;
+    }
+    j = pa_alsa_jack_new(NULL, mixer_device_name, name);
     PA_LLIST_PREPEND(pa_alsa_jack, ucm->jacks, j);
 
 finish:
@@ -1606,7 +1664,7 @@ static int ucm_create_profile(
     pa_alsa_ucm_modifier *mod;
     int i = 0;
     const char *name, *sink, *source;
-    char *verb_cmp, *c;
+    unsigned int priority;
 
     pa_assert(ps);
 
@@ -1626,24 +1684,26 @@ static int ucm_create_profile(
     p->supported = true;
     pa_hashmap_put(ps->profiles, p->name, p);
 
-    /* TODO: get profile priority from ucm info or policy management */
-    c = verb_cmp = pa_xstrdup(verb_name);
-    while (*c) {
-        if (*c == '_') *c = ' ';
-        c++;
-    }
+    /* TODO: get profile priority from policy management */
+    priority = verb->priority;
 
-    for (i = 0; verb_info[i].id; i++) {
-        if (strcasecmp(verb_info[i].id, verb_cmp) == 0) {
-            p->priority = verb_info[i].priority;
-            break;
+    if (priority == 0) {
+        char *verb_cmp, *c;
+        c = verb_cmp = pa_xstrdup(verb_name);
+        while (*c) {
+            if (*c == '_') *c = ' ';
+            c++;
+        }
+        for (i = 0; verb_info[i].id; i++) {
+            if (strcasecmp(verb_info[i].id, verb_cmp) == 0) {
+                priority = verb_info[i].priority;
+                break;
+            }
         }
+        pa_xfree(verb_cmp);
     }
 
-    pa_xfree(verb_cmp);
-
-    if (verb_info[i].id == NULL)
-        p->priority = 1000;
+    p->priority = priority;
 
     PA_LLIST_FOREACH(dev, verb->devices) {
         pa_alsa_jack *jack;
@@ -1711,6 +1771,33 @@ static int ucm_create_profile(
     return 0;
 }
 
+static void mapping_init_eld(pa_alsa_mapping *m, snd_pcm_t *pcm)
+{
+    pa_alsa_ucm_mapping_context *context = &m->ucm_context;
+    pa_alsa_ucm_device *dev;
+    uint32_t idx;
+    char *mdev;
+    snd_pcm_info_t *info;
+    int pcm_card, pcm_device;
+
+    snd_pcm_info_alloca(&info);
+    if (snd_pcm_info(pcm, info) < 0)
+        return;
+
+    if ((pcm_card = snd_pcm_info_get_card(info)) < 0)
+        return;
+    if ((pcm_device = snd_pcm_info_get_device(info)) < 0)
+        return;
+
+    PA_IDXSET_FOREACH(dev, context->ucm_devices, idx) {
+       mdev = pa_sprintf_malloc("hw:%i", pcm_card);
+       if (mdev == NULL)
+           continue;
+       dev->eld_mixer_device_name = mdev;
+       dev->eld_device = pcm_device;
+    }
+}
+
 static snd_pcm_t* mapping_open_pcm(pa_alsa_ucm_config *ucm, pa_alsa_mapping *m, int mode) {
     snd_pcm_t* pcm;
     pa_sample_spec try_ss = ucm->core->default_sample_spec;
@@ -1732,8 +1819,11 @@ static snd_pcm_t* mapping_open_pcm(pa_alsa_ucm_config *ucm, pa_alsa_mapping *m,
     pcm = pa_alsa_open_by_device_string(m->device_strings[0], NULL, &try_ss,
             &try_map, mode, &try_period_size, &try_buffer_size, 0, NULL, NULL, exact_channels);
 
-    if (pcm && !exact_channels)
-        m->channel_map = try_map;
+    if (pcm) {
+        if (!exact_channels)
+            m->channel_map = try_map;
+        mapping_init_eld(m, pcm);
+    }
 
     return pcm;
 }
@@ -1765,44 +1855,28 @@ static void profile_finalize_probing(pa_alsa_profile *p) {
     }
 }
 
-static void ucm_mapping_jack_probe(pa_alsa_mapping *m) {
-    snd_mixer_t *mixer_handle = NULL;
+static void ucm_mapping_jack_probe(pa_alsa_mapping *m, pa_hashmap *mixers) {
+    snd_mixer_t *mixer_handle;
     pa_alsa_ucm_mapping_context *context = &m->ucm_context;
     pa_alsa_ucm_device *dev;
-    bool is_sink = m->direction == PA_ALSA_DIRECTION_OUTPUT;
-    const char *mdev_opened = NULL, *mdev;
     uint32_t idx;
 
     PA_IDXSET_FOREACH(dev, context->ucm_devices, idx) {
         bool has_control;
 
-        if (!dev->jack)
+        if (!dev->jack || !dev->jack->mixer_device_name)
             continue;
 
-        mdev = get_jack_mixer_device(dev, is_sink);
-        if (mdev == NULL) {
-            pa_log_error("Unable to determine mixer device for jack %s", dev->jack->name);
+        mixer_handle = pa_alsa_open_mixer_by_name(mixers, dev->jack->mixer_device_name, true);
+        if (!mixer_handle) {
+            pa_log_error("Unable to determine open mixer device '%s' for jack %s", dev->jack->mixer_device_name, dev->jack->name);
             continue;
         }
 
-        if (!mdev_opened || !pa_streq(mdev_opened, mdev)) {
-            if (mixer_handle) {
-                snd_mixer_close(mixer_handle);
-                mdev_opened = NULL;
-            }
-            mixer_handle = pa_alsa_open_mixer_by_name(mdev);
-            if (!mixer_handle)
-                continue;
-            mdev_opened = mdev;
-        }
-
         has_control = pa_alsa_mixer_find_card(mixer_handle, dev->jack->alsa_name, 0) != NULL;
         pa_alsa_jack_set_has_control(dev->jack, has_control);
         pa_log_info("UCM jack %s has_control=%d", dev->jack->name, dev->jack->has_control);
     }
-
-    if (mixer_handle)
-        snd_mixer_close(mixer_handle);
 }
 
 static void ucm_probe_profile_set(pa_alsa_ucm_config *ucm, pa_alsa_profile_set *ps) {
@@ -1860,11 +1934,11 @@ static void ucm_probe_profile_set(pa_alsa_ucm_config *ucm, pa_alsa_profile_set *
 
         PA_IDXSET_FOREACH(m, p->output_mappings, idx)
             if (!PA_UCM_IS_MODIFIER_MAPPING(m))
-                ucm_mapping_jack_probe(m);
+                ucm_mapping_jack_probe(m, ucm->mixers);
 
         PA_IDXSET_FOREACH(m, p->input_mappings, idx)
             if (!PA_UCM_IS_MODIFIER_MAPPING(m))
-                ucm_mapping_jack_probe(m);
+                ucm_mapping_jack_probe(m, ucm->mixers);
 
         profile_finalize_probing(p);
     }
@@ -1930,6 +2004,8 @@ static void free_verb(pa_alsa_ucm_verb *verb) {
         if (di->supported_devices)
             pa_idxset_free(di->supported_devices, NULL);
 
+        pa_xfree(di->eld_mixer_device_name);
+
         pa_xfree(di);
     }
 
@@ -2133,6 +2209,7 @@ static void ucm_port_data_init(pa_alsa_ucm_port_data *port, pa_alsa_ucm_config *
     port->ucm = ucm;
     port->core_port = core_port;
     port->devices = pa_dynarray_new(NULL);
+    port->eld_device = -1;
 
     for (i = 0; i < n_devices; i++) {
         pa_dynarray_append(port->devices, devices[i]);
@@ -2157,6 +2234,8 @@ static void ucm_port_data_free(pa_device_port *port) {
 
     if (ucm_port->paths)
         pa_hashmap_free(ucm_port->paths);
+
+    pa_xfree(ucm_port->eld_mixer_device_name);
 }
 
 static void ucm_port_update_available(pa_alsa_ucm_port_data *port) {


=====================================
src/modules/alsa/alsa-ucm.h
=====================================
@@ -207,6 +207,9 @@ struct pa_alsa_ucm_device {
     pa_alsa_jack *jack;
     pa_dynarray *hw_mute_jacks; /* pa_alsa_jack */
     pa_available_t available;
+
+    char *eld_mixer_device_name;
+    int eld_device;
 };
 
 void pa_alsa_ucm_device_update_available(pa_alsa_ucm_device *device);
@@ -238,6 +241,7 @@ struct pa_alsa_ucm_verb {
     PA_LLIST_FIELDS(pa_alsa_ucm_verb);
 
     pa_proplist *proplist;
+    unsigned priority;
 
     PA_LLIST_HEAD(pa_alsa_ucm_device, devices);
     PA_LLIST_HEAD(pa_alsa_ucm_modifier, modifiers);
@@ -248,6 +252,7 @@ struct pa_alsa_ucm_config {
     snd_use_case_mgr_t *ucm_mgr;
     pa_alsa_ucm_verb *active_verb;
 
+    pa_hashmap *mixers;
     PA_LLIST_HEAD(pa_alsa_ucm_verb, verbs);
     PA_LLIST_HEAD(pa_alsa_jack, jacks);
 };
@@ -272,6 +277,10 @@ struct pa_alsa_ucm_port_data {
     pa_hashmap *paths;
     /* Current path, set when activating profile */
     pa_alsa_path *path;
+
+    /* ELD info */
+    char *eld_mixer_device_name;
+    int eld_device; /* PCM device number */
 };
 
 struct pa_alsa_ucm_volume {


=====================================
src/modules/alsa/alsa-util.c
=====================================
@@ -1726,83 +1726,119 @@ static int prepare_mixer(snd_mixer_t *mixer, const char *dev) {
     return 0;
 }
 
-snd_mixer_t *pa_alsa_open_mixer(int alsa_card_index, char **ctl_device) {
-    int err;
-    snd_mixer_t *m;
-    char *md;
-    snd_pcm_info_t* info;
-    snd_pcm_info_alloca(&info);
-
-    if ((err = snd_mixer_open(&m, 0)) < 0) {
-        pa_log("Error opening mixer: %s", pa_alsa_strerror(err));
-        return NULL;
-    }
-
-    /* Then, try by card index */
-    md = pa_sprintf_malloc("hw:%i", alsa_card_index);
-    if (prepare_mixer(m, md) >= 0) {
-
-        if (ctl_device)
-            *ctl_device = md;
-        else
-            pa_xfree(md);
-
-        return m;
-    }
-
+snd_mixer_t *pa_alsa_open_mixer(pa_hashmap *mixers, int alsa_card_index, bool probe) {
+    char *md = pa_sprintf_malloc("hw:%i", alsa_card_index);
+    snd_mixer_t *m = pa_alsa_open_mixer_by_name(mixers, md, probe);
     pa_xfree(md);
-
-    snd_mixer_close(m);
-    return NULL;
+    return m;
 }
 
-snd_mixer_t *pa_alsa_open_mixer_by_name(const char *dev) {
+snd_mixer_t *pa_alsa_open_mixer_by_name(pa_hashmap *mixers, const char *dev, bool probe) {
     int err;
     snd_mixer_t *m;
+    pa_alsa_mixer *pm;
+    char *dev2;
+    void *state;
 
+    pa_assert(mixers);
     pa_assert(dev);
 
+    pm = pa_hashmap_get(mixers, dev);
+
+    /* The quick card number/index lookup (hw:#)
+     * We already know the card number/index, thus use the mixer
+     * from the cache at first.
+     */
+    if (!pm && pa_strneq(dev, "hw:", 3)) {
+        const char *s = dev + 3;
+        int card_index;
+        while (*s && *s >= 0 && *s <= '9') s++;
+        if (*s == '\0' && pa_atoi(dev + 3, &card_index) >= 0) {
+            PA_HASHMAP_FOREACH_KV(dev2, pm, mixers, state) {
+                if (pm->card_index == card_index) {
+                    dev = dev2;
+                    pm = pa_hashmap_get(mixers, dev);
+                    break;
+                }
+            }
+        }
+    }
+
+    if (pm) {
+        if (!probe)
+            pm->used_for_probe_only = false;
+        return pm->mixer_handle;
+    }
+
     if ((err = snd_mixer_open(&m, 0)) < 0) {
         pa_log("Error opening mixer: %s", pa_alsa_strerror(err));
         return NULL;
     }
 
-    if (prepare_mixer(m, dev) >= 0)
-        return m;
+    if (prepare_mixer(m, dev) >= 0) {
+        pm = pa_xnew0(pa_alsa_mixer, 1);
+        if (pm) {
+            snd_hctl_t *hctl;
+            pm->card_index = -1;
+            /* determine the ALSA card number (index) and store it to card_index */
+            err = snd_mixer_get_hctl(m, dev, &hctl);
+            if (err >= 0) {
+                snd_ctl_card_info_t *info;
+                snd_ctl_card_info_alloca(&info);
+                err = snd_ctl_card_info(snd_hctl_ctl(hctl), info);
+                if (err >= 0)
+                    pm->card_index = snd_ctl_card_info_get_card(info);
+            }
+            pm->used_for_probe_only = probe;
+            pm->mixer_handle = m;
+            pa_hashmap_put(mixers, pa_xstrdup(dev), pm);
+            return m;
+        }
+    }
 
     snd_mixer_close(m);
     return NULL;
 }
 
-snd_mixer_t *pa_alsa_open_mixer_for_pcm(snd_pcm_t *pcm, char **ctl_device) {
-    snd_mixer_t *m;
+snd_mixer_t *pa_alsa_open_mixer_for_pcm(pa_hashmap *mixers, snd_pcm_t *pcm, bool probe) {
     snd_pcm_info_t* info;
     snd_pcm_info_alloca(&info);
 
     pa_assert(pcm);
 
     if (snd_pcm_info(pcm, info) >= 0) {
-        char *md;
         int card_idx;
 
-        if ((card_idx = snd_pcm_info_get_card(info)) >= 0) {
+        if ((card_idx = snd_pcm_info_get_card(info)) >= 0)
+            return pa_alsa_open_mixer(mixers, card_idx, probe);
+    }
+
+    return NULL;
+}
 
-            md = pa_sprintf_malloc("hw:%i", card_idx);
-            m = pa_alsa_open_mixer_by_name(md);
-            if (m) {
-                if (ctl_device)
-                    *ctl_device = md;
-                else
-                    pa_xfree(md);
+void pa_alsa_mixer_set_fdlist(pa_hashmap *mixers, snd_mixer_t *mixer_handle, pa_mainloop_api *ml)
+{
+    pa_alsa_mixer *pm;
+    void *state;
 
-                return m;
+    PA_HASHMAP_FOREACH(pm, mixers, state)
+        if (pm->mixer_handle == mixer_handle) {
+            pm->used_for_probe_only = false;
+            if (!pm->fdl) {
+                pm->fdl = pa_alsa_fdlist_new();
+                if (pm->fdl)
+                    pa_alsa_fdlist_set_handle(pm->fdl, pm->mixer_handle, NULL, ml);
             }
-
-            pa_xfree(md);
         }
-    }
+}
 
-    return NULL;
+void pa_alsa_mixer_free(pa_alsa_mixer *mixer)
+{
+    if (mixer->fdl)
+        pa_alsa_fdlist_free(mixer->fdl);
+    if (mixer->mixer_handle)
+        snd_mixer_close(mixer->mixer_handle);
+    pa_xfree(mixer);
 }
 
 int pa_alsa_get_hdmi_eld(snd_hctl_elem_t *elem, pa_hdmi_eld *eld) {


=====================================
src/modules/alsa/alsa-util.h
=====================================
@@ -144,7 +144,11 @@ bool pa_alsa_may_tsched(bool want);
 snd_mixer_elem_t *pa_alsa_mixer_find_card(snd_mixer_t *mixer, const char *name, unsigned int device);
 snd_mixer_elem_t *pa_alsa_mixer_find_pcm(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_mixer_t *pa_alsa_open_mixer(pa_hashmap *mixers, int alsa_card_index, bool probe);
+snd_mixer_t *pa_alsa_open_mixer_by_name(pa_hashmap *mixers, const char *dev, bool probe);
+snd_mixer_t *pa_alsa_open_mixer_for_pcm(pa_hashmap *mixers, snd_pcm_t *pcm, bool probe);
+void pa_alsa_mixer_set_fdlist(pa_hashmap *mixers, snd_mixer_t *mixer, pa_mainloop_api *ml);
+void pa_alsa_mixer_free(pa_alsa_mixer *mixer);
 
 typedef struct pa_hdmi_eld pa_hdmi_eld;
 struct pa_hdmi_eld {


=====================================
src/modules/alsa/module-alsa-card.c
=====================================
@@ -111,9 +111,8 @@ struct userdata {
     char *device_id;
     int alsa_card_index;
 
-    snd_mixer_t *mixer_handle;
+    pa_hashmap *mixers;
     pa_hashmap *jacks;
-    pa_alsa_fdlist *mixer_fdl;
 
     pa_card *card;
 
@@ -513,15 +512,24 @@ static int report_jack_state(snd_mixer_elem_t *melem, unsigned int mask) {
     return 0;
 }
 
-static pa_device_port* find_port_with_eld_device(pa_hashmap *ports, int device) {
+static pa_device_port* find_port_with_eld_device(struct userdata *u, int device) {
     void *state;
     pa_device_port *p;
 
-    PA_HASHMAP_FOREACH(p, ports, state) {
-        pa_alsa_port_data *data = PA_DEVICE_PORT_DATA(p);
-        pa_assert(data->path);
-        if (device == data->path->eld_device)
-            return p;
+    if (u->use_ucm) {
+        PA_HASHMAP_FOREACH(p, u->card->ports, state) {
+            pa_alsa_ucm_port_data *data = PA_DEVICE_PORT_DATA(p);
+            pa_assert(data->eld_mixer_device_name);
+            if (device == data->eld_device)
+                return p;
+        }
+    } else {
+        PA_HASHMAP_FOREACH(p, u->card->ports, state) {
+            pa_alsa_port_data *data = PA_DEVICE_PORT_DATA(p);
+            pa_assert(data->path);
+            if (device == data->path->eld_device)
+                return p;
+        }
     }
     return NULL;
 }
@@ -538,10 +546,7 @@ static int hdmi_eld_changed(snd_mixer_elem_t *melem, unsigned int mask) {
     if (mask == SND_CTL_EVENT_MASK_REMOVE)
         return 0;
 
-    if (u->use_ucm)
-        return 0;
-
-    p = find_port_with_eld_device(u->card->ports, device);
+    p = find_port_with_eld_device(u, device);
     if (p == NULL) {
         pa_log_error("Invalid device changed in ALSA: %d", device);
         return 0;
@@ -569,33 +574,46 @@ static void init_eld_ctls(struct userdata *u) {
     void *state;
     pa_device_port *port;
 
-    if (!u->mixer_handle)
-        return;
-
     /* The code in this function expects ports to have a pa_alsa_port_data
      * struct as their data, but in UCM mode ports don't have any data. Hence,
      * the ELD controls can't currently be used in UCM mode. */
-    if (u->use_ucm)
-        return;
-
     PA_HASHMAP_FOREACH(port, u->card->ports, state) {
-        pa_alsa_port_data *data = PA_DEVICE_PORT_DATA(port);
+        snd_mixer_t *mixer_handle;
         snd_mixer_elem_t* melem;
         int device;
 
-        pa_assert(data->path);
-        device = data->path->eld_device;
-        if (device < 0)
+        if (u->use_ucm) {
+            pa_alsa_ucm_port_data *data = PA_DEVICE_PORT_DATA(port);
+            device = data->eld_device;
+            if (device < 0 || !data->eld_mixer_device_name)
+                continue;
+
+            mixer_handle = pa_alsa_open_mixer_by_name(u->mixers, data->eld_mixer_device_name, true);
+        } else {
+            pa_alsa_port_data *data = PA_DEVICE_PORT_DATA(port);
+
+            pa_assert(data->path);
+
+            device = data->path->eld_device;
+            if (device < 0)
+                continue;
+
+            mixer_handle = pa_alsa_open_mixer(u->mixers, u->alsa_card_index, true);
+        }
+
+        if (!mixer_handle)
             continue;
 
-        melem = pa_alsa_mixer_find_pcm(u->mixer_handle, "ELD", device);
+        melem = pa_alsa_mixer_find_pcm(mixer_handle, "ELD", device);
         if (melem) {
+            pa_alsa_mixer_set_fdlist(u->mixers, mixer_handle, u->core->mainloop);
             snd_mixer_elem_set_callback(melem, hdmi_eld_changed);
             snd_mixer_elem_set_callback_private(melem, u);
             hdmi_eld_changed(melem, 0);
+            pa_log_info("ELD device found for port %s (%d).", port->name, device);
         }
         else
-            pa_log_debug("No ELD device found for port %s.", port->name);
+            pa_log_debug("No ELD device found for port %s (%d).", port->name, device);
     }
 }
 
@@ -630,25 +648,31 @@ static void init_jacks(struct userdata *u) {
     if (pa_hashmap_size(u->jacks) == 0)
         return;
 
-    u->mixer_fdl = pa_alsa_fdlist_new();
-
-    u->mixer_handle = pa_alsa_open_mixer(u->alsa_card_index, NULL);
-    if (u->mixer_handle && pa_alsa_fdlist_set_handle(u->mixer_fdl, u->mixer_handle, NULL, u->core->mainloop) >= 0) {
-        PA_HASHMAP_FOREACH(jack, u->jacks, state) {
-            jack->melem = pa_alsa_mixer_find_card(u->mixer_handle, jack->alsa_name, 0);
-            if (!jack->melem) {
-                pa_log_warn("Jack '%s' seems to have disappeared.", jack->alsa_name);
-                pa_alsa_jack_set_has_control(jack, false);
-                continue;
+    PA_HASHMAP_FOREACH(jack, u->jacks, state) {
+        if (!jack->mixer_device_name) {
+            jack->mixer_handle = pa_alsa_open_mixer(u->mixers, u->alsa_card_index, false);
+            if (!jack->mixer_handle) {
+               pa_log("Failed to open mixer for card %d for jack detection", u->alsa_card_index);
+               continue;
+            }
+        } else {
+            jack->mixer_handle = pa_alsa_open_mixer_by_name(u->mixers, jack->mixer_device_name, false);
+            if (!jack->mixer_handle) {
+               pa_log("Failed to open mixer '%s' for jack detection", jack->mixer_device_name);
+              continue;
             }
-            snd_mixer_elem_set_callback(jack->melem, report_jack_state);
-            snd_mixer_elem_set_callback_private(jack->melem, u);
-            report_jack_state(jack->melem, 0);
         }
-
-    } else
-        pa_log("Failed to open mixer for jack detection");
-
+        pa_alsa_mixer_set_fdlist(u->mixers, jack->mixer_handle, u->core->mainloop);
+        jack->melem = pa_alsa_mixer_find_card(jack->mixer_handle, jack->alsa_name, 0);
+        if (!jack->melem) {
+            pa_log_warn("Jack '%s' seems to have disappeared.", jack->alsa_name);
+            pa_alsa_jack_set_has_control(jack, false);
+            continue;
+        }
+        snd_mixer_elem_set_callback(jack->melem, report_jack_state);
+        snd_mixer_elem_set_callback_private(jack->melem, u);
+        report_jack_state(jack->melem, 0);
+    }
 }
 
 static void set_card_name(pa_card_new_data *data, pa_modargs *ma, const char *device_id) {
@@ -772,6 +796,10 @@ int pa__init(pa_module *m) {
     u->use_ucm = true;
     u->ucm.core = m->core;
 
+    u->mixers = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func,
+                                    pa_xfree, (pa_free_cb_t) pa_alsa_mixer_free);
+    u->ucm.mixers = u->mixers; /* alias */
+
     if (!(u->modargs = pa_modargs_new(m->argument, valid_modargs))) {
         pa_log("Failed to parse module arguments.");
         goto fail;
@@ -852,7 +880,7 @@ int pa__init(pa_module *m) {
 
     u->profile_set->ignore_dB = ignore_dB;
 
-    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_probe(u->profile_set, u->mixers, 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);
 
     pa_card_new_data_init(&data);
@@ -952,6 +980,16 @@ int pa__init(pa_module *m) {
     init_profile(u);
     init_eld_ctls(u);
 
+    /* Remove all probe only mixers */
+    if (u->mixers) {
+       const char *devname;
+       pa_alsa_mixer *pm;
+       void *state;
+       PA_HASHMAP_FOREACH_KV(devname, pm, u->mixers, state)
+           if (pm->used_for_probe_only)
+               pa_hashmap_remove_and_free(u->mixers, devname);
+    }
+
     if (reserve)
         pa_reserve_wrapper_unref(reserve);
 
@@ -1002,10 +1040,8 @@ void pa__done(pa_module*m) {
     if (!(u = m->userdata))
         goto finish;
 
-    if (u->mixer_fdl)
-        pa_alsa_fdlist_free(u->mixer_fdl);
-    if (u->mixer_handle)
-        snd_mixer_close(u->mixer_handle);
+    if (u->mixers)
+        pa_hashmap_free(u->mixers);
     if (u->jacks)
         pa_hashmap_free(u->jacks);
 



View it on GitLab: https://gitlab.freedesktop.org/pulseaudio/pulseaudio/compare/6438e5c46dc449e4726ec9312859cc70388d2851...cd4a69374cefe7c720bd6916f06ff7151da9892a

-- 
View it on GitLab: https://gitlab.freedesktop.org/pulseaudio/pulseaudio/compare/6438e5c46dc449e4726ec9312859cc70388d2851...cd4a69374cefe7c720bd6916f06ff7151da9892a
You're receiving this email because of your account on gitlab.freedesktop.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.freedesktop.org/archives/pulseaudio-commits/attachments/20191223/3acb2991/attachment-0001.htm>


More information about the pulseaudio-commits mailing list