From d50847ef6d1b121cb72f268f35cae0336c686e49 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 2 Jun 2017 12:38:11 +0200 Subject: [PATCH] Make client-node with a factory Register a new factory to make client nodes. Create client nodes with the more generic node_factory. We can then remove the messages and interfaces. --- pipewire/client/interfaces.h | 22 ++------ pipewire/client/protocol-native.c | 33 ------------ pipewire/client/stream.c | 7 +-- pipewire/daemon/pipewire.conf.in | 1 + pipewire/modules/meson.build | 9 ++++ pipewire/modules/module-flatpak.c | 56 ++++++++++++-------- pipewire/server/access.h | 11 ++-- pipewire/server/core.c | 86 ++++++++++++++----------------- pipewire/server/node-factory.h | 23 ++++++--- pipewire/server/protocol-native.c | 29 ----------- 10 files changed, 114 insertions(+), 163 deletions(-) diff --git a/pipewire/client/interfaces.h b/pipewire/client/interfaces.h index 4cc048a5e..01e8c3cb2 100644 --- a/pipewire/client/interfaces.h +++ b/pipewire/client/interfaces.h @@ -53,9 +53,8 @@ extern "C" { #define PW_CORE_METHOD_GET_REGISTRY 2 #define PW_CORE_METHOD_CLIENT_UPDATE 3 #define PW_CORE_METHOD_CREATE_NODE 4 -#define PW_CORE_METHOD_CREATE_CLIENT_NODE 5 -#define PW_CORE_METHOD_CREATE_LINK 6 -#define PW_CORE_METHOD_NUM 7 +#define PW_CORE_METHOD_CREATE_LINK 5 +#define PW_CORE_METHOD_NUM 6 /** * \struct pw_core_methods @@ -103,7 +102,9 @@ struct pw_core_methods { */ void (*client_update) (void *object, const struct spa_dict *props); /** - * Create a new node on the PipeWire server from a factory + * Create a new node on the PipeWire server from a factory. + * Use a \a fectory_name of "client-node" to create a + * \ref pw_client_node. * * \param factory_name the factory name to use * \param name the node name @@ -115,18 +116,6 @@ struct pw_core_methods { const char *name, const struct spa_dict *props, uint32_t new_id); - /** - * Create a new node on the server. The node can be controlled - * with the client node interface. - * - * \param name the node name - * \param props extra properties - * \param new_id the client proxy id - */ - void (*create_client_node) (void *object, - const char *name, - const struct spa_dict *props, - uint32_t new_id); /** * Create a new link between two node ports * @@ -153,7 +142,6 @@ struct pw_core_methods { #define pw_core_do_get_registry(r,...) ((struct pw_core_methods*)r->iface->methods)->get_registry(r,__VA_ARGS__) #define pw_core_do_client_update(r,...) ((struct pw_core_methods*)r->iface->methods)->client_update(r,__VA_ARGS__) #define pw_core_do_create_node(r,...) ((struct pw_core_methods*)r->iface->methods)->create_node(r,__VA_ARGS__) -#define pw_core_do_create_client_node(r,...) ((struct pw_core_methods*)r->iface->methods)->create_client_node(r,__VA_ARGS__) #define pw_core_do_create_link(r,...) ((struct pw_core_methods*)r->iface->methods)->create_link(r,__VA_ARGS__) #define PW_CORE_EVENT_UPDATE_TYPES 0 diff --git a/pipewire/client/protocol-native.c b/pipewire/client/protocol-native.c index 76456e099..97ef68aa9 100644 --- a/pipewire/client/protocol-native.c +++ b/pipewire/client/protocol-native.c @@ -161,38 +161,6 @@ core_marshal_create_node(void *object, pw_connection_end_write(connection, proxy->id, PW_CORE_METHOD_CREATE_NODE, b.b.offset); } -static void -core_marshal_create_client_node(void *object, - const char *name, const struct spa_dict *props, uint32_t new_id) -{ - struct pw_proxy *proxy = object; - struct pw_connection *connection = proxy->context->protocol_private; - struct builder b = { {NULL, 0, 0, NULL, write_pod}, connection }; - struct spa_pod_frame f; - uint32_t i, n_items; - - if (connection == NULL) - return; - - core_update_map(proxy->context); - - n_items = props ? props->n_items : 0; - - spa_pod_builder_add(&b.b, - SPA_POD_TYPE_STRUCT, &f, - SPA_POD_TYPE_STRING, name, SPA_POD_TYPE_INT, n_items, 0); - - for (i = 0; i < n_items; i++) { - spa_pod_builder_add(&b.b, - SPA_POD_TYPE_STRING, props->items[i].key, - SPA_POD_TYPE_STRING, props->items[i].value, 0); - } - spa_pod_builder_add(&b.b, SPA_POD_TYPE_INT, new_id, -SPA_POD_TYPE_STRUCT, &f, 0); - - pw_connection_end_write(connection, proxy->id, PW_CORE_METHOD_CREATE_CLIENT_NODE, - b.b.offset); -} - static void core_marshal_create_link(void *object, uint32_t output_node_id, @@ -942,7 +910,6 @@ static const struct pw_core_methods pw_protocol_native_client_core_methods = { &core_marshal_get_registry, &core_marshal_client_update, &core_marshal_create_node, - &core_marshal_create_client_node, &core_marshal_create_link }; diff --git a/pipewire/client/stream.c b/pipewire/client/stream.c index c789634e0..92a7f83b7 100644 --- a/pipewire/client/stream.c +++ b/pipewire/client/stream.c @@ -956,9 +956,10 @@ pw_stream_connect(struct pw_stream *stream, impl->node_proxy->user_data = stream; impl->node_proxy->implementation = &client_node_events; - pw_core_do_create_client_node(stream->context->core_proxy, - "client-node", - &stream->properties->dict, impl->node_proxy->id); + pw_core_do_create_node(stream->context->core_proxy, + "client-node", + "client-node", + &stream->properties->dict, impl->node_proxy->id); return true; } diff --git a/pipewire/daemon/pipewire.conf.in b/pipewire/daemon/pipewire.conf.in index 79949cb9d..2a4b8412b 100644 --- a/pipewire/daemon/pipewire.conf.in +++ b/pipewire/daemon/pipewire.conf.in @@ -4,4 +4,5 @@ load-module libpipewire-module-suspend-on-idle load-module libpipewire-module-spa --pattern snow load-module libpipewire-module-autolink #load-module libpipewire-module-mixer +load-module libpipewire-module-client-node load-module libpipewire-module-flatpak diff --git a/pipewire/modules/meson.build b/pipewire/modules/meson.build index bb8143bc4..420949e75 100644 --- a/pipewire/modules/meson.build +++ b/pipewire/modules/meson.build @@ -33,6 +33,15 @@ pipewire_module_mixer = shared_library('pipewire-module-mixer', [ 'module-mixer. dependencies : [mathlib, dl_lib, pipewire_dep, pipewirecore_dep], ) +pipewire_module_client_node = shared_library('pipewire-module-client-node', [ 'module-client-node.c' ], + c_args : pipewire_module_c_args, + include_directories : [configinc, spa_inc], + link_with : spalib, + install : true, + install_dir : modules_install_dir, + dependencies : [mathlib, dl_lib, pipewire_dep, pipewirecore_dep], +) + #pipewire_module_protocol_dbus = shared_library('pipewire-module-protocol-dbus', [ 'module-protocol-dbus.c', gdbus_target ], # c_args : pipewire_module_c_args, # include_directories : [configinc, spa_inc], diff --git a/pipewire/modules/module-flatpak.c b/pipewire/modules/module-flatpak.c index 3ad2c74cb..3154e7702 100644 --- a/pipewire/modules/module-flatpak.c +++ b/pipewire/modules/module-flatpak.c @@ -242,24 +242,6 @@ do_view_global(struct pw_access *access, struct pw_client *client, struct pw_glo return SPA_RESULT_OK; } -static int -do_create_node(struct pw_access *access, - struct pw_access_data *data, - const char *factory_name, const char *name, struct pw_properties *properties) -{ - struct impl *impl = SPA_CONTAINER_OF(access, struct impl, access); - struct client_info *cinfo = find_client_info(impl, data->resource->client); - - if (cinfo->is_sandboxed) - data->res = SPA_RESULT_NO_PERMISSION; - else - data->res = SPA_RESULT_OK; - - data->complete_cb(data); - return SPA_RESULT_OK; -} - - static DBusHandlerResult portal_response(DBusConnection *connection, DBusMessage *msg, void *user_data) { @@ -299,9 +281,11 @@ portal_response(DBusConnection *connection, DBusMessage *msg, void *user_data) } static int -do_create_client_node(struct pw_access *access, - struct pw_access_data *data, - const char *name, struct pw_properties *properties) +do_create_node(struct pw_access *access, + struct pw_access_data *data, + const char *factory_name, + const char *name, + struct pw_properties *properties) { struct impl *impl = SPA_CONTAINER_OF(access, struct impl, access); struct client_info *cinfo = find_client_info(impl, data->resource->client); @@ -318,6 +302,11 @@ do_create_client_node(struct pw_access *access, data->complete_cb(data); return SPA_RESULT_OK; } + if (strcmp(factory_name, "client-node") != 0) { + data->res = SPA_RESULT_NO_PERMISSION; + data->complete_cb(data); + return SPA_RESULT_NO_PERMISSION; + } pw_log_info("ask portal for client %p", cinfo->client); @@ -386,10 +375,33 @@ do_create_client_node(struct pw_access *access, return SPA_RESULT_NO_PERMISSION; } +static int +do_create_link(struct pw_access *access, + struct pw_access_data *data, + uint32_t output_node_id, + uint32_t output_port_id, + uint32_t input_node_id, + uint32_t input_port_id, + const struct spa_format *filter, + const struct pw_properties *props) +{ + struct impl *impl = SPA_CONTAINER_OF(access, struct impl, access); + struct client_info *cinfo = find_client_info(impl, data->resource->client); + + if (cinfo->is_sandboxed) + data->res = SPA_RESULT_NO_PERMISSION; + else + data->res = SPA_RESULT_OK; + + data->complete_cb(data); + return SPA_RESULT_OK; +} + + static struct pw_access access_checks = { do_view_global, do_create_node, - do_create_client_node, + do_create_link, }; static void diff --git a/pipewire/server/access.h b/pipewire/server/access.h index 6884aa6c4..400edcd3d 100644 --- a/pipewire/server/access.h +++ b/pipewire/server/access.h @@ -54,9 +54,14 @@ struct pw_access { struct pw_access_data *data, const char *factory_name, const char *name, struct pw_properties *properties); - int (*create_client_node) (struct pw_access *access, - struct pw_access_data *data, - const char *name, struct pw_properties *properties); + int (*create_link) (struct pw_access *access, + struct pw_access_data *data, + uint32_t output_node_id, + uint32_t output_port_id, + uint32_t input_node_id, + uint32_t input_port_id, + const struct spa_format *filter, + const struct pw_properties *props); }; #ifdef __cplusplus diff --git a/pipewire/server/core.c b/pipewire/server/core.c index 0d1eaaf00..fcbacb75c 100644 --- a/pipewire/server/core.c +++ b/pipewire/server/core.c @@ -38,8 +38,9 @@ struct impl { struct spa_support support[4]; }; -struct access_create_client_node { +struct access_create_node { struct pw_access_data data; + char *factory_name; char *name; struct pw_properties *properties; uint32_t new_id; @@ -142,33 +143,22 @@ static void core_get_registry(void *object, uint32_t new_id) resource->id, SPA_RESULT_NO_MEMORY, "no memory"); } -static void -core_create_node(void *object, - const char *factory_name, - const char *name, const struct spa_dict *props, uint32_t new_id) +static void *async_create_node_copy(struct pw_access_data *data, size_t size) { - struct pw_resource *resource = object; - struct pw_client *client = resource->client; + struct access_create_node *d; - pw_core_notify_error(client->core_resource, - resource->id, SPA_RESULT_NOT_IMPLEMENTED, "not implemented"); -} - -static void *async_create_client_node_copy(struct pw_access_data *data, size_t size) -{ - struct access_create_client_node *d; - - d = calloc(1, sizeof(struct access_create_client_node) + size); - memcpy(d, data, sizeof(struct access_create_client_node)); + d = calloc(1, sizeof(struct access_create_node) + size); + memcpy(d, data, sizeof(struct access_create_node)); + d->factory_name = strdup(d->factory_name); d->name = strdup(d->name); d->async = true; - d->data.user_data = SPA_MEMBER(d, sizeof(struct access_create_client_node), void); + d->data.user_data = SPA_MEMBER(d, sizeof(struct access_create_node), void); return d; } -static void async_create_client_node_free(struct pw_access_data *data) +static void async_create_node_free(struct pw_access_data *data) { - struct access_create_client_node *d = (struct access_create_client_node *) data; + struct access_create_node *d = (struct access_create_node *) data; if (d->async) { if (d->data.free_cb) @@ -178,54 +168,51 @@ static void async_create_client_node_free(struct pw_access_data *data) } } -static void async_create_client_node_complete(struct pw_access_data *data) +static void async_create_node_complete(struct pw_access_data *data) { - struct access_create_client_node *d = (struct access_create_client_node *) data; + struct access_create_node *d = (struct access_create_node *) data; struct pw_resource *resource = d->data.resource; struct pw_client *client = resource->client; - struct pw_client_node *node; - int res; - int readfd, writefd; + struct pw_node_factory *factory; if (data->res != SPA_RESULT_OK) goto denied; - node = pw_client_node_new(client, d->new_id, d->name, d->properties); - if (node == NULL) - goto no_mem; + factory = pw_core_find_node_factory(client->core, d->factory_name); + if (factory == NULL) + goto no_factory; - if ((res = pw_client_node_get_fds(node, &readfd, &writefd)) < 0) { - pw_core_notify_error(client->core_resource, - resource->id, SPA_RESULT_ERROR, "can't get data fds"); - return; - } + /* error will be posted */ + pw_node_factory_create_node(factory, client, d->name, d->properties, d->new_id); - pw_client_node_notify_done(node->resource, readfd, writefd); goto done; - no_mem: - pw_log_error("can't create client node"); + no_factory: + pw_log_error("can't find node factory"); pw_core_notify_error(client->core_resource, - resource->id, SPA_RESULT_NO_MEMORY, "no memory"); + resource->id, SPA_RESULT_INVALID_ARGUMENTS, "unknown factory name"); goto done; denied: - pw_log_error("create client node refused"); + pw_log_error("create node refused"); pw_core_notify_error(client->core_resource, resource->id, SPA_RESULT_NO_PERMISSION, "operation not allowed"); done: - async_create_client_node_free(&d->data); + async_create_node_free(&d->data); return; } static void -core_create_client_node(void *object, - const char *name, const struct spa_dict *props, uint32_t new_id) +core_create_node(void *object, + const char *factory_name, + const char *name, + const struct spa_dict *props, + uint32_t new_id) { struct pw_resource *resource = object; struct pw_client *client = resource->client; int i; struct pw_properties *properties; - struct access_create_client_node access_data; + struct access_create_node access_data; int res; properties = pw_properties_new(NULL, NULL); @@ -237,9 +224,10 @@ core_create_client_node(void *object, } access_data.data.resource = resource; - access_data.data.async_copy = async_create_client_node_copy; - access_data.data.complete_cb = async_create_client_node_complete; + access_data.data.async_copy = async_create_node_copy; + access_data.data.complete_cb = async_create_node_complete; access_data.data.free_cb = NULL; + access_data.factory_name = (char *) factory_name; access_data.name = (char *) name; access_data.properties = properties; access_data.new_id = new_id; @@ -247,13 +235,16 @@ core_create_client_node(void *object, if (client->core->access) { access_data.data.res = SPA_RESULT_NO_PERMISSION; - res = client->core->access->create_client_node(client->core->access, - &access_data.data, name, properties); + res = client->core->access->create_node(client->core->access, + &access_data.data, + factory_name, + name, + properties); } else { res = access_data.data.res = SPA_RESULT_OK; } if (!SPA_RESULT_IS_ASYNC(res)) - async_create_client_node_complete(&access_data.data); + async_create_node_complete(&access_data.data); return; no_mem: @@ -301,7 +292,6 @@ static struct pw_core_methods core_methods = { &core_get_registry, &core_client_update, &core_create_node, - &core_create_client_node, &core_create_link }; diff --git a/pipewire/server/node-factory.h b/pipewire/server/node-factory.h index be45c4614..452357523 100644 --- a/pipewire/server/node-factory.h +++ b/pipewire/server/node-factory.h @@ -30,21 +30,28 @@ extern "C" { #include #include -/** - * pw_node_factory: +/** \class pw_node_factory * - * PipeWire node factory interface. + * \brief PipeWire node factory interface. + * + * The factory object is used to make nodes on demand. */ struct pw_node_factory { - struct pw_core *core; - struct spa_list link; - struct pw_global *global; + struct pw_core *core; /**< the core */ + struct spa_list link; /**< link in core node_factory_list */ + struct pw_global *global; /**< global for this factory */ - const char *name; + const char *name; /**< the factory name */ + /** Emited when the factory is destroyed */ + PW_SIGNAL(destroy_signal, (struct pw_listener *listener, struct pw_node_factory *object)); + + /** The function to create a node from this factory */ struct pw_node *(*create_node) (struct pw_node_factory *factory, struct pw_client *client, - const char *name, struct pw_properties *properties); + const char *name, + struct pw_properties *properties, + uint32_t new_id); }; #define pw_node_factory_create_node(f,...) (f)->create_node((f),__VA_ARGS__) diff --git a/pipewire/server/protocol-native.c b/pipewire/server/protocol-native.c index a16b0b52f..3edb0efd2 100644 --- a/pipewire/server/protocol-native.c +++ b/pipewire/server/protocol-native.c @@ -248,34 +248,6 @@ static bool core_demarshal_create_node(void *object, void *data, size_t size) return true; } -static bool core_demarshal_create_client_node(void *object, void *data, size_t size) -{ - struct pw_resource *resource = object; - struct spa_pod_iter it; - uint32_t new_id, i; - const char *name; - struct spa_dict props; - - if (!spa_pod_iter_struct(&it, data, size) || - !spa_pod_iter_get(&it, SPA_POD_TYPE_STRING, &name, SPA_POD_TYPE_INT, &props.n_items, 0)) - return false; - - props.items = alloca(props.n_items * sizeof(struct spa_dict_item)); - for (i = 0; i < props.n_items; i++) { - if (!spa_pod_iter_get(&it, - SPA_POD_TYPE_STRING, &props.items[i].key, - SPA_POD_TYPE_STRING, &props.items[i].value, 0)) - return false; - } - if (!spa_pod_iter_get(&it, SPA_POD_TYPE_INT, &new_id, 0)) - return false; - - ((struct pw_core_methods *) resource->implementation)->create_client_node(resource, - name, - &props, new_id); - return true; -} - static bool core_demarshal_create_link(void *object, void *data, size_t size) { struct pw_resource *resource = object; @@ -895,7 +867,6 @@ static const demarshal_func_t pw_protocol_native_server_core_demarshal[PW_CORE_M &core_demarshal_get_registry, &core_demarshal_client_update, &core_demarshal_create_node, - &core_demarshal_create_client_node, &core_demarshal_create_link };