"Fossies" - the Fresh Open Source Software Archive

Member "pulseaudio-14.2/src/modules/alsa/module-alsa-card.c" (16 Jan 2021, 37560 Bytes) of package /linux/misc/pulseaudio-14.2.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "module-alsa-card.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 14.0_vs_14.2.

    1 /***
    2   This file is part of PulseAudio.
    3 
    4   Copyright 2009 Lennart Poettering
    5 
    6   PulseAudio is free software; you can redistribute it and/or modify
    7   it under the terms of the GNU Lesser General Public License as published
    8   by the Free Software Foundation; either version 2.1 of the License,
    9   or (at your option) any later version.
   10 
   11   PulseAudio is distributed in the hope that it will be useful, but
   12   WITHOUT ANY WARRANTY; without even the implied warranty of
   13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
   14   General Public License for more details.
   15 
   16   You should have received a copy of the GNU Lesser General Public License
   17   along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
   18 ***/
   19 
   20 #ifdef HAVE_CONFIG_H
   21 #include <config.h>
   22 #endif
   23 
   24 #include <pulse/xmalloc.h>
   25 
   26 #include <pulsecore/core-util.h>
   27 #include <pulsecore/i18n.h>
   28 #include <pulsecore/modargs.h>
   29 #include <pulsecore/queue.h>
   30 
   31 #include <modules/reserve-wrap.h>
   32 
   33 #ifdef HAVE_UDEV
   34 #include <modules/udev-util.h>
   35 #endif
   36 
   37 #include "alsa-util.h"
   38 #include "alsa-ucm.h"
   39 #include "alsa-sink.h"
   40 #include "alsa-source.h"
   41 
   42 PA_MODULE_AUTHOR("Lennart Poettering");
   43 PA_MODULE_DESCRIPTION("ALSA Card");
   44 PA_MODULE_VERSION(PACKAGE_VERSION);
   45 PA_MODULE_LOAD_ONCE(false);
   46 PA_MODULE_USAGE(
   47         "name=<name for the card/sink/source, to be prefixed> "
   48         "card_name=<name for the card> "
   49         "card_properties=<properties for the card> "
   50         "sink_name=<name for the sink> "
   51         "sink_properties=<properties for the sink> "
   52         "source_name=<name for the source> "
   53         "source_properties=<properties for the source> "
   54         "namereg_fail=<when false attempt to synthesise new names if they are already taken> "
   55         "device_id=<ALSA card index> "
   56         "format=<sample format> "
   57         "rate=<sample rate> "
   58         "fragments=<number of fragments> "
   59         "fragment_size=<fragment size> "
   60         "mmap=<enable memory mapping?> "
   61         "tsched=<enable system timer based scheduling mode?> "
   62         "tsched_buffer_size=<buffer size when using timer based scheduling> "
   63         "tsched_buffer_watermark=<lower fill watermark> "
   64         "profile=<profile name> "
   65         "fixed_latency_range=<disable latency range changes on underrun?> "
   66         "ignore_dB=<ignore dB information from the device?> "
   67         "deferred_volume=<Synchronize software and hardware volume changes to avoid momentary jumps?> "
   68         "profile_set=<profile set configuration file> "
   69         "paths_dir=<directory containing the path configuration files> "
   70         "use_ucm=<load use case manager> "
   71         "avoid_resampling=<use stream original sample rate if possible?> "
   72         "control=<name of mixer control> "
   73 );
   74 
   75 static const char* const valid_modargs[] = {
   76     "name",
   77     "card_name",
   78     "card_properties",
   79     "sink_name",
   80     "sink_properties",
   81     "source_name",
   82     "source_properties",
   83     "namereg_fail",
   84     "device_id",
   85     "format",
   86     "rate",
   87     "fragments",
   88     "fragment_size",
   89     "mmap",
   90     "tsched",
   91     "tsched_buffer_size",
   92     "tsched_buffer_watermark",
   93     "fixed_latency_range",
   94     "profile",
   95     "ignore_dB",
   96     "deferred_volume",
   97     "profile_set",
   98     "paths_dir",
   99     "use_ucm",
  100     "avoid_resampling",
  101     "control",
  102     NULL
  103 };
  104 
  105 #define DEFAULT_DEVICE_ID "0"
  106 
  107 struct userdata {
  108     pa_core *core;
  109     pa_module *module;
  110 
  111     char *device_id;
  112     int alsa_card_index;
  113 
  114     pa_hashmap *mixers;
  115     pa_hashmap *jacks;
  116 
  117     pa_card *card;
  118 
  119     pa_modargs *modargs;
  120 
  121     pa_alsa_profile_set *profile_set;
  122 
  123     /* ucm stuffs */
  124     bool use_ucm;
  125     pa_alsa_ucm_config ucm;
  126 
  127 };
  128 
  129 struct profile_data {
  130     pa_alsa_profile *profile;
  131 };
  132 
  133 static void add_profiles(struct userdata *u, pa_hashmap *h, pa_hashmap *ports) {
  134     pa_alsa_profile *ap;
  135     void *state;
  136 
  137     pa_assert(u);
  138     pa_assert(h);
  139 
  140     PA_HASHMAP_FOREACH(ap, u->profile_set->profiles, state) {
  141         struct profile_data *d;
  142         pa_card_profile *cp;
  143         pa_alsa_mapping *m;
  144         uint32_t idx;
  145 
  146         cp = pa_card_profile_new(ap->name, ap->description, sizeof(struct profile_data));
  147         cp->priority = ap->priority ? ap->priority : 1;
  148         cp->input_name = pa_xstrdup(ap->input_name);
  149         cp->output_name = pa_xstrdup(ap->output_name);
  150 
  151         if (ap->output_mappings) {
  152             cp->n_sinks = pa_idxset_size(ap->output_mappings);
  153 
  154             PA_IDXSET_FOREACH(m, ap->output_mappings, idx) {
  155                 if (u->use_ucm)
  156                     pa_alsa_ucm_add_ports_combination(NULL, &m->ucm_context, true, ports, cp, u->core);
  157                 else
  158                     pa_alsa_path_set_add_ports(m->output_path_set, cp, ports, NULL, u->core);
  159                 if (m->channel_map.channels > cp->max_sink_channels)
  160                     cp->max_sink_channels = m->channel_map.channels;
  161             }
  162         }
  163 
  164         if (ap->input_mappings) {
  165             cp->n_sources = pa_idxset_size(ap->input_mappings);
  166 
  167             PA_IDXSET_FOREACH(m, ap->input_mappings, idx) {
  168                 if (u->use_ucm)
  169                     pa_alsa_ucm_add_ports_combination(NULL, &m->ucm_context, false, ports, cp, u->core);
  170                 else
  171                     pa_alsa_path_set_add_ports(m->input_path_set, cp, ports, NULL, u->core);
  172                 if (m->channel_map.channels > cp->max_source_channels)
  173                     cp->max_source_channels = m->channel_map.channels;
  174             }
  175         }
  176 
  177         d = PA_CARD_PROFILE_DATA(cp);
  178         d->profile = ap;
  179 
  180         pa_hashmap_put(h, cp->name, cp);
  181     }
  182 }
  183 
  184 static void add_disabled_profile(pa_hashmap *profiles) {
  185     pa_card_profile *p;
  186     struct profile_data *d;
  187 
  188     p = pa_card_profile_new("off", _("Off"), sizeof(struct profile_data));
  189 
  190     d = PA_CARD_PROFILE_DATA(p);
  191     d->profile = NULL;
  192 
  193     pa_hashmap_put(profiles, p->name, p);
  194 }
  195 
  196 static int card_set_profile(pa_card *c, pa_card_profile *new_profile) {
  197     struct userdata *u;
  198     struct profile_data *nd, *od;
  199     uint32_t idx;
  200     pa_alsa_mapping *am;
  201     pa_queue *sink_inputs = NULL, *source_outputs = NULL;
  202     int ret = 0;
  203 
  204     pa_assert(c);
  205     pa_assert(new_profile);
  206     pa_assert_se(u = c->userdata);
  207 
  208     nd = PA_CARD_PROFILE_DATA(new_profile);
  209     od = PA_CARD_PROFILE_DATA(c->active_profile);
  210 
  211     if (od->profile && od->profile->output_mappings)
  212         PA_IDXSET_FOREACH(am, od->profile->output_mappings, idx) {
  213             if (!am->sink)
  214                 continue;
  215 
  216             if (nd->profile &&
  217                 nd->profile->output_mappings &&
  218                 pa_idxset_get_by_data(nd->profile->output_mappings, am, NULL))
  219                 continue;
  220 
  221             sink_inputs = pa_sink_move_all_start(am->sink, sink_inputs);
  222             pa_alsa_sink_free(am->sink);
  223             am->sink = NULL;
  224         }
  225 
  226     if (od->profile && od->profile->input_mappings)
  227         PA_IDXSET_FOREACH(am, od->profile->input_mappings, idx) {
  228             if (!am->source)
  229                 continue;
  230 
  231             if (nd->profile &&
  232                 nd->profile->input_mappings &&
  233                 pa_idxset_get_by_data(nd->profile->input_mappings, am, NULL))
  234                 continue;
  235 
  236             source_outputs = pa_source_move_all_start(am->source, source_outputs);
  237             pa_alsa_source_free(am->source);
  238             am->source = NULL;
  239         }
  240 
  241     /* if UCM is available for this card then update the verb */
  242     if (u->use_ucm) {
  243         if (pa_alsa_ucm_set_profile(&u->ucm, c, nd->profile ? nd->profile->name : NULL,
  244                     od->profile ? od->profile->name : NULL) < 0) {
  245             ret = -1;
  246             goto finish;
  247         }
  248     }
  249 
  250     if (nd->profile && nd->profile->output_mappings)
  251         PA_IDXSET_FOREACH(am, nd->profile->output_mappings, idx) {
  252 
  253             if (!am->sink)
  254                 am->sink = pa_alsa_sink_new(c->module, u->modargs, __FILE__, c, am);
  255 
  256             if (sink_inputs && am->sink) {
  257                 pa_sink_move_all_finish(am->sink, sink_inputs, false);
  258                 sink_inputs = NULL;
  259             }
  260         }
  261 
  262     if (nd->profile && nd->profile->input_mappings)
  263         PA_IDXSET_FOREACH(am, nd->profile->input_mappings, idx) {
  264 
  265             if (!am->source)
  266                 am->source = pa_alsa_source_new(c->module, u->modargs, __FILE__, c, am);
  267 
  268             if (source_outputs && am->source) {
  269                 pa_source_move_all_finish(am->source, source_outputs, false);
  270                 source_outputs = NULL;
  271             }
  272         }
  273 
  274 finish:
  275     if (sink_inputs)
  276         pa_sink_move_all_fail(sink_inputs);
  277 
  278     if (source_outputs)
  279         pa_source_move_all_fail(source_outputs);
  280 
  281     return ret;
  282 }
  283 
  284 static void init_profile(struct userdata *u) {
  285     uint32_t idx;
  286     pa_alsa_mapping *am;
  287     struct profile_data *d;
  288     pa_alsa_ucm_config *ucm = &u->ucm;
  289 
  290     pa_assert(u);
  291 
  292     d = PA_CARD_PROFILE_DATA(u->card->active_profile);
  293 
  294     if (d->profile && u->use_ucm) {
  295         /* Set initial verb */
  296         if (pa_alsa_ucm_set_profile(ucm, u->card, d->profile->name, NULL) < 0) {
  297             pa_log("Failed to set ucm profile %s", d->profile->name);
  298             return;
  299         }
  300     }
  301 
  302     if (d->profile && d->profile->output_mappings)
  303         PA_IDXSET_FOREACH(am, d->profile->output_mappings, idx)
  304             am->sink = pa_alsa_sink_new(u->module, u->modargs, __FILE__, u->card, am);
  305 
  306     if (d->profile && d->profile->input_mappings)
  307         PA_IDXSET_FOREACH(am, d->profile->input_mappings, idx)
  308             am->source = pa_alsa_source_new(u->module, u->modargs, __FILE__, u->card, am);
  309 }
  310 
  311 static pa_available_t calc_port_state(pa_device_port *p, struct userdata *u) {
  312     void *state;
  313     pa_alsa_jack *jack;
  314     pa_available_t pa = PA_AVAILABLE_UNKNOWN;
  315     pa_device_port *port;
  316 
  317     PA_HASHMAP_FOREACH(jack, u->jacks, state) {
  318         pa_available_t cpa;
  319 
  320         if (u->use_ucm)
  321             port = pa_hashmap_get(u->card->ports, jack->name);
  322         else {
  323             if (jack->path)
  324                 port = jack->path->port;
  325             else
  326                 continue;
  327         }
  328 
  329         if (p != port)
  330             continue;
  331 
  332         cpa = jack->plugged_in ? jack->state_plugged : jack->state_unplugged;
  333 
  334         if (cpa == PA_AVAILABLE_NO) {
  335           /* If a plugged-in jack causes the availability to go to NO, it
  336            * should override all other availability information (like a
  337            * blacklist) so set and bail */
  338           if (jack->plugged_in) {
  339             pa = cpa;
  340             break;
  341           }
  342 
  343           /* If the current availablility is unknown go the more precise no,
  344            * but otherwise don't change state */
  345           if (pa == PA_AVAILABLE_UNKNOWN)
  346             pa = cpa;
  347         } else if (cpa == PA_AVAILABLE_YES) {
  348           /* Output is available through at least one jack, so go to that
  349            * level of availability. We still need to continue iterating through
  350            * the jacks in case a jack is plugged in that forces the state to no
  351            */
  352           pa = cpa;
  353         }
  354     }
  355     return pa;
  356 }
  357 
  358 struct temp_port_avail {
  359     pa_device_port *port;
  360     pa_available_t avail;
  361 };
  362 
  363 static int report_jack_state(snd_mixer_elem_t *melem, unsigned int mask) {
  364     struct userdata *u = snd_mixer_elem_get_callback_private(melem);
  365     snd_hctl_elem_t *elem = snd_mixer_elem_get_private(melem);
  366     snd_ctl_elem_value_t *elem_value;
  367     bool plugged_in;
  368     void *state;
  369     pa_alsa_jack *jack;
  370     struct temp_port_avail *tp, *tports;
  371     pa_card_profile *profile;
  372     pa_available_t active_available = PA_AVAILABLE_UNKNOWN;
  373 
  374     pa_assert(u);
  375 
  376     /* Changing the jack state may cause a port change, and a port change will
  377      * make the sink or source change the mixer settings. If there are multiple
  378      * users having pulseaudio running, the mixer changes done by inactive
  379      * users may mess up the volume settings for the active users, because when
  380      * the inactive users change the mixer settings, those changes are picked
  381      * up by the active user's pulseaudio instance and the changes are
  382      * interpreted as if the active user changed the settings manually e.g.
  383      * with alsamixer. Even single-user systems suffer from this, because gdm
  384      * runs its own pulseaudio instance.
  385      *
  386      * We rerun this function when being unsuspended to catch up on jack state
  387      * changes */
  388     if (u->card->suspend_cause & PA_SUSPEND_SESSION)
  389         return 0;
  390 
  391     if (mask == SND_CTL_EVENT_MASK_REMOVE)
  392         return 0;
  393 
  394     snd_ctl_elem_value_alloca(&elem_value);
  395     if (snd_hctl_elem_read(elem, elem_value) < 0) {
  396         pa_log_warn("Failed to read jack detection from '%s'", pa_strnull(snd_hctl_elem_get_name(elem)));
  397         return 0;
  398     }
  399 
  400     plugged_in = !!snd_ctl_elem_value_get_boolean(elem_value, 0);
  401 
  402     pa_log_debug("Jack '%s' is now %s", pa_strnull(snd_hctl_elem_get_name(elem)), plugged_in ? "plugged in" : "unplugged");
  403 
  404     tports = tp = pa_xnew0(struct temp_port_avail, pa_hashmap_size(u->jacks)+1);
  405 
  406     PA_HASHMAP_FOREACH(jack, u->jacks, state)
  407         if (jack->melem == melem) {
  408             pa_alsa_jack_set_plugged_in(jack, plugged_in);
  409 
  410             if (u->use_ucm) {
  411                 /* When using UCM, pa_alsa_jack_set_plugged_in() maps the jack
  412                  * state to port availability. */
  413                 continue;
  414             }
  415 
  416             /* When not using UCM, we have to do the jack state -> port
  417              * availability mapping ourselves. */
  418             pa_assert_se(tp->port = jack->path->port);
  419             tp->avail = calc_port_state(tp->port, u);
  420             tp++;
  421         }
  422 
  423     /* Report available ports before unavailable ones: in case port 1 becomes available when port 2 becomes unavailable,
  424        this prevents an unnecessary switch port 1 -> port 3 -> port 2 */
  425 
  426     for (tp = tports; tp->port; tp++)
  427         if (tp->avail != PA_AVAILABLE_NO)
  428            pa_device_port_set_available(tp->port, tp->avail);
  429     for (tp = tports; tp->port; tp++)
  430         if (tp->avail == PA_AVAILABLE_NO)
  431            pa_device_port_set_available(tp->port, tp->avail);
  432 
  433     for (tp = tports; tp->port; tp++) {
  434         pa_alsa_port_data *data;
  435         pa_sink *sink;
  436         uint32_t idx;
  437 
  438         data = PA_DEVICE_PORT_DATA(tp->port);
  439 
  440         if (!data->suspend_when_unavailable)
  441             continue;
  442 
  443         PA_IDXSET_FOREACH(sink, u->core->sinks, idx) {
  444             if (sink->active_port == tp->port)
  445                 pa_sink_suspend(sink, tp->avail == PA_AVAILABLE_NO, PA_SUSPEND_UNAVAILABLE);
  446         }
  447     }
  448 
  449     /* Update profile availabilities. Ideally we would mark all profiles
  450      * unavailable that contain unavailable devices. We can't currently do that
  451      * in all cases, because if there are multiple sinks in a profile, and the
  452      * profile contains a mix of available and unavailable ports, we don't know
  453      * how the ports are distributed between the different sinks. It's possible
  454      * that some sinks contain only unavailable ports, in which case we should
  455      * mark the profile as unavailable, but it's also possible that all sinks
  456      * contain at least one available port, in which case we should mark the
  457      * profile as available. Until the data structures are improved so that we
  458      * can distinguish between these two cases, we mark the problematic cases
  459      * as available (well, "unknown" to be precise, but there's little
  460      * practical difference).
  461      *
  462      * When all output ports are unavailable, we know that all sinks are
  463      * unavailable, and therefore the profile is marked unavailable as well.
  464      * The same applies to input ports as well, of course.
  465      *
  466      * If there are no output ports at all, but the profile contains at least
  467      * one sink, then the output is considered to be available. */
  468     if (u->card->active_profile)
  469         active_available = u->card->active_profile->available;
  470     PA_HASHMAP_FOREACH(profile, u->card->profiles, state) {
  471         pa_device_port *port;
  472         void *state2;
  473         bool has_input_port = false;
  474         bool has_output_port = false;
  475         bool found_available_input_port = false;
  476         bool found_available_output_port = false;
  477         pa_available_t available = PA_AVAILABLE_UNKNOWN;
  478 
  479         PA_HASHMAP_FOREACH(port, u->card->ports, state2) {
  480             if (!pa_hashmap_get(port->profiles, profile->name))
  481                 continue;
  482 
  483             if (port->direction == PA_DIRECTION_INPUT) {
  484                 has_input_port = true;
  485 
  486                 if (port->available != PA_AVAILABLE_NO)
  487                     found_available_input_port = true;
  488             } else {
  489                 has_output_port = true;
  490 
  491                 if (port->available != PA_AVAILABLE_NO)
  492                     found_available_output_port = true;
  493             }
  494         }
  495 
  496         if ((has_input_port && !found_available_input_port) || (has_output_port && !found_available_output_port))
  497             available = PA_AVAILABLE_NO;
  498 
  499         /* We want to update the active profile's status last, so logic that
  500          * may change the active profile based on profile availability status
  501          * has an updated view of all profiles' availabilities. */
  502         if (profile == u->card->active_profile)
  503             active_available = available;
  504         else
  505             pa_card_profile_set_available(profile, available);
  506     }
  507 
  508     if (u->card->active_profile)
  509         pa_card_profile_set_available(u->card->active_profile, active_available);
  510 
  511     pa_xfree(tports);
  512     return 0;
  513 }
  514 
  515 static pa_device_port* find_port_with_eld_device(struct userdata *u, int device) {
  516     void *state;
  517     pa_device_port *p;
  518 
  519     if (u->use_ucm) {
  520         PA_HASHMAP_FOREACH(p, u->card->ports, state) {
  521             pa_alsa_ucm_port_data *data = PA_DEVICE_PORT_DATA(p);
  522             pa_assert(data->eld_mixer_device_name);
  523             if (device == data->eld_device)
  524                 return p;
  525         }
  526     } else {
  527         PA_HASHMAP_FOREACH(p, u->card->ports, state) {
  528             pa_alsa_port_data *data = PA_DEVICE_PORT_DATA(p);
  529             pa_assert(data->path);
  530             if (device == data->path->eld_device)
  531                 return p;
  532         }
  533     }
  534     return NULL;
  535 }
  536 
  537 static int hdmi_eld_changed(snd_mixer_elem_t *melem, unsigned int mask) {
  538     struct userdata *u = snd_mixer_elem_get_callback_private(melem);
  539     snd_hctl_elem_t *elem = snd_mixer_elem_get_private(melem);
  540     int device = snd_hctl_elem_get_device(elem);
  541     const char *old_monitor_name;
  542     pa_device_port *p;
  543     pa_hdmi_eld eld;
  544     bool changed = false;
  545 
  546     if (mask == SND_CTL_EVENT_MASK_REMOVE)
  547         return 0;
  548 
  549     p = find_port_with_eld_device(u, device);
  550     if (p == NULL) {
  551         pa_log_error("Invalid device changed in ALSA: %d", device);
  552         return 0;
  553     }
  554 
  555     if (pa_alsa_get_hdmi_eld(elem, &eld) < 0)
  556         memset(&eld, 0, sizeof(eld));
  557 
  558     old_monitor_name = pa_proplist_gets(p->proplist, PA_PROP_DEVICE_PRODUCT_NAME);
  559     if (eld.monitor_name[0] == '\0') {
  560         changed |= old_monitor_name != NULL;
  561         pa_proplist_unset(p->proplist, PA_PROP_DEVICE_PRODUCT_NAME);
  562     } else {
  563         changed |= (old_monitor_name == NULL) || (strcmp(old_monitor_name, eld.monitor_name) != 0);
  564         pa_proplist_sets(p->proplist, PA_PROP_DEVICE_PRODUCT_NAME, eld.monitor_name);
  565     }
  566 
  567     if (changed && mask != 0)
  568         pa_subscription_post(u->core, PA_SUBSCRIPTION_EVENT_CARD|PA_SUBSCRIPTION_EVENT_CHANGE, u->card->index);
  569 
  570     return 0;
  571 }
  572 
  573 static void init_eld_ctls(struct userdata *u) {
  574     void *state;
  575     pa_device_port *port;
  576 
  577     /* The code in this function expects ports to have a pa_alsa_port_data
  578      * struct as their data, but in UCM mode ports don't have any data. Hence,
  579      * the ELD controls can't currently be used in UCM mode. */
  580     PA_HASHMAP_FOREACH(port, u->card->ports, state) {
  581         snd_mixer_t *mixer_handle;
  582         snd_mixer_elem_t* melem;
  583         int device;
  584 
  585         if (u->use_ucm) {
  586             pa_alsa_ucm_port_data *data = PA_DEVICE_PORT_DATA(port);
  587             device = data->eld_device;
  588             if (device < 0 || !data->eld_mixer_device_name)
  589                 continue;
  590 
  591             mixer_handle = pa_alsa_open_mixer_by_name(u->mixers, data->eld_mixer_device_name, true);
  592         } else {
  593             pa_alsa_port_data *data = PA_DEVICE_PORT_DATA(port);
  594 
  595             pa_assert(data->path);
  596 
  597             device = data->path->eld_device;
  598             if (device < 0)
  599                 continue;
  600 
  601             mixer_handle = pa_alsa_open_mixer(u->mixers, u->alsa_card_index, true);
  602         }
  603 
  604         if (!mixer_handle)
  605             continue;
  606 
  607         melem = pa_alsa_mixer_find_pcm(mixer_handle, "ELD", device);
  608         if (melem) {
  609             pa_alsa_mixer_set_fdlist(u->mixers, mixer_handle, u->core->mainloop);
  610             snd_mixer_elem_set_callback(melem, hdmi_eld_changed);
  611             snd_mixer_elem_set_callback_private(melem, u);
  612             hdmi_eld_changed(melem, 0);
  613             pa_log_info("ELD device found for port %s (%d).", port->name, device);
  614         }
  615         else
  616             pa_log_debug("No ELD device found for port %s (%d).", port->name, device);
  617     }
  618 }
  619 
  620 static void init_jacks(struct userdata *u) {
  621     void *state;
  622     pa_alsa_path* path;
  623     pa_alsa_jack* jack;
  624     char buf[64];
  625 
  626     u->jacks = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
  627 
  628     if (u->use_ucm) {
  629         PA_LLIST_FOREACH(jack, u->ucm.jacks)
  630             if (jack->has_control)
  631                 pa_hashmap_put(u->jacks, jack, jack);
  632     } else {
  633         /* See if we have any jacks */
  634         if (u->profile_set->output_paths)
  635             PA_HASHMAP_FOREACH(path, u->profile_set->output_paths, state)
  636                 PA_LLIST_FOREACH(jack, path->jacks)
  637                     if (jack->has_control)
  638                         pa_hashmap_put(u->jacks, jack, jack);
  639 
  640         if (u->profile_set->input_paths)
  641             PA_HASHMAP_FOREACH(path, u->profile_set->input_paths, state)
  642                 PA_LLIST_FOREACH(jack, path->jacks)
  643                     if (jack->has_control)
  644                         pa_hashmap_put(u->jacks, jack, jack);
  645     }
  646 
  647     pa_log_debug("Found %d jacks.", pa_hashmap_size(u->jacks));
  648 
  649     if (pa_hashmap_size(u->jacks) == 0)
  650         return;
  651 
  652     PA_HASHMAP_FOREACH(jack, u->jacks, state) {
  653         if (!jack->mixer_device_name) {
  654             jack->mixer_handle = pa_alsa_open_mixer(u->mixers, u->alsa_card_index, false);
  655             if (!jack->mixer_handle) {
  656                pa_log("Failed to open mixer for card %d for jack detection", u->alsa_card_index);
  657                continue;
  658             }
  659         } else {
  660             jack->mixer_handle = pa_alsa_open_mixer_by_name(u->mixers, jack->mixer_device_name, false);
  661             if (!jack->mixer_handle) {
  662                pa_log("Failed to open mixer '%s' for jack detection", jack->mixer_device_name);
  663               continue;
  664             }
  665         }
  666         pa_alsa_mixer_set_fdlist(u->mixers, jack->mixer_handle, u->core->mainloop);
  667         jack->melem = pa_alsa_mixer_find_card(jack->mixer_handle, &jack->alsa_id, 0);
  668         if (!jack->melem) {
  669             pa_alsa_mixer_id_to_string(buf, sizeof(buf), &jack->alsa_id);
  670             pa_log_warn("Jack %s seems to have disappeared.", buf);
  671             pa_alsa_jack_set_has_control(jack, false);
  672             continue;
  673         }
  674         snd_mixer_elem_set_callback(jack->melem, report_jack_state);
  675         snd_mixer_elem_set_callback_private(jack->melem, u);
  676         report_jack_state(jack->melem, 0);
  677     }
  678 }
  679 
  680 static void prune_singleton_availability_groups(pa_hashmap *ports) {
  681     pa_device_port *p;
  682     pa_hashmap *group_counts;
  683     void *state, *count;
  684     const char *group;
  685 
  686     /* Collect groups and erase those that don't have more than 1 path */
  687     group_counts = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
  688 
  689     PA_HASHMAP_FOREACH(p, ports, state) {
  690         if (p->availability_group) {
  691             count = pa_hashmap_get(group_counts, p->availability_group);
  692             pa_hashmap_remove(group_counts, p->availability_group);
  693             pa_hashmap_put(group_counts, p->availability_group, PA_UINT_TO_PTR(PA_PTR_TO_UINT(count) + 1));
  694         }
  695     }
  696 
  697     /* Now we have an availability_group -> count map, let's drop all groups
  698      * that have only one member */
  699     PA_HASHMAP_FOREACH_KV(group, count, group_counts, state) {
  700         if (count == PA_UINT_TO_PTR(1))
  701             pa_hashmap_remove(group_counts, group);
  702     }
  703 
  704     PA_HASHMAP_FOREACH(p, ports, state) {
  705         if (p->availability_group && !pa_hashmap_get(group_counts, p->availability_group)) {
  706             pa_log_debug("Pruned singleton availability group %s from port %s", p->availability_group, p->name);
  707 
  708             pa_xfree(p->availability_group);
  709             p->availability_group = NULL;
  710         }
  711     }
  712 
  713     pa_hashmap_free(group_counts);
  714 }
  715 
  716 static void set_card_name(pa_card_new_data *data, pa_modargs *ma, const char *device_id) {
  717     char *t;
  718     const char *n;
  719 
  720     pa_assert(data);
  721     pa_assert(ma);
  722     pa_assert(device_id);
  723 
  724     if ((n = pa_modargs_get_value(ma, "card_name", NULL))) {
  725         pa_card_new_data_set_name(data, n);
  726         data->namereg_fail = true;
  727         return;
  728     }
  729 
  730     if ((n = pa_modargs_get_value(ma, "name", NULL)))
  731         data->namereg_fail = true;
  732     else {
  733         n = device_id;
  734         data->namereg_fail = false;
  735     }
  736 
  737     t = pa_sprintf_malloc("alsa_card.%s", n);
  738     pa_card_new_data_set_name(data, t);
  739     pa_xfree(t);
  740 }
  741 
  742 static pa_hook_result_t card_suspend_changed(pa_core *c, pa_card *card, struct userdata *u) {
  743     void *state;
  744     pa_alsa_jack *jack;
  745 
  746     if (card->suspend_cause == 0) {
  747         /* We were unsuspended, update jack state in case it changed while we were suspended */
  748         PA_HASHMAP_FOREACH(jack, u->jacks, state) {
  749             if (jack->melem)
  750                 report_jack_state(jack->melem, 0);
  751         }
  752     }
  753 
  754     return PA_HOOK_OK;
  755 }
  756 
  757 static pa_hook_result_t sink_input_put_hook_callback(pa_core *c, pa_sink_input *sink_input, struct userdata *u) {
  758     const char *role;
  759     pa_sink *sink = sink_input->sink;
  760 
  761     pa_assert(sink);
  762 
  763     role = pa_proplist_gets(sink_input->proplist, PA_PROP_MEDIA_ROLE);
  764 
  765     /* new sink input linked to sink of this card */
  766     if (role && sink->card == u->card)
  767         pa_alsa_ucm_roled_stream_begin(&u->ucm, role, PA_DIRECTION_OUTPUT);
  768 
  769     return PA_HOOK_OK;
  770 }
  771 
  772 static pa_hook_result_t source_output_put_hook_callback(pa_core *c, pa_source_output *source_output, struct userdata *u) {
  773     const char *role;
  774     pa_source *source = source_output->source;
  775 
  776     pa_assert(source);
  777 
  778     role = pa_proplist_gets(source_output->proplist, PA_PROP_MEDIA_ROLE);
  779 
  780     /* new source output linked to source of this card */
  781     if (role && source->card == u->card)
  782         pa_alsa_ucm_roled_stream_begin(&u->ucm, role, PA_DIRECTION_INPUT);
  783 
  784     return PA_HOOK_OK;
  785 }
  786 
  787 static pa_hook_result_t sink_input_unlink_hook_callback(pa_core *c, pa_sink_input *sink_input, struct userdata *u) {
  788     const char *role;
  789     pa_sink *sink = sink_input->sink;
  790 
  791     pa_assert(sink);
  792 
  793     role = pa_proplist_gets(sink_input->proplist, PA_PROP_MEDIA_ROLE);
  794 
  795     /* new sink input unlinked from sink of this card */
  796     if (role && sink->card == u->card)
  797         pa_alsa_ucm_roled_stream_end(&u->ucm, role, PA_DIRECTION_OUTPUT);
  798 
  799     return PA_HOOK_OK;
  800 }
  801 
  802 static pa_hook_result_t source_output_unlink_hook_callback(pa_core *c, pa_source_output *source_output, struct userdata *u) {
  803     const char *role;
  804     pa_source *source = source_output->source;
  805 
  806     pa_assert(source);
  807 
  808     role = pa_proplist_gets(source_output->proplist, PA_PROP_MEDIA_ROLE);
  809 
  810     /* new source output unlinked from source of this card */
  811     if (role && source->card == u->card)
  812         pa_alsa_ucm_roled_stream_end(&u->ucm, role, PA_DIRECTION_INPUT);
  813 
  814     return PA_HOOK_OK;
  815 }
  816 
  817 int pa__init(pa_module *m) {
  818     pa_card_new_data data;
  819     bool ignore_dB = false;
  820     struct userdata *u;
  821     pa_reserve_wrapper *reserve = NULL;
  822     const char *description;
  823     const char *profile_str = NULL;
  824     char *fn = NULL;
  825     bool namereg_fail = false;
  826     int err = -PA_MODULE_ERR_UNSPECIFIED, rval;
  827 
  828     pa_alsa_refcnt_inc();
  829 
  830     pa_assert(m);
  831 
  832     m->userdata = u = pa_xnew0(struct userdata, 1);
  833     u->core = m->core;
  834     u->module = m;
  835     u->use_ucm = true;
  836     u->ucm.core = m->core;
  837 
  838     u->mixers = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func,
  839                                     pa_xfree, (pa_free_cb_t) pa_alsa_mixer_free);
  840     u->ucm.mixers = u->mixers; /* alias */
  841 
  842     if (!(u->modargs = pa_modargs_new(m->argument, valid_modargs))) {
  843         pa_log("Failed to parse module arguments.");
  844         goto fail;
  845     }
  846 
  847     u->device_id = pa_xstrdup(pa_modargs_get_value(u->modargs, "device_id", DEFAULT_DEVICE_ID));
  848 
  849     if ((u->alsa_card_index = snd_card_get_index(u->device_id)) < 0) {
  850         pa_log("Card '%s' doesn't exist: %s", u->device_id, pa_alsa_strerror(u->alsa_card_index));
  851         goto fail;
  852     }
  853 
  854     if (pa_modargs_get_value_boolean(u->modargs, "ignore_dB", &ignore_dB) < 0) {
  855         pa_log("Failed to parse ignore_dB argument.");
  856         goto fail;
  857     }
  858 
  859     if (!pa_in_system_mode()) {
  860         char *rname;
  861 
  862         if ((rname = pa_alsa_get_reserve_name(u->device_id))) {
  863             reserve = pa_reserve_wrapper_get(m->core, rname);
  864             pa_xfree(rname);
  865 
  866             if (!reserve)
  867                 goto fail;
  868         }
  869     }
  870 
  871     if (pa_modargs_get_value_boolean(u->modargs, "use_ucm", &u->use_ucm) < 0) {
  872         pa_log("Failed to parse use_ucm argument.");
  873         goto fail;
  874     }
  875 
  876     /* Force ALSA to reread its configuration. This matters if our device
  877      * was hot-plugged after ALSA has already read its configuration - see
  878      * https://bugs.freedesktop.org/show_bug.cgi?id=54029
  879      */
  880 
  881     snd_config_update_free_global();
  882 
  883     rval = u->use_ucm ? pa_alsa_ucm_query_profiles(&u->ucm, u->alsa_card_index) : -1;
  884     if (rval == -PA_ALSA_ERR_UCM_LINKED) {
  885         err = -PA_MODULE_ERR_SKIP;
  886         goto fail;
  887     }
  888     if (rval == 0) {
  889         pa_log_info("Found UCM profiles");
  890 
  891         u->profile_set = pa_alsa_ucm_add_profile_set(&u->ucm, &u->core->default_channel_map);
  892 
  893         /* hook start of sink input/source output to enable modifiers */
  894         /* A little bit later than module-role-cork */
  895         pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_SINK_INPUT_PUT], PA_HOOK_LATE+10,
  896                 (pa_hook_cb_t) sink_input_put_hook_callback, u);
  897         pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_PUT], PA_HOOK_LATE+10,
  898                 (pa_hook_cb_t) source_output_put_hook_callback, u);
  899 
  900         /* hook end of sink input/source output to disable modifiers */
  901         /* A little bit later than module-role-cork */
  902         pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_SINK_INPUT_UNLINK], PA_HOOK_LATE+10,
  903                 (pa_hook_cb_t) sink_input_unlink_hook_callback, u);
  904         pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_UNLINK], PA_HOOK_LATE+10,
  905                 (pa_hook_cb_t) source_output_unlink_hook_callback, u);
  906     }
  907     else {
  908         u->use_ucm = false;
  909 #ifdef HAVE_UDEV
  910         fn = pa_udev_get_property(u->alsa_card_index, "PULSE_PROFILE_SET");
  911 #endif
  912 
  913         if (pa_modargs_get_value(u->modargs, "profile_set", NULL)) {
  914             pa_xfree(fn);
  915             fn = pa_xstrdup(pa_modargs_get_value(u->modargs, "profile_set", NULL));
  916         }
  917 
  918         u->profile_set = pa_alsa_profile_set_new(fn, &u->core->default_channel_map);
  919         pa_xfree(fn);
  920     }
  921 
  922     if (!u->profile_set)
  923         goto fail;
  924 
  925     u->profile_set->ignore_dB = ignore_dB;
  926 
  927     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);
  928     pa_alsa_profile_set_dump(u->profile_set);
  929 
  930     pa_card_new_data_init(&data);
  931     data.driver = __FILE__;
  932     data.module = m;
  933 
  934     pa_alsa_init_proplist_card(m->core, data.proplist, u->alsa_card_index);
  935 
  936     pa_proplist_sets(data.proplist, PA_PROP_DEVICE_STRING, u->device_id);
  937     pa_alsa_init_description(data.proplist, NULL);
  938     set_card_name(&data, u->modargs, u->device_id);
  939 
  940     /* We need to give pa_modargs_get_value_boolean() a pointer to a local
  941      * variable instead of using &data.namereg_fail directly, because
  942      * data.namereg_fail is a bitfield and taking the address of a bitfield
  943      * variable is impossible. */
  944     namereg_fail = data.namereg_fail;
  945     if (pa_modargs_get_value_boolean(u->modargs, "namereg_fail", &namereg_fail) < 0) {
  946         pa_log("Failed to parse namereg_fail argument.");
  947         pa_card_new_data_done(&data);
  948         goto fail;
  949     }
  950     data.namereg_fail = namereg_fail;
  951 
  952     if (reserve)
  953         if ((description = pa_proplist_gets(data.proplist, PA_PROP_DEVICE_DESCRIPTION)))
  954             pa_reserve_wrapper_set_application_device_name(reserve, description);
  955 
  956     add_profiles(u, data.profiles, data.ports);
  957 
  958     if (pa_hashmap_isempty(data.profiles)) {
  959         pa_log("Failed to find a working profile.");
  960         pa_card_new_data_done(&data);
  961         goto fail;
  962     }
  963 
  964     add_disabled_profile(data.profiles);
  965     prune_singleton_availability_groups(data.ports);
  966 
  967     if (pa_modargs_get_proplist(u->modargs, "card_properties", data.proplist, PA_UPDATE_REPLACE) < 0) {
  968         pa_log("Invalid properties");
  969         pa_card_new_data_done(&data);
  970         goto fail;
  971     }
  972 
  973     /* The Intel HDMI LPE driver needs some special handling. When the HDMI
  974      * cable is not plugged in, trying to play audio doesn't work. Any written
  975      * audio is immediately discarded and an underrun is reported, and that
  976      * results in an infinite loop of "fill buffer, handle underrun". To work
  977      * around this issue, the suspend_when_unavailable flag is used to stop
  978      * playback when the HDMI cable is unplugged. */
  979     if (!u->use_ucm &&
  980         pa_safe_streq(pa_proplist_gets(data.proplist, "alsa.driver_name"), "snd_hdmi_lpe_audio")) {
  981         pa_device_port *port;
  982         void *state;
  983 
  984         PA_HASHMAP_FOREACH(port, data.ports, state) {
  985             pa_alsa_port_data *port_data;
  986 
  987             port_data = PA_DEVICE_PORT_DATA(port);
  988             port_data->suspend_when_unavailable = true;
  989         }
  990     }
  991 
  992     u->card = pa_card_new(m->core, &data);
  993     pa_card_new_data_done(&data);
  994 
  995     if (!u->card)
  996         goto fail;
  997 
  998     u->card->userdata = u;
  999     u->card->set_profile = card_set_profile;
 1000 
 1001     pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_CARD_SUSPEND_CHANGED], PA_HOOK_NORMAL,
 1002             (pa_hook_cb_t) card_suspend_changed, u);
 1003 
 1004     init_jacks(u);
 1005 
 1006     pa_card_choose_initial_profile(u->card);
 1007 
 1008     /* If the "profile" modarg is given, we have to override whatever the usual
 1009      * policy chose in pa_card_choose_initial_profile(). */
 1010     profile_str = pa_modargs_get_value(u->modargs, "profile", NULL);
 1011     if (profile_str) {
 1012         pa_card_profile *profile;
 1013 
 1014         profile = pa_hashmap_get(u->card->profiles, profile_str);
 1015         if (!profile) {
 1016             pa_log("No such profile: %s", profile_str);
 1017             goto fail;
 1018         }
 1019 
 1020         pa_card_set_profile(u->card, profile, false);
 1021     }
 1022 
 1023     pa_card_put(u->card);
 1024 
 1025     init_profile(u);
 1026     init_eld_ctls(u);
 1027 
 1028     /* Remove all probe only mixers */
 1029     if (u->mixers) {
 1030        const char *devname;
 1031        pa_alsa_mixer *pm;
 1032        void *state;
 1033        PA_HASHMAP_FOREACH_KV(devname, pm, u->mixers, state)
 1034            if (pm->used_for_probe_only)
 1035                pa_hashmap_remove_and_free(u->mixers, devname);
 1036     }
 1037 
 1038     if (reserve)
 1039         pa_reserve_wrapper_unref(reserve);
 1040 
 1041     if (!pa_hashmap_isempty(u->profile_set->decibel_fixes))
 1042         pa_log_warn("Card %s uses decibel fixes (i.e. overrides the decibel information for some alsa volume elements). "
 1043                     "Please note that this feature is meant just as a help for figuring out the correct decibel values. "
 1044                     "PulseAudio is not the correct place to maintain the decibel mappings! The fixed decibel values "
 1045                     "should be sent to ALSA developers so that they can fix the driver. If it turns out that this feature "
 1046                     "is abused (i.e. fixes are not pushed to ALSA), the decibel fix feature may be removed in some future "
 1047                     "PulseAudio version.", u->card->name);
 1048 
 1049     return 0;
 1050 
 1051 fail:
 1052     if (reserve)
 1053         pa_reserve_wrapper_unref(reserve);
 1054 
 1055     pa__done(m);
 1056 
 1057     return err;
 1058 }
 1059 
 1060 int pa__get_n_used(pa_module *m) {
 1061     struct userdata *u;
 1062     int n = 0;
 1063     uint32_t idx;
 1064     pa_sink *sink;
 1065     pa_source *source;
 1066 
 1067     pa_assert(m);
 1068     pa_assert_se(u = m->userdata);
 1069     pa_assert(u->card);
 1070 
 1071     PA_IDXSET_FOREACH(sink, u->card->sinks, idx)
 1072         n += pa_sink_linked_by(sink);
 1073 
 1074     PA_IDXSET_FOREACH(source, u->card->sources, idx)
 1075         n += pa_source_linked_by(source);
 1076 
 1077     return n;
 1078 }
 1079 
 1080 void pa__done(pa_module*m) {
 1081     struct userdata *u;
 1082 
 1083     pa_assert(m);
 1084 
 1085     if (!(u = m->userdata))
 1086         goto finish;
 1087 
 1088     if (u->mixers)
 1089         pa_hashmap_free(u->mixers);
 1090     if (u->jacks)
 1091         pa_hashmap_free(u->jacks);
 1092 
 1093     if (u->card && u->card->sinks)
 1094         pa_idxset_remove_all(u->card->sinks, (pa_free_cb_t) pa_alsa_sink_free);
 1095 
 1096     if (u->card && u->card->sources)
 1097         pa_idxset_remove_all(u->card->sources, (pa_free_cb_t) pa_alsa_source_free);
 1098 
 1099     if (u->card)
 1100         pa_card_free(u->card);
 1101 
 1102     if (u->modargs)
 1103         pa_modargs_free(u->modargs);
 1104 
 1105     if (u->profile_set)
 1106         pa_alsa_profile_set_free(u->profile_set);
 1107 
 1108     pa_alsa_ucm_free(&u->ucm);
 1109 
 1110     pa_xfree(u->device_id);
 1111     pa_xfree(u);
 1112 
 1113 finish:
 1114     pa_alsa_refcnt_dec();
 1115 }