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.
This commit is contained in:
Wim Taymans 2017-06-02 12:38:11 +02:00
parent c3aa0f24d2
commit d50847ef6d
10 changed files with 114 additions and 163 deletions

View file

@ -53,9 +53,8 @@ extern "C" {
#define PW_CORE_METHOD_GET_REGISTRY 2 #define PW_CORE_METHOD_GET_REGISTRY 2
#define PW_CORE_METHOD_CLIENT_UPDATE 3 #define PW_CORE_METHOD_CLIENT_UPDATE 3
#define PW_CORE_METHOD_CREATE_NODE 4 #define PW_CORE_METHOD_CREATE_NODE 4
#define PW_CORE_METHOD_CREATE_CLIENT_NODE 5 #define PW_CORE_METHOD_CREATE_LINK 5
#define PW_CORE_METHOD_CREATE_LINK 6 #define PW_CORE_METHOD_NUM 6
#define PW_CORE_METHOD_NUM 7
/** /**
* \struct pw_core_methods * \struct pw_core_methods
@ -103,7 +102,9 @@ struct pw_core_methods {
*/ */
void (*client_update) (void *object, const struct spa_dict *props); 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 factory_name the factory name to use
* \param name the node name * \param name the node name
@ -115,18 +116,6 @@ struct pw_core_methods {
const char *name, const char *name,
const struct spa_dict *props, const struct spa_dict *props,
uint32_t new_id); 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 * 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_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_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_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_do_create_link(r,...) ((struct pw_core_methods*)r->iface->methods)->create_link(r,__VA_ARGS__)
#define PW_CORE_EVENT_UPDATE_TYPES 0 #define PW_CORE_EVENT_UPDATE_TYPES 0

View file

@ -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); 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 static void
core_marshal_create_link(void *object, core_marshal_create_link(void *object,
uint32_t output_node_id, 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_get_registry,
&core_marshal_client_update, &core_marshal_client_update,
&core_marshal_create_node, &core_marshal_create_node,
&core_marshal_create_client_node,
&core_marshal_create_link &core_marshal_create_link
}; };

View file

@ -956,9 +956,10 @@ pw_stream_connect(struct pw_stream *stream,
impl->node_proxy->user_data = stream; impl->node_proxy->user_data = stream;
impl->node_proxy->implementation = &client_node_events; impl->node_proxy->implementation = &client_node_events;
pw_core_do_create_client_node(stream->context->core_proxy, pw_core_do_create_node(stream->context->core_proxy,
"client-node", "client-node",
&stream->properties->dict, impl->node_proxy->id); "client-node",
&stream->properties->dict, impl->node_proxy->id);
return true; return true;
} }

View file

@ -4,4 +4,5 @@ load-module libpipewire-module-suspend-on-idle
load-module libpipewire-module-spa --pattern snow load-module libpipewire-module-spa --pattern snow
load-module libpipewire-module-autolink load-module libpipewire-module-autolink
#load-module libpipewire-module-mixer #load-module libpipewire-module-mixer
load-module libpipewire-module-client-node
load-module libpipewire-module-flatpak load-module libpipewire-module-flatpak

View file

