mirror of
https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
synced 2025-10-31 22:25:33 -04:00
Merge branch 'pr/workaround-950-module-switch-on-port-available-blacklist-hdmi' into 'master'
module-switch-on-port-available: Also blacklist HDMI devices by default See merge request pulseaudio/pulseaudio!420
This commit is contained in:
commit
d3f421a269
1 changed files with 93 additions and 6 deletions
|
|
@ -26,11 +26,29 @@
|
||||||
#include <pulsecore/core-util.h>
|
#include <pulsecore/core-util.h>
|
||||||
#include <pulsecore/device-port.h>
|
#include <pulsecore/device-port.h>
|
||||||
#include <pulsecore/hashmap.h>
|
#include <pulsecore/hashmap.h>
|
||||||
|
#include <pulsecore/modargs.h>
|
||||||
|
|
||||||
|
/* Ignore HDMI devices by default. HDMI monitors don't necessarily have audio
|
||||||
|
* output on them, and even if they do, waking up from sleep or changing
|
||||||
|
* monitor resolution may appear as a plugin event, which causes trouble if the
|
||||||
|
* user doesn't want to use the monitor for audio. */
|
||||||
|
#define DEFAULT_BLACKLIST_PORTS "hdmi"
|
||||||
|
#define DEFAULT_BLACKLIST_PROFILES "hdmi"
|
||||||
|
|
||||||
PA_MODULE_AUTHOR("David Henningsson");
|
PA_MODULE_AUTHOR("David Henningsson");
|
||||||
PA_MODULE_DESCRIPTION("Switches ports and profiles when devices are plugged/unplugged");
|
PA_MODULE_DESCRIPTION("Switches ports and profiles when devices are plugged/unplugged");
|
||||||
PA_MODULE_LOAD_ONCE(true);
|
PA_MODULE_LOAD_ONCE(true);
|
||||||
PA_MODULE_VERSION(PACKAGE_VERSION);
|
PA_MODULE_VERSION(PACKAGE_VERSION);
|
||||||
|
PA_MODULE_USAGE(
|
||||||
|
"blacklist_ports=<regex, ignore matching ports> "
|
||||||
|
"blacklist_profiles=<regex, ignore matching card profiles> "
|
||||||
|
);
|
||||||
|
|
||||||
|
static const char* const valid_modargs[] = {
|
||||||
|
"blacklist_ports",
|
||||||
|
"blacklist_profiles",
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|
||||||
struct card_info {
|
struct card_info {
|
||||||
struct userdata *userdata;
|
struct userdata *userdata;
|
||||||
|
|
@ -44,6 +62,8 @@ struct card_info {
|
||||||
|
|
||||||
struct userdata {
|
struct userdata {
|
||||||
pa_hashmap *card_infos; /* pa_card -> struct card_info */
|
pa_hashmap *card_infos; /* pa_card -> struct card_info */
|
||||||
|
char *blacklist_ports;
|
||||||
|
char *blacklist_profiles;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void card_info_new(struct userdata *u, pa_card *card) {
|
static void card_info_new(struct userdata *u, pa_card *card) {
|
||||||
|
|
@ -296,9 +316,13 @@ static void switch_from_port(pa_device_port *port, struct port_pointers pp) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static pa_hook_result_t port_available_hook_callback(pa_core *c, pa_device_port *port, void* userdata) {
|
static pa_hook_result_t port_available_hook_callback(pa_core *c, pa_device_port *port, struct userdata *u) {
|
||||||
struct port_pointers pp = find_port_pointers(port);
|
struct port_pointers pp = find_port_pointers(port);
|
||||||
|
|
||||||
|
pa_assert(c);
|
||||||
|
pa_assert(port);
|
||||||
|
pa_assert(u);
|
||||||
|
|
||||||
if (!port->card) {
|
if (!port->card) {
|
||||||
pa_log_warn("Port %s does not have a card", port->name);
|
pa_log_warn("Port %s does not have a card", port->name);
|
||||||
return PA_HOOK_OK;
|
return PA_HOOK_OK;
|
||||||
|
|
@ -312,6 +336,12 @@ static pa_hook_result_t port_available_hook_callback(pa_core *c, pa_device_port
|
||||||
if (pa_safe_streq(pa_proplist_gets(port->card->proplist, PA_PROP_DEVICE_BUS), "bluetooth"))
|
if (pa_safe_streq(pa_proplist_gets(port->card->proplist, PA_PROP_DEVICE_BUS), "bluetooth"))
|
||||||
return PA_HOOK_OK;
|
return PA_HOOK_OK;
|
||||||
|
|
||||||
|
/* Ignore ports matching the blacklist regex */
|
||||||
|
if (u->blacklist_ports && (pa_match(u->blacklist_ports, port->name) > 0)) {
|
||||||
|
pa_log_info("Ignoring blacklisted port %s", port->name);
|
||||||
|
return PA_HOOK_OK;
|
||||||
|
}
|
||||||
|
|
||||||
switch (port->available) {
|
switch (port->available) {
|
||||||
case PA_AVAILABLE_UNKNOWN:
|
case PA_AVAILABLE_UNKNOWN:
|
||||||
/* If a port availability became unknown, let's see if it's part of
|
/* If a port availability became unknown, let's see if it's part of
|
||||||
|
|
@ -387,6 +417,7 @@ static pa_card_profile *find_best_profile(pa_card *card) {
|
||||||
static pa_hook_result_t card_profile_available_hook_callback(pa_core *c, pa_card_profile *profile, struct userdata *u) {
|
static pa_hook_result_t card_profile_available_hook_callback(pa_core *c, pa_card_profile *profile, struct userdata *u) {
|
||||||
pa_card *card;
|
pa_card *card;
|
||||||
|
|
||||||
|
pa_assert(u);
|
||||||
pa_assert(profile);
|
pa_assert(profile);
|
||||||
pa_assert_se(card = profile->card);
|
pa_assert_se(card = profile->card);
|
||||||
|
|
||||||
|
|
@ -401,6 +432,12 @@ static pa_hook_result_t card_profile_available_hook_callback(pa_core *c, pa_card
|
||||||
return PA_HOOK_OK;
|
return PA_HOOK_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Ignore p matching the blacklist regex */
|
||||||
|
if (u->blacklist_profiles && (pa_match(u->blacklist_profiles, profile->name) > 0)) {
|
||||||
|
pa_log_info("Ignoring blacklisted card profile %s", profile->name);
|
||||||
|
return PA_HOOK_OK;
|
||||||
|
}
|
||||||
|
|
||||||
pa_log_debug("Active profile %s on card %s became unavailable, switching to another profile", profile->name, card->name);
|
pa_log_debug("Active profile %s on card %s became unavailable, switching to another profile", profile->name, card->name);
|
||||||
pa_card_set_profile(card, find_best_profile(card), false);
|
pa_card_set_profile(card, find_best_profile(card), false);
|
||||||
|
|
||||||
|
|
@ -408,7 +445,7 @@ static pa_hook_result_t card_profile_available_hook_callback(pa_core *c, pa_card
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handle_all_unavailable(pa_core *core) {
|
static void handle_all_unavailable(pa_core *core, struct userdata *u) {
|
||||||
pa_card *card;
|
pa_card *card;
|
||||||
uint32_t state;
|
uint32_t state;
|
||||||
|
|
||||||
|
|
@ -418,7 +455,7 @@ static void handle_all_unavailable(pa_core *core) {
|
||||||
|
|
||||||
PA_HASHMAP_FOREACH(port, card->ports, state2) {
|
PA_HASHMAP_FOREACH(port, card->ports, state2) {
|
||||||
if (port->available == PA_AVAILABLE_NO)
|
if (port->available == PA_AVAILABLE_NO)
|
||||||
port_available_hook_callback(core, port, NULL);
|
port_available_hook_callback(core, port, u);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -591,15 +628,49 @@ static pa_hook_result_t sink_port_changed_callback(pa_core *core, pa_sink *sink,
|
||||||
}
|
}
|
||||||
|
|
||||||
int pa__init(pa_module*m) {
|
int pa__init(pa_module*m) {
|
||||||
|
pa_modargs *ma;
|
||||||
struct userdata *u;
|
struct userdata *u;
|
||||||
pa_card *card;
|
pa_card *card;
|
||||||
uint32_t idx;
|
uint32_t idx;
|
||||||
|
|
||||||
pa_assert(m);
|
pa_assert(m);
|
||||||
|
|
||||||
|
if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
|
||||||
|
pa_log("Failed to parse module arguments");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
u = m->userdata = pa_xnew0(struct userdata, 1);
|
u = m->userdata = pa_xnew0(struct userdata, 1);
|
||||||
u->card_infos = pa_hashmap_new(NULL, NULL);
|
u->card_infos = pa_hashmap_new(NULL, NULL);
|
||||||
|
|
||||||
|
u->blacklist_ports = pa_xstrdup(pa_modargs_get_value(ma, "blacklist_ports", DEFAULT_BLACKLIST_PORTS));
|
||||||
|
|
||||||
|
/* An empty string disables all blacklisting. */
|
||||||
|
if (!*u->blacklist_ports) {
|
||||||
|
pa_xfree(u->blacklist_ports);
|
||||||
|
u->blacklist_ports = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (u->blacklist_ports != NULL && !pa_is_regex_valid(u->blacklist_ports)) {
|
||||||
|
pa_log_error("A port blacklist pattern was provided but is not a valid regex");
|
||||||
|
pa_xfree(u->blacklist_ports);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
u->blacklist_profiles = pa_xstrdup(pa_modargs_get_value(ma, "blacklist_profiles", DEFAULT_BLACKLIST_PROFILES));
|
||||||
|
|
||||||
|
/* An empty string disables all blacklisting. */
|
||||||
|
if (!*u->blacklist_profiles) {
|
||||||
|
pa_xfree(u->blacklist_profiles);
|
||||||
|
u->blacklist_profiles = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (u->blacklist_profiles != NULL && !pa_is_regex_valid(u->blacklist_profiles)) {
|
||||||
|
pa_log_error("A card profile blacklist pattern was provided but is not a valid regex");
|
||||||
|
pa_xfree(u->blacklist_profiles);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
PA_IDXSET_FOREACH(card, m->core->cards, idx)
|
PA_IDXSET_FOREACH(card, m->core->cards, idx)
|
||||||
card_info_new(u, card);
|
card_info_new(u, card);
|
||||||
|
|
||||||
|
|
@ -609,9 +680,9 @@ int pa__init(pa_module*m) {
|
||||||
pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_SOURCE_NEW],
|
pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_SOURCE_NEW],
|
||||||
PA_HOOK_NORMAL, (pa_hook_cb_t) source_new_hook_callback, NULL);
|
PA_HOOK_NORMAL, (pa_hook_cb_t) source_new_hook_callback, NULL);
|
||||||
pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_PORT_AVAILABLE_CHANGED],
|
pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_PORT_AVAILABLE_CHANGED],
|
||||||
PA_HOOK_LATE, (pa_hook_cb_t) port_available_hook_callback, NULL);
|
PA_HOOK_LATE, (pa_hook_cb_t) port_available_hook_callback, u);
|
||||||
pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_CARD_PROFILE_AVAILABLE_CHANGED],
|
pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_CARD_PROFILE_AVAILABLE_CHANGED],
|
||||||
PA_HOOK_LATE, (pa_hook_cb_t) card_profile_available_hook_callback, NULL);
|
PA_HOOK_LATE, (pa_hook_cb_t) card_profile_available_hook_callback, u);
|
||||||
pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_CARD_PUT],
|
pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_CARD_PUT],
|
||||||
PA_HOOK_NORMAL, (pa_hook_cb_t) card_put_hook_callback, u);
|
PA_HOOK_NORMAL, (pa_hook_cb_t) card_put_hook_callback, u);
|
||||||
pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_CARD_UNLINK],
|
pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_CARD_UNLINK],
|
||||||
|
|
@ -623,9 +694,19 @@ int pa__init(pa_module*m) {
|
||||||
pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_SINK_PORT_CHANGED],
|
pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_SINK_PORT_CHANGED],
|
||||||
PA_HOOK_NORMAL, (pa_hook_cb_t) sink_port_changed_callback, NULL);
|
PA_HOOK_NORMAL, (pa_hook_cb_t) sink_port_changed_callback, NULL);
|
||||||
|
|
||||||
handle_all_unavailable(m->core);
|
handle_all_unavailable(m->core, u);
|
||||||
|
|
||||||
|
pa_modargs_free(ma);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
if (ma)
|
||||||
|
pa_modargs_free(ma);
|
||||||
|
|
||||||
|
pa__done(m);
|
||||||
|
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pa__done(pa_module *module) {
|
void pa__done(pa_module *module) {
|
||||||
|
|
@ -642,5 +723,11 @@ void pa__done(pa_module *module) {
|
||||||
|
|
||||||
pa_hashmap_free(u->card_infos);
|
pa_hashmap_free(u->card_infos);
|
||||||
|
|
||||||
|
if (u->blacklist_ports)
|
||||||
|
pa_xfree(u->blacklist_ports);
|
||||||
|
|
||||||
|
if (u->blacklist_profiles)
|
||||||
|
pa_xfree(u->blacklist_profiles);
|
||||||
|
|
||||||
pa_xfree(u);
|
pa_xfree(u);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue