[pulseaudio-discuss] [PATCH 1/3] core: Don't let moving filter sources/sinks become the default source/sink
Georg Chini
georg at chini.tk
Sat May 6 21:21:43 UTC 2017
When a virtual sink is loaded and there is only one sound card, then during
a profile switch, all sinks and sources can become temporarily unavailable.
In that situation, the virtual sink will become the default sink, although
it is not connected to a master sink due to the move operation initiated by
the profile switch. If module-always sink is loaded, it will load a null-sink
in that situation. If also module-switch-on-connect is present, it will change
the default sink to the new null sink and try to move the sink-inputs from the
virtual sink to the null sink. This leads to a segfault because the master
sink of the virtual sink is invalid.
This patch fixes the issue by disallowing a moving virtual sink to become the
default sink.
The same applies to the source side.
The is_filter_{sink,source}_moving() functions were stolen from one of Tanu's
previous unapplied patches.
Buglink: https://bugs.freedesktop.org/show_bug.cgi?id=100277
---
src/pulsecore/core.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 54 insertions(+)
diff --git a/src/pulsecore/core.c b/src/pulsecore/core.c
index 52e51db1..91a9da84 100644
--- a/src/pulsecore/core.c
+++ b/src/pulsecore/core.c
@@ -258,6 +258,23 @@ void pa_core_set_configured_default_source(pa_core *core, pa_source *source) {
pa_core_update_default_source(core);
}
+/* Test if a sink is a moving filter sink */
+static bool is_filter_sink_moving(pa_sink *s) {
+ pa_sink *sink = s;
+
+ if (!sink)
+ return false;
+
+ while (sink->input_to_master) {
+ sink = sink->input_to_master->sink;
+
+ if (!sink)
+ return true;
+ }
+
+ return false;
+}
+
/* a < b -> return -1
* a == b -> return 0
* a > b -> return 1 */
@@ -266,6 +283,12 @@ static int compare_sinks(pa_sink *a, pa_sink *b) {
core = a->core;
+ /* A moving filter sink is always worse than any other sink */
+ if (is_filter_sink_moving(a) && !is_filter_sink_moving(b))
+ return -1;
+ if (!is_filter_sink_moving(a) && is_filter_sink_moving(b))
+ return 1;
+
/* Available sinks always beat unavailable sinks. */
if (a->active_port && a->active_port->available == PA_AVAILABLE_NO
&& (!b->active_port || b->active_port->available != PA_AVAILABLE_NO))
@@ -314,6 +337,10 @@ void pa_core_update_default_sink(pa_core *core) {
best = sink;
}
+ /* A moving filter sink cannot be the default sink */
+ if (is_filter_sink_moving(best))
+ best = NULL;
+
old_default_sink = core->default_sink;
if (best == old_default_sink)
@@ -332,6 +359,23 @@ void pa_core_update_default_sink(pa_core *core) {
pa_hook_fire(&core->hooks[PA_CORE_HOOK_DEFAULT_SINK_CHANGED], core->default_sink);
}
+/* Test if a source is a moving filter source */
+static bool is_filter_source_moving(pa_source *o) {
+ pa_source *source = o;
+
+ if (!source)
+ return false;
+
+ while (source->output_from_master) {
+ source = source->output_from_master->source;
+
+ if (!source)
+ return true;
+ }
+
+ return false;
+}
+
/* a < b -> return -1
* a == b -> return 0
* a > b -> return 1 */
@@ -340,6 +384,12 @@ static int compare_sources(pa_source *a, pa_source *b) {
core = a->core;
+ /* A moving filter source is always worse than any other source */
+ if (is_filter_source_moving(a) && !is_filter_source_moving(b))
+ return -1;
+ if (!is_filter_source_moving(a) && is_filter_source_moving(b))
+ return 1;
+
/* Available sources always beat unavailable sources. */
if (a->active_port && a->active_port->available == PA_AVAILABLE_NO
&& (!b->active_port || b->active_port->available != PA_AVAILABLE_NO))
@@ -398,6 +448,10 @@ void pa_core_update_default_source(pa_core *core) {
best = source;
}
+ /* A moving filter source cannot be the default source */
+ if (is_filter_source_moving(best))
+ best = NULL;
+
old_default_source = core->default_source;
if (best == old_default_source)
--
2.11.0
More information about the pulseaudio-discuss
mailing list