mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-10-31 22:25:38 -04:00
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.
This commit is contained in:
parent
b86f141273
commit
6c000229f0
18 changed files with 416 additions and 99 deletions
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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 = {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -55,12 +55,24 @@ struct pw_global;
|
|||
#include <pipewire/client.h>
|
||||
#include <pipewire/properties.h>
|
||||
|
||||
/** 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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue