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_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

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);
}
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
};

View file

@ -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;
}

View file

@ -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

View file

@ -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],

View file

@ -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

View file

@ -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

View file

@ -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
};

View file

@ -30,21 +30,28 @@ extern "C" {
#include <pipewire/server/core.h>
#include <pipewire/server/client.h>
/**
* 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__)

View file

@ -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
};