1 /***
2 This file is part of PulseAudio.
3
4 Copyright 2006 Lennart Poettering
5 Copyright 2011 Canonical Ltd
6
7 PulseAudio is free software; you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as published
9 by the Free Software Foundation; either version 2.1 of the License,
10 or (at your option) any later version.
11
12 PulseAudio is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
19 ***/
20
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24
25 #include <pulsecore/core.h>
26 #include <pulsecore/core-util.h>
27 #include <pulsecore/device-port.h>
28 #include <pulsecore/hashmap.h>
29
30 PA_MODULE_AUTHOR("David Henningsson");
31 PA_MODULE_DESCRIPTION("Switches ports and profiles when devices are plugged/unplugged");
32 PA_MODULE_LOAD_ONCE(true);
33 PA_MODULE_VERSION(PACKAGE_VERSION);
34
35 struct card_info {
36 struct userdata *userdata;
37 pa_card *card;
38
39 /* We need to cache the active profile, because we want to compare the old
40 * and new profiles in the PROFILE_CHANGED hook. Without this we'd only
41 * have access to the new profile. */
42 pa_card_profile *active_profile;
43 };
44
45 struct userdata {
46 pa_hashmap *card_infos; /* pa_card -> struct card_info */
47 };
48
card_info_new(struct userdata * u,pa_card * card)49 static void card_info_new(struct userdata *u, pa_card *card) {
50 struct card_info *info;
51
52 info = pa_xnew0(struct card_info, 1);
53 info->userdata = u;
54 info->card = card;
55 info->active_profile = card->active_profile;
56
57 pa_hashmap_put(u->card_infos, card, info);
58 }
59
card_info_free(struct card_info * info)60 static void card_info_free(struct card_info *info) {
61 pa_hashmap_remove(info->userdata->card_infos, info->card);
62 pa_xfree(info);
63 }
64
profile_good_for_output(pa_card_profile * profile,pa_device_port * port)65 static bool profile_good_for_output(pa_card_profile *profile, pa_device_port *port) {
66 pa_card *card;
67 pa_sink *sink;
68 uint32_t idx;
69
70 pa_assert(profile);
71
72 card = profile->card;
73
74 if (!pa_safe_streq(card->active_profile->input_name, profile->input_name))
75 return false;
76
77 if (card->active_profile->n_sources != profile->n_sources)
78 return false;
79
80 if (card->active_profile->max_source_channels != profile->max_source_channels)
81 return false;
82
83 if (port == card->preferred_output_port)
84 return true;
85
86 PA_IDXSET_FOREACH(sink, card->sinks, idx) {
87 if (!sink->active_port)
88 continue;
89
90 if ((sink->active_port->available != PA_AVAILABLE_NO) && (sink->active_port->priority >= port->priority))
91 return false;
92 }
93
94 return true;
95 }
96
profile_good_for_input(pa_card_profile * profile,pa_device_port * port)97 static bool profile_good_for_input(pa_card_profile *profile, pa_device_port *port) {
98 pa_card *card;
99 pa_source *source;
100 uint32_t idx;
101
102 pa_assert(profile);
103
104 card = profile->card;
105
106 if (!pa_safe_streq(card->active_profile->output_name, profile->output_name))
107 return false;
108
109 if (card->active_profile->n_sinks != profile->n_sinks)
110 return false;
111
112 if (card->active_profile->max_sink_channels != profile->max_sink_channels)
113 return false;
114
115 if (port == card->preferred_input_port)
116 return true;
117
118 PA_IDXSET_FOREACH(source, card->sources, idx) {
119 if (!source->active_port)
120 continue;
121
122 if ((source->active_port->available != PA_AVAILABLE_NO) && (source->active_port->priority >= port->priority))
123 return false;
124 }
125
126 return true;
127 }
128
try_to_switch_profile(pa_device_port * port)129 static int try_to_switch_profile(pa_device_port *port) {
130 pa_card_profile *best_profile = NULL, *profile;
131 void *state;
132 unsigned best_prio = 0;
133
134 pa_log_debug("Finding best profile for port %s, preferred = %s",
135 port->name, pa_strnull(port->preferred_profile));
136
137 PA_HASHMAP_FOREACH(profile, port->profiles, state) {
138 bool good = false;
139 const char *name;
140 unsigned prio = profile->priority;
141
142 /* We make a best effort to keep other direction unchanged */
143 switch (port->direction) {
144 case PA_DIRECTION_OUTPUT:
145 name = profile->output_name;
146 good = profile_good_for_output(profile, port);
147 break;
148
149 case PA_DIRECTION_INPUT:
150 name = profile->input_name;
151 good = profile_good_for_input(profile, port);
152 break;
153 }
154
155 if (!good)
156 continue;
157
158 /* Give a high bonus in case this is the preferred profile */
159 if (pa_safe_streq(name ? name : profile->name, port->preferred_profile))
160 prio += 1000000;
161
162 if (best_profile && best_prio >= prio)
163 continue;
164
165 best_profile = profile;
166 best_prio = prio;
167 }
168
169 if (!best_profile) {
170 pa_log_debug("No suitable profile found");
171 return -1;
172 }
173
174 if (pa_card_set_profile(port->card, best_profile, false) != 0) {
175 pa_log_debug("Could not set profile %s", best_profile->name);
176 return -1;
177 }
178
179 return 0;
180 }
181
182 struct port_pointers {
183 pa_device_port *port;
184 pa_sink *sink;
185 pa_source *source;
186 bool is_possible_profile_active;
187 bool is_preferred_profile_active;
188 bool is_port_active;
189 };
190
profile_name_for_dir(pa_card_profile * cp,pa_direction_t dir)191 static const char* profile_name_for_dir(pa_card_profile *cp, pa_direction_t dir) {
192 if (dir == PA_DIRECTION_OUTPUT && cp->output_name)
193 return cp->output_name;
194 if (dir == PA_DIRECTION_INPUT && cp->input_name)
195 return cp->input_name;
196 return cp->name;
197 }
198
find_port_pointers(pa_device_port * port)199 static struct port_pointers find_port_pointers(pa_device_port *port) {
200 struct port_pointers pp = { .port = port };
201 uint32_t state;
202 pa_card *card;
203
204 pa_assert(port);
205 pa_assert_se(card = port->card);
206
207 switch (port->direction) {
208 case PA_DIRECTION_OUTPUT:
209 PA_IDXSET_FOREACH(pp.sink, card->sinks, state)
210 if (port == pa_hashmap_get(pp.sink->ports, port->name))
211 break;
212 break;
213
214 case PA_DIRECTION_INPUT:
215 PA_IDXSET_FOREACH(pp.source, card->sources, state)
216 if (port == pa_hashmap_get(pp.source->ports, port->name))
217 break;
218 break;
219 }
220
221 pp.is_possible_profile_active =
222 card->active_profile == pa_hashmap_get(port->profiles, card->active_profile->name);
223 pp.is_preferred_profile_active = pp.is_possible_profile_active && (!port->preferred_profile ||
224 pa_safe_streq(port->preferred_profile, profile_name_for_dir(card->active_profile, port->direction)));
225 pp.is_port_active = (pp.sink && pp.sink->active_port == port) || (pp.source && pp.source->active_port == port);
226
227 return pp;
228 }
229
230 /* Switches to a port, switching profiles if necessary or preferred */
switch_to_port(pa_device_port * port,struct port_pointers pp)231 static void switch_to_port(pa_device_port *port, struct port_pointers pp) {
232 if (pp.is_port_active)
233 return; /* Already selected */
234
235 pa_log_debug("Trying to switch to port %s", port->name);
236 if (!pp.is_preferred_profile_active) {
237 if (try_to_switch_profile(port) < 0) {
238 if (!pp.is_possible_profile_active)
239 return;
240 }
241 else
242 /* Now that profile has changed, our sink and source pointers must be updated */
243 pp = find_port_pointers(port);
244 }
245
246 if (pp.source)
247 pa_source_set_port(pp.source, port->name, false);
248 if (pp.sink)
249 pa_sink_set_port(pp.sink, port->name, false);
250 }
251
252 /* Switches away from a port, switching profiles if necessary or preferred */
switch_from_port(pa_device_port * port,struct port_pointers pp)253 static void switch_from_port(pa_device_port *port, struct port_pointers pp) {
254 pa_device_port *p, *best_port = NULL;
255 void *state;
256
257 if (!pp.is_port_active)
258 return; /* Already deselected */
259
260 /* Try to find a good enough port to switch to */
261 PA_HASHMAP_FOREACH(p, port->card->ports, state) {
262 if (p == port)
263 continue;
264
265 if (p->available == PA_AVAILABLE_NO)
266 continue;
267
268 if (p->direction != port->direction)
269 continue;
270
271 if (!best_port || best_port->priority < p->priority)
272 best_port = p;
273 }
274
275 pa_log_debug("Trying to switch away from port %s, found %s", port->name, best_port ? best_port->name : "no better option");
276
277 /* If there is no available port to switch to we need check if the active
278 * profile is still available in the
279 * PA_CORE_HOOK_CARD_PROFILE_AVAILABLE_CHANGED callback, as at this point
280 * the profile availability hasn't been updated yet. */
281 if (best_port) {
282 struct port_pointers best_pp = find_port_pointers(best_port);
283 switch_to_port(best_port, best_pp);
284 }
285 }
286
287
port_available_hook_callback(pa_core * c,pa_device_port * port,void * userdata)288 static pa_hook_result_t port_available_hook_callback(pa_core *c, pa_device_port *port, void* userdata) {
289 struct port_pointers pp = find_port_pointers(port);
290
291 if (!port->card) {
292 pa_log_warn("Port %s does not have a card", port->name);
293 return PA_HOOK_OK;
294 }
295
296 /* Our profile switching logic caused trouble with bluetooth headsets (see
297 * https://bugs.freedesktop.org/show_bug.cgi?id=107044) and
298 * module-bluetooth-policy takes care of automatic profile switching
299 * anyway, so we ignore bluetooth cards in
300 * module-switch-on-port-available. */
301 if (pa_safe_streq(pa_proplist_gets(port->card->proplist, PA_PROP_DEVICE_BUS), "bluetooth"))
302 return PA_HOOK_OK;
303
304 switch (port->available) {
305 case PA_AVAILABLE_UNKNOWN:
306 /* If a port availability became unknown, let's see if it's part of
307 * some availability group. If it is, it is likely to be a headphone
308 * jack that does not have impedance sensing to detect whether what was
309 * plugged in was a headphone, headset or microphone. In desktop
310 * environments that support it, this will trigger a user choice to
311 * select what kind of device was plugged in. However, let's switch to
312 * the headphone port at least, so that we have don't break
313 * functionality for setups that can't trigger this kind of
314 * interaction.
315 *
316 * For headset or microphone, if they are part of some availability group
317 * and they become unknown from off, it needs to check if their source is
318 * unlinked or not, if their source is unlinked, let switch_to_port()
319 * process them, then with the running of pa_card_set_profile(), their
320 * source will be created, otherwise the headset or microphone can't be used
321 * to record sound since there is no source for these 2 ports. This issue
322 * is observed on Dell machines which have multi-function audio jack but no
323 * internal mic.
324 *
325 * We should make this configurable so that users can optionally
326 * override the default to a headset or mic. */
327
328 /* Not part of a group of ports, so likely not a combination port */
329 if (!port->availability_group) {
330 pa_log_debug("Not switching to port %s, its availability is unknown and it's not in any availability group.", port->name);
331 break;
332 }
333
334 /* Switch the headphone port, the input ports without source and the
335 * input ports their source->active_port is part of a group of ports.
336 */
337 if (port->direction == PA_DIRECTION_INPUT && pp.source && !pp.source->active_port->availability_group) {
338 pa_log_debug("Not switching to input port %s, its availability is unknown.", port->name);
339 break;
340 }
341
342 switch_to_port(port, pp);
343 break;
344
345 case PA_AVAILABLE_YES:
346 switch_to_port(port, pp);
347 break;
348 case PA_AVAILABLE_NO:
349 switch_from_port(port, pp);
350 break;
351 default:
352 break;
353 }
354
355 return PA_HOOK_OK;
356 }
357
find_best_profile(pa_card * card)358 static pa_card_profile *find_best_profile(pa_card *card) {
359 pa_card_profile *profile, *best_profile;
360 void *state;
361
362 pa_assert(card);
363 best_profile = pa_hashmap_get(card->profiles, "off");
364
365 PA_HASHMAP_FOREACH(profile, card->profiles, state) {
366 if (profile->available == PA_AVAILABLE_NO)
367 continue;
368
369 if (profile->priority > best_profile->priority)
370 best_profile = profile;
371 }
372
373 return best_profile;
374 }
375
card_profile_available_hook_callback(pa_core * c,pa_card_profile * profile,struct userdata * u)376 static pa_hook_result_t card_profile_available_hook_callback(pa_core *c, pa_card_profile *profile, struct userdata *u) {
377 pa_card *card;
378
379 pa_assert(profile);
380 pa_assert_se(card = profile->card);
381
382 if (profile->available != PA_AVAILABLE_NO)
383 return PA_HOOK_OK;
384
385 if (!pa_streq(profile->name, card->active_profile->name))
386 return PA_HOOK_OK;
387
388 pa_log_debug("Active profile %s on card %s became unavailable, switching to another profile", profile->name, card->name);
389 pa_card_set_profile(card, find_best_profile(card), false);
390
391 return PA_HOOK_OK;
392
393 }
394
handle_all_unavailable(pa_core * core)395 static void handle_all_unavailable(pa_core *core) {
396 pa_card *card;
397 uint32_t state;
398
399 PA_IDXSET_FOREACH(card, core->cards, state) {
400 pa_device_port *port;
401 void *state2;
402
403 PA_HASHMAP_FOREACH(port, card->ports, state2) {
404 if (port->available == PA_AVAILABLE_NO)
405 port_available_hook_callback(core, port, NULL);
406 }
407 }
408 }
409
new_sink_source(pa_hashmap * ports,const char * name)410 static pa_device_port *new_sink_source(pa_hashmap *ports, const char *name) {
411
412 void *state;
413 pa_device_port *i, *p = NULL;
414
415 if (!ports)
416 return NULL;
417 if (name)
418 p = pa_hashmap_get(ports, name);
419 if (!p)
420 PA_HASHMAP_FOREACH(i, ports, state)
421 if (!p || i->priority > p->priority)
422 p = i;
423 if (!p)
424 return NULL;
425 if (p->available != PA_AVAILABLE_NO)
426 return NULL;
427
428 pa_assert_se(p = pa_device_port_find_best(ports));
429 return p;
430 }
431
sink_new_hook_callback(pa_core * c,pa_sink_new_data * new_data,void * u)432 static pa_hook_result_t sink_new_hook_callback(pa_core *c, pa_sink_new_data *new_data, void *u) {
433
434 pa_device_port *p = new_sink_source(new_data->ports, new_data->active_port);
435
436 if (p) {
437 pa_log_debug("Switching initial port for sink '%s' to '%s'", new_data->name, p->name);
438 pa_sink_new_data_set_port(new_data, p->name);
439 }
440 return PA_HOOK_OK;
441 }
442
source_new_hook_callback(pa_core * c,pa_source_new_data * new_data,void * u)443 static pa_hook_result_t source_new_hook_callback(pa_core *c, pa_source_new_data *new_data, void *u) {
444
445 pa_device_port *p = new_sink_source(new_data->ports, new_data->active_port);
446
447 if (p) {
448 pa_log_debug("Switching initial port for source '%s' to '%s'", new_data->name, p->name);
449 pa_source_new_data_set_port(new_data, p->name);
450 }
451 return PA_HOOK_OK;
452 }
453
card_put_hook_callback(pa_core * core,pa_card * card,struct userdata * u)454 static pa_hook_result_t card_put_hook_callback(pa_core *core, pa_card *card, struct userdata *u) {
455 card_info_new(u, card);
456
457 return PA_HOOK_OK;
458 }
459
card_unlink_hook_callback(pa_core * core,pa_card * card,struct userdata * u)460 static pa_hook_result_t card_unlink_hook_callback(pa_core *core, pa_card *card, struct userdata *u) {
461 card_info_free(pa_hashmap_get(u->card_infos, card));
462
463 return PA_HOOK_OK;
464 }
465
update_preferred_input_port(pa_card * card,pa_card_profile * old_profile,pa_card_profile * new_profile)466 static void update_preferred_input_port(pa_card *card, pa_card_profile *old_profile, pa_card_profile *new_profile) {
467 pa_source *source;
468
469 /* If the profile change didn't affect input, it doesn't indicate change in
470 * the user's input port preference. */
471 if (pa_safe_streq(old_profile->input_name, new_profile->input_name))
472 return;
473
474 /* If there are more than one source, we don't know which of those the user
475 * prefers. If there are no sources, then the user doesn't seem to care
476 * about input at all. */
477 if (pa_idxset_size(card->sources) != 1) {
478 pa_card_set_preferred_port(card, PA_DIRECTION_INPUT, NULL);
479 return;
480 }
481
482 /* If the profile change modified the set of sinks, then it's unclear
483 * whether the user wanted to activate some specific input port, or was the
484 * input change only a side effect of activating some output. If the new
485 * profile contains no sinks, though, then we know the user only cares
486 * about input. */
487 if (pa_idxset_size(card->sinks) > 0 && !pa_safe_streq(old_profile->output_name, new_profile->output_name)) {
488 pa_card_set_preferred_port(card, PA_DIRECTION_INPUT, NULL);
489 return;
490 }
491
492 source = pa_idxset_first(card->sources, NULL);
493
494 /* We know the user wanted to activate this source. The user might not have
495 * wanted to activate the port that was selected by default, but if that's
496 * the case, the user will change the port manually, and we'll update the
497 * port preference at that time. If no port change occurs, we can assume
498 * that the user likes the port that is now active. */
499 pa_card_set_preferred_port(card, PA_DIRECTION_INPUT, source->active_port);
500 }
501
update_preferred_output_port(pa_card * card,pa_card_profile * old_profile,pa_card_profile * new_profile)502 static void update_preferred_output_port(pa_card *card, pa_card_profile *old_profile, pa_card_profile *new_profile) {
503 pa_sink *sink;
504
505 /* If the profile change didn't affect output, it doesn't indicate change in
506 * the user's output port preference. */
507 if (pa_safe_streq(old_profile->output_name, new_profile->output_name))
508 return;
509
510 /* If there are more than one sink, we don't know which of those the user
511 * prefers. If there are no sinks, then the user doesn't seem to care about
512 * output at all. */
513 if (pa_idxset_size(card->sinks) != 1) {
514 pa_card_set_preferred_port(card, PA_DIRECTION_OUTPUT, NULL);
515 return;
516 }
517
518 /* If the profile change modified the set of sources, then it's unclear
519 * whether the user wanted to activate some specific output port, or was
520 * the output change only a side effect of activating some input. If the
521 * new profile contains no sources, though, then we know the user only
522 * cares about output. */
523 if (pa_idxset_size(card->sources) > 0 && !pa_safe_streq(old_profile->input_name, new_profile->input_name)) {
524 pa_card_set_preferred_port(card, PA_DIRECTION_OUTPUT, NULL);
525 return;
526 }
527
528 sink = pa_idxset_first(card->sinks, NULL);
529
530 /* We know the user wanted to activate this sink. The user might not have
531 * wanted to activate the port that was selected by default, but if that's
532 * the case, the user will change the port manually, and we'll update the
533 * port preference at that time. If no port change occurs, we can assume
534 * that the user likes the port that is now active. */
535 pa_card_set_preferred_port(card, PA_DIRECTION_OUTPUT, sink->active_port);
536 }
537
card_profile_changed_callback(pa_core * core,pa_card * card,struct userdata * u)538 static pa_hook_result_t card_profile_changed_callback(pa_core *core, pa_card *card, struct userdata *u) {
539 struct card_info *info;
540 pa_card_profile *old_profile;
541 pa_card_profile *new_profile;
542
543 info = pa_hashmap_get(u->card_infos, card);
544 old_profile = info->active_profile;
545 new_profile = card->active_profile;
546 info->active_profile = new_profile;
547
548 /* This profile change wasn't initiated by the user, so it doesn't signal
549 * a change in the user's port preferences. */
550 if (!card->save_profile)
551 return PA_HOOK_OK;
552
553 update_preferred_input_port(card, old_profile, new_profile);
554 update_preferred_output_port(card, old_profile, new_profile);
555
556 return PA_HOOK_OK;
557 }
558
source_port_changed_callback(pa_core * core,pa_source * source,void * userdata)559 static pa_hook_result_t source_port_changed_callback(pa_core *core, pa_source *source, void *userdata) {
560 if (!source->save_port)
561 return PA_HOOK_OK;
562
563 pa_card_set_preferred_port(source->card, PA_DIRECTION_INPUT, source->active_port);
564
565 return PA_HOOK_OK;
566 }
567
sink_port_changed_callback(pa_core * core,pa_sink * sink,void * userdata)568 static pa_hook_result_t sink_port_changed_callback(pa_core *core, pa_sink *sink, void *userdata) {
569 if (!sink->save_port)
570 return PA_HOOK_OK;
571
572 pa_card_set_preferred_port(sink->card, PA_DIRECTION_OUTPUT, sink->active_port);
573
574 return PA_HOOK_OK;
575 }
576
pa__init(pa_module * m)577 int pa__init(pa_module*m) {
578 struct userdata *u;
579 pa_card *card;
580 uint32_t idx;
581
582 pa_assert(m);
583
584 u = m->userdata = pa_xnew0(struct userdata, 1);
585 u->card_infos = pa_hashmap_new(NULL, NULL);
586
587 PA_IDXSET_FOREACH(card, m->core->cards, idx)
588 card_info_new(u, card);
589
590 /* Make sure we are after module-device-restore, so we can overwrite that suggestion if necessary */
591 pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_SINK_NEW],
592 PA_HOOK_NORMAL, (pa_hook_cb_t) sink_new_hook_callback, NULL);
593 pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_SOURCE_NEW],
594 PA_HOOK_NORMAL, (pa_hook_cb_t) source_new_hook_callback, NULL);
595 pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_PORT_AVAILABLE_CHANGED],
596 PA_HOOK_LATE, (pa_hook_cb_t) port_available_hook_callback, NULL);
597 pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_CARD_PROFILE_AVAILABLE_CHANGED],
598 PA_HOOK_LATE, (pa_hook_cb_t) card_profile_available_hook_callback, NULL);
599 pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_CARD_PUT],
600 PA_HOOK_NORMAL, (pa_hook_cb_t) card_put_hook_callback, u);
601 pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_CARD_UNLINK],
602 PA_HOOK_NORMAL, (pa_hook_cb_t) card_unlink_hook_callback, u);
603 pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_CARD_PROFILE_CHANGED],
604 PA_HOOK_NORMAL, (pa_hook_cb_t) card_profile_changed_callback, u);
605 pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_SOURCE_PORT_CHANGED],
606 PA_HOOK_NORMAL, (pa_hook_cb_t) source_port_changed_callback, NULL);
607 pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_SINK_PORT_CHANGED],
608 PA_HOOK_NORMAL, (pa_hook_cb_t) sink_port_changed_callback, NULL);
609
610 handle_all_unavailable(m->core);
611
612 return 0;
613 }
614
pa__done(pa_module * module)615 void pa__done(pa_module *module) {
616 struct userdata *u;
617 struct card_info *info;
618
619 pa_assert(module);
620
621 if (!(u = module->userdata))
622 return;
623
624 while ((info = pa_hashmap_last(u->card_infos)))
625 card_info_free(info);
626
627 pa_hashmap_free(u->card_infos);
628
629 pa_xfree(u);
630 }
631