From 6c000229f05f5ea578b72e5d2fc0c26622fc1971 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 15 Feb 2018 17:49:04 +0100 Subject: [PATCH] port: add port globals Expose all ports as globals, linking is then done by specifying the global id of the ports. Add method to destroy objects. not much security on this one but yet but it should allow priviledged clients to kill connections and other clients etc. Make events on the global object. Implement the bind with the event, handle destroy of the globals. Add link properties Use append to preserve the order. --- src/modules/module-link-factory.c | 18 ++++-- .../module-protocol-native/protocol-native.c | 33 +++++++++- src/pipewire/client.c | 36 ++++++++--- src/pipewire/core.c | 63 ++++++++++++++----- src/pipewire/factory.c | 29 ++++++--- src/pipewire/global.c | 31 ++++----- src/pipewire/global.h | 31 ++++++--- src/pipewire/interfaces.h | 49 ++++++++++++++- src/pipewire/introspect.h | 4 ++ src/pipewire/link.c | 49 ++++++++++++--- src/pipewire/mem.c | 2 +- src/pipewire/module.c | 34 +++++++--- src/pipewire/node.c | 58 ++++++++++++----- src/pipewire/pipewire.c | 2 - src/pipewire/port.c | 54 +++++++++++++++- src/pipewire/private.h | 20 +++++- src/pipewire/type.c | 1 + src/pipewire/type.h | 1 + 18 files changed, 416 insertions(+), 99 deletions(-) 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;