From cae3235369f923dcf1e1ee402a4b3d6aafe9c27b Mon Sep 17 00:00:00 2001 From: Arun Raghavan Date: Tue, 20 Sep 2011 17:05:22 +0530 Subject: [PATCH] sink,source: Handle missing in the shared volume case This makes sure that when we're traversing the device chain for sources and sinks with shared volume, we handle the case that a sink-input or source-output of one of these might be unlinked (while unloading a module, for example). --- src/pulsecore/sink-input.c | 6 +++--- src/pulsecore/sink.c | 41 +++++++++++++++++++++++++++++------------ src/pulsecore/sink.h | 3 +++ src/pulsecore/source-output.c | 8 +++++--- src/pulsecore/source.c | 41 +++++++++++++++++++++++++++++------------ src/pulsecore/source.h | 3 +++ 6 files changed, 72 insertions(+), 30 deletions(-) diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c index 8f157ec..15944f4 100644 --- a/src/pulsecore/sink-input.c +++ b/src/pulsecore/sink-input.c @@ -1438,12 +1438,12 @@ static void update_volume_due_to_moving(pa_sink_input *i, pa_sink *dest) { pa_assert(i->sink); /* The destination sink should already be set. */ if (i->origin_sink && (i->origin_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER)) { - pa_sink *root_sink = i->sink; + pa_sink *root_sink = pa_sink_get_master(i->sink); pa_sink_input *origin_sink_input; uint32_t idx; - while (root_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER) - root_sink = root_sink->input_to_master->sink; + if (PA_UNLIKELY(!root_sink)) + return; if (pa_sink_flat_volume_enabled(i->sink)) { /* Ok, so the origin sink uses volume sharing, and flat volume is diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c index d97fb7e..21c6723 100644 --- a/src/pulsecore/sink.c +++ b/src/pulsecore/sink.c @@ -618,10 +618,9 @@ void pa_sink_put(pa_sink* s) { enable_flat_volume(s, TRUE); if (s->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER) { - pa_sink *root_sink = s->input_to_master->sink; + pa_sink *root_sink = pa_sink_get_master(s); - while (root_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER) - root_sink = root_sink->input_to_master->sink; + pa_assert(root_sink); s->reference_volume = root_sink->reference_volume; pa_cvolume_remap(&s->reference_volume, &root_sink->channel_map, &s->channel_map); @@ -1370,10 +1369,27 @@ pa_usec_t pa_sink_get_latency_within_thread(pa_sink *s) { pa_bool_t pa_sink_flat_volume_enabled(pa_sink *s) { pa_sink_assert_ref(s); - while (s->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER) + s = pa_sink_get_master(s); + + if (PA_LIKELY(s)) + return (s->flags & PA_SINK_FLAT_VOLUME); + else + return FALSE; +} + +/* Called from the main thread (and also from the IO thread while the main + * thread is waiting). */ +pa_sink *pa_sink_get_master(pa_sink *s) { + pa_sink_assert_ref(s); + + while (s && (s->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER)) { + if (PA_UNLIKELY(!s->input_to_master)) + return NULL; + s = s->input_to_master->sink; + } - return (s->flags & PA_SINK_FLAT_VOLUME); + return s; } /* Called from main context */ @@ -1804,7 +1820,7 @@ void pa_sink_set_volume( pa_bool_t save) { pa_cvolume new_reference_volume; - pa_sink *root_sink = s; + pa_sink *root_sink; pa_sink_assert_ref(s); pa_assert_ctl_context(); @@ -1822,8 +1838,10 @@ void pa_sink_set_volume( /* In case of volume sharing, the volume is set for the root sink first, * from which it's then propagated to the sharing sinks. */ - while (root_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER) - root_sink = root_sink->input_to_master->sink; + root_sink = pa_sink_get_master(s); + + if (PA_UNLIKELY(!root_sink)) + return; /* As a special exception we accept mono volumes on all sinks -- * even on those with more complex channel maps */ @@ -2447,12 +2465,11 @@ int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offse } case PA_SINK_MESSAGE_SET_SHARED_VOLUME: { - pa_sink *root_sink = s; + pa_sink *root_sink = pa_sink_get_master(s); - while (root_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER) - root_sink = root_sink->input_to_master->sink; + if (PA_LIKELY(root_sink)) + set_shared_volume_within_thread(root_sink); - set_shared_volume_within_thread(root_sink); return 0; } diff --git a/src/pulsecore/sink.h b/src/pulsecore/sink.h index 0642dda..7f639e2 100644 --- a/src/pulsecore/sink.h +++ b/src/pulsecore/sink.h @@ -419,6 +419,9 @@ int pa_sink_suspend_all(pa_core *c, pa_bool_t suspend, pa_suspend_cause_t cause) /* Use this instead of checking s->flags & PA_SINK_FLAT_VOLUME directly. */ pa_bool_t pa_sink_flat_volume_enabled(pa_sink *s); +/* Get the master sink when sharing volumes */ +pa_sink *pa_sink_get_master(pa_sink *s); + /* Is the sink in passthrough mode? (that is, is there a passthrough sink input * connected to this sink? */ pa_bool_t pa_sink_is_passthrough(pa_sink *s); diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c index d54e7f6..1e08a03 100644 --- a/src/pulsecore/source-output.c +++ b/src/pulsecore/source-output.c @@ -1218,12 +1218,14 @@ static void update_volume_due_to_moving(pa_source_output *o, pa_source *dest) { pa_assert(o->source); /* The destination source should already be set. */ if (o->destination_source && (o->destination_source->flags & PA_SOURCE_SHARE_VOLUME_WITH_MASTER)) { - pa_source *root_source = o->source; + pa_source *root_source; pa_source_output *destination_source_output; uint32_t idx; - while (root_source->flags & PA_SOURCE_SHARE_VOLUME_WITH_MASTER) - root_source = root_source->output_from_master->source; + root_source = pa_source_get_master(o->source); + + if (PA_UNLIKELY(!root_source)) + return; if (pa_source_flat_volume_enabled(o->source)) { /* Ok, so the origin source uses volume sharing, and flat volume is diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c index 0282828..5239610 100644 --- a/src/pulsecore/source.c +++ b/src/pulsecore/source.c @@ -549,10 +549,9 @@ void pa_source_put(pa_source *s) { enable_flat_volume(s, TRUE); if (s->flags & PA_SOURCE_SHARE_VOLUME_WITH_MASTER) { - pa_source *root_source = s->output_from_master->source; + pa_source *root_source = pa_source_get_master(s); - while (root_source->flags & PA_SOURCE_SHARE_VOLUME_WITH_MASTER) - root_source = root_source->output_from_master->source; + pa_assert(PA_LIKELY(root_source)); s->reference_volume = root_source->reference_volume; pa_cvolume_remap(&s->reference_volume, &root_source->channel_map, &s->channel_map); @@ -963,10 +962,27 @@ pa_usec_t pa_source_get_latency_within_thread(pa_source *s) { pa_bool_t pa_source_flat_volume_enabled(pa_source *s) { pa_source_assert_ref(s); - while (s->flags & PA_SOURCE_SHARE_VOLUME_WITH_MASTER) + s = pa_source_get_master(s); + + if (PA_LIKELY(s)) + return (s->flags & PA_SOURCE_FLAT_VOLUME); + else + return FALSE; +} + +/* Called from the main thread (and also from the IO thread while the main + * thread is waiting). */ +pa_source *pa_source_get_master(pa_source *s) { + pa_source_assert_ref(s); + + while (s && (s->flags & PA_SOURCE_SHARE_VOLUME_WITH_MASTER)) { + if (PA_UNLIKELY(!s->output_from_master)) + return NULL; + s = s->output_from_master->source; + } - return (s->flags & PA_SOURCE_FLAT_VOLUME); + return s; } /* Called from main context */ @@ -1380,7 +1396,7 @@ void pa_source_set_volume( pa_bool_t save) { pa_cvolume new_reference_volume; - pa_source *root_source = s; + pa_source *root_source; pa_source_assert_ref(s); pa_assert_ctl_context(); @@ -1398,8 +1414,10 @@ void pa_source_set_volume( /* In case of volume sharing, the volume is set for the root source first, * from which it's then propagated to the sharing sources. */ - while (root_source->flags & PA_SOURCE_SHARE_VOLUME_WITH_MASTER) - root_source = root_source->output_from_master->source; + root_source = pa_source_get_master(s); + + if (PA_UNLIKELY(!root_source)) + return; /* As a special exception we accept mono volumes on all sources -- * even on those with more complex channel maps */ @@ -1877,12 +1895,11 @@ int pa_source_process_msg(pa_msgobject *object, int code, void *userdata, int64_ } case PA_SOURCE_MESSAGE_SET_SHARED_VOLUME: { - pa_source *root_source = s; + pa_source *root_source = pa_source_get_master(s); - while (root_source->flags & PA_SOURCE_SHARE_VOLUME_WITH_MASTER) - root_source = root_source->output_from_master->source; + if (PA_LIKELY(root_source)) + set_shared_volume_within_thread(root_source); - set_shared_volume_within_thread(root_source); return 0; } diff --git a/src/pulsecore/source.h b/src/pulsecore/source.h index 05f8242..949ae48 100644 --- a/src/pulsecore/source.h +++ b/src/pulsecore/source.h @@ -339,6 +339,9 @@ int pa_source_suspend_all(pa_core *c, pa_bool_t suspend, pa_suspend_cause_t caus /* Use this instead of checking s->flags & PA_SOURCE_FLAT_VOLUME directly. */ pa_bool_t pa_source_flat_volume_enabled(pa_source *s); +/* Get the master source when sharing volumes */ +pa_source *pa_source_get_master(pa_source *s); + /* Is the source in passthrough mode? (that is, is this a monitor source for a sink * that has a passthrough sink input connected to it. */ pa_bool_t pa_source_is_passthrough(pa_source *s); -- 2.7.4