allow _unlink() functions to be called as many times as people want, even before...
authorLennart Poettering <lennart@poettering.net>
Fri, 21 Sep 2007 13:32:00 +0000 (13:32 +0000)
committerLennart Poettering <lennart@poettering.net>
Fri, 21 Sep 2007 13:32:00 +0000 (13:32 +0000)
git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/lennart@1878 fefdeb5f-60dc-0310-8127-8f9354f1896f

src/pulsecore/sink-input.c
src/pulsecore/sink.c
src/pulsecore/source-output.c
src/pulsecore/source.c

index c06da13..57c6c60 100644 (file)
@@ -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);
 }
index 409d026..b814f83 100644 (file)
@@ -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) {
index 34eef8b..1991613 100644 (file)
@@ -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;
index 8f9cbc4..9745a13 100644 (file)
@@ -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) {