diff --git a/src/context.c b/src/context.c index b6f18da6f..8c674b9b8 100644 --- a/src/context.c +++ b/src/context.c @@ -63,6 +63,10 @@ static void context_unlink(pa_context *c) pw_log_debug("context %p: unlink %d", c, c->state); + c->disconnect = true; + c->state_callback = NULL; + c->state_userdata = NULL; + spa_list_for_each_safe(s, t, &c->streams, link) { pa_stream_set_state(s, c->state == PA_CONTEXT_FAILED ? PA_STREAM_FAILED : PA_STREAM_TERMINATED); @@ -397,6 +401,8 @@ static void remote_state_changed(void *data, enum pw_remote_state old, context_fail(c, PA_ERR_CONNECTIONTERMINATED); break; case PW_REMOTE_STATE_UNCONNECTED: + if (!c->disconnect) + context_fail(c, PA_ERR_CONNECTIONTERMINATED); break; case PW_REMOTE_STATE_CONNECTING: pa_context_set_state(c, PA_CONTEXT_CONNECTING); @@ -480,6 +486,12 @@ pa_context *pa_context_new_with_proplist(pa_mainloop_api *mainloop, const char * return c; } +static void do_core_destroy(pa_mainloop_api*m, void *userdata) +{ + pa_context *c = userdata; + pw_core_destroy(c->core); +} + static void context_free(pa_context *c) { pw_log_debug("context %p: free", c); @@ -491,7 +503,7 @@ static void context_free(pa_context *c) if (c->core_info) pw_core_info_free(c->core_info); - pw_core_destroy(c->core); + pa_mainloop_api_once(c->mainloop, do_core_destroy, c); } SPA_EXPORT @@ -598,6 +610,7 @@ void pa_context_disconnect(pa_context *c) pa_assert(c); pa_assert(c->refcount >= 1); + c->disconnect = true; pw_remote_disconnect(c->remote); if (PA_CONTEXT_IS_GOOD(c->state)) diff --git a/src/internal.h b/src/internal.h index c562531f2..bc9e30cca 100644 --- a/src/internal.h +++ b/src/internal.h @@ -257,6 +257,7 @@ struct global { struct pa_context { int refcount; + uint32_t client_index; struct pw_loop *loop; struct pw_core *core; @@ -284,13 +285,13 @@ struct pa_context { void *subscribe_userdata; pa_subscription_mask_t subscribe_mask; - bool no_fail; - uint32_t client_index; - struct spa_list globals; struct spa_list streams; struct spa_list operations; + + int no_fail:1; + int disconnect:1; }; struct global *pa_context_find_global(pa_context *c, uint32_t id); diff --git a/src/mainloop.c b/src/mainloop.c index ef509ece1..e5c85589c 100644 --- a/src/mainloop.c +++ b/src/mainloop.c @@ -23,6 +23,7 @@ #include #include +#include #include "internal.h" @@ -376,3 +377,49 @@ void pa_mainloop_set_poll_func(pa_mainloop *m, pa_poll_func poll_func, void *use { pw_log_warn("Not Implemented"); } + + +struct once_info { + void (*callback)(pa_mainloop_api*m, void *userdata); + void *userdata; +}; + +static void once_callback(pa_mainloop_api *m, pa_defer_event *e, void *userdata) { + struct once_info *i = userdata; + + pa_assert(m); + pa_assert(i); + + pa_assert(i->callback); + i->callback(m, i->userdata); + + pa_assert(m->defer_free); + m->defer_free(e); +} + +static void free_callback(pa_mainloop_api *m, pa_defer_event *e, void *userdata) { + struct once_info *i = userdata; + + pa_assert(m); + pa_assert(i); + pa_xfree(i); +} + + +void pa_mainloop_api_once(pa_mainloop_api* m, void (*callback)(pa_mainloop_api *m, void *userdata), void *userdata) { + struct once_info *i; + pa_defer_event *e; + + pa_assert(m); + pa_assert(callback); + + pa_init_i18n(); + + i = pa_xnew(struct once_info, 1); + i->callback = callback; + i->userdata = userdata; + + pa_assert(m->defer_new); + pa_assert_se(e = m->defer_new(m, once_callback, i)); + m->defer_set_destroy(e, free_callback); +}