diff --git a/src/context.c b/src/context.c index 066f6da62..b6f18da6f 100644 --- a/src/context.c +++ b/src/context.c @@ -37,9 +37,17 @@ int pa_context_set_error(pa_context *c, int error) { return error; } -static void global_free(struct global *g) +static void global_free(pa_context *c, struct global *g) { + pa_operation *o, *t; + spa_list_remove(&g->link); + + spa_list_for_each_safe(o, t, &g->operations, owner_link) + pa_operation_cancel(o); + + if (g->proxy) + spa_hook_remove(&g->proxy_proxy_listener); if (g->props) pw_properties_free(g->props); if (g->destroy) @@ -60,7 +68,7 @@ static void context_unlink(pa_context *c) PA_STREAM_FAILED : PA_STREAM_TERMINATED); } spa_list_consume(g, &c->globals, link) - global_free(g); + global_free(c, g); spa_list_consume(o, &c->operations, link) pa_operation_cancel(o); @@ -300,10 +308,11 @@ static void registry_event_global(void *data, uint32_t id, uint32_t parent_id, g->parent_id = parent_id; g->type = type; g->props = props ? pw_properties_new_dict(props) : NULL; + spa_list_init(&g->operations); spa_list_append(&c->globals, &g->link); if (set_mask(c, g) == 0) { - global_free(g); + global_free(c, g); return; } @@ -323,7 +332,7 @@ static void registry_event_global_remove(void *object, uint32_t id) emit_event(c, g, PA_SUBSCRIPTION_EVENT_REMOVE); pw_log_debug("context %p: free %d %p", c, id, g); - global_free(g); + global_free(c, g); } static const struct pw_registry_proxy_events registry_events = diff --git a/src/internal.h b/src/internal.h index 2b980c469..c562531f2 100644 --- a/src/internal.h +++ b/src/internal.h @@ -217,7 +217,8 @@ struct global { pa_subscription_mask_t mask; pa_subscription_event_type_t event; - pa_operation *operation; + struct spa_list operations; + void *info; pw_destroy_t destroy; @@ -390,6 +391,9 @@ struct pa_operation pa_context *context; pa_stream *stream; + struct spa_list owner_link; + struct global *owner; + int seq; pa_operation_state_t state; diff --git a/src/introspect.c b/src/introspect.c index 8d00ddaf2..b6843f524 100644 --- a/src/introspect.c +++ b/src/introspect.c @@ -30,6 +30,7 @@ static void node_event_info(void *object, const struct pw_node_info *info) { struct global *g = object; + pa_operation *o; uint32_t i; pw_log_debug("update %d", g->id); @@ -50,10 +51,8 @@ static void node_event_info(void *object, const struct pw_node_info *info) } } } - if (g->operation) { - pa_operation_sync(g->operation); - g->operation = NULL; - } + spa_list_for_each(o, &g->operations, owner_link) + pa_operation_sync(o); } static void node_event_param(void *object, int seq, @@ -173,6 +172,7 @@ static void device_event_info(void *object, const struct pw_device_info *info) { struct global *g = object; pa_card_info *i = &g->card_info.info; + pa_operation *o; uint32_t n; pw_log_debug("update %d %"PRIu64, g->id, info->change_mask); @@ -208,10 +208,8 @@ static void device_event_info(void *object, const struct pw_device_info *info) } } } - if (g->operation) { - pa_operation_sync(g->operation); - g->operation = NULL; - } + spa_list_for_each(o, &g->operations, owner_link) + pa_operation_sync(o); } static const struct pw_device_proxy_events device_events = { @@ -265,6 +263,13 @@ static int ensure_global(pa_context *c, struct global *g, pa_operation *o) const void *events; pw_destroy_t destroy; + if (o) { + if (o->owner) + spa_list_remove(&o->owner_link); + o->owner = g; + spa_list_append(&g->operations, &o->owner_link); + } + if (g->proxy != NULL) return 0; @@ -303,8 +308,6 @@ static int ensure_global(pa_context *c, struct global *g, pa_operation *o) pw_proxy_add_proxy_listener(g->proxy, &g->proxy_proxy_listener, events, g); g->destroy = destroy; - if (o) - g->operation = o; return 0; } diff --git a/src/operation.c b/src/operation.c index 5115815af..e4dd582d9 100644 --- a/src/operation.c +++ b/src/operation.c @@ -88,6 +88,8 @@ static void operation_unlink(pa_operation *o) { } if (o->stream) pa_stream_unref(o->stream); + if (o->owner) + spa_list_remove(&o->owner_link); o->stream = NULL; o->callback = NULL; o->userdata = NULL;