This is an automated email from the git hooks/post-receive script. themuso-guest pushed a commit to branch ubuntu-xenial in repository pulseaudio.
commit d8f501fd12c0443487725f02f339e27212ceb944 Author: Luke Yelavich <[email protected]> Date: Tue Nov 22 11:16:36 2016 +1100 Backport from upstream to fix audio switching away from HDMI monitor when it sleeps --- debian/changelog | 11 + ...0101-card-add-preferred-input-output-port.patch | 156 ++++++++++ ...ort-available-prefer-ports-that-have-been.patch | 316 +++++++++++++++++++++ ...0203-card-Add-hook-before-profile-changes.patch | 6 +- debian/patches/series | 2 + 5 files changed, 488 insertions(+), 3 deletions(-) diff --git a/debian/changelog b/debian/changelog index 4ad5468..c2db4ff 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,14 @@ +pulseaudio (1:8.0-0ubuntu3.2) UNRELEASED; urgency=medium + + * 0101-card-add-preferred-input-output-port.patch, + 0102-switch-on-port-available-prefer-ports-that-have-been.patch, + 0103-card-Add-hook-before-profile-changes.patch: + - Backport from upstream to fix a bug in PulseAudio 8 where audio switches + to another audio device when an HDMI monitor goes to sleep, thanks to + Cristian Klein <[email protected]> for the backport (LP: #1641954) + + -- Luke Yelavich <[email protected]> Tue, 22 Nov 2016 11:13:00 +1100 + pulseaudio (1:8.0-0ubuntu3.1) xenial; urgency=medium * debian/pulseaudio.maintscript: Bump versions for files that need to be diff --git a/debian/patches/0101-card-add-preferred-input-output-port.patch b/debian/patches/0101-card-add-preferred-input-output-port.patch new file mode 100644 index 0000000..9b4b1b2 --- /dev/null +++ b/debian/patches/0101-card-add-preferred-input-output-port.patch @@ -0,0 +1,156 @@ +From 04040c522f5f62dda50ac927e92453381d419f09 Mon Sep 17 00:00:00 2001 +From: Tanu Kaskinen <[email protected]> +Date: Fri, 4 Mar 2016 15:23:30 +0200 +Subject: card: add preferred_{input, output}_port + +I will modify module-switch-on-port-available so that it will keep +track of which input and output port the user prefers on the card, +based on the user's profile and port switches. The preference needs +to be saved on disk, for which I will use module-card-restore. + +To facilitate communication between the two modules, this patch adds +preferred_input_port and preferred_output_port fields to pa_card, and +a hook for monitoring the variable changes. It would be nice if the +two modules would communicate directly with each other, but +implementing that would be somewhat complicated, so I chose this time +for adding the functionality to the core. In theory some other routing +module might want to manage the new variables instead of +module-switch-on-port-available, but admittedly that's not very likely +to happen... + +diff --git a/src/pulsecore/card.c b/src/pulsecore/card.c +index b6cbbf7..0eaccff 100644 +--- a/src/pulsecore/card.c ++++ b/src/pulsecore/card.c +@@ -103,6 +103,15 @@ void pa_card_new_data_set_profile(pa_card_new_data *data, const char *profile) { + data->active_profile = pa_xstrdup(profile); + } + ++void pa_card_new_data_set_preferred_port(pa_card_new_data *data, pa_direction_t direction, pa_device_port *port) { ++ pa_assert(data); ++ ++ if (direction == PA_DIRECTION_INPUT) ++ data->preferred_input_port = port; ++ else ++ data->preferred_output_port = port; ++} ++ + void pa_card_new_data_done(pa_card_new_data *data) { + + pa_assert(data); +@@ -169,6 +178,9 @@ pa_card *pa_card_new(pa_core *core, pa_card_new_data *data) { + PA_HASHMAP_FOREACH(port, c->ports, state) + port->card = c; + ++ c->preferred_input_port = data->preferred_input_port; ++ c->preferred_output_port = data->preferred_output_port; ++ + if (data->active_profile) + if ((c->active_profile = pa_hashmap_get(c->profiles, data->active_profile))) + c->save_profile = data->save_profile; +@@ -309,6 +321,40 @@ int pa_card_set_profile(pa_card *c, pa_card_profile *profile, bool save) { + return 0; + } + ++void pa_card_set_preferred_port(pa_card *c, pa_direction_t direction, pa_device_port *port) { ++ pa_device_port *old_port; ++ const char *old_port_str; ++ const char *new_port_str; ++ pa_card_preferred_port_changed_hook_data data; ++ ++ pa_assert(c); ++ ++ if (direction == PA_DIRECTION_INPUT) { ++ old_port = c->preferred_input_port; ++ old_port_str = c->preferred_input_port ? c->preferred_input_port->name : "(unset)"; ++ } else { ++ old_port = c->preferred_output_port; ++ old_port_str = c->preferred_output_port ? c->preferred_output_port->name : "(unset)"; ++ } ++ ++ if (port == old_port) ++ return; ++ ++ new_port_str = port ? port->name : "(unset)"; ++ ++ if (direction == PA_DIRECTION_INPUT) { ++ c->preferred_input_port = port; ++ pa_log_debug("%s: preferred_input_port: %s -> %s", c->name, old_port_str, new_port_str); ++ } else { ++ c->preferred_output_port = port; ++ pa_log_debug("%s: preferred_output_port: %s -> %s", c->name, old_port_str, new_port_str); ++ } ++ ++ data.card = c; ++ data.direction = direction; ++ pa_hook_fire(&c->core->hooks[PA_CORE_HOOK_CARD_PREFERRED_PORT_CHANGED], &data); ++} ++ + int pa_card_suspend(pa_card *c, bool suspend, pa_suspend_cause_t cause) { + pa_sink *sink; + pa_source *source; +diff --git a/src/pulsecore/card.h b/src/pulsecore/card.h +index 30bfc0e..79966f3 100644 +--- a/src/pulsecore/card.h ++++ b/src/pulsecore/card.h +@@ -79,6 +79,8 @@ struct pa_card { + pa_card_profile *active_profile; + + pa_hashmap *ports; ++ pa_device_port *preferred_input_port; ++ pa_device_port *preferred_output_port; + + bool save_profile:1; + +@@ -98,12 +100,19 @@ typedef struct pa_card_new_data { + char *active_profile; + + pa_hashmap *ports; ++ pa_device_port *preferred_input_port; ++ pa_device_port *preferred_output_port; + + bool namereg_fail:1; + + bool save_profile:1; + } pa_card_new_data; + ++typedef struct { ++ pa_card *card; ++ pa_direction_t direction; ++} pa_card_preferred_port_changed_hook_data; ++ + pa_card_profile *pa_card_profile_new(const char *name, const char *description, size_t extra); + void pa_card_profile_free(pa_card_profile *c); + +@@ -113,6 +122,7 @@ void pa_card_profile_set_available(pa_card_profile *c, pa_available_t available) + pa_card_new_data *pa_card_new_data_init(pa_card_new_data *data); + void pa_card_new_data_set_name(pa_card_new_data *data, const char *name); + void pa_card_new_data_set_profile(pa_card_new_data *data, const char *profile); ++void pa_card_new_data_set_preferred_port(pa_card_new_data *data, pa_direction_t direction, pa_device_port *port); + void pa_card_new_data_done(pa_card_new_data *data); + + pa_card *pa_card_new(pa_core *c, pa_card_new_data *data); +@@ -122,6 +132,8 @@ void pa_card_add_profile(pa_card *c, pa_card_profile *profile); + + int pa_card_set_profile(pa_card *c, pa_card_profile *profile, bool save); + ++void pa_card_set_preferred_port(pa_card *c, pa_direction_t direction, pa_device_port *port); ++ + int pa_card_suspend(pa_card *c, bool suspend, pa_suspend_cause_t cause); + + #endif +diff --git a/src/pulsecore/core.h b/src/pulsecore/core.h +index 1a3c490..69ab4d0 100644 +--- a/src/pulsecore/core.h ++++ b/src/pulsecore/core.h +@@ -120,6 +120,7 @@ typedef enum pa_core_hook { + PA_CORE_HOOK_CARD_NEW, + PA_CORE_HOOK_CARD_PUT, + PA_CORE_HOOK_CARD_UNLINK, ++ PA_CORE_HOOK_CARD_PREFERRED_PORT_CHANGED, + PA_CORE_HOOK_CARD_PROFILE_CHANGED, + PA_CORE_HOOK_CARD_PROFILE_ADDED, + PA_CORE_HOOK_CARD_PROFILE_AVAILABLE_CHANGED, +-- +cgit v0.10.2 + diff --git a/debian/patches/0102-switch-on-port-available-prefer-ports-that-have-been.patch b/debian/patches/0102-switch-on-port-available-prefer-ports-that-have-been.patch new file mode 100644 index 0000000..aff34c1 --- /dev/null +++ b/debian/patches/0102-switch-on-port-available-prefer-ports-that-have-been.patch @@ -0,0 +1,316 @@ +Index: pulseaudio-8.0/src/modules/module-switch-on-port-available.c +=================================================================== +--- pulseaudio-8.0.orig/src/modules/module-switch-on-port-available.c ++++ pulseaudio-8.0/src/modules/module-switch-on-port-available.c +@@ -29,45 +29,97 @@ + + #include "module-switch-on-port-available-symdef.h" + +-static bool profile_good_for_output(pa_card_profile *profile, unsigned prio) { ++struct card_info { ++ struct userdata *userdata; ++ pa_card *card; ++ ++ /* We need to cache the active profile, because we want to compare the old ++ * and new profiles in the PROFILE_CHANGED hook. Without this we'd only ++ * have access to the new profile. */ ++ pa_card_profile *active_profile; ++}; ++ ++struct userdata { ++ pa_hashmap *card_infos; /* pa_card -> struct card_info */ ++}; ++ ++static void card_info_new(struct userdata *u, pa_card *card) { ++ struct card_info *info; ++ ++ info = pa_xnew0(struct card_info, 1); ++ info->userdata = u; ++ info->card = card; ++ info->active_profile = card->active_profile; ++ ++ pa_hashmap_put(u->card_infos, card, info); ++} ++ ++static void card_info_free(struct card_info *info) { ++ pa_hashmap_remove(info->userdata->card_infos, info->card); ++ pa_xfree(info); ++} ++ ++static bool profile_good_for_output(pa_card_profile *profile, pa_device_port *port) { ++ pa_card *card; + pa_sink *sink; + uint32_t idx; + + pa_assert(profile); + +- if (!pa_safe_streq(profile->card->active_profile->input_name, profile->input_name)) ++ card = profile->card; ++ ++ if (!pa_safe_streq(card->active_profile->input_name, profile->input_name)) + return false; + +- if (profile->card->active_profile->n_sources != profile->n_sources) ++ if (card->active_profile->n_sources != profile->n_sources) + return false; + +- if (profile->card->active_profile->max_source_channels != profile->max_source_channels) ++ if (card->active_profile->max_source_channels != profile->max_source_channels) + return false; + +- /* Try not to switch to HDMI sinks from analog when HDMI is becoming available */ +- PA_IDXSET_FOREACH(sink, profile->card->sinks, idx) { ++ if (port == card->preferred_output_port) ++ return true; ++ ++ PA_IDXSET_FOREACH(sink, card->sinks, idx) { + if (!sink->active_port) + continue; + +- if ((sink->active_port->available != PA_AVAILABLE_NO) && (sink->active_port->priority >= prio)) ++ if ((sink->active_port->available != PA_AVAILABLE_NO) && (sink->active_port->priority >= port->priority)) + return false; + } + + return true; + } + +-static bool profile_good_for_input(pa_card_profile *profile) { ++static bool profile_good_for_input(pa_card_profile *profile, pa_device_port *port) { ++ pa_card *card; ++ pa_source *source; ++ uint32_t idx; ++ + pa_assert(profile); + +- if (!pa_safe_streq(profile->card->active_profile->output_name, profile->output_name)) ++ card = profile->card; ++ ++ if (!pa_safe_streq(card->active_profile->output_name, profile->output_name)) + return false; + +- if (profile->card->active_profile->n_sinks != profile->n_sinks) ++ if (card->active_profile->n_sinks != profile->n_sinks) + return false; + +- if (profile->card->active_profile->max_sink_channels != profile->max_sink_channels) ++ if (card->active_profile->max_sink_channels != profile->max_sink_channels) + return false; + ++ if (port == card->preferred_input_port) ++ return true; ++ ++ PA_IDXSET_FOREACH(source, card->sources, idx) { ++ if (!source->active_port) ++ continue; ++ ++ if ((source->active_port->available != PA_AVAILABLE_NO) && (source->active_port->priority >= port->priority)) ++ return false; ++ } ++ + return true; + } + +@@ -88,12 +140,12 @@ static int try_to_switch_profile(pa_devi + switch (port->direction) { + case PA_DIRECTION_OUTPUT: + name = profile->output_name; +- good = profile_good_for_output(profile, port->priority); ++ good = profile_good_for_output(profile, port); + break; + + case PA_DIRECTION_INPUT: + name = profile->input_name; +- good = profile_good_for_input(profile); ++ good = profile_good_for_input(profile, port); + break; + } + +@@ -182,7 +234,7 @@ static bool switch_to_port(pa_device_por + pa_log_debug("Trying to switch to port %s", port->name); + if (!pp.is_preferred_profile_active) { + if (try_to_switch_profile(port) < 0) { +- if (pp.is_possible_profile_active) ++ if (!pp.is_possible_profile_active) + return false; + } + else +@@ -307,9 +359,142 @@ static pa_hook_result_t source_new_hook_ + return PA_HOOK_OK; + } + ++static pa_hook_result_t card_put_hook_callback(pa_core *core, pa_card *card, struct userdata *u) { ++ card_info_new(u, card); ++ ++ return PA_HOOK_OK; ++} ++ ++static pa_hook_result_t card_unlink_hook_callback(pa_core *core, pa_card *card, struct userdata *u) { ++ card_info_free(pa_hashmap_get(u->card_infos, card)); ++ ++ return PA_HOOK_OK; ++} ++ ++static void update_preferred_input_port(pa_card *card, pa_card_profile *old_profile, pa_card_profile *new_profile) { ++ pa_source *source; ++ ++ /* If the profile change didn't affect input, it doesn't indicate change in ++ * the user's input port preference. */ ++ if (pa_safe_streq(old_profile->input_name, new_profile->input_name)) ++ return; ++ ++ /* If there are more than one source, we don't know which of those the user ++ * prefers. If there are no sources, then the user doesn't seem to care ++ * about input at all. */ ++ if (pa_idxset_size(card->sources) != 1) { ++ pa_card_set_preferred_port(card, PA_DIRECTION_INPUT, NULL); ++ return; ++ } ++ ++ /* If the profile change modified the set of sinks, then it's unclear ++ * whether the user wanted to activate some specific input port, or was the ++ * input change only a side effect of activating some output. If the new ++ * profile contains no sinks, though, then we know the user only cares ++ * about input. */ ++ if (pa_idxset_size(card->sinks) > 0 && !pa_safe_streq(old_profile->output_name, new_profile->output_name)) { ++ pa_card_set_preferred_port(card, PA_DIRECTION_INPUT, NULL); ++ return; ++ } ++ ++ source = pa_idxset_first(card->sources, NULL); ++ ++ /* We know the user wanted to activate this source. The user might not have ++ * wanted to activate the port that was selected by default, but if that's ++ * the case, the user will change the port manually, and we'll update the ++ * port preference at that time. If no port change occurs, we can assume ++ * that the user likes the port that is now active. */ ++ pa_card_set_preferred_port(card, PA_DIRECTION_INPUT, source->active_port); ++} ++ ++static void update_preferred_output_port(pa_card *card, pa_card_profile *old_profile, pa_card_profile *new_profile) { ++ pa_sink *sink; ++ ++ /* If the profile change didn't affect output, it doesn't indicate change in ++ * the user's output port preference. */ ++ if (pa_safe_streq(old_profile->output_name, new_profile->output_name)) ++ return; ++ ++ /* If there are more than one sink, we don't know which of those the user ++ * prefers. If there are no sinks, then the user doesn't seem to care about ++ * output at all. */ ++ if (pa_idxset_size(card->sinks) != 1) { ++ pa_card_set_preferred_port(card, PA_DIRECTION_OUTPUT, NULL); ++ return; ++ } ++ ++ /* If the profile change modified the set of sources, then it's unclear ++ * whether the user wanted to activate some specific output port, or was ++ * the output change only a side effect of activating some input. If the ++ * new profile contains no sources, though, then we know the user only ++ * cares about output. */ ++ if (pa_idxset_size(card->sources) > 0 && !pa_safe_streq(old_profile->input_name, new_profile->input_name)) { ++ pa_card_set_preferred_port(card, PA_DIRECTION_OUTPUT, NULL); ++ return; ++ } ++ ++ sink = pa_idxset_first(card->sinks, NULL); ++ ++ /* We know the user wanted to activate this sink. The user might not have ++ * wanted to activate the port that was selected by default, but if that's ++ * the case, the user will change the port manually, and we'll update the ++ * port preference at that time. If no port change occurs, we can assume ++ * that the user likes the port that is now active. */ ++ pa_card_set_preferred_port(card, PA_DIRECTION_OUTPUT, sink->active_port); ++} ++ ++static pa_hook_result_t card_profile_changed_callback(pa_core *core, pa_card *card, struct userdata *u) { ++ struct card_info *info; ++ pa_card_profile *old_profile; ++ pa_card_profile *new_profile; ++ ++ info = pa_hashmap_get(u->card_infos, card); ++ old_profile = info->active_profile; ++ new_profile = card->active_profile; ++ info->active_profile = new_profile; ++ ++ /* This profile change wasn't initiated by the user, so it doesn't signal ++ * a change in the user's port preferences. */ ++ if (!card->save_profile) ++ return PA_HOOK_OK; ++ ++ update_preferred_input_port(card, old_profile, new_profile); ++ update_preferred_output_port(card, old_profile, new_profile); ++ ++ return PA_HOOK_OK; ++} ++ ++static pa_hook_result_t source_port_changed_callback(pa_core *core, pa_source *source, void *userdata) { ++ if (!source->save_port) ++ return PA_HOOK_OK; ++ ++ pa_card_set_preferred_port(source->card, PA_DIRECTION_INPUT, source->active_port); ++ ++ return PA_HOOK_OK; ++} ++ ++static pa_hook_result_t sink_port_changed_callback(pa_core *core, pa_sink *sink, void *userdata) { ++ if (!sink->save_port) ++ return PA_HOOK_OK; ++ ++ pa_card_set_preferred_port(sink->card, PA_DIRECTION_OUTPUT, sink->active_port); ++ ++ return PA_HOOK_OK; ++} ++ + int pa__init(pa_module*m) { ++ struct userdata *u; ++ pa_card *card; ++ uint32_t idx; ++ + pa_assert(m); + ++ u = m->userdata = pa_xnew0(struct userdata, 1); ++ u->card_infos = pa_hashmap_new(NULL, NULL); ++ ++ PA_IDXSET_FOREACH(card, m->core->cards, idx) ++ card_info_new(u, card); ++ + /* Make sure we are after module-device-restore, so we can overwrite that suggestion if necessary */ + pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_SINK_NEW], + PA_HOOK_NORMAL, (pa_hook_cb_t) sink_new_hook_callback, NULL); +@@ -317,8 +502,35 @@ int pa__init(pa_module*m) { + 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_HOOK_LATE, (pa_hook_cb_t) port_available_hook_callback, NULL); ++ 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_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_CARD_UNLINK], ++ PA_HOOK_NORMAL, (pa_hook_cb_t) card_unlink_hook_callback, u); ++ pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_CARD_PROFILE_CHANGED], ++ PA_HOOK_NORMAL, (pa_hook_cb_t) card_profile_changed_callback, u); ++ pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_SOURCE_PORT_CHANGED], ++ PA_HOOK_NORMAL, (pa_hook_cb_t) source_port_changed_callback, NULL); ++ 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); + + handle_all_unavailable(m->core); + + return 0; + } ++ ++void pa__done(pa_module *module) { ++ struct userdata *u; ++ struct card_info *info; ++ ++ pa_assert(module); ++ ++ if (!(u = module->userdata)) ++ return; ++ ++ while ((info = pa_hashmap_last(u->card_infos))) ++ card_info_free(info); ++ ++ pa_hashmap_free(u->card_infos); ++ ++ pa_xfree(u); ++} diff --git a/debian/patches/0203-card-Add-hook-before-profile-changes.patch b/debian/patches/0203-card-Add-hook-before-profile-changes.patch index 5af5223..f85ef01 100644 --- a/debian/patches/0203-card-Add-hook-before-profile-changes.patch +++ b/debian/patches/0203-card-Add-hook-before-profile-changes.patch @@ -14,7 +14,7 @@ Index: pulseaudio/src/pulsecore/card.c =================================================================== --- pulseaudio.orig/src/pulsecore/card.c +++ pulseaudio/src/pulsecore/card.c -@@ -291,6 +291,8 @@ int pa_card_set_profile(pa_card *c, pa_c +@@ -303,6 +303,8 @@ int pa_card_set_profile(pa_card *c, pa_c return 0; } @@ -27,9 +27,9 @@ Index: pulseaudio/src/pulsecore/core.h =================================================================== --- pulseaudio.orig/src/pulsecore/core.h +++ pulseaudio/src/pulsecore/core.h -@@ -121,6 +121,7 @@ typedef enum pa_core_hook { - PA_CORE_HOOK_CARD_PUT, +@@ -122,6 +122,7 @@ typedef enum pa_core_hook { PA_CORE_HOOK_CARD_UNLINK, + PA_CORE_HOOK_CARD_PREFERRED_PORT_CHANGED, PA_CORE_HOOK_CARD_PROFILE_CHANGED, + PA_CORE_HOOK_CARD_PROFILE_CHANGING, PA_CORE_HOOK_CARD_PROFILE_ADDED, diff --git a/debian/patches/series b/debian/patches/series index 646bf2a..0cd4be0 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -8,6 +8,8 @@ # Cherry-picked from upstream 0100-switch-on-port-available-Switch-from-HDMI-to-analog-.patch +0101-card-add-preferred-input-output-port.patch +0102-switch-on-port-available-prefer-ports-that-have-been.patch # Ubuntu touch stuff 0202-dont-probe-ucm.patch -- Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-pulseaudio/pulseaudio.git _______________________________________________ pkg-pulseaudio-devel mailing list [email protected] http://lists.alioth.debian.org/cgi-bin/mailman/listinfo/pkg-pulseaudio-devel

