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