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 42PA_MODULE_AUTHOR("Lennart Poettering"); 43PA_MODULE_DESCRIPTION("ALSA Card"); 44PA_MODULE_VERSION(PACKAGE_VERSION); 45PA_MODULE_LOAD_ONCE(false); 46PA_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 75static 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 116struct 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 138struct profile_data { 139 pa_alsa_profile *profile; 140}; 141 142static 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 193static 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 205static 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 283finish: 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 293static 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 320static 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 367struct temp_port_avail { 368 pa_device_port *port; 369 pa_available_t avail; 370}; 371 372static 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 542static 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 564static 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 600static 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 647static 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 707static 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 743static 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 769static 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 784static 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 799static 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 814static 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 829static 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 844int 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 1120fail: 1121 if (reserve) 1122 pa_reserve_wrapper_unref(reserve); 1123 1124 pa__done(m); 1125 1126 return err; 1127} 1128 1129int 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 1149void 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 1182finish: 1183 pa_alsa_refcnt_dec(); 1184} 1185