[pulseaudio] 01/02: Backport from upstream to fix audio switching away from HDMI monitor when it sleeps
Luke Yelavich
themuso-guest at moszumanska.debian.org
Wed Jan 18 05:30:31 UTC 2017
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 <themuso at ubuntu.com>
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 <cristiklein at gmail.com> for the backport (LP: #1641954)
+
+ -- Luke Yelavich <themuso at ubuntu.com> 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 <tanuk at iki.fi>
+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
More information about the pkg-pulseaudio-devel
mailing list