An example: let's say that there's an alsa sink and two filter sinks on top of each other: alsa-sink -> filter1 -> filter2 With the old code, if filter1 gets moved to another sink, and the new sink doesn't have the DYNAMIC_LATENCY flag set (unlike alsa-sink), the DYNAMIC_LATENCY flag of filter1 is updated fine in the moving() callback, but filter2 is not notified at all about the flag change. With this patch, filter2 can unset its DYNAMIC_LATENCY flag as it should. --- src/modules/echo-cancel/module-echo-cancel.c | 6 ++++-- src/modules/module-equalizer-sink.c | 3 ++- src/modules/module-ladspa-sink.c | 3 ++- src/modules/module-remap-sink.c | 3 ++- src/modules/module-virtual-sink.c | 3 ++- src/modules/module-virtual-source.c | 3 ++- src/modules/module-virtual-surround-sink.c | 3 ++- src/pulsecore/sink-input.c | 10 +++++++++ src/pulsecore/sink-input.h | 9 +++++++++ src/pulsecore/sink.c | 28 +++++++++++++++++--------- src/pulsecore/sink.h | 2 +- src/pulsecore/source-output.c | 10 +++++++++ src/pulsecore/source-output.h | 9 +++++++++ src/pulsecore/source.c | 24 ++++++++++++++++------ src/pulsecore/source.h | 2 +- 15 files changed, 93 insertions(+), 25 deletions(-) diff --git a/src/modules/echo-cancel/module-echo-cancel.c b/src/modules/echo-cancel/module-echo-cancel.c index fbeac69..db166e5 100644 --- a/src/modules/echo-cancel/module-echo-cancel.c +++ b/src/modules/echo-cancel/module-echo-cancel.c @@ -1453,7 +1453,7 @@ static void source_output_moving_cb(pa_source_output *o, pa_source *dest) { if (dest) { pa_source_set_asyncmsgq(u->source, dest->asyncmsgq); pa_source_set_latency_flag(u->source, dest->flags & PA_SOURCE_LATENCY); - pa_source_update_flags(u->source, PA_SOURCE_DYNAMIC_LATENCY, dest->flags); + pa_source_set_dynamic_latency_flag(u->source, dest->flags & PA_SOURCE_DYNAMIC_LATENCY); } else pa_source_set_asyncmsgq(u->source, NULL); @@ -1482,7 +1482,7 @@ static void sink_input_moving_cb(pa_sink_input *i, pa_sink *dest) { if (dest) { pa_sink_set_asyncmsgq(u->sink, dest->asyncmsgq); pa_sink_set_latency_flag(u->sink, dest->flags & PA_SINK_LATENCY); - pa_sink_update_flags(u->sink, PA_SINK_DYNAMIC_LATENCY, dest->flags); + pa_sink_set_dynamic_latency_flag(u->sink, dest->flags & PA_SINK_DYNAMIC_LATENCY); } else pa_sink_set_asyncmsgq(u->sink, NULL); @@ -1866,6 +1866,7 @@ int pa__init(pa_module*m) { u->source_output->update_source_latency_range = source_output_update_source_latency_range_cb; u->source_output->update_source_fixed_latency = source_output_update_source_fixed_latency_cb; u->source_output->update_source_latency_flag = pa_source_output_update_source_latency_flag_cb; + u->source_output->update_source_dynamic_latency_flag = pa_source_output_update_source_dynamic_latency_flag_cb; u->source_output->kill = source_output_kill_cb; u->source_output->attach = source_output_attach_cb; u->source_output->detach = source_output_detach_cb; @@ -1903,6 +1904,7 @@ int pa__init(pa_module*m) { u->sink_input->update_sink_latency_range = sink_input_update_sink_latency_range_cb; u->sink_input->update_sink_fixed_latency = sink_input_update_sink_fixed_latency_cb; u->sink_input->update_sink_latency_flag = pa_sink_input_update_sink_latency_flag_cb; + u->sink_input->update_sink_dynamic_latency_flag = pa_sink_input_update_sink_dynamic_latency_flag_cb; u->sink_input->kill = sink_input_kill_cb; u->sink_input->attach = sink_input_attach_cb; u->sink_input->detach = sink_input_detach_cb; diff --git a/src/modules/module-equalizer-sink.c b/src/modules/module-equalizer-sink.c index 42334b3..0ebf605 100644 --- a/src/modules/module-equalizer-sink.c +++ b/src/modules/module-equalizer-sink.c @@ -1076,7 +1076,7 @@ static void sink_input_moving_cb(pa_sink_input *i, pa_sink *dest) { if (dest) { pa_sink_set_asyncmsgq(u->sink, dest->asyncmsgq); pa_sink_set_latency_flag(u->sink, dest->flags & PA_SINK_LATENCY); - pa_sink_update_flags(u->sink, PA_SINK_DYNAMIC_LATENCY, dest->flags); + pa_sink_set_dynamic_latency_flag(u->sink, dest->flags & PA_SINK_DYNAMIC_LATENCY); } else pa_sink_set_asyncmsgq(u->sink, NULL); } @@ -1249,6 +1249,7 @@ int pa__init(pa_module*m) { u->sink_input->update_sink_latency_range = sink_input_update_sink_latency_range_cb; u->sink_input->update_sink_fixed_latency = sink_input_update_sink_fixed_latency_cb; u->sink_input->update_sink_latency_flag = pa_sink_input_update_sink_latency_flag_cb; + u->sink_input->update_sink_dynamic_latency_flag = pa_sink_input_update_sink_dynamic_latency_flag_cb; u->sink_input->kill = sink_input_kill_cb; u->sink_input->attach = sink_input_attach_cb; u->sink_input->detach = sink_input_detach_cb; diff --git a/src/modules/module-ladspa-sink.c b/src/modules/module-ladspa-sink.c index 441b2fa..1234813 100644 --- a/src/modules/module-ladspa-sink.c +++ b/src/modules/module-ladspa-sink.c @@ -675,7 +675,7 @@ static void sink_input_moving_cb(pa_sink_input *i, pa_sink *dest) { if (dest) { pa_sink_set_asyncmsgq(u->sink, dest->asyncmsgq); pa_sink_set_latency_flag(u->sink, dest->flags & PA_SINK_LATENCY); - pa_sink_update_flags(u->sink, PA_SINK_DYNAMIC_LATENCY, dest->flags); + pa_sink_set_dynamic_latency_flag(u->sink, dest->flags & PA_SINK_DYNAMIC_LATENCY); } else pa_sink_set_asyncmsgq(u->sink, NULL); @@ -1315,6 +1315,7 @@ int pa__init(pa_module*m) { u->sink_input->update_sink_latency_range = sink_input_update_sink_latency_range_cb; u->sink_input->update_sink_fixed_latency = sink_input_update_sink_fixed_latency_cb; u->sink_input->update_sink_latency_flag = pa_sink_input_update_sink_latency_flag_cb; + u->sink_input->update_sink_dynamic_latency_flag = pa_sink_input_update_sink_dynamic_latency_flag_cb; u->sink_input->kill = sink_input_kill_cb; u->sink_input->attach = sink_input_attach_cb; u->sink_input->detach = sink_input_detach_cb; diff --git a/src/modules/module-remap-sink.c b/src/modules/module-remap-sink.c index 179743b..0e52c83 100644 --- a/src/modules/module-remap-sink.c +++ b/src/modules/module-remap-sink.c @@ -309,7 +309,7 @@ static void sink_input_moving_cb(pa_sink_input *i, pa_sink *dest) { if (dest) { pa_sink_set_asyncmsgq(u->sink, dest->asyncmsgq); pa_sink_set_latency_flag(u->sink, dest->flags & PA_SINK_LATENCY); - pa_sink_update_flags(u->sink, PA_SINK_DYNAMIC_LATENCY, dest->flags); + pa_sink_set_dynamic_latency_flag(u->sink, dest->flags & PA_SINK_DYNAMIC_LATENCY); } else pa_sink_set_asyncmsgq(u->sink, NULL); @@ -443,6 +443,7 @@ int pa__init(pa_module*m) { u->sink_input->update_sink_latency_range = sink_input_update_sink_latency_range_cb; u->sink_input->update_sink_fixed_latency = sink_input_update_sink_fixed_latency_cb; u->sink_input->update_sink_latency_flag = pa_sink_input_update_sink_latency_flag_cb; + u->sink_input->update_sink_dynamic_latency_flag = pa_sink_input_update_sink_dynamic_latency_flag_cb; u->sink_input->attach = sink_input_attach_cb; u->sink_input->detach = sink_input_detach_cb; u->sink_input->kill = sink_input_kill_cb; diff --git a/src/modules/module-virtual-sink.c b/src/modules/module-virtual-sink.c index 1883d00..97ab64e 100644 --- a/src/modules/module-virtual-sink.c +++ b/src/modules/module-virtual-sink.c @@ -439,7 +439,7 @@ static void sink_input_moving_cb(pa_sink_input *i, pa_sink *dest) { if (dest) { pa_sink_set_asyncmsgq(u->sink, dest->asyncmsgq); pa_sink_set_latency_flag(u->sink, dest->flags & PA_SINK_LATENCY); - pa_sink_update_flags(u->sink, PA_SINK_DYNAMIC_LATENCY, dest->flags); + pa_sink_set_dynamic_latency_flag(u->sink, dest->flags & PA_SINK_DYNAMIC_LATENCY); } else pa_sink_set_asyncmsgq(u->sink, NULL); @@ -605,6 +605,7 @@ int pa__init(pa_module*m) { u->sink_input->update_sink_latency_range = sink_input_update_sink_latency_range_cb; u->sink_input->update_sink_fixed_latency = sink_input_update_sink_fixed_latency_cb; u->sink_input->update_sink_latency_flag = pa_sink_input_update_sink_latency_flag_cb; + u->sink_input->update_sink_dynamic_latency_flag = pa_sink_input_update_sink_dynamic_latency_flag_cb; u->sink_input->kill = sink_input_kill_cb; u->sink_input->attach = sink_input_attach_cb; u->sink_input->detach = sink_input_detach_cb; diff --git a/src/modules/module-virtual-source.c b/src/modules/module-virtual-source.c index 212bbc6..6909edc 100644 --- a/src/modules/module-virtual-source.c +++ b/src/modules/module-virtual-source.c @@ -470,7 +470,7 @@ static void source_output_moving_cb(pa_source_output *o, pa_source *dest) { if (dest) { pa_source_set_asyncmsgq(u->source, dest->asyncmsgq); pa_source_set_latency_flag(u->source, dest->flags & PA_SOURCE_LATENCY); - pa_source_update_flags(u->source, PA_SOURCE_DYNAMIC_LATENCY, dest->flags); + pa_source_set_dynamic_latency_flag(u->source, dest->flags & PA_SOURCE_DYNAMIC_LATENCY); } else pa_source_set_asyncmsgq(u->source, NULL); @@ -629,6 +629,7 @@ int pa__init(pa_module*m) { u->source_output->push = source_output_push_cb; u->source_output->process_rewind = source_output_process_rewind_cb; u->source_output->update_source_latency_flag = pa_source_output_update_source_latency_flag_cb; + u->source_output->update_source_dynamic_latency_flag = pa_source_output_update_source_dynamic_latency_flag_cb; u->source_output->kill = source_output_kill_cb; u->source_output->attach = source_output_attach_cb; u->source_output->detach = source_output_detach_cb; diff --git a/src/modules/module-virtual-surround-sink.c b/src/modules/module-virtual-surround-sink.c index 4bef912..7216345 100644 --- a/src/modules/module-virtual-surround-sink.c +++ b/src/modules/module-virtual-surround-sink.c @@ -449,7 +449,7 @@ static void sink_input_moving_cb(pa_sink_input *i, pa_sink *dest) { if (dest) { pa_sink_set_asyncmsgq(u->sink, dest->asyncmsgq); pa_sink_set_latency_flag(u->sink, dest->flags & PA_SINK_LATENCY); - pa_sink_update_flags(u->sink, PA_SINK_DYNAMIC_LATENCY, dest->flags); + pa_sink_set_dynamic_latency_flag(u->sink, dest->flags & PA_SINK_DYNAMIC_LATENCY); } else pa_sink_set_asyncmsgq(u->sink, NULL); @@ -702,6 +702,7 @@ int pa__init(pa_module*m) { u->sink_input->update_sink_latency_range = sink_input_update_sink_latency_range_cb; u->sink_input->update_sink_fixed_latency = sink_input_update_sink_fixed_latency_cb; u->sink_input->update_sink_latency_flag = pa_sink_input_update_sink_latency_flag_cb; + u->sink_input->update_sink_dynamic_latency_flag = pa_sink_input_update_sink_dynamic_latency_flag_cb; u->sink_input->kill = sink_input_kill_cb; u->sink_input->attach = sink_input_attach_cb; u->sink_input->detach = sink_input_detach_cb; diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c index fa5e979..4562560 100644 --- a/src/pulsecore/sink-input.c +++ b/src/pulsecore/sink-input.c @@ -219,6 +219,7 @@ static void reset_callbacks(pa_sink_input *i) { i->update_sink_latency_range = NULL; i->update_sink_fixed_latency = NULL; i->update_sink_latency_flag = NULL; + i->update_sink_dynamic_latency_flag = NULL; i->attach = NULL; i->detach = NULL; i->suspend = NULL; @@ -2106,3 +2107,12 @@ void pa_sink_input_update_sink_latency_flag_cb(pa_sink_input *i) { if (i->origin_sink) pa_sink_set_latency_flag(i->origin_sink, i->sink->flags & PA_SINK_LATENCY); } + +/* Called from the main thread while the IO thread is inactive. */ +void pa_sink_input_update_sink_dynamic_latency_flag_cb(pa_sink_input *i) { + pa_sink_input_assert_ref(i); + pa_assert_ctl_context(); + + if (i->origin_sink) + pa_sink_set_dynamic_latency_flag(i->origin_sink, i->sink->flags & PA_SINK_DYNAMIC_LATENCY); +} diff --git a/src/pulsecore/sink-input.h b/src/pulsecore/sink-input.h index 28a8eb4..0e7cf4a 100644 --- a/src/pulsecore/sink-input.h +++ b/src/pulsecore/sink-input.h @@ -156,6 +156,10 @@ struct pa_sink_input { * Called from the main context while the IO thread is inactive. */ void (*update_sink_latency_flag) (pa_sink_input *i); /* may be NULL */ + /* Called whenever the PA_SINK_DYNAMIC_LATENCY flag of the sink changes + * state. Called from the main context while the IO thread is inactive. */ + void (*update_sink_dynamic_latency_flag) (pa_sink_input *i); /* may be NULL */ + /* If non-NULL this function is called when the input is first * connected to a sink or when the rtpoll/asyncmsgq fields * change. You usually don't need to implement this function @@ -410,6 +414,11 @@ pa_memchunk* pa_sink_input_get_silence(pa_sink_input *i, pa_memchunk *ret); * sink, this does nothing. */ void pa_sink_input_update_sink_latency_flag_cb(pa_sink_input *i); +/* update_sink_dynamic_latency_flag() implementation that propagates the + * PA_SINK_DYNAMIC_LATENCY flag to the origin sink. If the input doesn't have + * an origin sink, this does nothing. */ +void pa_sink_input_update_sink_dynamic_latency_flag_cb(pa_sink_input *i); + #define pa_sink_input_assert_io_context(s) \ pa_assert(pa_thread_mq_get() || !PA_SINK_INPUT_IS_LINKED((s)->state)) diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c index 722db15..89273c8 100644 --- a/src/pulsecore/sink.c +++ b/src/pulsecore/sink.c @@ -789,23 +789,33 @@ void pa_sink_set_latency_flag(pa_sink *s, bool enabled) { pa_source_set_latency_flag(s->monitor_source, enabled); } -/* Called from main context, and not while the IO thread is active, please */ -void pa_sink_update_flags(pa_sink *s, pa_sink_flags_t mask, pa_sink_flags_t value) { +/* Called from main context, and not while the IO thread is active, please. */ +void pa_sink_set_dynamic_latency_flag(pa_sink *s, bool enabled) { + pa_sink_input *i; + uint32_t idx; + pa_sink_assert_ref(s); pa_assert_ctl_context(); - if (mask == 0) + if (enabled == !!(s->flags & PA_SINK_DYNAMIC_LATENCY)) return; - /* For now, allow only a minimal set of flags to be changed. */ - pa_assert((mask & ~PA_SINK_DYNAMIC_LATENCY) == 0); + if (enabled) + s->flags |= PA_SINK_DYNAMIC_LATENCY; + else + s->flags &= ~PA_SINK_DYNAMIC_LATENCY; + + pa_log_debug("Sink %s DYNAMIC_LATENCY flag %s.", s->name, enabled ? "enabled" : "disabled"); + + pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); - s->flags = (s->flags & ~mask) | (value & mask); + PA_IDXSET_FOREACH(i, s->inputs, idx) { + if (i->update_sink_dynamic_latency_flag) + i->update_sink_dynamic_latency_flag(i); + } if (s->monitor_source) - pa_source_update_flags(s->monitor_source, - (mask & PA_SINK_DYNAMIC_LATENCY) ? PA_SOURCE_DYNAMIC_LATENCY : 0, - (value & PA_SINK_DYNAMIC_LATENCY) ? PA_SOURCE_DYNAMIC_LATENCY : 0); + pa_source_set_dynamic_latency_flag(s->monitor_source, enabled); } /* Called from IO context, or before _put() from main context */ diff --git a/src/pulsecore/sink.h b/src/pulsecore/sink.h index c0ef8ce..eb616d6 100644 --- a/src/pulsecore/sink.h +++ b/src/pulsecore/sink.h @@ -401,7 +401,7 @@ void pa_sink_volume_changed(pa_sink *s, const pa_cvolume *new_volume); void pa_sink_mute_changed(pa_sink *s, pa_bool_t new_muted); void pa_sink_set_latency_flag(pa_sink *s, bool enabled); -void pa_sink_update_flags(pa_sink *s, pa_sink_flags_t mask, pa_sink_flags_t value); +void pa_sink_set_dynamic_latency_flag(pa_sink *s, bool enabled); pa_bool_t pa_device_init_description(pa_proplist *p); pa_bool_t pa_device_init_icon(pa_proplist *p, pa_bool_t is_sink); diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c index d19d903..8a89780 100644 --- a/src/pulsecore/source-output.c +++ b/src/pulsecore/source-output.c @@ -199,6 +199,7 @@ static void reset_callbacks(pa_source_output *o) { o->update_source_latency_range = NULL; o->update_source_fixed_latency = NULL; o->update_source_latency_flag = NULL; + o->update_source_dynamic_latency_flag = NULL; o->attach = NULL; o->detach = NULL; o->suspend = NULL; @@ -1693,3 +1694,12 @@ void pa_source_output_update_source_latency_flag_cb(pa_source_output *o) { if (o->destination_source) pa_source_set_latency_flag(o->destination_source, o->source->flags & PA_SOURCE_LATENCY); } + +/* Called from the main thread while the IO thread is inactive. */ +void pa_source_output_update_source_dynamic_latency_flag_cb(pa_source_output *o) { + pa_source_output_assert_ref(o); + pa_assert_ctl_context(); + + if (o->destination_source) + pa_source_set_dynamic_latency_flag(o->destination_source, o->source->flags & PA_SOURCE_DYNAMIC_LATENCY); +} diff --git a/src/pulsecore/source-output.h b/src/pulsecore/source-output.h index 50a0aba..749d7fd 100644 --- a/src/pulsecore/source-output.h +++ b/src/pulsecore/source-output.h @@ -136,6 +136,10 @@ struct pa_source_output { * Called from the main context while the IO thread is inactive. */ void (*update_source_latency_flag) (pa_source_output *o); /* may be NULL */ + /* Called whenever the PA_SOURCE_DYNAMIC_LATENCY flag of the source changes + * state. Called from the main context while the IO thread is inactive. */ + void (*update_source_dynamic_latency_flag) (pa_source_output *o); /* may be NULL */ + /* If non-NULL this function is called when the output is first * connected to a source or when the rtpoll/asyncmsgq fields * change. You usually don't need to implement this function @@ -365,6 +369,11 @@ pa_usec_t pa_source_output_set_requested_latency_within_thread(pa_source_output * a destination source, this does nothing. */ void pa_source_output_update_source_latency_flag_cb(pa_source_output *o); +/* update_source_dynamic_latency_flag() implementation that propagates the + * PA_SOURCE_DYNAMIC_LATENCY flag to the destination source. If the output + * doesn't have a destination source, this does nothing. */ +void pa_source_output_update_source_dynamic_latency_flag_cb(pa_source_output *o); + #define pa_source_output_assert_io_context(s) \ pa_assert(pa_thread_mq_get() || !PA_SOURCE_OUTPUT_IS_LINKED((s)->state)) diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c index 947a773..45923b2 100644 --- a/src/pulsecore/source.c +++ b/src/pulsecore/source.c @@ -713,18 +713,30 @@ void pa_source_set_latency_flag(pa_source *s, bool enabled) { } } -/* Called from main context, and not while the IO thread is active, please */ -void pa_source_update_flags(pa_source *s, pa_source_flags_t mask, pa_source_flags_t value) { +/* Called from main context, and not while the IO thread is active, please. */ +void pa_source_set_dynamic_latency_flag(pa_source *s, bool enabled) { + pa_source_output *o; + uint32_t idx; + pa_source_assert_ref(s); pa_assert_ctl_context(); - if (mask == 0) + if (enabled == !!(s->flags & PA_SOURCE_DYNAMIC_LATENCY)) return; - /* For now, allow only a minimal set of flags to be changed. */ - pa_assert((mask & ~PA_SOURCE_DYNAMIC_LATENCY) == 0); + if (enabled) + s->flags |= PA_SOURCE_DYNAMIC_LATENCY; + else + s->flags &= ~PA_SOURCE_DYNAMIC_LATENCY; + + pa_log_debug("Source %s DYNAMIC_LATENCY flag %s.", s->name, enabled ? "enabled" : "disabled"); + + pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); - s->flags = (s->flags & ~mask) | (value & mask); + PA_IDXSET_FOREACH(o, s->outputs, idx) { + if (o->update_source_dynamic_latency_flag) + o->update_source_dynamic_latency_flag(o); + } } /* Called from IO context, or before _put() from main context */ diff --git a/src/pulsecore/source.h b/src/pulsecore/source.h index ca83ad0..7d7a9a9 100644 --- a/src/pulsecore/source.h +++ b/src/pulsecore/source.h @@ -339,7 +339,7 @@ void pa_source_mute_changed(pa_source *s, pa_bool_t new_muted); int pa_source_sync_suspend(pa_source *s); void pa_source_set_latency_flag(pa_source *s, bool enabled); -void pa_source_update_flags(pa_source *s, pa_source_flags_t mask, pa_source_flags_t value); +void pa_source_set_dynamic_latency_flag(pa_source *s, bool enabled); /*** May be called by everyone, from main context */ -- 1.7.10.4