From c34a2635b20cf72f906999c3ccedf4433ddf96ed Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 21 Sep 2007 13:32:00 +0000 Subject: allow _unlink() functions to be called as many times as people want, even before _put() was called git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/lennart@1878 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/sink-input.c | 32 +++++++++++++++++++++++--------- src/pulsecore/sink.c | 34 +++++++++++++++++++++++++--------- src/pulsecore/source-output.c | 31 +++++++++++++++++++++---------- src/pulsecore/source.c | 25 ++++++++++++++++++------- 4 files changed, 87 insertions(+), 35 deletions(-) diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c index c06da13f..57c6c601 100644 --- a/src/pulsecore/sink-input.c +++ b/src/pulsecore/sink-input.c @@ -264,10 +264,18 @@ static int sink_input_set_state(pa_sink_input *i, pa_sink_input_state_t state) { } void pa_sink_input_unlink(pa_sink_input *i) { + pa_bool_t linked; pa_assert(i); - pa_assert(PA_SINK_INPUT_LINKED(i->state)); - pa_hook_fire(&i->sink->core->hooks[PA_CORE_HOOK_SINK_INPUT_UNLINK], i); + /* See pa_sink_unlink() for a couple of comments how this function + * works */ + + pa_sink_input_ref(i); + + linked = PA_SINK_INPUT_LINKED(i->state); + + if (linked) + pa_hook_fire(&i->sink->core->hooks[PA_CORE_HOOK_SINK_INPUT_UNLINK], i); if (i->sync_prev) i->sync_prev->sync_next = i->sync_next; @@ -276,14 +284,16 @@ void pa_sink_input_unlink(pa_sink_input *i) { i->sync_prev = i->sync_next = NULL; - pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i->sink), PA_SINK_MESSAGE_REMOVE_INPUT, i, 0, NULL); pa_idxset_remove_by_data(i->sink->core->sink_inputs, i, NULL); - pa_idxset_remove_by_data(i->sink->inputs, i, NULL); - - pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_REMOVE, i->index); + if (pa_idxset_remove_by_data(i->sink->inputs, i, NULL)) + pa_sink_input_unref(i); - sink_input_set_state(i, PA_SINK_INPUT_UNLINKED); - pa_sink_update_status(i->sink); + if (linked) { + pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i->sink), PA_SINK_MESSAGE_REMOVE_INPUT, i, 0, NULL); + sink_input_set_state(i, PA_SINK_INPUT_UNLINKED); + pa_sink_update_status(i->sink); + } else + i->state = PA_SINK_INPUT_UNLINKED; i->peek = NULL; i->drop = NULL; @@ -293,7 +303,11 @@ void pa_sink_input_unlink(pa_sink_input *i) { i->detach = NULL; i->suspend = NULL; - pa_hook_fire(&i->sink->core->hooks[PA_CORE_HOOK_SINK_INPUT_UNLINK_POST], i); + if (linked) { + pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_REMOVE, i->index); + pa_hook_fire(&i->sink->core->hooks[PA_CORE_HOOK_SINK_INPUT_UNLINK_POST], i); + } + i->sink = NULL; pa_sink_input_unref(i); } diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c index 409d0260..b814f837 100644 --- a/src/pulsecore/sink.c +++ b/src/pulsecore/sink.c @@ -200,14 +200,26 @@ static int sink_set_state(pa_sink *s, pa_sink_state_t state) { } void pa_sink_unlink(pa_sink* s) { + pa_bool_t linked; pa_sink_input *i, *j = NULL; pa_assert(s); - pa_assert(PA_SINK_LINKED(s->state)); - pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_UNLINK], s); + /* Please note that pa_sink_unlink() does more than simply + * 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. */ + + linked = PA_SINK_LINKED(s->state); - pa_namereg_unregister(s->core, s->name); + if (linked) + pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_UNLINK], s); + + if (s->state != PA_SINK_UNLINKED) + pa_namereg_unregister(s->core, s->name); pa_idxset_remove_by_data(s->core->sinks, s, NULL); while ((i = pa_idxset_first(s->inputs, NULL))) { @@ -216,10 +228,10 @@ void pa_sink_unlink(pa_sink* s) { j = i; } - sink_set_state(s, PA_SINK_UNLINKED); - - if (s->monitor_source) - pa_source_unlink(s->monitor_source); + if (linked) + sink_set_state(s, PA_SINK_UNLINKED); + else + s->state = PA_SINK_UNLINKED; s->get_latency = NULL; s->get_volume = NULL; @@ -228,9 +240,13 @@ void pa_sink_unlink(pa_sink* s) { s->get_mute = NULL; s->set_state = NULL; - pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_REMOVE, s->index); + if (s->monitor_source) + pa_source_unlink(s->monitor_source); - pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_UNLINK_POST], s); + if (linked) { + pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_REMOVE, s->index); + pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_UNLINK_POST], s); + } } static void sink_free(pa_object *o) { diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c index 34eef8ba..1991613e 100644 --- a/src/pulsecore/source-output.c +++ b/src/pulsecore/source-output.c @@ -194,20 +194,29 @@ static int source_output_set_state(pa_source_output *o, pa_source_output_state_t } void pa_source_output_unlink(pa_source_output*o) { + pa_bool_t linked; pa_assert(o); - pa_assert(PA_SOURCE_OUTPUT_LINKED(o->state)); - pa_hook_fire(&o->source->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_UNLINK], o); + /* See pa_sink_unlink() for a couple of comments how this function + * works */ - pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o->source), PA_SOURCE_MESSAGE_REMOVE_OUTPUT, o, 0, NULL); + pa_source_output_ref(o); - pa_idxset_remove_by_data(o->source->core->source_outputs, o, NULL); - pa_idxset_remove_by_data(o->source->outputs, o, NULL); + linked = PA_SOURCE_OUTPUT_LINKED(o->state); - pa_subscription_post(o->source->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_REMOVE, o->index); + if (linked) + pa_hook_fire(&o->source->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_UNLINK], o); - source_output_set_state(o, PA_SOURCE_OUTPUT_UNLINKED); - pa_source_update_status(o->source); + pa_idxset_remove_by_data(o->source->core->source_outputs, o, NULL); + if (pa_idxset_remove_by_data(o->source->outputs, o, NULL)) + pa_source_output_unref(o); + + if (linked) { + pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o->source), PA_SOURCE_MESSAGE_REMOVE_OUTPUT, o, 0, NULL); + source_output_set_state(o, PA_SOURCE_OUTPUT_UNLINKED); + pa_source_update_status(o->source); + } else + o->state = PA_SOURCE_OUTPUT_UNLINKED; o->push = NULL; o->kill = NULL; @@ -216,7 +225,10 @@ void pa_source_output_unlink(pa_source_output*o) { o->detach = NULL; o->suspend = NULL; - pa_hook_fire(&o->source->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_UNLINK_POST], o); + if (linked) { + pa_subscription_post(o->source->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_REMOVE, o->index); + pa_hook_fire(&o->source->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_UNLINK_POST], o); + } o->source = NULL; pa_source_output_unref(o); @@ -451,7 +463,6 @@ int pa_source_output_process_msg(pa_msgobject *mo, int code, void *userdata, int return 0; } - } return -1; diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c index 8f9cbc4a..9745a13e 100644 --- a/src/pulsecore/source.c +++ b/src/pulsecore/source.c @@ -175,14 +175,21 @@ static int source_set_state(pa_source *s, pa_source_state_t state) { } void pa_source_unlink(pa_source *s) { + pa_bool_t linked; pa_source_output *o, *j = NULL; pa_assert(s); - pa_assert(PA_SOURCE_LINKED(s->state)); - pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_UNLINK], s); + /* See pa_sink_unlink() for a couple of comments how this function + * works. */ + + linked = PA_SOURCE_LINKED(s->state); + + if (linked) + pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_UNLINK], s); - pa_namereg_unregister(s->core, s->name); + if (s->state != PA_SOURCE_UNLINKED) + pa_namereg_unregister(s->core, s->name); pa_idxset_remove_by_data(s->core->sources, s, NULL); while ((o = pa_idxset_first(s->outputs, NULL))) { @@ -191,7 +198,10 @@ void pa_source_unlink(pa_source *s) { j = o; } - source_set_state(s, PA_SOURCE_UNLINKED); + if (linked) + source_set_state(s, PA_SOURCE_UNLINKED); + else + s->state = PA_SOURCE_UNLINKED; s->get_latency = NULL; s->get_volume = NULL; @@ -200,9 +210,10 @@ void pa_source_unlink(pa_source *s) { s->get_mute = NULL; s->set_state = NULL; - pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPTION_EVENT_REMOVE, s->index); - - pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_UNLINK_POST], s); + if (linked) { + pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPTION_EVENT_REMOVE, s->index); + pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_UNLINK_POST], s); + } } static void source_free(pa_object *o) { -- cgit