mirror of
https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
synced 2025-11-03 09:01:50 -05:00
core: Allow rescue of filter streams
Since 14.0, filter streams would be killed if the master sink or source disappeared. This patch changes the behavior to allow rescuing of filter streams.
This commit is contained in:
parent
ed4074ae08
commit
95be21c736
8 changed files with 178 additions and 51 deletions
|
|
@ -415,7 +415,7 @@ finish:
|
||||||
/* a < b -> return -1
|
/* a < b -> return -1
|
||||||
* a == b -> return 0
|
* a == b -> return 0
|
||||||
* a > b -> return 1 */
|
* a > b -> return 1 */
|
||||||
static int compare_sinks(pa_sink *a, pa_sink *b) {
|
static int compare_sinks(pa_sink *a, pa_sink *b, bool ignore_configured_virtual_default) {
|
||||||
pa_core *core;
|
pa_core *core;
|
||||||
|
|
||||||
core = a->core;
|
core = a->core;
|
||||||
|
|
@ -429,23 +429,37 @@ static int compare_sinks(pa_sink *a, pa_sink *b) {
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
/* The policy default sink is preferred over any other sink. */
|
/* The policy default sink is preferred over any other sink. */
|
||||||
if (pa_safe_streq(b->name, core->policy_default_sink))
|
if (pa_safe_streq(b->name, core->policy_default_sink)) {
|
||||||
return -1;
|
if (!ignore_configured_virtual_default || !pa_sink_is_filter(b))
|
||||||
if (pa_safe_streq(a->name, core->policy_default_sink))
|
return -1;
|
||||||
return 1;
|
}
|
||||||
|
if (pa_safe_streq(a->name, core->policy_default_sink)) {
|
||||||
|
if (!ignore_configured_virtual_default || !pa_sink_is_filter(a))
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/* The configured default sink is preferred over any other sink
|
/* The configured default sink is preferred over any other sink
|
||||||
* except the policy default sink. */
|
* except the policy default sink. */
|
||||||
if (pa_safe_streq(b->name, core->configured_default_sink))
|
if (pa_safe_streq(b->name, core->configured_default_sink)) {
|
||||||
return -1;
|
if (!ignore_configured_virtual_default || !pa_sink_is_filter(b))
|
||||||
if (pa_safe_streq(a->name, core->configured_default_sink))
|
return -1;
|
||||||
return 1;
|
}
|
||||||
|
if (pa_safe_streq(a->name, core->configured_default_sink)) {
|
||||||
|
if (!ignore_configured_virtual_default || !pa_sink_is_filter(a))
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (a->priority < b->priority)
|
if (a->priority < b->priority)
|
||||||
return -1;
|
return -1;
|
||||||
if (a->priority > b->priority)
|
if (a->priority > b->priority)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
/* Let sinks like pipe sink or null sink win against filter sinks */
|
||||||
|
if (a->vsink && !b->vsink)
|
||||||
|
return -1;
|
||||||
|
if (!a->vsink && b->vsink)
|
||||||
|
return 1;
|
||||||
|
|
||||||
/* It's hard to find any difference between these sinks, but maybe one of
|
/* It's hard to find any difference between these sinks, but maybe one of
|
||||||
* them is already the default sink? If so, it's best to keep it as the
|
* them is already the default sink? If so, it's best to keep it as the
|
||||||
* default to avoid changing the routing for no good reason. */
|
* default to avoid changing the routing for no good reason. */
|
||||||
|
|
@ -457,11 +471,10 @@ static int compare_sinks(pa_sink *a, pa_sink *b) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pa_core_update_default_sink(pa_core *core) {
|
pa_sink *pa_core_find_best_sink(pa_core *core, bool ignore_configured_virtual_default) {
|
||||||
pa_sink *best = NULL;
|
pa_sink *best = NULL;
|
||||||
pa_sink *sink;
|
pa_sink *sink;
|
||||||
uint32_t idx;
|
uint32_t idx;
|
||||||
pa_sink *old_default_sink;
|
|
||||||
|
|
||||||
pa_assert(core);
|
pa_assert(core);
|
||||||
|
|
||||||
|
|
@ -474,10 +487,21 @@ void pa_core_update_default_sink(pa_core *core) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (compare_sinks(sink, best) > 0)
|
if (compare_sinks(sink, best, ignore_configured_virtual_default) > 0)
|
||||||
best = sink;
|
best = sink;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return best;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pa_core_update_default_sink(pa_core *core) {
|
||||||
|
pa_sink *best;
|
||||||
|
pa_sink *old_default_sink;
|
||||||
|
|
||||||
|
pa_assert(core);
|
||||||
|
|
||||||
|
best = pa_core_find_best_sink(core, false);
|
||||||
|
|
||||||
old_default_sink = core->default_sink;
|
old_default_sink = core->default_sink;
|
||||||
|
|
||||||
if (best == old_default_sink)
|
if (best == old_default_sink)
|
||||||
|
|
@ -503,7 +527,7 @@ void pa_core_update_default_sink(pa_core *core) {
|
||||||
/* a < b -> return -1
|
/* a < b -> return -1
|
||||||
* a == b -> return 0
|
* a == b -> return 0
|
||||||
* a > b -> return 1 */
|
* a > b -> return 1 */
|
||||||
static int compare_sources(pa_source *a, pa_source *b) {
|
static int compare_sources(pa_source *a, pa_source *b, bool ignore_configured_virtual_default) {
|
||||||
pa_core *core;
|
pa_core *core;
|
||||||
|
|
||||||
core = a->core;
|
core = a->core;
|
||||||
|
|
@ -517,17 +541,25 @@ static int compare_sources(pa_source *a, pa_source *b) {
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
/* The policy default source is preferred over any other source. */
|
/* The policy default source is preferred over any other source. */
|
||||||
if (pa_safe_streq(b->name, core->policy_default_source))
|
if (pa_safe_streq(b->name, core->policy_default_source)) {
|
||||||
return -1;
|
if (!ignore_configured_virtual_default || !pa_source_is_filter(b))
|
||||||
if (pa_safe_streq(a->name, core->policy_default_source))
|
return -1;
|
||||||
return 1;
|
}
|
||||||
|
if (pa_safe_streq(a->name, core->policy_default_source)) {
|
||||||
|
if (!ignore_configured_virtual_default || !pa_source_is_filter(a))
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/* The configured default source is preferred over any other source
|
/* The configured default source is preferred over any other source
|
||||||
* except the policy default source. */
|
* except the policy default source. */
|
||||||
if (pa_safe_streq(b->name, core->configured_default_source))
|
if (pa_safe_streq(b->name, core->configured_default_source)) {
|
||||||
return -1;
|
if (!ignore_configured_virtual_default || !pa_source_is_filter(b))
|
||||||
if (pa_safe_streq(a->name, core->configured_default_source))
|
return -1;
|
||||||
return 1;
|
}
|
||||||
|
if (pa_safe_streq(a->name, core->configured_default_source)) {
|
||||||
|
if (!ignore_configured_virtual_default || !pa_source_is_filter(a))
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/* Monitor sources lose to non-monitor sources. */
|
/* Monitor sources lose to non-monitor sources. */
|
||||||
if (a->monitor_of && !b->monitor_of)
|
if (a->monitor_of && !b->monitor_of)
|
||||||
|
|
@ -540,9 +572,15 @@ static int compare_sources(pa_source *a, pa_source *b) {
|
||||||
if (a->priority > b->priority)
|
if (a->priority > b->priority)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
/* Let sources like pipe source or null source win against filter sources */
|
||||||
|
if (a->output_from_master && !b->output_from_master)
|
||||||
|
return -1;
|
||||||
|
if (!a->output_from_master && b->output_from_master)
|
||||||
|
return 1;
|
||||||
|
|
||||||
/* If the sources are monitors, we can compare the monitored sinks. */
|
/* If the sources are monitors, we can compare the monitored sinks. */
|
||||||
if (a->monitor_of)
|
if (a->monitor_of)
|
||||||
return compare_sinks(a->monitor_of, b->monitor_of);
|
return compare_sinks(a->monitor_of, b->monitor_of, false);
|
||||||
|
|
||||||
/* It's hard to find any difference between these sources, but maybe one of
|
/* It's hard to find any difference between these sources, but maybe one of
|
||||||
* them is already the default source? If so, it's best to keep it as the
|
* them is already the default source? If so, it's best to keep it as the
|
||||||
|
|
@ -555,11 +593,10 @@ static int compare_sources(pa_source *a, pa_source *b) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pa_core_update_default_source(pa_core *core) {
|
pa_source *pa_core_find_best_source(pa_core *core, bool ignore_configured_virtual_default) {
|
||||||
pa_source *best = NULL;
|
pa_source *best = NULL;
|
||||||
pa_source *source;
|
pa_source *source;
|
||||||
uint32_t idx;
|
uint32_t idx;
|
||||||
pa_source *old_default_source;
|
|
||||||
|
|
||||||
pa_assert(core);
|
pa_assert(core);
|
||||||
|
|
||||||
|
|
@ -572,10 +609,21 @@ void pa_core_update_default_source(pa_core *core) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (compare_sources(source, best) > 0)
|
if (compare_sources(source, best, ignore_configured_virtual_default) > 0)
|
||||||
best = source;
|
best = source;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return best;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pa_core_update_default_source(pa_core *core) {
|
||||||
|
pa_source *best;
|
||||||
|
pa_source *old_default_source;
|
||||||
|
|
||||||
|
pa_assert(core);
|
||||||
|
|
||||||
|
best = pa_core_find_best_source(core, false);
|
||||||
|
|
||||||
old_default_source = core->default_source;
|
old_default_source = core->default_source;
|
||||||
|
|
||||||
if (best == old_default_source)
|
if (best == old_default_source)
|
||||||
|
|
@ -693,11 +741,6 @@ void pa_core_move_streams_to_newly_available_preferred_sink(pa_core *c, pa_sink
|
||||||
if (!si->sink)
|
if (!si->sink)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Skip this sink input if it is connecting a filter sink to
|
|
||||||
* the master */
|
|
||||||
if (si->origin_sink)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/* It might happen that a stream and a sink are set up at the
|
/* It might happen that a stream and a sink are set up at the
|
||||||
same time, in which case we want to make sure we don't
|
same time, in which case we want to make sure we don't
|
||||||
interfere with that */
|
interfere with that */
|
||||||
|
|
@ -727,11 +770,6 @@ void pa_core_move_streams_to_newly_available_preferred_source(pa_core *c, pa_sou
|
||||||
if (!so->source)
|
if (!so->source)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Skip this source output if it is connecting a filter source to
|
|
||||||
* the master */
|
|
||||||
if (so->destination_source)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/* It might happen that a stream and a source are set up at the
|
/* It might happen that a stream and a source are set up at the
|
||||||
same time, in which case we want to make sure we don't
|
same time, in which case we want to make sure we don't
|
||||||
interfere with that */
|
interfere with that */
|
||||||
|
|
|
||||||
|
|
@ -271,6 +271,9 @@ void pa_core_set_policy_default_source(pa_core *core, const char *source);
|
||||||
void pa_core_update_default_sink(pa_core *core);
|
void pa_core_update_default_sink(pa_core *core);
|
||||||
void pa_core_update_default_source(pa_core *core);
|
void pa_core_update_default_source(pa_core *core);
|
||||||
|
|
||||||
|
pa_sink *pa_core_find_best_sink(pa_core *core, bool ignore_configured_virtual_default);
|
||||||
|
pa_source *pa_core_find_best_source(pa_core *core, bool ignore_configured_virtual_default);
|
||||||
|
|
||||||
void pa_core_set_exit_idle_time(pa_core *core, int time);
|
void pa_core_set_exit_idle_time(pa_core *core, int time);
|
||||||
|
|
||||||
/* Check whether no one is connected to this core */
|
/* Check whether no one is connected to this core */
|
||||||
|
|
|
||||||
|
|
@ -1782,7 +1782,7 @@ bool pa_sink_input_may_move(pa_sink_input *i) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool find_filter_sink_input(pa_sink_input *target, pa_sink *s) {
|
bool pa_sink_input_is_filter_loop(pa_sink_input *target, pa_sink *s) {
|
||||||
unsigned PA_UNUSED i = 0;
|
unsigned PA_UNUSED i = 0;
|
||||||
|
|
||||||
while (s && (s->vsink && s->vsink->input_to_master)) {
|
while (s && (s->vsink && s->vsink->input_to_master)) {
|
||||||
|
|
@ -1827,7 +1827,7 @@ bool pa_sink_input_may_move_to(pa_sink_input *i, pa_sink *dest) {
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
/* Make sure we're not creating a filter sink cycle */
|
/* Make sure we're not creating a filter sink cycle */
|
||||||
if (find_filter_sink_input(i, dest)) {
|
if (pa_sink_input_is_filter_loop(i, dest)) {
|
||||||
pa_log_debug("Can't connect input to %s, as that would create a cycle.", dest->name);
|
pa_log_debug("Can't connect input to %s, as that would create a cycle.", dest->name);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -2240,10 +2240,28 @@ void pa_sink_input_fail_move(pa_sink_input *i) {
|
||||||
if (pa_hook_fire(&i->core->hooks[PA_CORE_HOOK_SINK_INPUT_MOVE_FAIL], i) == PA_HOOK_STOP)
|
if (pa_hook_fire(&i->core->hooks[PA_CORE_HOOK_SINK_INPUT_MOVE_FAIL], i) == PA_HOOK_STOP)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Can we move the sink input to the default sink? */
|
/* Try to rescue stream if configured */
|
||||||
if (i->core->rescue_streams && pa_sink_input_may_move_to(i, i->core->default_sink)) {
|
if (i->core->rescue_streams) {
|
||||||
if (pa_sink_input_finish_move(i, i->core->default_sink, false) >= 0)
|
|
||||||
return;
|
/* Can we move the sink input to the default sink? */
|
||||||
|
if (pa_sink_input_may_move_to(i, i->core->default_sink)) {
|
||||||
|
if (pa_sink_input_finish_move(i, i->core->default_sink, false) >= 0)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If this is a filter stream and the default sink is set to a filter sink within
|
||||||
|
* the same filter chain, we would create a loop and therefore have to find another
|
||||||
|
* sink to move to. */
|
||||||
|
if (i->origin_sink && pa_sink_input_is_filter_loop(i, i->core->default_sink)) {
|
||||||
|
pa_sink *best;
|
||||||
|
|
||||||
|
best = pa_core_find_best_sink(i->core, true);
|
||||||
|
|
||||||
|
if (best && pa_sink_input_may_move_to(i, best)) {
|
||||||
|
if (pa_sink_input_finish_move(i, best, false) >= 0)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i->moving)
|
if (i->moving)
|
||||||
|
|
|
||||||
|
|
@ -422,6 +422,8 @@ int pa_sink_input_start_move(pa_sink_input *i);
|
||||||
int pa_sink_input_finish_move(pa_sink_input *i, pa_sink *dest, bool save);
|
int pa_sink_input_finish_move(pa_sink_input *i, pa_sink *dest, bool save);
|
||||||
void pa_sink_input_fail_move(pa_sink_input *i);
|
void pa_sink_input_fail_move(pa_sink_input *i);
|
||||||
|
|
||||||
|
bool pa_sink_input_is_filter_loop(pa_sink_input *target, pa_sink *s);
|
||||||
|
|
||||||
pa_usec_t pa_sink_input_get_requested_latency(pa_sink_input *i);
|
pa_usec_t pa_sink_input_get_requested_latency(pa_sink_input *i);
|
||||||
|
|
||||||
/* To be used exclusively by the sink driver IO thread */
|
/* To be used exclusively by the sink driver IO thread */
|
||||||
|
|
|
||||||
|
|
@ -4064,9 +4064,32 @@ void pa_sink_move_streams_to_default_sink(pa_core *core, pa_sink *old_sink, bool
|
||||||
if (!i->sink)
|
if (!i->sink)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Don't move sink-inputs which connect filter sinks to their target sinks */
|
/* If this is a filter stream and the default sink is set to a filter sink within
|
||||||
if (i->origin_sink)
|
* the same filter chain, we would create a loop and therefore have to find another
|
||||||
|
* sink to move to. */
|
||||||
|
if (i->origin_sink && pa_sink_input_is_filter_loop(i, core->default_sink)) {
|
||||||
|
pa_sink *best;
|
||||||
|
|
||||||
|
/* If the default sink changed to our filter chain, lets make the current
|
||||||
|
* master the preferred sink. */
|
||||||
|
if (default_sink_changed) {
|
||||||
|
pa_xfree(i->preferred_sink);
|
||||||
|
i->preferred_sink = pa_xstrdup(i->sink->name);
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
best = pa_core_find_best_sink(core, true);
|
||||||
|
|
||||||
|
if (!best || !pa_sink_input_may_move_to(i, best))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
pa_log_info("Moving sink input %u \"%s\" to the default sink would create a filter loop, moving to %s instead.",
|
||||||
|
i->index, pa_strnull(pa_proplist_gets(i->proplist, PA_PROP_APPLICATION_NAME)), best->name);
|
||||||
|
|
||||||
|
pa_sink_input_move_to(i, best, false);
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
/* If default_sink_changed is false, the old sink became unavailable, so all streams must be moved. */
|
/* If default_sink_changed is false, the old sink became unavailable, so all streams must be moved. */
|
||||||
if (pa_safe_streq(old_sink->name, i->preferred_sink) && default_sink_changed)
|
if (pa_safe_streq(old_sink->name, i->preferred_sink) && default_sink_changed)
|
||||||
|
|
|
||||||
|
|
@ -1304,7 +1304,7 @@ bool pa_source_output_may_move(pa_source_output *o) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool find_filter_source_output(pa_source_output *target, pa_source *s) {
|
bool pa_source_output_is_filter_loop(pa_source_output *target, pa_source *s) {
|
||||||
unsigned PA_UNUSED i = 0;
|
unsigned PA_UNUSED i = 0;
|
||||||
while (s && s->output_from_master) {
|
while (s && s->output_from_master) {
|
||||||
if (s->output_from_master == target)
|
if (s->output_from_master == target)
|
||||||
|
|
@ -1347,7 +1347,7 @@ bool pa_source_output_may_move_to(pa_source_output *o, pa_source *dest) {
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
/* Make sure we're not creating a filter source cycle */
|
/* Make sure we're not creating a filter source cycle */
|
||||||
if (find_filter_source_output(o, dest)) {
|
if (pa_source_output_is_filter_loop(o, dest)) {
|
||||||
pa_log_debug("Can't connect output to %s, as that would create a cycle.", dest->name);
|
pa_log_debug("Can't connect output to %s, as that would create a cycle.", dest->name);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -1660,10 +1660,28 @@ void pa_source_output_fail_move(pa_source_output *o) {
|
||||||
if (pa_hook_fire(&o->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE_FAIL], o) == PA_HOOK_STOP)
|
if (pa_hook_fire(&o->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE_FAIL], o) == PA_HOOK_STOP)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Can we move the source output to the default source? */
|
/* Try to rescue stream if configured */
|
||||||
if (o->core->rescue_streams && pa_source_output_may_move_to(o, o->core->default_source)) {
|
if (o->core->rescue_streams) {
|
||||||
if (pa_source_output_finish_move(o, o->core->default_source, false) >= 0)
|
|
||||||
return;
|
/* Can we move the source output to the default source? */
|
||||||
|
if (pa_source_output_may_move_to(o, o->core->default_source)) {
|
||||||
|
if (pa_source_output_finish_move(o, o->core->default_source, false) >= 0)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If this is a filter stream and the default source is set to a filter source within
|
||||||
|
* the same filter chain, we would create a loop and therefore have to find another
|
||||||
|
* source to move to. */
|
||||||
|
if (o->destination_source && pa_source_output_is_filter_loop(o, o->core->default_source)) {
|
||||||
|
pa_source *best;
|
||||||
|
|
||||||
|
best = pa_core_find_best_source(o->core, true);
|
||||||
|
|
||||||
|
if (best && pa_source_output_may_move_to(o, best)) {
|
||||||
|
if (pa_source_output_finish_move(o, best, false) >= 0)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (o->moving)
|
if (o->moving)
|
||||||
|
|
|
||||||
|
|
@ -350,6 +350,8 @@ int pa_source_output_start_move(pa_source_output *o);
|
||||||
int pa_source_output_finish_move(pa_source_output *o, pa_source *dest, bool save);
|
int pa_source_output_finish_move(pa_source_output *o, pa_source *dest, bool save);
|
||||||
void pa_source_output_fail_move(pa_source_output *o);
|
void pa_source_output_fail_move(pa_source_output *o);
|
||||||
|
|
||||||
|
bool pa_source_output_is_filter_loop(pa_source_output *target, pa_source *s);
|
||||||
|
|
||||||
pa_usec_t pa_source_output_get_requested_latency(pa_source_output *o);
|
pa_usec_t pa_source_output_get_requested_latency(pa_source_output *o);
|
||||||
|
|
||||||
/* To be used exclusively by the source driver thread */
|
/* To be used exclusively by the source driver thread */
|
||||||
|
|
|
||||||
|
|
@ -3033,9 +3033,32 @@ void pa_source_move_streams_to_default_source(pa_core *core, pa_source *old_sour
|
||||||
if (!o->source)
|
if (!o->source)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Don't move source-outputs which connect sources to filter sources */
|
/* If this is a filter stream and the default source is set to a filter source within
|
||||||
if (o->destination_source)
|
* the same filter chain, we would create a loop and therefore have to find another
|
||||||
|
* source to move to. */
|
||||||
|
if (o->destination_source && pa_source_output_is_filter_loop(o, core->default_source)) {
|
||||||
|
pa_source *best;
|
||||||
|
|
||||||
|
/* If the default source changed to our filter chain, lets make the current
|
||||||
|
* master the preferred source. */
|
||||||
|
if (default_source_changed) {
|
||||||
|
pa_xfree(o->preferred_source);
|
||||||
|
o->preferred_source = pa_xstrdup(o->source->name);
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
best = pa_core_find_best_source(core, true);
|
||||||
|
|
||||||
|
if (!best || !pa_source_output_may_move_to(o, best))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
pa_log_info("Moving source output %u \"%s\" to the default source would create a filter loop, moving to %s instead.",
|
||||||
|
o->index, pa_strnull(pa_proplist_gets(o->proplist, PA_PROP_APPLICATION_NAME)), best->name);
|
||||||
|
|
||||||
|
pa_source_output_move_to(o, best, false);
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
/* If default_source_changed is false, the old source became unavailable, so all streams must be moved. */
|
/* If default_source_changed is false, the old source became unavailable, so all streams must be moved. */
|
||||||
if (pa_safe_streq(old_source->name, o->preferred_source) && default_source_changed)
|
if (pa_safe_streq(old_source->name, o->preferred_source) && default_source_changed)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue