}
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;
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;
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);
}
}
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))) {
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;
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) {
}
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;
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);
return 0;
}
-
}
return -1;
}
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))) {
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;
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) {