mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-11-08 13:30:08 -05:00
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:
parent
c3aa0f24d2
commit
d50847ef6d
10 changed files with 114 additions and 163 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -956,7 +956,8 @@ 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,
|
||||
pw_core_do_create_node(stream->context->core_proxy,
|
||||
"client-node",
|
||||
"client-node",
|
||||
&stream->properties->dict, impl->node_proxy->id);
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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],
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
do_create_node(struct pw_access *access,
|
||||
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 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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
int (*create_link) (struct pw_access *access,
|
||||
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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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__)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue