Add resource override method

Add an easy way to override a resource implementation and use this in
the flatpak module.
Add more methods
This commit is contained in:
Wim Taymans 2017-08-08 15:01:36 +02:00
parent 77e326bf6d
commit 6b6b827a3b
18 changed files with 323 additions and 179 deletions

View file

@ -67,18 +67,23 @@ static inline void spa_list_remove(struct spa_list *elem)
#define spa_list_last(item, type, member) \ #define spa_list_last(item, type, member) \
SPA_CONTAINER_OF((head)->prev, type, member) SPA_CONTAINER_OF((head)->prev, type, member)
#define spa_list_for_each(pos, head, member) \ #define spa_list_for_each_next(pos, head, curr, member) \
for (pos = SPA_CONTAINER_OF((head)->next, __typeof__(*pos), member); \ for (pos = SPA_CONTAINER_OF((curr)->next, __typeof__(*pos), member); \
&pos->member != (head); \ &pos->member != (head); \
pos = SPA_CONTAINER_OF(pos->member.next, __typeof__(*pos), member)) pos = SPA_CONTAINER_OF(pos->member.next, __typeof__(*pos), member))
#define spa_list_for_each_safe(pos, tmp, head, member) \ #define spa_list_for_each(pos, head, member) \
for (pos = SPA_CONTAINER_OF((head)->next, __typeof__(*pos), member), \ spa_list_for_each_next(pos, head, head, member) \
#define spa_list_for_each_safe_next(pos, tmp, head, curr, member) \
for (pos = SPA_CONTAINER_OF((curr)->next, __typeof__(*pos), member), \
tmp = SPA_CONTAINER_OF((pos)->member.next, __typeof__(*tmp), member); \ tmp = SPA_CONTAINER_OF((pos)->member.next, __typeof__(*tmp), member); \
&pos->member != (head); \ &pos->member != (head); \
pos = tmp, \ pos = tmp, \
tmp = SPA_CONTAINER_OF(pos->member.next, __typeof__(*tmp), member)) tmp = SPA_CONTAINER_OF(pos->member.next, __typeof__(*tmp), member))
#define spa_list_for_each_safe(pos, tmp, head, member) \
spa_list_for_each_safe_next(pos, tmp, head, head, member) \
#ifdef __cplusplus #ifdef __cplusplus
} /* extern "C" */ } /* extern "C" */

View file

