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