[pulseaudio-discuss] [PATCH 2/7] don't move streams to devices that are going away

Arun Raghavan arun at accosted.net
Thu Apr 21 06:56:57 UTC 2016


On 22 March 2016 at 19:11, Tanu Kaskinen <tanuk at iki.fi> wrote:
> Before a device is unlinked, the unlink hook is fired, and it's
> possible that a routing module tries to move streams to the unlinked
> device in that hook, because it doesn't know that the device is being
> unlinked. Of course, the unlinking is obvious when the code is in an
> unlink hook callback, but it's possible that some other module does
> something in the unlink hook that in turn triggers some other hook,
> and it's this second hook where the routing module may get confused.
> This patch adds an "unlink_requested" flag that is set before the
> unlink hook is fired, and moving streams to a device with that flag
> set is prevented.
>
> This patch is motivated by seeing module-device-manager moving a
> stream to a sink that was being unlinked. It was a complex case where
> an alsa card was changing its profile, while an echo-cancel sink was
> connected to the old alsa sink. module-always-sink loaded a null sink
> in the middle of the profile change, and after a stream had been
> rescued to the null sink, module-device-manager decided to move it
> back to the old alsa sink that was being unlinked. That move made no
> sense, so I came up with this patch.
> ---

I think this is a good solution to the problem. Still need to test
this in a few use cases, but it makes sense to me too.

I also think that it might be nicer to have this be a part of the
state enum rather than a separate bool. What do you think? I'm okay to
make that change quickly if you don't want to, fwiw.

-- Arun

>  src/pulsecore/sink-input.c    | 3 +++
>  src/pulsecore/sink.c          | 7 ++++---
>  src/pulsecore/sink.h          | 6 ++++++
>  src/pulsecore/source-output.c | 3 +++
>  src/pulsecore/source.c        | 5 +++++
>  src/pulsecore/source.h        | 6 ++++++
>  6 files changed, 27 insertions(+), 3 deletions(-)
>
> diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c
> index 8ec63b5..843297f 100644
> --- a/src/pulsecore/sink-input.c
> +++ b/src/pulsecore/sink-input.c
> @@ -1538,6 +1538,9 @@ bool pa_sink_input_may_move_to(pa_sink_input *i, pa_sink *dest) {
>      if (dest == i->sink)
>          return true;
>
> +    if (dest->unlink_requested)
> +        return false;
> +
>      if (!pa_sink_input_may_move(i))
>          return false;
>
> diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c
> index 0b44fc7..3f1ef72 100644
> --- a/src/pulsecore/sink.c
> +++ b/src/pulsecore/sink.c
> @@ -676,9 +676,10 @@ void pa_sink_unlink(pa_sink* s) {
>       * reversing pa_sink_put(). It also undoes the registrations
>       * already done in pa_sink_new()! */
>
> -    /* All operations here shall be idempotent, i.e. pa_sink_unlink()
> -     * may be called multiple times on the same sink without bad
> -     * effects. */
> +    if (s->unlink_requested)
> +        return;
> +
> +    s->unlink_requested = true;
>
>      linked = PA_SINK_IS_LINKED(s->state);
>
> diff --git a/src/pulsecore/sink.h b/src/pulsecore/sink.h
> index 5df109e..b64a666 100644
> --- a/src/pulsecore/sink.h
> +++ b/src/pulsecore/sink.h
> @@ -63,6 +63,12 @@ struct pa_sink {
>      pa_core *core;
>
>      pa_sink_state_t state;
> +
> +    /* Set in the beginning of pa_sink_unlink() before setting the sink state
> +     * to UNLINKED. The purpose is to prevent moving streams to a sink that is
> +     * about to be removed. */
> +    bool unlink_requested;
> +
>      pa_sink_flags_t flags;
>      pa_suspend_cause_t suspend_cause;
>
> diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c
> index 9217ad4..6d54ae8 100644
> --- a/src/pulsecore/source-output.c
> +++ b/src/pulsecore/source-output.c
> @@ -1187,6 +1187,9 @@ bool pa_source_output_may_move_to(pa_source_output *o, pa_source *dest) {
>      if (dest == o->source)
>          return true;
>
> +    if (dest->unlink_requested)
> +        return false;
> +
>      if (!pa_source_output_may_move(o))
>          return false;
>
> diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c
> index f4b96ab..98374ae 100644
> --- a/src/pulsecore/source.c
> +++ b/src/pulsecore/source.c
> @@ -618,6 +618,11 @@ void pa_source_unlink(pa_source *s) {
>      /* See pa_sink_unlink() for a couple of comments how this function
>       * works. */
>
> +    if (s->unlink_requested)
> +        return;
> +
> +    s->unlink_requested = true;
> +
>      linked = PA_SOURCE_IS_LINKED(s->state);
>
>      if (linked)
> diff --git a/src/pulsecore/source.h b/src/pulsecore/source.h
> index 19fb41b..91e8674 100644
> --- a/src/pulsecore/source.h
> +++ b/src/pulsecore/source.h
> @@ -64,6 +64,12 @@ struct pa_source {
>      pa_core *core;
>
>      pa_source_state_t state;
> +
> +    /* Set in the beginning of pa_source_unlink() before setting the source
> +     * state to UNLINKED. The purpose is to prevent moving streams to a source
> +     * that is about to be removed. */
> +    bool unlink_requested;
> +
>      pa_source_flags_t flags;
>      pa_suspend_cause_t suspend_cause;
>
> --
> 2.7.0
>
> _______________________________________________
> pulseaudio-discuss mailing list
> pulseaudio-discuss at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss


More information about the pulseaudio-discuss mailing list