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