@ -33,7 +33,6 @@
#include "spa/lib/format.h" #include "spa/lib/format.h"
#include "pipewire/pipewire.h" #include "pipewire/pipewire.h"
#include "pipewire/private.h"
#include "pipewire/interfaces.h" #include "pipewire/interfaces.h"
#include "pipewire/core.h" #include "pipewire/core.h"
@ -1136,7 +1135,11 @@ struct pw_client_node *pw_client_node_new(struct pw_resource *resource,
{ {
struct impl *impl; struct impl *impl;
struct pw_client_node *this; struct pw_client_node *this;
struct pw_core *core = resource->client->core; struct pw_client *client = pw_resource_get_client(resource);
struct pw_core *core = pw_client_get_core(client);
const struct spa_support *support;
uint32_t n_support;
impl = calloc(1, sizeof(struct impl)); impl = calloc(1, sizeof(struct impl));
if (impl == NULL) if (impl == NULL)
@ -1149,7 +1152,9 @@ struct pw_client_node *pw_client_node_new(struct pw_resource *resource,
impl->fds[0] = impl->fds[1] = -1; impl->fds[0] = impl->fds[1] = -1;
pw_log_debug("client-node %p: new", impl); pw_log_debug("client-node %p: new", impl);
proxy_init(&impl->proxy, NULL, core->support, core->n_support); support = pw_core_get_support(impl->core, &n_support);
proxy_init(&impl->proxy, NULL, support, n_support);
impl->proxy.impl = impl; impl->proxy.impl = impl;
this->resource = resource; this->resource = resource;

View file

@ -25,7 +25,6 @@
#include "pipewire/interfaces.h" #include "pipewire/interfaces.h"
#include "pipewire/protocol.h" #include "pipewire/protocol.h"
#include "pipewire/client.h" #include "pipewire/client.h"
#include "pipewire/private.h"
#include "extensions/protocol-native.h" #include "extensions/protocol-native.h"
#include "extensions/client-node.h" #include "extensions/client-node.h"

View file

@ -30,7 +30,6 @@
#include <dbus/dbus.h> #include <dbus/dbus.h>
#include "pipewire/interfaces.h" #include "pipewire/interfaces.h"
#include "pipewire/private.h"
#include "pipewire/utils.h" #include "pipewire/utils.h"
#include "pipewire/core.h" #include "pipewire/core.h"
@ -38,6 +37,7 @@
struct impl { struct impl {
struct pw_core *core; struct pw_core *core;
struct pw_type *type;
struct pw_properties *properties; struct pw_properties *properties;
DBusConnection *bus; DBusConnection *bus;
@ -54,9 +54,8 @@ struct client_info {
struct spa_list link; struct spa_list link;
struct pw_client *client; struct pw_client *client;
bool is_sandboxed; bool is_sandboxed;
bool in_override; struct pw_resource *core_resource;
const struct pw_core_proxy_methods *old_methods; struct pw_listener core_override;
struct pw_core_proxy_methods core_methods;
struct spa_list async_pending; struct spa_list async_pending;
struct pw_listener client_listener; struct pw_listener client_listener;
}; };
@ -153,15 +152,20 @@ static bool client_is_sandboxed(struct pw_client *cl)
bool result; bool result;
int fd; int fd;
pid_t pid; pid_t pid;
const struct ucred *ucred;
if (cl->ucred_valid) { return true;
pw_log_info("client has trusted pid %d", cl->ucred.pid);
ucred = pw_client_get_ucred(cl);
if (ucred) {
pw_log_info("client has trusted pid %d", ucred->pid);
} else { } else {
pw_log_info("no trusted pid found, assuming not sandboxed\n"); pw_log_info("no trusted pid found, assuming not sandboxed\n");
return false; return false;
} }
pid = cl->ucred.pid; pid = ucred->pid;
sprintf(data, "/proc/%u/cgroup", pid); sprintf(data, "/proc/%u/cgroup", pid);
fd = open(data, O_RDONLY | O_CLOEXEC, 0); fd = open(data, O_RDONLY | O_CLOEXEC, 0);
@ -206,34 +210,47 @@ static bool client_is_sandboxed(struct pw_client *cl)
static bool static bool
check_global_owner(struct pw_core *core, struct pw_client *client, struct pw_global *global) check_global_owner(struct pw_core *core, struct pw_client *client, struct pw_global *global)
{ {
struct pw_client *owner;
const struct ucred *owner_ucred, *client_ucred;
if (global == NULL) if (global == NULL)
return false; return false;
if (global->owner == NULL) owner = pw_global_get_owner(global);
if (owner == NULL)
return true; return true;
if (global->owner->ucred.uid == client->ucred.uid) owner_ucred = pw_client_get_ucred(owner);
client_ucred = pw_client_get_ucred(client);
if (owner_ucred == NULL || client_ucred == NULL)
return true; return true;
return false; return owner_ucred->uid == client_ucred->uid;
} }
static uint32_t static uint32_t
do_permission(struct pw_global *global, struct pw_client *client, void *data) do_permission(struct pw_global *global, struct pw_client *client, void *data)
{ {
if (global->type == client->core->type.link) { struct impl *impl = data;
struct pw_link *link = global->object;
if (pw_global_get_type(global) == impl->type->link) {
struct pw_link *link = pw_global_get_object(global);
struct pw_port *port;
struct pw_node *node;
port = pw_link_get_output(link);
node = pw_port_get_node(port);
/* we must be able to see both nodes */ /* we must be able to see both nodes */
if (link->output if (port && node && !check_global_owner(impl->core, client, pw_node_get_global(node)))
&& !check_global_owner(client->core, client, link->output->node->global))
return 0; return 0;
if (link->input port = pw_link_get_input(link);
&& !check_global_owner(client->core, client, link->input->node->global)) node = pw_port_get_node(port);
if (port && node && !check_global_owner(impl->core, client, pw_node_get_global(node)))
return 0; return 0;
} }
else if (!check_global_owner(client->core, client, global)) else if (!check_global_owner(impl->core, client, global))
return 0; return 0;
return PW_PERM_RWX; return PW_PERM_RWX;
@ -268,7 +285,10 @@ portal_response(DBusConnection *connection, DBusMessage *msg, void *user_data)
pw_log_debug("portal check result: %d", response); pw_log_debug("portal check result: %d", response);
if (response == 0) { if (response == 0) {
cinfo->old_methods->create_node (p->resource, pw_resource_do_parent(cinfo->core_resource,
&cinfo->core_override,
struct pw_core_proxy_methods,
create_node,
p->factory_name, p->factory_name,
p->name, p->name,
p->type, p->type,
@ -276,8 +296,7 @@ portal_response(DBusConnection *connection, DBusMessage *msg, void *user_data)
&p->properties->dict, &p->properties->dict,
p->new_id); p->new_id);
} else { } else {
pw_core_resource_error(cinfo->client->core_resource, pw_resource_error(p->resource, SPA_RESULT_NO_PERMISSION, "not allowed");
p->resource->id, SPA_RESULT_NO_PERMISSION, "not allowed");
} }
free_pending(p); free_pending(p);
@ -289,7 +308,7 @@ portal_response(DBusConnection *connection, DBusMessage *msg, void *user_data)
} }
static void do_create_node(void *object, static void do_create_node(void *data,
const char *factory_name, const char *factory_name,
const char *name, const char *name,
uint32_t type, uint32_t type,
@ -297,10 +316,9 @@ static void do_create_node(void *object,
const struct spa_dict *props, const struct spa_dict *props,
uint32_t new_id) uint32_t new_id)
{ {
struct pw_resource *resource = object; struct client_info *cinfo = data;
struct client_info *cinfo = resource->access_private;
struct impl *impl = cinfo->impl; struct impl *impl = cinfo->impl;
struct pw_client *client = resource->client; struct pw_client *client = cinfo->client;
DBusMessage *m = NULL, *r = NULL; DBusMessage *m = NULL, *r = NULL;
DBusError error; DBusError error;
pid_t pid; pid_t pid;
@ -311,7 +329,16 @@ static void do_create_node(void *object,
struct async_pending *p; struct async_pending *p;
if (!cinfo->is_sandboxed) { if (!cinfo->is_sandboxed) {
cinfo->old_methods->create_node (object, factory_name, name, type, version, props, new_id); pw_resource_do_parent(cinfo->core_resource,
&cinfo->core_override,
struct pw_core_proxy_methods,
create_node,
factory_name,
name,
type,
version,
props,
new_id);
return; return;
} }
if (strcmp(factory_name, "client-node") != 0) { if (strcmp(factory_name, "client-node") != 0) {
@ -320,6 +347,7 @@ static void do_create_node(void *object,
} }
pw_log_info("ask portal for client %p", cinfo->client); pw_log_info("ask portal for client %p", cinfo->client);
pw_client_set_busy(client, true);
dbus_error_init(&error); dbus_error_init(&error);
@ -330,7 +358,7 @@ static void do_create_node(void *object,
device = "camera"; device = "camera";
pid = cinfo->client->ucred.pid; pid = pw_client_get_ucred(cinfo->client)->pid;
if (!dbus_message_append_args(m, DBUS_TYPE_UINT32, &pid, DBUS_TYPE_INVALID)) if (!dbus_message_append_args(m, DBUS_TYPE_UINT32, &pid, DBUS_TYPE_INVALID))
goto message_failed; goto message_failed;
@ -364,14 +392,13 @@ static void do_create_node(void *object,
p->info = cinfo; p->info = cinfo;
p->handle = strdup(handle); p->handle = strdup(handle);
p->handled = false; p->handled = false;
p->resource = resource; p->resource = cinfo->core_resource;
p->factory_name = strdup(factory_name); p->factory_name = strdup(factory_name);
p->name = strdup(name); p->name = strdup(name);
p->type = type; p->type = type;
p->version = version; p->version = version;
p->properties = props ? pw_properties_new_dict(props) : NULL; p->properties = props ? pw_properties_new_dict(props) : NULL;
p->new_id = new_id; p->new_id = new_id;
pw_client_set_busy(client, true);
pw_log_debug("pending %p: handle %s", p, handle); pw_log_debug("pending %p: handle %s", p, handle);
spa_list_insert(cinfo->async_pending.prev, &p->link); spa_list_insert(cinfo->async_pending.prev, &p->link);
@ -399,13 +426,12 @@ static void do_create_node(void *object,
dbus_error_free(&error); dbus_error_free(&error);
goto not_allowed; goto not_allowed;
not_allowed: not_allowed:
pw_core_resource_error(client->core_resource, pw_resource_error(cinfo->core_resource, SPA_RESULT_NO_PERMISSION, "not allowed");
resource->id, SPA_RESULT_NO_PERMISSION, "not allowed");
return; return;
} }
static void static void
do_create_link(void *object, do_create_link(void *data,
uint32_t output_node_id, uint32_t output_node_id,
uint32_t output_port_id, uint32_t output_port_id,
uint32_t input_node_id, uint32_t input_node_id,
@ -414,16 +440,16 @@ do_create_link(void *object,
const struct spa_dict *props, const struct spa_dict *props,
uint32_t new_id) uint32_t new_id)
{ {
struct pw_resource *resource = object; struct client_info *cinfo = data;
struct client_info *cinfo = resource->access_private;
struct pw_client *client = resource->client;
if (cinfo->is_sandboxed) { if (cinfo->is_sandboxed) {
pw_core_resource_error(client->core_resource, pw_resource_error(cinfo->core_resource, SPA_RESULT_NO_PERMISSION, "not allowed");
resource->id, SPA_RESULT_NO_PERMISSION, "not allowed");
return; return;
} }
cinfo->old_methods->create_link (object, pw_resource_do_parent(cinfo->core_resource,
&cinfo->core_override,
struct pw_core_proxy_methods,
create_link,
output_node_id, output_node_id,
output_port_id, output_port_id,
input_node_id, input_node_id,
@ -433,29 +459,24 @@ do_create_link(void *object,
new_id); new_id);
} }
static const struct pw_core_proxy_methods core_override = {
PW_VERSION_CORE_PROXY_METHODS,
.create_node = do_create_node,
.create_link = do_create_link,
};
static void client_resource_impl(void *data, struct pw_resource *resource) static void client_resource_impl(void *data, struct pw_resource *resource)
{ {
struct client_info *cinfo = data; struct client_info *cinfo = data;
struct pw_client *client = cinfo->client; struct impl *impl = cinfo->impl;
if (resource->type == client->core->type.core) { if (pw_resource_get_type(resource) == impl->type->core) {
struct pw_listener *impl = pw_resource_get_implementation(resource); cinfo->core_resource = resource;
pw_log_debug("module %p: add core override", impl);
if (cinfo->in_override) pw_resource_add_override(resource,
return; &cinfo->core_override,
&core_override,
cinfo->old_methods = impl->events; cinfo);
cinfo->core_methods = *cinfo->old_methods;
cinfo->in_override = true;
pw_resource_set_implementation(resource,
&cinfo->core_methods,
impl->data);
cinfo->in_override = false;
resource->access_private = cinfo;
cinfo->core_methods.create_node = do_create_node;
cinfo->core_methods.create_link = do_create_link;
} }
} }
@ -469,8 +490,8 @@ core_global_added(void *data, struct pw_global *global)
{ {
struct impl *impl = data; struct impl *impl = data;
if (global->type == impl->core->type.client) { if (pw_global_get_type(global) == impl->type->client) {
struct pw_client *client = global->object; struct pw_client *client = pw_global_get_object(global);
struct client_info *cinfo; struct client_info *cinfo;
cinfo = calloc(1, sizeof(struct client_info)); cinfo = calloc(1, sizeof(struct client_info));
@ -492,8 +513,8 @@ core_global_removed(void *data, struct pw_global *global)
{ {
struct impl *impl = data; struct impl *impl = data;
if (global->type == impl->core->type.client) { if (pw_global_get_type(global) == impl->type->client) {
struct pw_client *client = global->object; struct pw_client *client = pw_global_get_object(global);
struct client_info *cinfo; struct client_info *cinfo;
if ((cinfo = find_client_info(impl, client))) if ((cinfo = find_client_info(impl, client)))
@ -514,14 +535,14 @@ static void dispatch_cb(struct spa_loop_utils *utils, struct spa_source *source,
struct impl *impl = userdata; struct impl *impl = userdata;
if (dbus_connection_dispatch(impl->bus) == DBUS_DISPATCH_COMPLETE) if (dbus_connection_dispatch(impl->bus) == DBUS_DISPATCH_COMPLETE)
pw_loop_enable_idle(impl->core->main_loop, source, false); pw_loop_enable_idle(pw_core_get_main_loop(impl->core), source, false);
} }
static void dispatch_status(DBusConnection *conn, DBusDispatchStatus status, void *userdata) static void dispatch_status(DBusConnection *conn, DBusDispatchStatus status, void *userdata)
{ {
struct impl *impl = userdata; struct impl *impl = userdata;
pw_loop_enable_idle(impl->core->main_loop, pw_loop_enable_idle(pw_core_get_main_loop(impl->core),
impl->dispatch_event, status == DBUS_DISPATCH_COMPLETE ? false : true); impl->dispatch_event, status == DBUS_DISPATCH_COMPLETE ? false : true);
} }
@ -582,7 +603,7 @@ static dbus_bool_t add_watch(DBusWatch *watch, void *userdata)
/* we dup because dbus tends to add the same fd multiple times and our epoll /* we dup because dbus tends to add the same fd multiple times and our epoll
* implementation does not like that */ * implementation does not like that */
source = pw_loop_add_io(impl->core->main_loop, source = pw_loop_add_io(pw_core_get_main_loop(impl->core),
dup(dbus_watch_get_unix_fd(watch)), dup(dbus_watch_get_unix_fd(watch)),
dbus_to_io(watch), true, handle_io_event, watch); dbus_to_io(watch), true, handle_io_event, watch);
@ -596,7 +617,7 @@ static void remove_watch(DBusWatch *watch, void *userdata)
struct spa_source *source; struct spa_source *source;
if ((source = dbus_watch_get_data(watch))) if ((source = dbus_watch_get_data(watch)))
pw_loop_destroy_source(impl->core->main_loop, source); pw_loop_destroy_source(pw_core_get_main_loop(impl->core), source);
} }
static void toggle_watch(DBusWatch *watch, void *userdata) static void toggle_watch(DBusWatch *watch, void *userdata)
@ -606,7 +627,7 @@ static void toggle_watch(DBusWatch *watch, void *userdata)
source = dbus_watch_get_data(watch); source = dbus_watch_get_data(watch);
pw_loop_update_io(impl->core->main_loop, source, dbus_to_io(watch)); pw_loop_update_io(pw_core_get_main_loop(impl->core), source, dbus_to_io(watch));
} }
static void static void
@ -636,14 +657,14 @@ static dbus_bool_t add_timeout(DBusTimeout *timeout, void *userdata)
if (!dbus_timeout_get_enabled(timeout)) if (!dbus_timeout_get_enabled(timeout))
return FALSE; return FALSE;
source = pw_loop_add_timer(impl->core->main_loop, handle_timer_event, timeout); source = pw_loop_add_timer(pw_core_get_main_loop(impl->core), handle_timer_event, timeout);
dbus_timeout_set_data(timeout, source, NULL); dbus_timeout_set_data(timeout, source, NULL);
t = dbus_timeout_get_interval(timeout) * SPA_NSEC_PER_MSEC; t = dbus_timeout_get_interval(timeout) * SPA_NSEC_PER_MSEC;
ts.tv_sec = t / SPA_NSEC_PER_SEC; ts.tv_sec = t / SPA_NSEC_PER_SEC;
ts.tv_nsec = t % SPA_NSEC_PER_SEC; ts.tv_nsec = t % SPA_NSEC_PER_SEC;
pw_loop_update_timer(impl->core->main_loop, source, &ts, NULL, false); pw_loop_update_timer(pw_core_get_main_loop(impl->core), source, &ts, NULL, false);
return TRUE; return TRUE;
} }
@ -653,7 +674,7 @@ static void remove_timeout(DBusTimeout *timeout, void *userdata)
struct spa_source *source; struct spa_source *source;
if ((source = dbus_timeout_get_data(timeout))) if ((source = dbus_timeout_get_data(timeout)))
pw_loop_destroy_source(impl->core->main_loop, source); pw_loop_destroy_source(pw_core_get_main_loop(impl->core), source);
} }
static void toggle_timeout(DBusTimeout *timeout, void *userdata) static void toggle_timeout(DBusTimeout *timeout, void *userdata)
@ -672,18 +693,19 @@ static void toggle_timeout(DBusTimeout *timeout, void *userdata)
} else { } else {
tsp = NULL; tsp = NULL;
} }
pw_loop_update_timer(impl->core->main_loop, source, tsp, NULL, false); pw_loop_update_timer(pw_core_get_main_loop(impl->core), source, tsp, NULL, false);
} }
static void wakeup_main(void *userdata) static void wakeup_main(void *userdata)
{ {
struct impl *impl = userdata; struct impl *impl = userdata;
pw_loop_enable_idle(impl->core->main_loop, impl->dispatch_event, true); pw_loop_enable_idle(pw_core_get_main_loop(impl->core), impl->dispatch_event, true);
} }
static struct impl *module_new(struct pw_core *core, struct pw_properties *properties) static bool module_init(struct pw_module *module, struct pw_properties *properties)
{ {
struct pw_core *core = pw_module_get_core(module);
struct impl *impl; struct impl *impl;
DBusError error; DBusError error;
@ -693,13 +715,14 @@ static struct impl *module_new(struct pw_core *core, struct pw_properties *prope
pw_log_debug("module %p: new", impl); pw_log_debug("module %p: new", impl);
impl->core = core; impl->core = core;
impl->type = pw_core_get_type(core);
impl->properties = properties; impl->properties = properties;
impl->bus = dbus_bus_get_private(DBUS_BUS_SESSION, &error); impl->bus = dbus_bus_get_private(DBUS_BUS_SESSION, &error);
if (impl->bus == NULL) if (impl->bus == NULL)
goto error; goto error;
impl->dispatch_event = pw_loop_add_idle(core->main_loop, false, dispatch_cb, impl); impl->dispatch_event = pw_loop_add_idle(pw_core_get_main_loop(core), false, dispatch_cb, impl);
dbus_connection_set_exit_on_disconnect(impl->bus, false); dbus_connection_set_exit_on_disconnect(impl->bus, false);
dbus_connection_set_dispatch_status_function(impl->bus, dispatch_status, impl, NULL); dbus_connection_set_dispatch_status_function(impl->bus, dispatch_status, impl, NULL);
@ -713,15 +736,14 @@ static struct impl *module_new(struct pw_core *core, struct pw_properties *prope
pw_core_add_listener(core, &impl->core_listener, &core_events, impl); pw_core_add_listener(core, &impl->core_listener, &core_events, impl);
core->permission_func = do_permission; pw_core_set_permission_callback(core, do_permission, impl);
core->permission_data = impl;
return impl; return true;
error: error:
pw_log_error("Failed to connect to system bus: %s", error.message); pw_log_error("Failed to connect to system bus: %s", error.message);
dbus_error_free(&error); dbus_error_free(&error);
return NULL; return false;
} }
#if 0 #if 0
@ -737,6 +759,5 @@ static void module_destroy(struct impl *impl)
bool pipewire__module_init(struct pw_module *module, const char *args) bool pipewire__module_init(struct pw_module *module, const char *args)
{ {
module_new(module->core, NULL); return module_init(module, NULL);
return true;
} }

View file

@ -93,13 +93,14 @@ struct client_data {
int fd; int fd;
struct spa_source *source; struct spa_source *source;
struct pw_protocol_native_connection *connection; struct pw_protocol_native_connection *connection;
bool busy;
}; };
static void static void
process_messages(struct pw_client *client) process_messages(struct client_data *data)
{ {
struct client_data *data = client->user_data;
struct pw_protocol_native_connection *conn = data->connection; struct pw_protocol_native_connection *conn = data->connection;
struct pw_client *client = data->client;
uint8_t opcode; uint8_t opcode;
uint32_t id; uint32_t id;
uint32_t size; uint32_t size;
@ -108,31 +109,40 @@ process_messages(struct pw_client *client)
while (pw_protocol_native_connection_get_next(conn, &opcode, &id, &message, &size)) { while (pw_protocol_native_connection_get_next(conn, &opcode, &id, &message, &size)) {
struct pw_resource *resource; struct pw_resource *resource;
const struct pw_protocol_native_demarshal *demarshal; const struct pw_protocol_native_demarshal *demarshal;
const struct pw_protocol_marshal *marshal;
uint32_t permissions;
/* when the client is busy processing an async action, stop processing messages
* for the client until it finishes the action */
if (data->busy)
break;
pw_log_trace("protocol-native %p: got message %d from %u", client->protocol, pw_log_trace("protocol-native %p: got message %d from %u", client->protocol,
opcode, id); opcode, id);
resource = pw_map_lookup(&client->objects, id); resource = pw_client_get_resource(client, id);
if (resource == NULL) { if (resource == NULL) {
pw_log_error("protocol-native %p: unknown resource %u", pw_log_error("protocol-native %p: unknown resource %u",
client->protocol, id); client->protocol, id);
continue; continue;
} }
if ((resource->permissions & PW_PERM_X) == 0) { permissions = pw_resource_get_permissions(resource);
if ((permissions & PW_PERM_X) == 0) {
pw_log_error("protocol-native %p: execute not allowed on resource %u", pw_log_error("protocol-native %p: execute not allowed on resource %u",
client->protocol, id); client->protocol, id);
continue; continue;
} }
if (opcode >= resource->marshal->n_methods) marshal = pw_resource_get_marshal(resource);
if (marshal == NULL || opcode >= marshal->n_methods)
goto invalid_method; goto invalid_method;
demarshal = resource->marshal->method_demarshal; demarshal = marshal->method_demarshal;
if (!demarshal[opcode].func) if (!demarshal[opcode].func)
goto invalid_message; goto invalid_message;
if ((demarshal[opcode].flags & PW_PROTOCOL_NATIVE_PERM_W) && if ((demarshal[opcode].flags & PW_PROTOCOL_NATIVE_PERM_W) &&
((resource->permissions & PW_PERM_X) == 0)) { ((permissions & PW_PERM_X) == 0)) {
pw_log_error("protocol-native %p: method %u requires write access on %u", pw_log_error("protocol-native %p: method %u requires write access on %u",
client->protocol, opcode, id); client->protocol, opcode, id);
continue; continue;
@ -144,11 +154,6 @@ process_messages(struct pw_client *client)
if (!demarshal[opcode].func (resource, message, size)) if (!demarshal[opcode].func (resource, message, size))
goto invalid_message; goto invalid_message;
/* when the client is busy processing an async action, stop processing messages
* for the client until it finishes the action */
if (client->busy)
break;
} }
return; return;
@ -167,17 +172,20 @@ process_messages(struct pw_client *client)
static void static void
client_busy_changed(void *data, bool busy) client_busy_changed(void *data, bool busy)
{ {
struct pw_client *client = data; struct client_data *c = data;
struct client_data *c = client->user_data; struct pw_client *client = c->client;
enum spa_io mask = SPA_IO_ERR | SPA_IO_HUP; enum spa_io mask = SPA_IO_ERR | SPA_IO_HUP;
c->busy = busy;
if (!busy) if (!busy)
mask |= SPA_IO_IN; mask |= SPA_IO_IN;
pw_log_debug("protocol-native %p: busy changed %d", client->protocol, busy);
pw_loop_update_io(client->core->main_loop, c->source, mask); pw_loop_update_io(client->core->main_loop, c->source, mask);
if (busy) if (!busy)
process_messages(client); process_messages(c);
} }
@ -198,7 +206,8 @@ static void
connection_data(struct spa_loop_utils *utils, connection_data(struct spa_loop_utils *utils,
struct spa_source *source, int fd, enum spa_io mask, void *data) struct spa_source *source, int fd, enum spa_io mask, void *data)
{ {
struct pw_client *client = data; struct client_data *this = data;
struct pw_client *client = this->client;
if (mask & (SPA_IO_ERR | SPA_IO_HUP)) { if (mask & (SPA_IO_ERR | SPA_IO_HUP)) {
pw_log_error("protocol-native %p: got connection error", client->protocol); pw_log_error("protocol-native %p: got connection error", client->protocol);
@ -207,13 +216,13 @@ connection_data(struct spa_loop_utils *utils,
} }
if (mask & SPA_IO_IN) if (mask & SPA_IO_IN)
process_messages(client); process_messages(this);
} }
static void client_free(void *data) static void client_free(void *data)
{ {
struct pw_client *client = data; struct client_data *this = data;
struct client_data *this = client->user_data; struct pw_client *client = this->client;
pw_loop_destroy_source(client->protocol->core->main_loop, this->source); pw_loop_destroy_source(client->protocol->core->main_loop, this->source);
spa_list_remove(&client->protocol_link); spa_list_remove(&client->protocol_link);
@ -236,6 +245,7 @@ static struct pw_client *client_new(struct listener *l, int fd)
struct protocol_data *pd = protocol->user_data; struct protocol_data *pd = protocol->user_data;
socklen_t len; socklen_t len;
struct ucred ucred, *ucredp; struct ucred ucred, *ucredp;
struct pw_core *core = protocol->core;
len = sizeof(ucred); len = sizeof(ucred);
if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &len) < 0) { if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &len) < 0) {
@ -245,16 +255,20 @@ static struct pw_client *client_new(struct listener *l, int fd)
ucredp = &ucred; ucredp = &ucred;
} }
client = pw_client_new(protocol->core, pd->module->global, ucredp, NULL, sizeof(struct client_data)); client = pw_client_new(protocol->core,
pw_module_get_global(pd->module),
ucredp,
NULL,
sizeof(struct client_data));
if (client == NULL) if (client == NULL)
goto no_client; goto no_client;
this = pw_client_get_user_data(client); this = pw_client_get_user_data(client);
this->client = client; this->client = client;
this->fd = fd; this->fd = fd;
this->source = pw_loop_add_io(protocol->core->main_loop, this->source = pw_loop_add_io(pw_core_get_main_loop(core),
this->fd, this->fd,
SPA_IO_ERR | SPA_IO_HUP, false, connection_data, client); SPA_IO_ERR | SPA_IO_HUP, false, connection_data, this);
if (this->source == NULL) if (this->source == NULL)
goto no_source; goto no_source;
@ -265,14 +279,14 @@ static struct pw_client *client_new(struct listener *l, int fd)
client->protocol = protocol; client->protocol = protocol;
spa_list_insert(l->this.client_list.prev, &client->protocol_link); spa_list_insert(l->this.client_list.prev, &client->protocol_link);
pw_client_add_listener(client, &this->client_listener, &client_events, client); pw_client_add_listener(client, &this->client_listener, &client_events, this);
pw_global_bind(protocol->core->global, client, PW_PERM_RWX, PW_VERSION_CORE, 0); pw_global_bind(pw_core_get_global(core), client, PW_PERM_RWX, PW_VERSION_CORE, 0);
return client; return client;
no_connection: no_connection:
pw_loop_destroy_source(protocol->core->main_loop, this->source); pw_loop_destroy_source(pw_core_get_main_loop(core), this->source);
no_source: no_source:
pw_client_destroy(client); pw_client_destroy(client);
no_client: no_client:
@ -389,7 +403,7 @@ static bool add_socket(struct pw_protocol *protocol, struct listener *l)
return false; return false;
} }
l->loop = protocol->core->main_loop; l->loop = pw_core_get_main_loop(protocol->core);
l->source = pw_loop_add_io(l->loop, l->fd, SPA_IO_IN, false, socket_data, l); l->source = pw_loop_add_io(l->loop, l->fd, SPA_IO_IN, false, socket_data, l);
if (l->source == NULL) if (l->source == NULL)
return false; return false;
@ -398,7 +412,7 @@ static bool add_socket(struct pw_protocol *protocol, struct listener *l)
} }
static const char * static const char *
get_name(struct pw_properties *properties) get_name(const struct pw_properties *properties)
{ {
const char *name = NULL; const char *name = NULL;
@ -459,10 +473,11 @@ on_remote_data(struct spa_loop_utils *utils,
struct connection *impl = data; struct connection *impl = data;
struct pw_remote *this = impl->this.remote; struct pw_remote *this = impl->this.remote;
struct pw_protocol_native_connection *conn = impl->connection; struct pw_protocol_native_connection *conn = impl->connection;
struct pw_core *core = pw_remote_get_core(this);
if (mask & (SPA_IO_ERR | SPA_IO_HUP)) { if (mask & (SPA_IO_ERR | SPA_IO_HUP)) {
pw_log_error("protocol-native %p: got connection error", impl); pw_log_error("protocol-native %p: got connection error", impl);
pw_loop_destroy_source(this->core->main_loop, impl->source); pw_loop_destroy_source(pw_core_get_main_loop(core), impl->source);
impl->source = NULL; impl->source = NULL;
pw_remote_update_state(this, PW_REMOTE_STATE_ERROR, "connection error"); pw_remote_update_state(this, PW_REMOTE_STATE_ERROR, "connection error");
return; return;
@ -478,21 +493,25 @@ on_remote_data(struct spa_loop_utils *utils,
&& pw_protocol_native_connection_get_next(conn, &opcode, &id, &message, &size)) { && pw_protocol_native_connection_get_next(conn, &opcode, &id, &message, &size)) {
struct pw_proxy *proxy; struct pw_proxy *proxy;
const struct pw_protocol_native_demarshal *demarshal; const struct pw_protocol_native_demarshal *demarshal;
const struct pw_protocol_marshal *marshal;
pw_log_trace("protocol-native %p: got message %d from %u", this, opcode, id); pw_log_trace("protocol-native %p: got message %d from %u", this, opcode, id);
proxy = pw_map_lookup(&this->objects, id); proxy = pw_remote_get_proxy(this, id);
if (proxy == NULL || proxy->marshal == NULL) {
if (proxy == NULL) {
pw_log_error("protocol-native %p: could not find proxy %u", this, id); pw_log_error("protocol-native %p: could not find proxy %u", this, id);
continue; continue;
} }
if (opcode >= proxy->marshal->n_events) {
marshal = pw_proxy_get_marshal(proxy);
if (marshal == NULL || opcode >= marshal->n_events) {
pw_log_error("protocol-native %p: invalid method %u for %u", this, opcode, pw_log_error("protocol-native %p: invalid method %u for %u", this, opcode,
id); id);
continue; continue;
} }
demarshal = proxy->marshal->event_demarshal; demarshal = marshal->event_demarshal;
if (!demarshal[opcode].func) { if (!demarshal[opcode].func) {
pw_log_error("protocol-native %p: function %d not implemented on %u", this, pw_log_error("protocol-native %p: function %d not implemented on %u", this,
opcode, id); opcode, id);
@ -665,7 +684,7 @@ impl_add_listener(struct pw_protocol *protocol,
spa_list_init(&this->client_list); spa_list_init(&this->client_list);
this->destroy = destroy_listener; this->destroy = destroy_listener;
name = get_name(core->properties); name = get_name(pw_core_get_properties(core));
if (!init_socket_name(l, name)) if (!init_socket_name(l, name))
goto error; goto error;
@ -679,7 +698,7 @@ impl_add_listener(struct pw_protocol *protocol,
spa_list_insert(protocol->listener_list.prev, &this->link); spa_list_insert(protocol->listener_list.prev, &this->link);
l->hooks.before = on_before_hook; l->hooks.before = on_before_hook;
pw_loop_add_hooks(protocol->core->main_loop, &l->hooks); pw_loop_add_hooks(pw_core_get_main_loop(core), &l->hooks);
pw_log_info("protocol-native %p: Added listener %p", protocol, this); pw_log_info("protocol-native %p: Added listener %p", protocol, this);
@ -761,7 +780,7 @@ const static struct pw_protocol_native_ext protocol_ext_impl = {
static bool module_init(struct pw_module *module, struct pw_properties *properties) static bool module_init(struct pw_module *module, struct pw_properties *properties)
{ {
struct pw_core *core = module->core; struct pw_core *core = pw_module_get_core(module);
struct pw_protocol *this; struct pw_protocol *this;
const char *val; const char *val;
struct protocol_data *d; struct protocol_data *d;
@ -783,7 +802,7 @@ static bool module_init(struct pw_module *module, struct pw_properties *properti
d = pw_protocol_get_user_data(this); d = pw_protocol_get_user_data(this);
d->module = module; d->module = module;
if ((val = pw_properties_get(core->properties, "pipewire.daemon"))) { if ((val = pw_properties_get(pw_core_get_properties(core), "pipewire.daemon"))) {
if (atoi(val) == 1) if (atoi(val) == 1)
impl_add_listener(this, core, properties); impl_add_listener(this, core, properties);
} }

View file

@ -189,13 +189,13 @@ static void update_monitor(struct pw_core *core, const char *name)
{ {
const char *monitors; const char *monitors;
struct spa_dict_item item; struct spa_dict_item item;
const struct spa_dict *props; const struct pw_properties *props;
struct spa_dict dict = SPA_DICT_INIT(1, &item); struct spa_dict dict = SPA_DICT_INIT(1, &item);
props = pw_core_get_properties(core); props = pw_core_get_properties(core);
if (props) if (props)
monitors = spa_dict_lookup(props, "monitors"); monitors = pw_properties_get(props, "monitors");
else else
monitors = NULL; monitors = NULL;

View file

@ -76,8 +76,7 @@ client_bind_func(struct pw_global *global,
no_mem: no_mem:
pw_log_error("can't create client resource"); pw_log_error("can't create client resource");
pw_core_resource_error(client->core_resource, pw_resource_error(client->core_resource, SPA_RESULT_NO_MEMORY, "no memory");
client->core_resource->id, SPA_RESULT_NO_MEMORY, "no memory");
return SPA_RESULT_NO_MEMORY; return SPA_RESULT_NO_MEMORY;
} }
@ -135,6 +134,16 @@ struct pw_core *pw_client_get_core(struct pw_client *client)
return client->core; return client->core;
} }
struct pw_resource *pw_client_get_core_resource(struct pw_client *client)
{
return client->core_resource;
}
struct pw_resource *pw_client_get_resource(struct pw_client *client, uint32_t id)
{
return pw_map_lookup(&client->objects, id);
}
struct pw_global *pw_client_get_global(struct pw_client *client) struct pw_global *pw_client_get_global(struct pw_client *client)
{ {
return client->global; return client->global;
@ -250,6 +259,7 @@ void pw_client_update_properties(struct pw_client *client, const struct spa_dict
void pw_client_set_busy(struct pw_client *client, bool busy) void pw_client_set_busy(struct pw_client *client, bool busy)
{ {
if (client->busy != busy) { if (client->busy != busy) {
pw_log_debug("client %p: busy %d", client, busy);
client->busy = busy; client->busy = busy;
pw_listener_list_emit(&client->listener_list, struct pw_client_events, busy_changed, busy); pw_listener_list_emit(&client->listener_list, struct pw_client_events, busy_changed, busy);
} }

View file

@ -81,25 +81,37 @@ struct pw_client;
* See also \ref page_resource * See also \ref page_resource
*/ */
/** The events that a client can emit */
struct pw_client_events { struct pw_client_events {
#define PW_VERSION_CLIENT_EVENTS 0 #define PW_VERSION_CLIENT_EVENTS 0
uint32_t version; uint32_t version;
/** emited when the client is destroyed */
void (*destroy) (void *data); void (*destroy) (void *data);
/** emited right before the client is freed */
void (*free) (void *data); void (*free) (void *data);
/** emited when the client info changed */
void (*info_changed) (void *data, struct pw_client_info *info); void (*info_changed) (void *data, struct pw_client_info *info);
/** emited when a new resource is added for client */
void (*resource_added) (void *data, struct pw_resource *resource); void (*resource_added) (void *data, struct pw_resource *resource);
/** emited when an implementation is set on a resource. This can
* be used to override the implementation */
void (*resource_impl) (void *data, struct pw_resource *resource); void (*resource_impl) (void *data, struct pw_resource *resource);
/** emited when a resource is removed */
void (*resource_removed) (void *data, struct pw_resource *resource); void (*resource_removed) (void *data, struct pw_resource *resource);
/** emited when the client becomes busy processing an asynchronous
* message. In the busy state no messages should be processed.
* Processing should resume when the client becomes not busy */
void (*busy_changed) (void *data, bool busy); void (*busy_changed) (void *data, bool busy);
}; };
/** Create a new client. This is mainly used by protocols. */
struct pw_client * struct pw_client *
pw_client_new(struct pw_core *core, pw_client_new(struct pw_core *core,
struct pw_global *parent, struct pw_global *parent,
@ -109,12 +121,20 @@ pw_client_new(struct pw_core *core,
void pw_client_destroy(struct pw_client *client); void pw_client_destroy(struct pw_client *client);
struct pw_core *pw_client_get_core(struct pw_client *client); const struct pw_client_info *pw_client_get_info(struct pw_client *client);
struct pw_global *pw_client_get_global(struct pw_client *client); void pw_client_update_properties(struct pw_client *client, const struct spa_dict *dict);
const struct pw_properties *pw_client_get_properties(struct pw_client *client); const struct pw_properties *pw_client_get_properties(struct pw_client *client);
struct pw_core *pw_client_get_core(struct pw_client *client);
struct pw_resource *pw_client_get_core_resource(struct pw_client *client);
struct pw_resource *pw_client_get_resource(struct pw_client *client, uint32_t id);
struct pw_global *pw_client_get_global(struct pw_client *client);
const struct ucred *pw_client_get_ucred(struct pw_client *client); const struct ucred *pw_client_get_ucred(struct pw_client *client);
void *pw_client_get_user_data(struct pw_client *client); void *pw_client_get_user_data(struct pw_client *client);
@ -125,10 +145,6 @@ void pw_client_add_listener(struct pw_client *client,
void *data); void *data);
const struct pw_client_info *pw_client_get_info(struct pw_client *client);
void pw_client_update_properties(struct pw_client *client, const struct spa_dict *dict);
/** Mark the client busy. This can be used when an asynchronous operation is /** Mark the client busy. This can be used when an asynchronous operation is
* started and no further processing is allowed to happen for the client */ * started and no further processing is allowed to happen for the client */
void pw_client_set_busy(struct pw_client *client, bool busy); void pw_client_set_busy(struct pw_client *client, bool busy);

View file

@ -500,14 +500,30 @@ pw_core_add_global(struct pw_core *core,
return this; return this;
} }
const struct pw_core_info *pw_core_get_info(struct pw_core *core)
{
return &core->info;
}
struct pw_global *pw_core_get_global(struct pw_core *core)
{
return core->global;
}
struct pw_core *pw_global_get_core(struct pw_global *global) struct pw_core *pw_global_get_core(struct pw_global *global)
{ {
return global->core; return global->core;
} }
const struct pw_core_info *pw_core_get_info(struct pw_core *core)
struct pw_client *pw_global_get_owner(struct pw_global *global)
{ {
return &core->info; return global->owner;
}
struct pw_global *pw_global_get_parent(struct pw_global *global)
{
return global->parent;
} }
uint32_t pw_global_get_type(struct pw_global *global) uint32_t pw_global_get_type(struct pw_global *global)
@ -610,6 +626,14 @@ void pw_core_add_listener(struct pw_core *core,
pw_listener_list_add(&core->listener_list, listener, events, data); pw_listener_list_add(&core->listener_list, listener, events, data);
} }
void pw_core_set_permission_callback(struct pw_core *core,
pw_permission_func_t callback,
void *data)
{
core->permission_func = callback;
core->permission_data = data;
}
struct pw_type *pw_core_get_type(struct pw_core *core) struct pw_type *pw_core_get_type(struct pw_core *core)
{ {
return &core->type; return &core->type;
@ -626,9 +650,9 @@ struct pw_loop *pw_core_get_main_loop(struct pw_core *core)
return core->main_loop; return core->main_loop;
} }
const struct spa_dict *pw_core_get_properties(struct pw_core *core) const struct pw_properties *pw_core_get_properties(struct pw_core *core)
{ {
return &core->properties->dict; return core->properties;
} }
/** Update core properties /** Update core properties

View file

@ -162,11 +162,17 @@ void pw_core_add_listener(struct pw_core *core,
const struct pw_core_events *events, const struct pw_core_events *events,
void *data); void *data);
void pw_core_set_permission_callback(struct pw_core *core,
pw_permission_func_t callback,
void *data);
struct pw_type *pw_core_get_type(struct pw_core *core); struct pw_type *pw_core_get_type(struct pw_core *core);
const struct pw_core_info *pw_core_get_info(struct pw_core *core); const struct pw_core_info *pw_core_get_info(struct pw_core *core);
const struct spa_dict *pw_core_get_properties(struct pw_core *core); struct pw_global *pw_core_get_global(struct pw_core *core);
const struct pw_properties *pw_core_get_properties(struct pw_core *core);
const struct spa_support *pw_core_get_support(struct pw_core *core, uint32_t *n_support); const struct spa_support *pw_core_get_support(struct pw_core *core, uint32_t *n_support);

View file

@ -57,16 +57,26 @@ static inline void pw_listener_remove(struct pw_listener *listener)
spa_list_remove(&listener->link); spa_list_remove(&listener->link);
} }
#define pw_listener_list_emit(l,type,method,...) ({ \ #define pw_listener_list_do_emit(l,start,type,method,once,...) ({ \
struct pw_listener_list *list = l; \ struct pw_listener_list *list = l; \
struct spa_list *s = start ? (struct spa_list *)start : &list->list; \
struct pw_listener *ci, *t; \ struct pw_listener *ci, *t; \
spa_list_for_each_safe(ci, t, &list->list, link) { \ spa_list_for_each_safe_next(ci, t, &list->list, s, link) { \
const type *cb = ci->events; \ const type *cb = ci->events; \
if (cb->method) \ if (cb->method) { \
cb->method(ci->data, ## __VA_ARGS__); \ cb->method(ci->data, ## __VA_ARGS__); \
if (once) \
break; \
} \
} \ } \
}); });
#define pw_listener_list_emit(l,t,m,...) pw_listener_list_do_emit(l,NULL,t,m,false,##__VA_ARGS__)
#define pw_listener_list_emit_once(l,t,m,...) pw_listener_list_do_emit(l,NULL,t,m,true,##__VA_ARGS__)
#define pw_listener_list_emit_start(l,s,t,m,...) pw_listener_list_do_emit(l,s,t,m,false,##__VA_ARGS__)
#define pw_listener_list_emit_once_start(l,s,t,m,...) pw_listener_list_do_emit(l,s,t,m,true,##__VA_ARGS__)
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View file

@ -270,7 +270,7 @@ struct pw_resource {
uint32_t version; /**< version of the client interface */ uint32_t version; /**< version of the client interface */
struct pw_listener implementation; struct pw_listener implementation;
struct pw_listener_list implementation_list;
struct pw_listener_list listener_list; struct pw_listener_list listener_list;
const struct pw_protocol_marshal *marshal; const struct pw_protocol_marshal *marshal;

View file

@ -132,7 +132,7 @@ struct pw_listener_list *pw_proxy_get_proxy_listeners(struct pw_proxy *proxy)
return &proxy->proxy_listener_list; return &proxy->proxy_listener_list;
} }
const void *pw_proxy_get_proxy_implementation(struct pw_proxy *proxy) const struct pw_protocol_marshal *pw_proxy_get_marshal(struct pw_proxy *proxy)
{ {
return proxy->marshal->method_marshal; return proxy->marshal;
} }

View file

@ -86,9 +86,10 @@ struct pw_remote;
*/ */
struct pw_proxy; struct pw_proxy;
#include <pipewire/type.h>
#include <pipewire/utils.h> #include <pipewire/utils.h>
#include <pipewire/listener.h> #include <pipewire/core.h>
#include <pipewire/client.h>
#include <pipewire/protocol.h>
struct pw_proxy_events { struct pw_proxy_events {
#define PW_VERSION_PROXY_EVENTS 0 #define PW_VERSION_PROXY_EVENTS 0
@ -125,10 +126,10 @@ struct pw_protocol *pw_proxy_get_protocol(struct pw_proxy *proxy);
struct pw_listener_list *pw_proxy_get_proxy_listeners(struct pw_proxy *proxy); struct pw_listener_list *pw_proxy_get_proxy_listeners(struct pw_proxy *proxy);
const void *pw_proxy_get_proxy_implementation(struct pw_proxy *proxy); const struct pw_protocol_marshal *pw_proxy_get_marshal(struct pw_proxy *proxy);
#define pw_proxy_notify(p,type,event,...) pw_listener_list_emit(pw_proxy_get_proxy_listeners(p),type,event,## __VA_ARGS__) #define pw_proxy_notify(p,type,event,...) pw_listener_list_emit(pw_proxy_get_proxy_listeners(p),type,event,## __VA_ARGS__)
#define pw_proxy_do(p,type,method,...) ((type*) pw_proxy_get_proxy_implementation(p))->method(p, ## __VA_ARGS__) #define pw_proxy_do(p,type,method,...) ((type*) pw_proxy_get_marshal(p)->method_marshal)->method(p, ## __VA_ARGS__)
#ifdef __cplusplus #ifdef __cplusplus
} }

View file

@ -337,6 +337,11 @@ const struct pw_core_info *pw_remote_get_core_info(struct pw_remote *remote)
return remote->info; return remote->info;
} }
struct pw_proxy *pw_remote_get_proxy(struct pw_remote *remote, uint32_t id)
{
return pw_map_lookup(&remote->objects, id);
}
int pw_remote_connect(struct pw_remote *remote) int pw_remote_connect(struct pw_remote *remote)
{ {
int res; int res;

View file

@ -168,6 +168,8 @@ struct pw_core_proxy * pw_remote_get_core_proxy(struct pw_remote *remote);
/** Get the remote core info, can only be called when connected */ /** Get the remote core info, can only be called when connected */
const struct pw_core_info *pw_remote_get_core_info(struct pw_remote *remote); const struct pw_core_info *pw_remote_get_core_info(struct pw_remote *remote);
struct pw_proxy *pw_remote_get_proxy(struct pw_remote *remote, uint32_t id);
/** Disconnect from the remote PipeWire. \memberof pw_remote */ /** Disconnect from the remote PipeWire. \memberof pw_remote */
void pw_remote_disconnect(struct pw_remote *remote); void pw_remote_disconnect(struct pw_remote *remote);

View file

@ -51,6 +51,7 @@ struct pw_resource *pw_resource_new(struct pw_client *client,
this->type = type; this->type = type;
this->version = version; this->version = version;
pw_listener_list_init(&this->implementation_list);
pw_listener_list_init(&this->listener_list); pw_listener_list_init(&this->listener_list);
if (id == SPA_ID_INVALID) { if (id == SPA_ID_INVALID) {
@ -64,6 +65,7 @@ struct pw_resource *pw_resource_new(struct pw_client *client,
this->user_data = SPA_MEMBER(impl, sizeof(struct impl), void); this->user_data = SPA_MEMBER(impl, sizeof(struct impl), void);
this->marshal = pw_protocol_get_marshal(client->protocol, type); this->marshal = pw_protocol_get_marshal(client->protocol, type);
pw_listener_list_add(&this->implementation_list, &this->implementation, NULL, NULL);
pw_log_debug("resource %p: new for client %p id %u", this, client, id); pw_log_debug("resource %p: new for client %p id %u", this, client, id);
pw_listener_list_emit(&client->listener_list, struct pw_client_events, resource_added, this); pw_listener_list_emit(&client->listener_list, struct pw_client_events, resource_added, this);
@ -91,6 +93,11 @@ uint32_t pw_resource_get_permissions(struct pw_resource *resource)
return resource->permissions; return resource->permissions;
} }
uint32_t pw_resource_get_type(struct pw_resource *resource)
{
return resource->type;
}
struct pw_protocol *pw_resource_get_protocol(struct pw_resource *resource) struct pw_protocol *pw_resource_get_protocol(struct pw_resource *resource)
{ {
return resource->client->protocol; return resource->client->protocol;
@ -121,14 +128,24 @@ void pw_resource_set_implementation(struct pw_resource *resource,
pw_listener_list_emit(&client->listener_list, struct pw_client_events, resource_impl, resource); pw_listener_list_emit(&client->listener_list, struct pw_client_events, resource_impl, resource);
} }
struct pw_listener *pw_resource_get_implementation(struct pw_resource *resource) void pw_resource_add_override(struct pw_resource *resource,
struct pw_listener *listener,
const void *implementation,
void *data)
{ {
return &resource->implementation; listener->events = implementation;
listener->data = data;
spa_list_insert(&resource->implementation_list.list, &listener->link);
} }
const void *pw_resource_get_proxy_notify(struct pw_resource *resource) struct pw_listener_list *pw_resource_get_implementation(struct pw_resource *resource)
{ {
return resource->marshal->event_marshal; return &resource->implementation_list;
}
const struct pw_protocol_marshal *pw_resource_get_marshal(struct pw_resource *resource)
{
return resource->marshal;
} }
void pw_resource_error(struct pw_resource *resource, int result, const char *error) void pw_resource_error(struct pw_resource *resource, int result, const char *error)

View file

@ -84,6 +84,8 @@ uint32_t pw_resource_get_id(struct pw_resource *resource);
uint32_t pw_resource_get_permissions(struct pw_resource *resource); uint32_t pw_resource_get_permissions(struct pw_resource *resource);
uint32_t pw_resource_get_type(struct pw_resource *resource);
struct pw_protocol *pw_resource_get_protocol(struct pw_resource *resource); struct pw_protocol *pw_resource_get_protocol(struct pw_resource *resource);
void *pw_resource_get_user_data(struct pw_resource *resource); void *pw_resource_get_user_data(struct pw_resource *resource);
@ -97,20 +99,22 @@ void pw_resource_set_implementation(struct pw_resource *resource,
const void *implementation, const void *implementation,
void *data); void *data);
void pw_resource_add_override(struct pw_resource *resource,
struct pw_listener *listener,
const void *implementation,
void *data);
void pw_resource_error(struct pw_resource *resource, int result, const char *error); void pw_resource_error(struct pw_resource *resource, int result, const char *error);
struct pw_listener *pw_resource_get_implementation(struct pw_resource *resource); struct pw_listener_list *pw_resource_get_implementation(struct pw_resource *resource);
const void *pw_resource_get_proxy_notify(struct pw_resource *resource); const struct pw_protocol_marshal *pw_resource_get_marshal(struct pw_resource *resource);
#define pw_resource_do(r,type,method,...) ({ \ #define pw_resource_do(r,type,method,...) pw_listener_list_emit_once(pw_resource_get_implementation(r),type,method,## __VA_ARGS__)
struct pw_listener *l = pw_resource_get_implementation(r); \
const type *cb = l->events; \
if (cb->method) \
cb->method(l->data, ## __VA_ARGS__); \
});
#define pw_resource_notify(r,type,event,...) ((type*) pw_resource_get_proxy_notify(r))->event(r, ## __VA_ARGS__) #define pw_resource_do_parent(r,l,type,method,...) pw_listener_list_emit_once_start(pw_resource_get_implementation(r),l,type,method,## __VA_ARGS__)
#define pw_resource_notify(r,type,event,...) ((type*) pw_resource_get_marshal(r)->event_marshal)->event(r, ## __VA_ARGS__)
#ifdef __cplusplus #ifdef __cplusplus
} }