diff --git a/src/pipewire/context.c b/src/pipewire/context.c index d1664ce6b..f77b2a029 100644 --- a/src/pipewire/context.c +++ b/src/pipewire/context.c @@ -570,6 +570,8 @@ int pw_context_for_each_global(struct pw_context *context, int res; spa_list_for_each_safe(g, t, &context->global_list, link) { + if (!g->registered) + continue; if (!global_can_read(context, g)) continue; if ((res = callback(data, g)) != 0) @@ -588,12 +590,36 @@ static struct pw_global *find_global(struct pw_context *context, uint32_t id) return NULL; } +static uint32_t next_global_id(struct pw_context *context) +{ + uint32_t id, retry = 0; + + while (true) { + id = context->serial++ & 0xffffff; + if (find_global(context, id) == NULL) + return id; + if (retry++ > 4096) + break; + } + return SPA_ID_INVALID; +} + +uint32_t pw_context_add_global(struct pw_context *context, struct pw_global *global) +{ + global->id = next_global_id(context); + spa_list_append(&context->global_list, &global->link); +} + +void pw_context_remove_global(struct pw_context *context, struct pw_global *global) +{ + spa_list_remove(&global->link); +} + SPA_EXPORT struct pw_global *pw_context_find_global(struct pw_context *context, uint32_t id) { struct pw_global *global; - global = find_global(context, id); if (global == NULL || !global->registered) { errno = ENOENT; diff --git a/src/pipewire/global.c b/src/pipewire/global.c index 632cc2424..635a8c0f4 100644 --- a/src/pipewire/global.c +++ b/src/pipewire/global.c @@ -36,8 +36,6 @@ PW_LOG_TOPIC_EXTERN(log_global); #define PW_LOG_TOPIC_DEFAULT log_global -static uint32_t serial = 0; - /** \cond */ struct impl { struct pw_global this; @@ -96,11 +94,12 @@ pw_global_new(struct pw_context *context, this->func = func; this->object = object; this->properties = properties; - this->id = serial++ & 0xffffff; spa_list_init(&this->resource_list); spa_hook_list_init(&this->listener_list); + pw_context_add_global(context, this); + pw_log_debug("%p: new %s %d", this, this->type, this->id); return this; @@ -126,7 +125,6 @@ int pw_global_register(struct pw_global *global) if (global->registered) return -EEXIST; - spa_list_append(&context->global_list, &global->link); global->registered = true; spa_list_for_each(registry, &context->registry_resource_list, link) { @@ -163,7 +161,6 @@ static int global_unregister(struct pw_global *global) pw_registry_resource_global_remove(resource, global->id); } - spa_list_remove(&global->link); global->registered = false; pw_log_debug("%p: unregistered %u", global, global->id); @@ -368,6 +365,7 @@ void pw_global_destroy(struct pw_global *global) struct pw_resource *resource; global->destroyed = true; + pw_context_remove_global(global->context, global); pw_log_debug("%p: destroy %u", global, global->id); pw_global_emit_destroy(global); diff --git a/src/pipewire/private.h b/src/pipewire/private.h index c56edf9cb..1c5751e44 100644 --- a/src/pipewire/private.h +++ b/src/pipewire/private.h @@ -450,6 +450,7 @@ struct pw_context { uint32_t n_support; /**< number of support items */ struct pw_array factory_lib; /**< mapping of factory_name regexp to library */ + uint32_t serial; struct pw_array objects; /**< objects */ struct pw_impl_client *current_client; /**< client currently executing code in mainloop */ @@ -1115,6 +1116,9 @@ struct pw_control { void *user_data; }; +uint32_t pw_context_add_global(struct pw_context *context, struct pw_global *global); +void pw_context_remove_global(struct pw_context *context, struct pw_global *global); + /** Find a good format between 2 ports */ int pw_context_find_format(struct pw_context *context, struct pw_impl_port *output,