@ -33,6 +33,15 @@ pipewire_module_mixer = shared_library('pipewire-module-mixer', [ 'module-mixer.
dependencies : [mathlib, dl_lib, pipewire_dep, pipewirecore_dep], 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 ], #pipewire_module_protocol_dbus = shared_library('pipewire-module-protocol-dbus', [ 'module-protocol-dbus.c', gdbus_target ],
# c_args : pipewire_module_c_args, # c_args : pipewire_module_c_args,
# include_directories : [configinc, spa_inc], # include_directories : [configinc, spa_inc],

View file

@ -242,24 +242,6 @@ do_view_global(struct pw_access *access, struct pw_client *client, struct pw_glo
return SPA_RESULT_OK; 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 static DBusHandlerResult
portal_response(DBusConnection *connection, DBusMessage *msg, void *user_data) portal_response(DBusConnection *connection, DBusMessage *msg, void *user_data)
{ {
@ -299,9 +281,11 @@ portal_response(DBusConnection *connection, DBusMessage *msg, void *user_data)
} }
static int static int
do_create_client_node(struct pw_access *access, do_create_node(struct pw_access *access,
struct pw_access_data *data, struct pw_access_data *data,
const char *name, struct pw_properties *properties) const char *factory_name,
const char *name,
struct pw_properties *properties)
{ {
struct impl *impl = SPA_CONTAINER_OF(access, struct impl, access); struct impl *impl = SPA_CONTAINER_OF(access, struct impl, access);
struct client_info *cinfo = find_client_info(impl, data->resource->client); 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); data->complete_cb(data);
return SPA_RESULT_OK; 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); 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; 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 = { static struct pw_access access_checks = {
do_view_global, do_view_global,
do_create_node, do_create_node,
do_create_client_node, do_create_link,
}; };
static void static void

View file

@ -54,9 +54,14 @@ struct pw_access {
struct pw_access_data *data, struct pw_access_data *data,
const char *factory_name, const char *factory_name,
const char *name, struct pw_properties *properties); const char *name, struct pw_properties *properties);
int (*create_client_node) (struct pw_access *access, int (*create_link) (struct pw_access *access,
struct pw_access_data *data, struct pw_access_data *data,
const char *name, struct pw_properties *properties); 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 #ifdef __cplusplus

View file

@ -38,8 +38,9 @@ struct impl {
struct spa_support support[4]; struct spa_support support[4];
}; };
struct access_create_client_node { struct access_create_node {
struct pw_access_data data; struct pw_access_data data;
char *factory_name;
char *name; char *name;
struct pw_properties *properties; struct pw_properties *properties;
uint32_t new_id; 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"); resource->id, SPA_RESULT_NO_MEMORY, "no memory");
} }
static void static void *async_create_node_copy(struct pw_access_data *data, size_t size)
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 access_create_node *d;
struct pw_client *client = resource->client;
pw_core_notify_error(client->core_resource, d = calloc(1, sizeof(struct access_create_node) + size);
resource->id, SPA_RESULT_NOT_IMPLEMENTED, "not implemented"); memcpy(d, data, sizeof(struct access_create_node));
} d->factory_name = strdup(d->factory_name);
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->name = strdup(d->name); d->name = strdup(d->name);
d->async = true; 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; 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->async) {
if (d->data.free_cb) 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_resource *resource = d->data.resource;
struct pw_client *client = resource->client; struct pw_client *client = resource->client;
struct pw_client_node *node; struct pw_node_factory *factory;
int res;
int readfd, writefd;
if (data->res != SPA_RESULT_OK) if (data->res != SPA_RESULT_OK)
goto denied; goto denied;
node = pw_client_node_new(client, d->new_id, d->name, d->properties); factory = pw_core_find_node_factory(client->core, d->factory_name);
if (node == NULL) if (factory == NULL)
goto no_mem; goto no_factory;
if ((res = pw_client_node_get_fds(node, &readfd, &writefd)) < 0) { /* error will be posted */
pw_core_notify_error(client->core_resource, pw_node_factory_create_node(factory, client, d->name, d->properties, d->new_id);
resource->id, SPA_RESULT_ERROR, "can't get data fds");
return;
}
pw_client_node_notify_done(node->resource, readfd, writefd);
goto done; goto done;
no_mem: no_factory:
pw_log_error("can't create client node"); pw_log_error("can't find node factory");
pw_core_notify_error(client->core_resource, 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; goto done;
denied: denied:
pw_log_error("create client node refused"); pw_log_error("create node refused");
pw_core_notify_error(client->core_resource, pw_core_notify_error(client->core_resource,
resource->id, SPA_RESULT_NO_PERMISSION, "operation not allowed"); resource->id, SPA_RESULT_NO_PERMISSION, "operation not allowed");
done: done:
async_create_client_node_free(&d->data); async_create_node_free(&d->data);
return; return;
} }
static void static void
core_create_client_node(void *object, core_create_node(void *object,
const char *name, const struct spa_dict *props, uint32_t new_id) const char *factory_name,
const char *name,
const struct spa_dict *props,
uint32_t new_id)
{ {
struct pw_resource *resource = object; struct pw_resource *resource = object;
struct pw_client *client = resource->client; struct pw_client *client = resource->client;
int i; int i;
struct pw_properties *properties; struct pw_properties *properties;
struct access_create_client_node access_data; struct access_create_node access_data;
int res; int res;
properties = pw_properties_new(NULL, NULL); properties = pw_properties_new(NULL, NULL);
@ -237,9 +224,10 @@ core_create_client_node(void *object,
} }
access_data.data.resource = resource; access_data.data.resource = resource;
access_data.data.async_copy = async_create_client_node_copy; access_data.data.async_copy = async_create_node_copy;
access_data.data.complete_cb = async_create_client_node_complete; access_data.data.complete_cb = async_create_node_complete;
access_data.data.free_cb = NULL; access_data.data.free_cb = NULL;
access_data.factory_name = (char *) factory_name;
access_data.name = (char *) name; access_data.name = (char *) name;
access_data.properties = properties; access_data.properties = properties;
access_data.new_id = new_id; access_data.new_id = new_id;
@ -247,13 +235,16 @@ core_create_client_node(void *object,
if (client->core->access) { if (client->core->access) {
access_data.data.res = SPA_RESULT_NO_PERMISSION; access_data.data.res = SPA_RESULT_NO_PERMISSION;
res = client->core->access->create_client_node(client->core->access, res = client->core->access->create_node(client->core->access,
&access_data.data, name, properties); &access_data.data,
factory_name,
name,
properties);
} else { } else {
res = access_data.data.res = SPA_RESULT_OK; res = access_data.data.res = SPA_RESULT_OK;
} }
if (!SPA_RESULT_IS_ASYNC(res)) if (!SPA_RESULT_IS_ASYNC(res))
async_create_client_node_complete(&access_data.data); async_create_node_complete(&access_data.data);
return; return;
no_mem: no_mem:
@ -301,7 +292,6 @@ static struct pw_core_methods core_methods = {
&core_get_registry, &core_get_registry,
&core_client_update, &core_client_update,
&core_create_node, &core_create_node,
&core_create_client_node,
&core_create_link &core_create_link
}; };

View file

@ -30,21 +30,28 @@ extern "C" {
#include <pipewire/server/core.h> #include <pipewire/server/core.h>
#include <pipewire/server/client.h> #include <pipewire/server/client.h>
/** /** \class pw_node_factory
* 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_node_factory {
struct pw_core *core; struct pw_core *core; /**< the core */
struct spa_list link; struct spa_list link; /**< link in core node_factory_list */
struct pw_global *global; 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_node *(*create_node) (struct pw_node_factory *factory,
struct pw_client *client, 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__) #define pw_node_factory_create_node(f,...) (f)->create_node((f),__VA_ARGS__)

View file

@ -248,34 +248,6 @@ static bool core_demarshal_create_node(void *object, void *data, size_t size)
return true; 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) static bool core_demarshal_create_link(void *object, void *data, size_t size)
{ {
struct pw_resource *resource = object; 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_get_registry,
&core_demarshal_client_update, &core_demarshal_client_update,
&core_demarshal_create_node, &core_demarshal_create_node,
&core_demarshal_create_client_node,
&core_demarshal_create_link &core_demarshal_create_link
}; };