diff --git a/src/modules/module-link-factory.c b/src/modules/module-link-factory.c index 5be8d5a79..2cd17bc58 100644 --- a/src/modules/module-link-factory.c +++ b/src/modules/module-link-factory.c @@ -97,15 +97,25 @@ static void *create_object(void *_data, if (output_port_id == -1) outport = pw_node_get_free_port(output_node, SPA_DIRECTION_OUTPUT); - else - outport = pw_node_find_port(output_node, SPA_DIRECTION_OUTPUT, output_port_id); + else { + global = pw_core_find_global(core, output_port_id); + if (global == NULL || pw_global_get_type(global) != t->port) + goto no_output_port; + + outport = pw_global_get_object(global); + } if (outport == NULL) goto no_output_port; if (input_port_id == -1) inport = pw_node_get_free_port(input_node, SPA_DIRECTION_INPUT); - else - inport = pw_node_find_port(input_node, SPA_DIRECTION_INPUT, input_port_id); + else { + global = pw_core_find_global(core, input_port_id); + if (global == NULL || pw_global_get_type(global) != t->port) + goto no_output_port; + + inport = pw_global_get_object(global); + } if (inport == NULL) goto no_input_port; diff --git a/src/modules/module-protocol-native/protocol-native.c b/src/modules/module-protocol-native/protocol-native.c index c07d5449a..bf2977d45 100644 --- a/src/modules/module-protocol-native/protocol-native.c +++ b/src/modules/module-protocol-native/protocol-native.c @@ -145,6 +145,19 @@ core_marshal_create_object(void *object, pw_protocol_native_end_proxy(proxy, b); } +static void +core_marshal_destroy(void *object, uint32_t id) +{ + struct pw_proxy *proxy = object; + struct spa_pod_builder *b; + + b = pw_protocol_native_begin_proxy(proxy, PW_CORE_PROXY_METHOD_DESTROY); + + spa_pod_builder_struct(b, "i", id); + + pw_protocol_native_end_proxy(proxy, b); +} + static void core_marshal_update_types_client(void *object, uint32_t first_id, const char **types, uint32_t n_types) { @@ -489,6 +502,20 @@ static int core_demarshal_create_object(void *object, void *data, size_t size) return 0; } +static int core_demarshal_destroy(void *object, void *data, size_t size) +{ + struct pw_resource *resource = object; + struct spa_pod_parser prs; + uint32_t id; + + spa_pod_parser_init(&prs, data, size, 0); + if (spa_pod_parser_get(&prs, "[i]", &id, NULL) < 0) + return -EINVAL; + + pw_resource_do(resource, struct pw_core_proxy_methods, destroy, id); + return 0; +} + static int core_demarshal_update_types_server(void *object, void *data, size_t size) { struct pw_resource *resource = object; @@ -979,7 +1006,8 @@ static const struct pw_core_proxy_methods pw_protocol_native_core_method_marshal &core_marshal_get_registry, &core_marshal_client_update, &core_marshal_permissions, - &core_marshal_create_object + &core_marshal_create_object, + &core_marshal_destroy, }; static const struct pw_protocol_native_demarshal pw_protocol_native_core_method_demarshal[PW_CORE_PROXY_METHOD_NUM] = { @@ -989,7 +1017,8 @@ static const struct pw_protocol_native_demarshal pw_protocol_native_core_method_ { &core_demarshal_get_registry, 0, }, { &core_demarshal_client_update, 0, }, { &core_demarshal_permissions, 0, }, - { &core_demarshal_create_object, PW_PROTOCOL_NATIVE_REMAP, } + { &core_demarshal_create_object, PW_PROTOCOL_NATIVE_REMAP, }, + { &core_demarshal_destroy, 0, } }; static const struct pw_core_proxy_events pw_protocol_native_core_event_marshal = { diff --git a/src/pipewire/client.c b/src/pipewire/client.c index 998d867d5..29d908462 100644 --- a/src/pipewire/client.c +++ b/src/pipewire/client.c @@ -89,12 +89,12 @@ static const struct pw_resource_events resource_events = { }; -static int -client_bind_func(struct pw_global *global, - struct pw_client *client, uint32_t permissions, +static void +global_bind(void *_data, struct pw_client *client, uint32_t permissions, uint32_t version, uint32_t id) { - struct pw_client *this = global->object; + struct pw_client *this = _data; + struct pw_global *global = this->global; struct pw_resource *resource; struct resource_data *data; @@ -113,12 +113,12 @@ client_bind_func(struct pw_global *global, pw_client_resource_info(resource, &this->info); this->info.change_mask = 0; - return 0; + return; no_mem: pw_log_error("can't create client resource"); pw_resource_error(client->core_resource, -ENOMEM, "no memory"); - return -ENOMEM; + return; } static void @@ -201,6 +201,20 @@ struct pw_client *pw_client_new(struct pw_core *core, return this; } +static void global_destroy(void *object) +{ + struct pw_client *client = object; + spa_hook_remove(&client->global_listener); + client->global = NULL; + pw_client_destroy(client); +} + +static const struct pw_global_events global_events = { + PW_VERSION_GLOBAL_EVENTS, + .destroy = global_destroy, + .bind = global_bind, +}; + int pw_client_register(struct pw_client *client, struct pw_client *owner, struct pw_global *parent, @@ -211,14 +225,16 @@ int pw_client_register(struct pw_client *client, pw_log_debug("client %p: register parent %d", client, parent ? parent->id : SPA_ID_INVALID); spa_list_append(&core->client_list, &client->link); + client->registered = true; client->global = pw_global_new(core, core->type.client, PW_VERSION_CLIENT, properties, - client_bind_func, client); + client); if (client->global == NULL) return -ENOMEM; + pw_global_add_listener(client->global, &client->global_listener, &global_events, client); pw_global_register(client->global, owner, parent); client->info.id = client->global->id; @@ -285,8 +301,12 @@ void pw_client_destroy(struct pw_client *client) spa_hook_remove(&impl->core_listener); - if (client->global) { + if (client->registered) { spa_list_remove(&client->link); + } + + if (client->global) { + spa_hook_remove(&client->global_listener); pw_global_destroy(client->global); } diff --git a/src/pipewire/core.c b/src/pipewire/core.c index 967618f00..aaf1020d6 100644 --- a/src/pipewire/core.c +++ b/src/pipewire/core.c @@ -247,6 +247,21 @@ core_create_object(void *object, goto done; } +static void core_destroy(void *object, uint32_t id) +{ + struct pw_resource *resource = object; + struct pw_core *this = resource->core; + struct pw_global *global; + + pw_log_debug("core %p: destroy %d from resource %p", resource->core, id, resource); + + global = pw_core_find_global(this, id); + if (global == NULL) + return; + + pw_global_destroy(global); +} + static void core_update_types(void *object, uint32_t first_id, const char **types, uint32_t n_types) { struct pw_resource *resource = object; @@ -270,6 +285,7 @@ static const struct pw_core_proxy_methods core_methods = { .client_update = core_client_update, .permissions = core_permissions, .create_object = core_create_object, + .destroy = core_destroy, }; static void core_unbind_func(void *data) @@ -284,14 +300,15 @@ static const struct pw_resource_events core_resource_events = { .destroy = core_unbind_func, }; -static int -core_bind_func(struct pw_global *global, - struct pw_client *client, - uint32_t permissions, - uint32_t version, - uint32_t id) +static void +global_bind(void *_data, + struct pw_client *client, + uint32_t permissions, + uint32_t version, + uint32_t id) { - struct pw_core *this = global->object; + struct pw_core *this = _data; + struct pw_global *global = this->global; struct pw_resource *resource; struct resource_data *data; @@ -311,14 +328,27 @@ core_bind_func(struct pw_global *global, pw_log_debug("core %p: bound to %d", this, resource->id); - - return 0; + return; no_mem: pw_log_error("can't create core resource"); - return -ENOMEM; + return; } +static void global_destroy(void *object) +{ + struct pw_core *core = object; + spa_hook_remove(&core->global_listener); + core->global = NULL; + pw_core_destroy(core); +} + +static const struct pw_global_events global_events = { + PW_VERSION_GLOBAL_EVENTS, + .destroy = global_destroy, + .bind = global_bind, +}; + /** Create a new core object * * \param main_loop the main loop to use @@ -413,12 +443,13 @@ struct pw_core *pw_core_new(struct pw_loop *main_loop, struct pw_properties *pro PW_CORE_PROP_NAME, this->info.name, PW_CORE_PROP_VERSION, this->info.version, NULL), - core_bind_func, this); - if (this->global != NULL) { - pw_global_register(this->global, NULL, NULL); - this->info.id = this->global->id; - } + if (this->global == NULL) + goto no_mem; + + pw_global_add_listener(this->global, &this->global_listener, &global_events, this); + pw_global_register(this->global, NULL, NULL); + this->info.id = this->global->id; return this; @@ -444,6 +475,8 @@ void pw_core_destroy(struct pw_core *core) pw_log_debug("core %p: destroy", core); spa_hook_list_call(&core->listener_list, struct pw_core_events, destroy); + spa_hook_remove(&core->global_listener); + spa_list_for_each_safe(remote, tr, &core->remote_list, link) pw_remote_destroy(remote); diff --git a/src/pipewire/factory.c b/src/pipewire/factory.c index 5bf2d05d7..c2a555d34 100644 --- a/src/pipewire/factory.c +++ b/src/pipewire/factory.c @@ -83,12 +83,12 @@ static const struct pw_resource_events resource_events = { .destroy = factory_unbind_func, }; -static int -factory_bind_func(struct pw_global *global, - struct pw_client *client, uint32_t permissions, +static void +global_bind(void *_data, struct pw_client *client, uint32_t permissions, uint32_t version, uint32_t id) { - struct pw_factory *this = global->object; + struct pw_factory *this = _data; + struct pw_global *global = this->global; struct pw_resource *resource; struct resource_data *data; @@ -107,15 +107,29 @@ factory_bind_func(struct pw_global *global, pw_factory_resource_info(resource, &this->info); this->info.change_mask = 0; - return 0; + return; no_mem: pw_log_error("can't create factory resource"); pw_core_resource_error(client->core_resource, client->core_resource->id, -ENOMEM, "no memory"); - return -ENOMEM; + return; } +static void global_destroy(void *object) +{ + struct pw_factory *factory = object; + spa_hook_remove(&factory->global_listener); + factory->global = NULL; + pw_factory_destroy(factory); +} + +static const struct pw_global_events global_events = { + PW_VERSION_GLOBAL_EVENTS, + .destroy = global_destroy, + .bind = global_bind, +}; + int pw_factory_register(struct pw_factory *factory, struct pw_client *owner, struct pw_global *parent, @@ -138,10 +152,11 @@ int pw_factory_register(struct pw_factory *factory, factory->global = pw_global_new(core, core->type.factory, PW_VERSION_FACTORY, properties, - factory_bind_func, factory); + factory); if (factory->global == NULL) return -ENOMEM; + pw_global_add_listener(factory->global, &factory->global_listener, &global_events, factory); pw_global_register(factory->global, owner, parent); factory->info.id = factory->global->id; diff --git a/src/pipewire/global.c b/src/pipewire/global.c index e3c420fdc..0e990247b 100644 --- a/src/pipewire/global.c +++ b/src/pipewire/global.c @@ -62,7 +62,6 @@ pw_global_new(struct pw_core *core, uint32_t type, uint32_t version, struct pw_properties *properties, - pw_bind_func_t bind, void *object) { struct global_impl *impl; @@ -77,11 +76,12 @@ pw_global_new(struct pw_core *core, this->core = core; this->type = type; this->version = version; - this->bind = bind; this->object = object; this->properties = properties; this->id = SPA_ID_INVALID; + spa_hook_list_init(&this->listener_list); + pw_log_debug("global %p: new %s", this, spa_type_map_get_type(core->type.map, this->type)); @@ -177,6 +177,14 @@ uint32_t pw_global_get_id(struct pw_global *global) return global->id; } +void pw_global_add_listener(struct pw_global *global, + struct spa_hook *listener, + const struct pw_global_events *events, + void *data) +{ + spa_hook_list_append(&global->listener_list, listener, events, data); +} + /** Bind to a global * * \param global the global to bind to @@ -196,15 +204,13 @@ pw_global_bind(struct pw_global *global, struct pw_client *client, uint32_t perm { int res; - if (global->bind == NULL) - goto no_bind; - if (global->version < version) goto wrong_version; - res = global->bind(global, client, permissions, version, id); + spa_hook_list_call(&global->listener_list, struct pw_global_events, bind, + client, permissions, version, id); - return res; + return 0; wrong_version: res = -EINVAL; @@ -213,12 +219,6 @@ pw_global_bind(struct pw_global *global, struct pw_client *client, uint32_t perm res, "id %d: interface version %d < %d", id, global->version, version); return res; - no_bind: - res = -ENOTSUP; - pw_core_resource_error(client->core_resource, - client->core_resource->id, - res, "can't bind object id %d to interface", id); - return res; } /** Destroy a global @@ -233,6 +233,7 @@ void pw_global_destroy(struct pw_global *global) struct pw_resource *registry; pw_log_debug("global %p: destroy %u", global, global->id); + spa_hook_list_call(&global->listener_list, struct pw_global_events, destroy); if (global->id != SPA_ID_INVALID) { spa_list_for_each(registry, &core->registry_resource_list, link) { @@ -248,9 +249,11 @@ void pw_global_destroy(struct pw_global *global) spa_hook_list_call(&core->listener_list, struct pw_core_events, global_removed, global); } + pw_log_debug("global %p: free", global); + spa_hook_list_call(&global->listener_list, struct pw_global_events, free); + if (global->properties) pw_properties_free(global->properties); - pw_log_debug("global %p: free", global); free(global); } diff --git a/src/pipewire/global.h b/src/pipewire/global.h index b85b2efa9..813409f92 100644 --- a/src/pipewire/global.h +++ b/src/pipewire/global.h @@ -55,12 +55,24 @@ struct pw_global; #include #include -/** The function to let a client bind to a global */ -typedef int (*pw_bind_func_t) (struct pw_global *global, /**< the global to bind */ - struct pw_client *client, /**< client that binds */ - uint32_t permissions, /**< permissions for the bind */ - uint32_t version, /**< client interface version */ - uint32_t id /**< client proxy id */); +/** Global events, use \ref pw_global_add_listener */ +struct pw_global_events { +#define PW_VERSION_GLOBAL_EVENTS 0 + uint32_t version; + + /** The global is destroyed */ + void (*destroy) (void *data); + + /** The global is freed */ + void (*free) (void *data); + + /* bind the global */ + void (*bind) (void *data, + struct pw_client *client, /**< client that binds */ + uint32_t permissions, /**< permissions for the bind */ + uint32_t version, /**< client interface version */ + uint32_t id /**< client proxy id */); +}; /** Create a new global object */ struct pw_global * @@ -68,7 +80,6 @@ pw_global_new(struct pw_core *core, /**< the core */ uint32_t type, /**< the interface type of the global */ uint32_t version, /**< the interface version of the global */ struct pw_properties *properties, /**< extra properties */ - pw_bind_func_t bind, /**< function to bind to the global */ void *object /**< global object */); /** Register a global object to the core registry */ @@ -76,6 +87,12 @@ int pw_global_register(struct pw_global *global, struct pw_client *owner, struct pw_global *parent); +/** Add an event listener on the global */ +void pw_global_add_listener(struct pw_global *global, + struct spa_hook *listener, + const struct pw_global_events *events, + void *data); + /** Get the permissions of the global for a given client */ uint32_t pw_global_get_permissions(struct pw_global *global, struct pw_client *client); diff --git a/src/pipewire/interfaces.h b/src/pipewire/interfaces.h index 0eeb8403e..484530901 100644 --- a/src/pipewire/interfaces.h +++ b/src/pipewire/interfaces.h @@ -35,6 +35,7 @@ struct pw_core_proxy; struct pw_registry_proxy; struct pw_module_proxy; struct pw_node_proxy; +struct pw_port_proxy; struct pw_factory_proxy; struct pw_client_proxy; struct pw_link_proxy; @@ -61,6 +62,7 @@ struct pw_link_proxy; #define PW_TYPE_INTERFACE__Registry PW_TYPE_INTERFACE_BASE "Registry" #define PW_TYPE_INTERFACE__Module PW_TYPE_INTERFACE_BASE "Module" #define PW_TYPE_INTERFACE__Node PW_TYPE_INTERFACE_BASE "Node" +#define PW_TYPE_INTERFACE__Port PW_TYPE_INTERFACE_BASE "Port" #define PW_TYPE_INTERFACE__Client PW_TYPE_INTERFACE_BASE "Client" #define PW_TYPE_INTERFACE__Link PW_TYPE_INTERFACE_BASE "Link" @@ -73,7 +75,8 @@ struct pw_link_proxy; #define PW_CORE_PROXY_METHOD_CLIENT_UPDATE 4 #define PW_CORE_PROXY_METHOD_PERMISSIONS 5 #define PW_CORE_PROXY_METHOD_CREATE_OBJECT 6 -#define PW_CORE_PROXY_METHOD_NUM 7 +#define PW_CORE_PROXY_METHOD_DESTROY 7 +#define PW_CORE_PROXY_METHOD_NUM 8 /** * Key to update default permissions of globals without specific @@ -183,6 +186,13 @@ struct pw_core_proxy_methods { uint32_t version, const struct spa_dict *props, uint32_t new_id); + + /** + * Destroy an object id + * + * \param id the object id to destroy + */ + void (*destroy) (void *object, uint32_t id); }; static inline void @@ -237,6 +247,12 @@ pw_core_proxy_create_object(struct pw_core_proxy *core, return p; } +static inline void +pw_core_proxy_destroy(struct pw_core_proxy *core, uint32_t id) +{ + pw_proxy_do((struct pw_proxy*)core, struct pw_core_proxy_methods, destroy, id); +} + #define PW_CORE_PROXY_EVENT_UPDATE_TYPES 0 #define PW_CORE_PROXY_EVENT_DONE 1 #define PW_CORE_PROXY_EVENT_ERROR 2 @@ -468,7 +484,7 @@ pw_module_proxy_add_listener(struct pw_module_proxy *module, #define PW_VERSION_NODE 0 #define PW_NODE_PROXY_EVENT_INFO 0 -#define PW_NODE_PROXY_EVENT_NUM 1 +#define PW_NODE_PROXY_EVENT_NUM 1 /** Node events */ struct pw_node_proxy_events { @@ -493,6 +509,35 @@ pw_node_proxy_add_listener(struct pw_node_proxy *node, #define pw_node_resource_info(r,...) pw_resource_notify(r,struct pw_node_proxy_events,info,__VA_ARGS__) + +#define PW_VERSION_PORT 0 + +#define PW_PORT_PROXY_EVENT_INFO 0 +#define PW_PORT_PROXY_EVENT_NUM 1 + +/** Port events */ +struct pw_port_proxy_events { +#define PW_VERSION_PORT_PROXY_EVENTS 0 + uint32_t version; + /** + * Notify port info + * + * \param info info about the port + */ + void (*info) (void *object, struct pw_port_info *info); +}; + +static inline void +pw_port_proxy_add_listener(struct pw_port_proxy *port, + struct spa_hook *listener, + const struct pw_port_proxy_events *events, + void *data) +{ + pw_proxy_add_proxy_listener((struct pw_proxy*)port, listener, events, data); +} + +#define pw_port_resource_info(r,...) pw_resource_notify(r,struct pw_port_proxy_events,info,__VA_ARGS__) + #define PW_VERSION_FACTORY 0 #define PW_FACTORY_PROXY_EVENT_INFO 0 diff --git a/src/pipewire/introspect.h b/src/pipewire/introspect.h index bbbcde149..bcbcfd87e 100644 --- a/src/pipewire/introspect.h +++ b/src/pipewire/introspect.h @@ -170,6 +170,10 @@ pw_node_info_update(struct pw_node_info *info, void pw_node_info_free(struct pw_node_info *info); +struct pw_port_info { + uint32_t id; /**< id of the global */ +}; + /** The factory information. Extra information can be added in later versions \memberof pw_introspect */ struct pw_factory_info { uint32_t id; /**< id of the global */ diff --git a/src/pipewire/link.c b/src/pipewire/link.c index cb885b058..4ad9333ed 100644 --- a/src/pipewire/link.c +++ b/src/pipewire/link.c @@ -992,12 +992,12 @@ static const struct pw_resource_events resource_events = { .destroy = link_unbind_func, }; -static int -link_bind_func(struct pw_global *global, - struct pw_client *client, uint32_t permissions, +static void +global_bind(void *_data, struct pw_client *client, uint32_t permissions, uint32_t version, uint32_t id) { - struct pw_link *this = global->object; + struct pw_link *this = _data; + struct pw_global *global = this->global; struct pw_resource *resource; struct resource_data *data; @@ -1016,13 +1016,13 @@ link_bind_func(struct pw_global *global, pw_link_resource_info(resource, &this->info); this->info.change_mask = 0; - return 0; + return; no_mem: pw_log_error("can't create link resource"); pw_core_resource_error(client->core_resource, client->core_resource->id, -ENOMEM, "no memory"); - return -ENOMEM; + return; } static int @@ -1132,9 +1132,9 @@ struct pw_link *pw_link_new(struct pw_core *core, spa_list_append(&input->links, &this->input_link); this->info.output_node_id = output_node->global->id; - this->info.output_port_id = output->port_id; + this->info.output_port_id = output->global->id; this->info.input_node_id = input_node->global->id; - this->info.input_port_id = input->port_id; + this->info.input_port_id = input->global->id; this->info.format = NULL; this->info.props = this->properties ? &this->properties->dict : NULL; @@ -1177,6 +1177,20 @@ struct pw_link *pw_link_new(struct pw_core *core, return NULL; } +static void global_destroy(void *object) +{ + struct pw_link *link = object; + spa_hook_remove(&link->global_listener); + link->global = NULL; + pw_link_destroy(link); +} + +static const struct pw_global_events global_events = { + PW_VERSION_GLOBAL_EVENTS, + .destroy = global_destroy, + .bind = global_bind, +}; + int pw_link_register(struct pw_link *link, struct pw_client *owner, struct pw_global *parent, @@ -1185,15 +1199,26 @@ int pw_link_register(struct pw_link *link, struct pw_core *core = link->core; struct pw_node *input_node, *output_node; + if (properties == NULL) + properties = pw_properties_new(NULL, NULL); + if (properties == NULL) + return -ENOMEM; + + pw_properties_setf(properties, "link.output", "%d", link->info.output_port_id); + pw_properties_setf(properties, "link.input", "%d", link->info.input_port_id); + spa_list_append(&core->link_list, &link->link); + link->registered = true; link->global = pw_global_new(core, core->type.link, PW_VERSION_LINK, properties, - link_bind_func, link); + link); if (link->global == NULL) return -ENOMEM; + pw_global_add_listener(link->global, &link->global_listener, &global_events, link); + pw_global_register(link->global, owner, parent); link->info.id = link->global->id; @@ -1228,8 +1253,12 @@ void pw_link_destroy(struct pw_link *link) pw_link_deactivate(link); - if (link->global) { + if (link->registered) { spa_list_remove(&link->link); + } + + if (link->global) { + spa_hook_remove(&link->global_listener); pw_global_destroy(link->global); } diff --git a/src/pipewire/mem.c b/src/pipewire/mem.c index 9b8071273..e23e32573 100644 --- a/src/pipewire/mem.c +++ b/src/pipewire/mem.c @@ -212,7 +212,7 @@ int pw_memblock_alloc(enum pw_memblock_flags flags, size_t size, struct pw_membl p = calloc(1, sizeof(struct memblock)); *p = tmp; - spa_list_prepend(&_memblocks, &p->link); + spa_list_append(&_memblocks, &p->link); *mem = &p->mem; return 0; diff --git a/src/pipewire/module.c b/src/pipewire/module.c index 13e5d5adc..580bb529e 100644 --- a/src/pipewire/module.c +++ b/src/pipewire/module.c @@ -105,12 +105,12 @@ static const struct pw_resource_events resource_events = { .destroy = module_unbind_func, }; -static int -module_bind_func(struct pw_global *global, - struct pw_client *client, uint32_t permissions, +static void +global_bind(void *_data, struct pw_client *client, uint32_t permissions, uint32_t version, uint32_t id) { - struct pw_module *this = global->object; + struct pw_module *this = _data; + struct pw_global *global = this->global; struct pw_resource *resource; struct resource_data *data; @@ -129,15 +129,29 @@ module_bind_func(struct pw_global *global, pw_module_resource_info(resource, &this->info); this->info.change_mask = 0; - return 0; + return; no_mem: pw_log_error("can't create module resource"); pw_core_resource_error(client->core_resource, client->core_resource->id, -ENOMEM, "no memory"); - return -ENOMEM; + return; } +static void global_destroy(void *object) +{ + struct pw_module *module = object; + spa_hook_remove(&module->global_listener); + module->global = NULL; + pw_module_destroy(module); +} + +static const struct pw_global_events global_events = { + PW_VERSION_GLOBAL_EVENTS, + .destroy = global_destroy, + .bind = global_bind, +}; + struct pw_module * pw_core_find_module(struct pw_core *core, const char *filename) { struct pw_module *module; @@ -235,11 +249,12 @@ pw_module_load(struct pw_core *core, this->global = pw_global_new(core, core->type.module, PW_VERSION_MODULE, properties, - module_bind_func, this); + this); if (this->global == NULL) goto no_global; + pw_global_add_listener(this->global, &this->global_listener, &global_events, this); pw_global_register(this->global, owner, parent); this->info.id = this->global->id; @@ -296,8 +311,11 @@ void pw_module_destroy(struct pw_module *module) free((char *) module->info.args); spa_list_remove(&module->link); - if (module->global) + + if (module->global) { + spa_hook_remove(&module->global_listener); pw_global_destroy(module->global); + } dlclose(impl->hnd); free(impl); } diff --git a/src/pipewire/node.c b/src/pipewire/node.c index 5c2ad753b..03d9de9df 100644 --- a/src/pipewire/node.c +++ b/src/pipewire/node.c @@ -288,12 +288,12 @@ static const struct pw_resource_events resource_events = { .destroy = node_unbind_func, }; -static int -node_bind_func(struct pw_global *global, - struct pw_client *client, uint32_t permissions, - uint32_t version, uint32_t id) +static void +global_bind(void *_data, struct pw_client *client, uint32_t permissions, + uint32_t version, uint32_t id) { - struct pw_node *this = global->object; + struct pw_node *this = _data; + struct pw_global *global = this->global; struct pw_resource *resource; struct resource_data *data; @@ -311,14 +311,13 @@ node_bind_func(struct pw_global *global, this->info.change_mask = ~0; pw_node_resource_info(resource, &this->info); this->info.change_mask = 0; - - return 0; + return; no_mem: pw_log_error("can't create node resource"); pw_core_resource_error(client->core_resource, client->core_resource->id, -ENOMEM, "no memory"); - return -ENOMEM; + return; } static int @@ -332,6 +331,20 @@ do_node_add(struct spa_loop *loop, return 0; } +static void global_destroy(void *data) +{ + struct pw_node *this = data; + spa_hook_remove(&this->global_listener); + this->global = NULL; + pw_node_destroy(this); +} + +static const struct pw_global_events global_events = { + PW_VERSION_GLOBAL_EVENTS, + .destroy = global_destroy, + .bind = global_bind, +}; + int pw_node_register(struct pw_node *this, struct pw_client *owner, struct pw_global *parent, @@ -339,34 +352,44 @@ int pw_node_register(struct pw_node *this, { struct pw_core *core = this->core; const char *str; + struct pw_port *port; pw_log_debug("node %p: register", this); - update_port_ids(this); - update_info(this); - - pw_loop_invoke(this->data_loop, do_node_add, 1, NULL, 0, false, this); - if (properties == NULL) properties = pw_properties_new(NULL, NULL); if (properties == NULL) return -ENOMEM; + update_port_ids(this); + update_info(this); + + pw_loop_invoke(this->data_loop, do_node_add, 1, NULL, 0, false, this); + if ((str = pw_properties_get(this->properties, "media.class")) != NULL) pw_properties_set(properties, "media.class", str); pw_properties_set(properties, "node.name", this->info.name); spa_list_append(&core->node_list, &this->link); + this->registered = true; + this->global = pw_global_new(core, core->type.node, PW_VERSION_NODE, properties, - node_bind_func, this); + this); if (this->global == NULL) return -ENOMEM; + pw_global_add_listener(this->global, &this->global_listener, &global_events, this); + pw_global_register(this->global, owner, parent); this->info.id = this->global->id; + spa_list_for_each(port, &this->input_ports, link) + pw_port_register(port, owner, this->global, pw_properties_copy(port->properties)); + spa_list_for_each(port, &this->output_ports, link) + pw_port_register(port, owner, this->global, pw_properties_copy(port->properties)); + spa_hook_list_call(&this->listener_list, struct pw_node_events, initialized); pw_node_update_state(this, PW_NODE_STATE_SUSPENDED, NULL); @@ -593,11 +616,14 @@ void pw_node_destroy(struct pw_node *node) pw_log_debug("node %p: destroy", impl); spa_hook_list_call(&node->listener_list, struct pw_node_events, destroy); - if (node->global) { + if (node->registered) { pw_loop_invoke(node->data_loop, do_node_remove, 1, NULL, 0, true, node); spa_list_remove(&node->link); + } + + if (node->global) { + spa_hook_remove(&node->global_listener); pw_global_destroy(node->global); - node->global = NULL; } spa_list_for_each_safe(resource, tmp, &node->resource_list, link) diff --git a/src/pipewire/pipewire.c b/src/pipewire/pipewire.c index 68c821b9f..ce9588968 100644 --- a/src/pipewire/pipewire.c +++ b/src/pipewire/pipewire.c @@ -121,8 +121,6 @@ load_interface(struct support_info *info, fprintf(stderr, "can't get %s interface %d\n", type, res); goto interface_failed; } - fprintf(stderr, "loaded interface %s from %s\n", type, factory_name); - return iface; interface_failed: diff --git a/src/pipewire/port.c b/src/pipewire/port.c index 48d08938d..a4d342710 100644 --- a/src/pipewire/port.c +++ b/src/pipewire/port.c @@ -284,6 +284,47 @@ static int make_control(void *data, struct spa_pod *param) return 0; } +static void +global_bind(void *_data, struct pw_client *client, uint32_t permissions, + uint32_t version, uint32_t id) +{ + return; +} + +static void global_destroy(void *object) +{ + struct pw_port *port = object; + spa_hook_remove(&port->global_listener); + port->global = NULL; + pw_port_destroy(port); +} + +static const struct pw_global_events global_events = { + PW_VERSION_GLOBAL_EVENTS, + .destroy = global_destroy, + .bind = global_bind, +}; + +int pw_port_register(struct pw_port *port, + struct pw_client *owner, + struct pw_global *parent, + struct pw_properties *properties) +{ + struct pw_node *node = port->node; + struct pw_core *core = node->core; + + port->global = pw_global_new(core, + core->type.port, PW_VERSION_PORT, + properties, + port); + if (port->global == NULL) + return -ENOMEM; + + pw_global_add_listener(port->global, &port->global_listener, &global_events, port); + + return pw_global_register(port->global, owner, parent); +} + int pw_port_add(struct pw_port *port, struct pw_node *node) { uint32_t port_id = port->port_id; @@ -314,13 +355,13 @@ int pw_port_add(struct pw_port *port, struct pw_node *node) pw_log_debug("port %p: add to node %p %08x", port, node, port->info->flags); if (port->direction == PW_DIRECTION_INPUT) { - spa_list_insert(&node->input_ports, &port->link); + spa_list_append(&node->input_ports, &port->link); pw_map_insert_at(&node->input_port_map, port_id, port); node->info.n_input_ports++; node->info.change_mask |= PW_NODE_CHANGE_MASK_INPUT_PORTS; } else { - spa_list_insert(&node->output_ports, &port->link); + spa_list_append(&node->output_ports, &port->link); pw_map_insert_at(&node->output_port_map, port_id, port); node->info.n_output_ports++; node->info.change_mask |= PW_NODE_CHANGE_MASK_OUTPUT_PORTS; @@ -335,6 +376,10 @@ int pw_port_add(struct pw_port *port, struct pw_node *node) node->core->type.io.Buffers, port->rt.port.io, sizeof(*port->rt.port.io)); + if (node->global) + pw_port_register(port, node->global->owner, node->global, + pw_properties_copy(port->properties)); + port->rt.graph = node->rt.graph; pw_loop_invoke(node->data_loop, do_add_port, SPA_ID_INVALID, NULL, 0, false, port); @@ -373,6 +418,11 @@ void pw_port_destroy(struct pw_port *port) spa_hook_list_call(&port->listener_list, struct pw_port_events, destroy); + if (port->global) { + spa_hook_remove(&port->global_listener); + pw_global_destroy(port->global); + } + if (node) { if (port->rt.graph) pw_loop_invoke(port->node->data_loop, do_remove_port, diff --git a/src/pipewire/private.h b/src/pipewire/private.h index 20f725caa..dcc7f8ad8 100644 --- a/src/pipewire/private.h +++ b/src/pipewire/private.h @@ -78,6 +78,8 @@ struct pw_client { struct pw_core *core; /**< core object */ struct spa_list link; /**< link in core object client list */ struct pw_global *global; /**< global object created for this client */ + struct spa_hook global_listener; + bool registered; pw_permission_func_t permission_func; /**< get permissions of an object */ void *permission_data; /**< data passed to permission function */ @@ -117,15 +119,17 @@ struct pw_global { struct pw_properties *properties; /**< properties of the global */ + struct spa_hook_list listener_list; + uint32_t type; /**< type of interface */ uint32_t version; /**< version of interface */ - pw_bind_func_t bind; /**< function to bind to the interface */ void *object; /**< object associated with the interface */ }; struct pw_core { struct pw_global *global; /**< the global of the core */ + struct spa_hook global_listener; struct pw_core_info info; /**< info about the core */ @@ -189,6 +193,8 @@ struct pw_link { struct pw_core *core; /**< core object */ struct spa_list link; /**< link in core link_list */ struct pw_global *global; /**< global for this link */ + struct spa_hook global_listener; + bool registered; struct pw_link_info info; /**< introspectable link info */ struct pw_properties *properties; /**< extra link properties */ @@ -224,6 +230,7 @@ struct pw_module { struct pw_core *core; /**< the core object */ struct spa_list link; /**< link in the core module_list */ struct pw_global *global; /**< global object for this module */ + struct spa_hook global_listener; struct pw_module_info info; /**< introspectable module info */ @@ -238,6 +245,8 @@ struct pw_node { struct pw_core *core; /**< core object */ struct spa_list link; /**< link in core node_list */ struct pw_global *global; /**< global for this node */ + struct spa_hook global_listener; + bool registered; struct pw_properties *properties; /**< properties of the node */ @@ -277,6 +286,9 @@ struct pw_port { struct spa_list link; /**< link in node port_list */ struct pw_node *node; /**< owner node */ + struct pw_global *global; /**< global for this port */ + struct spa_hook global_listener; + bool registered; enum pw_direction direction; /**< port direction */ uint32_t port_id; /**< port id */ @@ -394,6 +406,7 @@ struct pw_factory { struct pw_core *core; /**< the core */ struct spa_list link; /**< link in core node_factory_list */ struct pw_global *global; /**< global for this factory */ + struct spa_hook global_listener; struct pw_factory_info info; /**< introspectable factory info */ struct pw_properties *properties; /**< properties of the factory */ @@ -462,6 +475,11 @@ pw_port_new(enum pw_direction direction, struct pw_properties *properties, size_t user_data_size); +int pw_port_register(struct pw_port *port, + struct pw_client *owner, + struct pw_global *parent, + struct pw_properties *properties); + /** Get the user data of a port, the size of the memory was given \ref in pw_port_new */ void * pw_port_get_user_data(struct pw_port *port); diff --git a/src/pipewire/type.c b/src/pipewire/type.c index da2083137..89c9b3c25 100644 --- a/src/pipewire/type.c +++ b/src/pipewire/type.c @@ -42,6 +42,7 @@ int pw_type_init(struct pw_type *type) type->core = spa_type_map_get_id(type->map, PW_TYPE_INTERFACE__Core); type->registry = spa_type_map_get_id(type->map, PW_TYPE_INTERFACE__Registry); type->node = spa_type_map_get_id(type->map, PW_TYPE_INTERFACE__Node); + type->port = spa_type_map_get_id(type->map, PW_TYPE_INTERFACE__Port); type->factory = spa_type_map_get_id(type->map, PW_TYPE_INTERFACE__Factory); type->link = spa_type_map_get_id(type->map, PW_TYPE_INTERFACE__Link); type->client = spa_type_map_get_id(type->map, PW_TYPE_INTERFACE__Client); diff --git a/src/pipewire/type.h b/src/pipewire/type.h index 5bf7ad0d8..6c4b75298 100644 --- a/src/pipewire/type.h +++ b/src/pipewire/type.h @@ -54,6 +54,7 @@ struct pw_type { uint32_t core; uint32_t registry; uint32_t node; + uint32_t port; uint32_t factory; uint32_t link; uint32_t client;