From ae708c14e7b1610b86e185ef0ef90b86127a5757 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 15 Jun 2017 17:54:55 +0200 Subject: [PATCH] Improve version handling Add version numbers to protocol interfaces and implementation. Allow allocating user_data in proxy and resource Use separate methods to set implementation. Add protocol object to keep track of available protocols and interfaces. Add possibility to dynamically register interfaces. --- pipewire/client/context.c | 173 +++++++++++++--------- pipewire/client/context.h | 2 + pipewire/client/interfaces.h | 29 +++- pipewire/client/meson.build | 4 +- pipewire/client/protocol-native.c | 66 ++++++--- pipewire/client/protocol-native.h | 6 +- pipewire/client/protocol.c | 82 ++++++++++ pipewire/client/protocol.h | 67 +++++++++ pipewire/client/proxy.c | 26 +++- pipewire/client/proxy.h | 32 ++-- pipewire/client/stream.c | 19 +-- pipewire/client/subscribe.h | 3 + pipewire/client/type.c | 10 +- pipewire/client/type.h | 2 + pipewire/modules/module-autolink.c | 12 +- pipewire/modules/module-flatpak.c | 12 +- pipewire/modules/module-protocol-native.c | 54 +++---- pipewire/server/client-node.c | 12 +- pipewire/server/client-node.h | 2 +- pipewire/server/client.c | 17 ++- pipewire/server/client.h | 15 +- pipewire/server/core.c | 15 +- pipewire/server/link.c | 4 +- pipewire/server/module.c | 4 +- pipewire/server/node.c | 4 +- pipewire/server/protocol-native.c | 66 ++++++--- pipewire/server/protocol-native.h | 2 +- pipewire/server/resource.c | 34 +++-- pipewire/server/resource.h | 23 ++- 29 files changed, 572 insertions(+), 225 deletions(-) create mode 100644 pipewire/client/protocol.c create mode 100644 pipewire/client/protocol.h diff --git a/pipewire/client/context.c b/pipewire/client/context.c index 4c97b671d..2dc91c24a 100644 --- a/pipewire/client/context.c +++ b/pipewire/client/context.c @@ -27,6 +27,7 @@ #include "pipewire/client/context.h" #include "pipewire/client/introspect.h" +#include "pipewire/client/interfaces.h" #include "pipewire/client/protocol-native.h" #include "pipewire/client/connection.h" #include "pipewire/client/subscribe.h" @@ -49,6 +50,10 @@ struct context { struct pw_listener need_flush; struct spa_source *flush_event; }; + +struct proxy_data { + void *info; +}; /** \endcond */ const char *pw_context_state_as_string(enum pw_context_state state) @@ -97,15 +102,16 @@ static void core_event_info(void *object, struct pw_core_info *info) struct pw_proxy *proxy = object; struct pw_context *this = proxy->context; enum pw_subscription_event event; + struct proxy_data *data = proxy->user_data; pw_log_debug("got core info"); - if (proxy->user_data == NULL) + if (data->info == NULL) event = PW_SUBSCRIPTION_EVENT_NEW; else event = PW_SUBSCRIPTION_EVENT_CHANGE; - proxy->user_data = pw_core_info_update(proxy->user_data, info); + data->info = pw_core_info_update(data->info, info); pw_signal_emit(&this->subscription, this, event, proxy->type, proxy->id); } @@ -169,15 +175,16 @@ static void module_event_info(void *object, struct pw_module_info *info) struct pw_proxy *proxy = object; struct pw_context *this = proxy->context; enum pw_subscription_event event; + struct proxy_data *data = proxy->user_data; pw_log_debug("got module info"); - if (proxy->user_data == NULL) + if (data->info == NULL) event = PW_SUBSCRIPTION_EVENT_NEW; else event = PW_SUBSCRIPTION_EVENT_CHANGE; - proxy->user_data = pw_module_info_update(proxy->user_data, info); + data->info = pw_module_info_update(data->info, info); pw_signal_emit(&this->subscription, this, event, proxy->type, proxy->id); } @@ -191,15 +198,16 @@ static void node_event_info(void *object, struct pw_node_info *info) struct pw_proxy *proxy = object; struct pw_context *this = proxy->context; enum pw_subscription_event event; + struct proxy_data *data = proxy->user_data; pw_log_debug("got node info"); - if (proxy->user_data == NULL) + if (data->info == NULL) event = PW_SUBSCRIPTION_EVENT_NEW; else event = PW_SUBSCRIPTION_EVENT_CHANGE; - proxy->user_data = pw_node_info_update(proxy->user_data, info); + data->info = pw_node_info_update(data->info, info); pw_signal_emit(&this->subscription, this, event, proxy->type, proxy->id); } @@ -213,15 +221,16 @@ static void client_event_info(void *object, struct pw_client_info *info) struct pw_proxy *proxy = object; struct pw_context *this = proxy->context; enum pw_subscription_event event; + struct proxy_data *data = proxy->user_data; pw_log_debug("got client info"); - if (proxy->user_data == NULL) + if (data->info == NULL) event = PW_SUBSCRIPTION_EVENT_NEW; else event = PW_SUBSCRIPTION_EVENT_CHANGE; - proxy->user_data = pw_client_info_update(proxy->user_data, info); + data->info = pw_client_info_update(data->info, info); pw_signal_emit(&this->subscription, this, event, proxy->type, proxy->id); } @@ -235,15 +244,16 @@ static void link_event_info(void *object, struct pw_link_info *info) struct pw_proxy *proxy = object; struct pw_context *this = proxy->context; enum pw_subscription_event event; + struct proxy_data *data = proxy->user_data; pw_log_debug("got link info"); - if (proxy->user_data == NULL) + if (data->info == NULL) event = PW_SUBSCRIPTION_EVENT_NEW; else event = PW_SUBSCRIPTION_EVENT_CHANGE; - proxy->user_data = pw_link_info_update(proxy->user_data, info); + data->info = pw_link_info_update(data->info, info); pw_signal_emit(&this->subscription, this, event, proxy->type, proxy->id); } @@ -253,23 +263,26 @@ static const struct pw_link_events link_events = { }; static void -destroy_proxy (struct pw_proxy *proxy) +destroy_proxy (void *data) { - if (proxy->user_data == NULL) + struct pw_proxy *proxy = data; + struct proxy_data *user_data = proxy->user_data; + + if (user_data->info == NULL) return; if (proxy->type == proxy->context->type.core) { - pw_core_info_free (proxy->user_data); + pw_core_info_free (user_data->info); } else if (proxy->type == proxy->context->type.node) { - pw_node_info_free (proxy->user_data); + pw_node_info_free (user_data->info); } else if (proxy->type == proxy->context->type.module) { - pw_module_info_free (proxy->user_data); + pw_module_info_free (user_data->info); } else if (proxy->type == proxy->context->type.client) { - pw_client_info_free (proxy->user_data); + pw_client_info_free (user_data->info); } else if (proxy->type == proxy->context->type.link) { - pw_link_info_free (proxy->user_data); + pw_link_info_free (user_data->info); } - proxy->user_data = NULL; + user_data->info = NULL; } static void registry_event_global(void *object, uint32_t id, const char *type, uint32_t version) @@ -278,6 +291,8 @@ static void registry_event_global(void *object, uint32_t id, const char *type, u struct pw_context *this = registry_proxy->context; struct context *impl = SPA_CONTAINER_OF(this, struct context, this); struct pw_proxy *proxy = NULL; + uint32_t proxy_type, client_version; + const void *implementation; if (impl->no_proxy) return; @@ -285,34 +300,31 @@ static void registry_event_global(void *object, uint32_t id, const char *type, u pw_log_debug("got global %u %s %u", id, type, version); if (!strcmp(type, PIPEWIRE_TYPE__Node)) { - proxy = pw_proxy_new(this, SPA_ID_INVALID, this->type.node); - if (proxy == NULL) - goto no_mem; - - proxy->implementation = &node_events; + proxy_type = this->type.node; + implementation = &node_events; + client_version = PW_VERSION_NODE; } else if (!strcmp(type, PIPEWIRE_TYPE__Module)) { - proxy = pw_proxy_new(this, SPA_ID_INVALID, this->type.module); - if (proxy == NULL) - goto no_mem; - - proxy->implementation = &module_events; + proxy_type = this->type.module; + implementation = &module_events; + client_version = PW_VERSION_MODULE; } else if (!strcmp(type, PIPEWIRE_TYPE__Client)) { - proxy = pw_proxy_new(this, SPA_ID_INVALID, this->type.client); - if (proxy == NULL) - goto no_mem; - - proxy->implementation = &client_events; + proxy_type = this->type.client; + implementation = &client_events; + client_version = PW_VERSION_CLIENT; } else if (!strcmp(type, PIPEWIRE_TYPE__Link)) { - proxy = pw_proxy_new(this, SPA_ID_INVALID, this->type.link); - if (proxy == NULL) - goto no_mem; + proxy_type = this->type.link; + implementation = &link_events; + client_version = PW_VERSION_LINK; + } else + return; - proxy->implementation = &link_events; - } - if (proxy) { - proxy->destroy = (pw_destroy_t)destroy_proxy; - pw_registry_do_bind(registry_proxy, id, version, proxy->id); - } + proxy = pw_proxy_new(this, SPA_ID_INVALID, proxy_type, sizeof(struct proxy_data)); + if (proxy == NULL) + goto no_mem; + + pw_proxy_set_implementation(proxy, this, client_version, implementation, destroy_proxy); + + pw_registry_do_bind(registry_proxy, id, version, proxy->id); return; @@ -441,6 +453,9 @@ struct pw_context *pw_context_new(struct pw_loop *loop, this->loop = loop; + this->protocol = pw_protocol_get(PW_TYPE_PROTOCOL__Native); + pw_protocol_native_client_init(); + pw_type_init(&this->type); spa_debug_set_type_map(this->type.map); @@ -593,25 +608,26 @@ bool pw_context_connect_fd(struct pw_context *context, enum pw_context_flags fla SPA_IO_IN | SPA_IO_HUP | SPA_IO_ERR, false, on_context_data, impl); - context->core_proxy = pw_proxy_new(context, 0, context->type.core); + context->core_proxy = pw_proxy_new(context, 0, context->type.core, sizeof(struct proxy_data)); if (context->core_proxy == NULL) goto no_proxy; - context->core_proxy->implementation = &core_events; - context->core_proxy->destroy = (pw_destroy_t)destroy_proxy; + pw_proxy_set_implementation(context->core_proxy, context, PW_VERSION_CORE, + &core_events, destroy_proxy); pw_core_do_client_update(context->core_proxy, &context->properties->dict); if (!(flags & PW_CONTEXT_FLAG_NO_REGISTRY)) { context->registry_proxy = pw_proxy_new(context, - SPA_ID_INVALID, context->type.registry); + SPA_ID_INVALID, context->type.registry, 0); + if (context->registry_proxy == NULL) goto no_registry; - context->registry_proxy->implementation = ®istry_events; + pw_proxy_set_implementation(context->registry_proxy, context, PW_VERSION_REGISTRY, + ®istry_events, NULL); pw_core_do_get_registry(context->core_proxy, context->registry_proxy->id); - } impl->no_proxy = ! !(flags & PW_CONTEXT_FLAG_NO_PROXY); @@ -683,10 +699,13 @@ void pw_context_get_core_info(struct pw_context *context, pw_core_info_cb_t cb, proxy = pw_map_lookup(&context->objects, 0); if (proxy == NULL) { cb(context, SPA_RESULT_INVALID_OBJECT_ID, NULL, user_data); - } else if (proxy->type == context->type.core && proxy->user_data) { - struct pw_core_info *info = proxy->user_data; - cb(context, SPA_RESULT_OK, info, user_data); - info->change_mask = 0; + } else if (proxy->type == context->type.core) { + struct proxy_data *data = proxy->user_data; + struct pw_core_info *info = data->info; + if (info) { + cb(context, SPA_RESULT_OK, info, user_data); + info->change_mask = 0; + } } cb(context, SPA_RESULT_ENUM_END, NULL, user_data); } @@ -699,6 +718,7 @@ static void do_list(struct pw_context *context, uint32_t type, list_func_t cb, v pw_array_for_each(item, &context->objects.items) { struct pw_proxy *proxy; + struct proxy_data *data; if (pw_map_item_is_free(item)) continue; @@ -707,8 +727,9 @@ static void do_list(struct pw_context *context, uint32_t type, list_func_t cb, v if (proxy->type != type) continue; - if (proxy->user_data) - cb(context, SPA_RESULT_OK, proxy->user_data, user_data); + data = proxy->user_data; + if (data->info) + cb(context, SPA_RESULT_OK, data->info, user_data); } cb(context, SPA_RESULT_ENUM_END, NULL, user_data); } @@ -749,10 +770,13 @@ pw_context_get_module_info_by_id(struct pw_context *context, proxy = pw_map_lookup(&context->objects, id); if (proxy == NULL) { cb(context, SPA_RESULT_INVALID_OBJECT_ID, NULL, user_data); - } else if (proxy->type == context->type.module && proxy->user_data) { - struct pw_module_info *info = proxy->user_data; - cb(context, SPA_RESULT_OK, info, user_data); - info->change_mask = 0; + } else if (proxy->type == context->type.module) { + struct proxy_data *data = proxy->user_data; + struct pw_module_info *info = data->info; + if (info) { + cb(context, SPA_RESULT_OK, info, user_data); + info->change_mask = 0; + } } cb(context, SPA_RESULT_ENUM_END, NULL, user_data); } @@ -793,10 +817,13 @@ pw_context_get_client_info_by_id(struct pw_context *context, proxy = pw_map_lookup(&context->objects, id); if (proxy == NULL) { cb(context, SPA_RESULT_INVALID_OBJECT_ID, NULL, user_data); - } else if (proxy->type == context->type.client && proxy->user_data) { - struct pw_client_info *info = proxy->user_data; - cb(context, SPA_RESULT_OK, info, user_data); - info->change_mask = 0; + } else if (proxy->type == context->type.client) { + struct proxy_data *data = proxy->user_data; + struct pw_client_info *info = data->info; + if (info) { + cb(context, SPA_RESULT_OK, info, user_data); + info->change_mask = 0; + } } cb(context, SPA_RESULT_ENUM_END, NULL, user_data); } @@ -836,10 +863,13 @@ pw_context_get_node_info_by_id(struct pw_context *context, proxy = pw_map_lookup(&context->objects, id); if (proxy == NULL) { cb(context, SPA_RESULT_INVALID_OBJECT_ID, NULL, user_data); - } else if (proxy->type == context->type.node && proxy->user_data) { - struct pw_node_info *info = proxy->user_data; - cb(context, SPA_RESULT_OK, info, user_data); - info->change_mask = 0; + } else if (proxy->type == context->type.node) { + struct proxy_data *data = proxy->user_data; + struct pw_node_info *info = data->info; + if (info) { + cb(context, SPA_RESULT_OK, info, user_data); + info->change_mask = 0; + } } cb(context, SPA_RESULT_ENUM_END, NULL, user_data); } @@ -879,10 +909,13 @@ pw_context_get_link_info_by_id(struct pw_context *context, proxy = pw_map_lookup(&context->objects, id); if (proxy == NULL) { cb(context, SPA_RESULT_INVALID_OBJECT_ID, NULL, user_data); - } else if (proxy->type == context->type.link && proxy->user_data) { - struct pw_link_info *info = proxy->user_data; - cb(context, SPA_RESULT_OK, info, user_data); - info->change_mask = 0; + } else if (proxy->type == context->type.link) { + struct proxy_data *data = proxy->user_data; + struct pw_link_info *info = data->info; + if (info) { + cb(context, SPA_RESULT_OK, info, user_data); + info->change_mask = 0; + } } cb(context, SPA_RESULT_ENUM_END, NULL, user_data); } diff --git a/pipewire/client/context.h b/pipewire/client/context.h index 33a31ad86..9b8df2041 100644 --- a/pipewire/client/context.h +++ b/pipewire/client/context.h @@ -103,6 +103,7 @@ extern "C" { #include #include #include +#include #include #include #include @@ -159,6 +160,7 @@ struct pw_context { struct spa_list stream_list; /**< list of \ref pw_stream objects */ struct spa_list proxy_list; /**< list of \ref pw_proxy objects */ + struct pw_protocol *protocol; /**< the protocol in use */ void *protocol_private; /**< private data for the protocol */ enum pw_context_state state; /**< context state */ diff --git a/pipewire/client/interfaces.h b/pipewire/client/interfaces.h index 07a4302cf..588d89c1e 100644 --- a/pipewire/client/interfaces.h +++ b/pipewire/client/interfaces.h @@ -48,6 +48,8 @@ extern "C" { * \section page_iface_pw_core API */ +#define PW_VERSION_CORE 0 + #define PW_CORE_METHOD_UPDATE_TYPES 0 #define PW_CORE_METHOD_SYNC 1 #define PW_CORE_METHOD_GET_REGISTRY 2 @@ -215,6 +217,7 @@ struct pw_core_events { #define pw_core_notify_remove_id(r,...) ((struct pw_core_events*)r->iface->events)->remove_id(r,__VA_ARGS__) #define pw_core_notify_info(r,...) ((struct pw_core_events*)r->iface->events)->info(r,__VA_ARGS__) +#define PW_VERSION_REGISTRY 0 #define PW_REGISTRY_METHOD_BIND 0 #define PW_REGISTRY_METHOD_NUM 1 @@ -269,8 +272,10 @@ struct pw_registry_events { #define pw_registry_notify_global(r,...) ((struct pw_registry_events*)r->iface->events)->global(r,__VA_ARGS__) #define pw_registry_notify_global_remove(r,...) ((struct pw_registry_events*)r->iface->events)->global_remove(r,__VA_ARGS__) -#define PW_MODULE_EVENT_INFO 0 -#define PW_MODULE_EVENT_NUM 1 +#define PW_VERSION_MODULE 0 + +#define PW_MODULE_EVENT_INFO 0 +#define PW_MODULE_EVENT_NUM 1 /** Module events */ struct pw_module_events { @@ -284,8 +289,10 @@ struct pw_module_events { #define pw_module_notify_info(r,...) ((struct pw_module_events*)r->iface->events)->info(r,__VA_ARGS__) -#define PW_NODE_EVENT_INFO 0 -#define PW_NODE_EVENT_NUM 1 +#define PW_VERSION_NODE 0 + +#define PW_NODE_EVENT_INFO 0 +#define PW_NODE_EVENT_NUM 1 /** Node events */ struct pw_node_events { @@ -307,6 +314,8 @@ struct pw_client_node_buffer { struct spa_buffer *buffer; /**< buffer describing metadata and buffer memory */ }; +#define PW_VERSION_CLIENT_NODE 0 + #define PW_CLIENT_NODE_METHOD_DONE 0 #define PW_CLIENT_NODE_METHOD_UPDATE 1 #define PW_CLIENT_NODE_METHOD_PORT_UPDATE 2 @@ -554,8 +563,10 @@ struct pw_client_node_events { #define pw_client_node_notify_port_command(r,...) ((struct pw_client_node_events*)r->iface->events)->port_command(r,__VA_ARGS__) #define pw_client_node_notify_transport(r,...) ((struct pw_client_node_events*)r->iface->events)->transport(r,__VA_ARGS__) -#define PW_CLIENT_EVENT_INFO 0 -#define PW_CLIENT_EVENT_NUM 1 +#define PW_VERSION_CLIENT 0 + +#define PW_CLIENT_EVENT_INFO 0 +#define PW_CLIENT_EVENT_NUM 1 /** Client events */ struct pw_client_events { @@ -569,8 +580,10 @@ struct pw_client_events { #define pw_client_notify_info(r,...) ((struct pw_client_events*)r->iface->events)->info(r,__VA_ARGS__) -#define PW_LINK_EVENT_INFO 0 -#define PW_LINK_EVENT_NUM 1 +#define PW_VERSION_LINK 0 + +#define PW_LINK_EVENT_INFO 0 +#define PW_LINK_EVENT_NUM 1 /** Link events */ struct pw_link_events { diff --git a/pipewire/client/meson.build b/pipewire/client/meson.build index acab158d3..b50a968a0 100644 --- a/pipewire/client/meson.build +++ b/pipewire/client/meson.build @@ -10,6 +10,7 @@ pipewire_headers = [ 'mem.h', 'pipewire.h', 'properties.h', + 'protocol.h', 'protocol-native.h', 'proxy.h', 'rtkit.h', @@ -29,11 +30,12 @@ pipewire_sources = [ 'log.c', 'loop.c', 'mem.c', + 'pipewire.c', 'properties.c', + 'protocol.c', 'protocol-native.c', 'proxy.c', 'stream.c', - 'pipewire.c', 'rtkit.c', 'thread-loop.c', 'transport.c', diff --git a/pipewire/client/protocol-native.c b/pipewire/client/protocol-native.c index e7ec11d33..1b88859e8 100644 --- a/pipewire/client/protocol-native.c +++ b/pipewire/client/protocol-native.c @@ -23,6 +23,7 @@ #include "pipewire/client/pipewire.h" #include "pipewire/client/protocol-native.h" +#include "pipewire/client/protocol.h" #include "pipewire/client/interfaces.h" #include "pipewire/client/connection.h" @@ -929,6 +930,8 @@ static const demarshal_func_t pw_protocol_native_client_core_demarshal[PW_CORE_E }; static const struct pw_interface pw_protocol_native_client_core_interface = { + PIPEWIRE_TYPE__Core, + PW_VERSION_CORE, PW_CORE_METHOD_NUM, &pw_protocol_native_client_core_methods, PW_CORE_EVENT_NUM, pw_protocol_native_client_core_demarshal }; @@ -943,6 +946,8 @@ static const demarshal_func_t pw_protocol_native_client_registry_demarshal[] = { }; static const struct pw_interface pw_protocol_native_client_registry_interface = { + PIPEWIRE_TYPE__Registry, + PW_VERSION_REGISTRY, PW_REGISTRY_METHOD_NUM, &pw_protocol_native_client_registry_methods, PW_REGISTRY_EVENT_NUM, pw_protocol_native_client_registry_demarshal, }; @@ -970,6 +975,8 @@ static const demarshal_func_t pw_protocol_native_client_client_node_demarshal[] }; static const struct pw_interface pw_protocol_native_client_client_node_interface = { + PIPEWIRE_TYPE_NODE_BASE "Client", + PW_VERSION_CLIENT_NODE, PW_CLIENT_NODE_METHOD_NUM, &pw_protocol_native_client_client_node_methods, PW_CLIENT_NODE_EVENT_NUM, pw_protocol_native_client_client_node_demarshal, }; @@ -979,6 +986,8 @@ static const demarshal_func_t pw_protocol_native_client_module_demarshal[] = { }; static const struct pw_interface pw_protocol_native_client_module_interface = { + PIPEWIRE_TYPE__Module, + PW_VERSION_MODULE, 0, NULL, PW_MODULE_EVENT_NUM, pw_protocol_native_client_module_demarshal, }; @@ -988,6 +997,8 @@ static const demarshal_func_t pw_protocol_native_client_node_demarshal[] = { }; static const struct pw_interface pw_protocol_native_client_node_interface = { + PIPEWIRE_TYPE__Node, + PW_VERSION_NODE, 0, NULL, PW_NODE_EVENT_NUM, pw_protocol_native_client_node_demarshal, }; @@ -997,6 +1008,8 @@ static const demarshal_func_t pw_protocol_native_client_client_demarshal[] = { }; static const struct pw_interface pw_protocol_native_client_client_interface = { + PIPEWIRE_TYPE__Client, + PW_VERSION_CLIENT, 0, NULL, PW_CLIENT_EVENT_NUM, pw_protocol_native_client_client_demarshal, }; @@ -1006,30 +1019,43 @@ static const demarshal_func_t pw_protocol_native_client_link_demarshal[] = { }; static const struct pw_interface pw_protocol_native_client_link_interface = { + PIPEWIRE_TYPE__Link, + PW_VERSION_LINK, 0, NULL, PW_LINK_EVENT_NUM, pw_protocol_native_client_link_demarshal, }; -bool pw_protocol_native_client_setup(struct pw_proxy *proxy) +void pw_protocol_native_client_init(void) { - const struct pw_interface *iface; + static bool init = false; + struct pw_protocol *protocol; - if (proxy->type == proxy->context->type.core) { - iface = &pw_protocol_native_client_core_interface; - } else if (proxy->type == proxy->context->type.registry) { - iface = &pw_protocol_native_client_registry_interface; - } else if (proxy->type == proxy->context->type.module) { - iface = &pw_protocol_native_client_module_interface; - } else if (proxy->type == proxy->context->type.node) { - iface = &pw_protocol_native_client_node_interface; - } else if (proxy->type == proxy->context->type.client_node) { - iface = &pw_protocol_native_client_client_node_interface; - } else if (proxy->type == proxy->context->type.client) { - iface = &pw_protocol_native_client_client_interface; - } else if (proxy->type == proxy->context->type.link) { - iface = &pw_protocol_native_client_link_interface; - } else - return false; - proxy->iface = iface; - return true; + if (init) + return; + + protocol = pw_protocol_get(PW_TYPE_PROTOCOL__Native); + + pw_protocol_add_interfaces(protocol, + &pw_protocol_native_client_core_interface, + NULL); + pw_protocol_add_interfaces(protocol, + &pw_protocol_native_client_registry_interface, + NULL); + pw_protocol_add_interfaces(protocol, + &pw_protocol_native_client_module_interface, + NULL); + pw_protocol_add_interfaces(protocol, + &pw_protocol_native_client_node_interface, + NULL); + pw_protocol_add_interfaces(protocol, + &pw_protocol_native_client_client_node_interface, + NULL); + pw_protocol_add_interfaces(protocol, + &pw_protocol_native_client_client_interface, + NULL); + pw_protocol_add_interfaces(protocol, + &pw_protocol_native_client_link_interface, + NULL); + + init = true; } diff --git a/pipewire/client/protocol-native.h b/pipewire/client/protocol-native.h index af00463c4..f36ec6cb8 100644 --- a/pipewire/client/protocol-native.h +++ b/pipewire/client/protocol-native.h @@ -17,8 +17,4 @@ * Boston, MA 02110-1301, USA. */ -#include "pipewire/client/pipewire.h" -#include "pipewire/client/interfaces.h" - -bool -pw_protocol_native_client_setup(struct pw_proxy *proxy); +void pw_protocol_native_client_init(void); diff --git a/pipewire/client/protocol.c b/pipewire/client/protocol.c new file mode 100644 index 000000000..a09582986 --- /dev/null +++ b/pipewire/client/protocol.c @@ -0,0 +1,82 @@ +/* PipeWire + * Copyright (C) 2016 Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include + +static struct impl { + bool init; + struct spa_list protocol_list; +} protocols; + +static struct impl *get_impl(void) +{ + if (!protocols.init) { + spa_list_init(&protocols.protocol_list); + protocols.init = true; + } + return &protocols; +} + +struct pw_protocol *pw_protocol_get(const char *name) +{ + struct impl *impl = get_impl(); + struct pw_protocol *protocol; + + spa_list_for_each(protocol, &impl->protocol_list, link) { + if (strcmp(protocol->name, name) == 0) + return protocol; + } + + protocol = calloc(1, sizeof(struct pw_protocol)); + protocol->name = name; + spa_list_init(&protocol->iface_list); + spa_list_insert(impl->protocol_list.prev, &protocol->link); + + return protocol; +} + +void +pw_protocol_add_interfaces(struct pw_protocol *protocol, + const struct pw_interface *client_iface, + const struct pw_interface *server_iface) +{ + struct pw_protocol_iface *iface; + + iface = calloc(1, sizeof(struct pw_protocol_iface)); + iface->client_iface = client_iface; + iface->server_iface = server_iface; + + spa_list_insert(protocol->iface_list.prev, &iface->link); +} + +const struct pw_interface * +pw_protocol_get_interface(struct pw_protocol *protocol, + const char *type, + bool server) +{ + struct pw_protocol_iface *protocol_iface; + + spa_list_for_each(protocol_iface, &protocol->iface_list, link) { + const struct pw_interface *iface = server ? protocol_iface->server_iface : + protocol_iface->client_iface; + if (strcmp(iface->type, type) == 0) + return iface; + } + return NULL; +} diff --git a/pipewire/client/protocol.h b/pipewire/client/protocol.h new file mode 100644 index 000000000..2c888a617 --- /dev/null +++ b/pipewire/client/protocol.h @@ -0,0 +1,67 @@ +/* PipeWire + * Copyright (C) 2016 Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __PIPEWIRE_PROTOCOL_H__ +#define __PIPEWIRE_PROTOCOL_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#include +#include + +#define PW_TYPE_PROTOCOL__Native PW_TYPE_PROTOCOL_BASE "Native" + +struct pw_protocol_iface { + struct spa_list link; + const struct pw_interface *client_iface; + const struct pw_interface *server_iface; +}; + +struct pw_protocol { + struct spa_list link; + const char *name; + struct spa_list iface_list; +}; + +struct pw_protocol *pw_protocol_get(const char *name); + +/** \class pw_protocol + * + * \brief Manages protocols and their implementation + */ +void +pw_protocol_add_interfaces(struct pw_protocol *protocol, + const struct pw_interface *client_iface, + const struct pw_interface *server_iface); + +const struct pw_interface * +pw_protocol_get_interface(struct pw_protocol *protocol, + const char *type, + bool server); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* __PIPEWIRE_PROTOCOL_H__ */ diff --git a/pipewire/client/proxy.c b/pipewire/client/proxy.c index daf79879e..76635bd3a 100644 --- a/pipewire/client/proxy.c +++ b/pipewire/client/proxy.c @@ -41,12 +41,14 @@ struct proxy { * * \memberof pw_proxy */ -struct pw_proxy *pw_proxy_new(struct pw_context *context, uint32_t id, uint32_t type) +struct pw_proxy *pw_proxy_new(struct pw_context *context, + uint32_t id, uint32_t type, + size_t user_data_size) { struct proxy *impl; struct pw_proxy *this; - impl = calloc(1, sizeof(struct proxy)); + impl = calloc(1, sizeof(struct proxy) + user_data_size); if (impl == NULL) return NULL; @@ -63,7 +65,12 @@ struct pw_proxy *pw_proxy_new(struct pw_context *context, uint32_t id, uint32_t this->id = id; - pw_protocol_native_client_setup(this); + if (user_data_size > 0) + this->user_data = SPA_MEMBER(impl, sizeof(struct proxy), void); + + this->iface = pw_protocol_get_interface(context->protocol, + spa_type_map_get_type(context->type.map, type), + false); spa_list_insert(&this->context->proxy_list, &this->link); @@ -77,6 +84,19 @@ struct pw_proxy *pw_proxy_new(struct pw_context *context, uint32_t id, uint32_t return NULL; } +int pw_proxy_set_implementation(struct pw_proxy *proxy, + void *object, + uint32_t version, + const void *implementation, + pw_destroy_t destroy) +{ + proxy->object = object; + proxy->version = version; + proxy->implementation = implementation; + proxy->destroy = destroy; + return SPA_RESULT_OK; +} + /** Destroy a proxy object * * \param proxy Proxy object to destroy diff --git a/pipewire/client/proxy.h b/pipewire/client/proxy.h index 83a688ac8..bada46ba7 100644 --- a/pipewire/client/proxy.h +++ b/pipewire/client/proxy.h @@ -88,26 +88,36 @@ extern "C" { * See \ref page_proxy */ struct pw_proxy { - /** the owner context of this proxy */ - struct pw_context *context; - /** link in the context */ - struct spa_list link; - - uint32_t id; /**< client side id */ - uint32_t type; /**< object type id */ + struct pw_context *context; /**< the owner context of this proxy */ + struct spa_list link; /**< link in the context */ + uint32_t id; /**< client side id */ + uint32_t type; /**< object type id */ const struct pw_interface *iface; /**< methods/events marshal/demarshal functions */ - const void *implementation; /**< event handler implementation */ - void *user_data; /**< optional client user data */ - pw_destroy_t destroy; /**< optional destroy function to clean up user_data */ + void *object; /**< client side object */ + uint32_t version; + const void *implementation; /**< event handler implementation */ + pw_destroy_t destroy; /**< optional destroy function to clean up the object */ /** destroy_signal is emited when the proxy is destroyed */ PW_SIGNAL(destroy_signal, (struct pw_listener *listener, struct pw_proxy *proxy)); + + void *user_data; /**< extra user data */ }; struct pw_proxy * -pw_proxy_new(struct pw_context *context, uint32_t id, uint32_t type); +pw_proxy_new(struct pw_context *context, + uint32_t id, + uint32_t type, + size_t user_data_size); + +int +pw_proxy_set_implementation(struct pw_proxy *proxy, + void *object, + uint32_t version, + const void *implementation, + pw_destroy_t destroy); void pw_proxy_destroy(struct pw_proxy *proxy); diff --git a/pipewire/client/stream.c b/pipewire/client/stream.c index b27e04ea2..d7ac73925 100644 --- a/pipewire/client/stream.c +++ b/pipewire/client/stream.c @@ -652,7 +652,7 @@ client_node_set_format(void *object, uint32_t port_id, uint32_t flags, const struct spa_format *format) { struct pw_proxy *proxy = object; - struct pw_stream *stream = proxy->user_data; + struct pw_stream *stream = proxy->object; struct stream *impl = SPA_CONTAINER_OF(stream, struct stream, this); if (impl->format) @@ -686,7 +686,7 @@ client_node_add_mem(void *object, uint32_t type, int memfd, uint32_t flags, uint32_t offset, uint32_t size) { struct pw_proxy *proxy = object; - struct pw_stream *stream = proxy->user_data; + struct pw_stream *stream = proxy->object; struct stream *impl = SPA_CONTAINER_OF(stream, struct stream, this); struct mem_id *m; @@ -715,7 +715,7 @@ client_node_use_buffers(void *object, uint32_t port_id, uint32_t n_buffers, struct pw_client_node_buffer *buffers) { struct pw_proxy *proxy = object; - struct pw_stream *stream = proxy->user_data; + struct pw_stream *stream = proxy->object; struct stream *impl = SPA_CONTAINER_OF(stream, struct stream, this); struct buffer_id *bid; uint32_t i, j, len; @@ -828,7 +828,7 @@ client_node_use_buffers(void *object, static void client_node_node_command(void *object, uint32_t seq, const struct spa_command *command) { struct pw_proxy *proxy = object; - struct pw_stream *stream = proxy->user_data; + struct pw_stream *stream = proxy->object; handle_node_command(stream, seq, command); } @@ -844,7 +844,7 @@ client_node_port_command(void *object, static void client_node_transport(void *object, int readfd, int writefd, int memfd, uint32_t offset, uint32_t size) { struct pw_proxy *proxy = object; - struct pw_stream *stream = proxy->user_data; + struct pw_stream *stream = proxy->object; struct stream *impl = SPA_CONTAINER_OF(stream, struct stream, this); struct pw_transport_info info; @@ -933,16 +933,17 @@ pw_stream_connect(struct pw_stream *stream, pw_properties_set(stream->properties, "pipewire.autoconnect", "1"); impl->node_proxy = pw_proxy_new(stream->context, - SPA_ID_INVALID, stream->context->type.client_node); + SPA_ID_INVALID, stream->context->type.client_node, 0); + if (impl->node_proxy == NULL) return false; + pw_proxy_set_implementation(impl->node_proxy, stream, PW_VERSION_CLIENT_NODE, + &client_node_events, NULL); + pw_signal_add(&impl->node_proxy->destroy_signal, &impl->node_proxy_destroy, on_node_proxy_destroy); - impl->node_proxy->user_data = stream; - impl->node_proxy->implementation = &client_node_events; - pw_core_do_create_node(stream->context->core_proxy, "client-node", "client-node", diff --git a/pipewire/client/subscribe.h b/pipewire/client/subscribe.h index 20c571593..86bfcac8b 100644 --- a/pipewire/client/subscribe.h +++ b/pipewire/client/subscribe.h @@ -44,6 +44,9 @@ extern "C" { #define PIPEWIRE_TYPE__Module "PipeWire:Object:Module" #define PIPEWIRE_TYPE_MODULE_BASE PIPEWIRE_TYPE__Module ":" +#define PW_TYPE__Protocol "PipeWire:Protocol" +#define PW_TYPE_PROTOCOL_BASE PW_TYPE__Protocol ":" + /** \enum pw_subscription_event * subscription events */ diff --git a/pipewire/client/type.c b/pipewire/client/type.c index f2f753ba0..152d24480 100644 --- a/pipewire/client/type.c +++ b/pipewire/client/type.c @@ -19,17 +19,17 @@ #include +#include "spa/defs.h" +#include "spa/clock.h" +#include "spa/type-map.h" +#include "spa/monitor.h" + #include "pipewire/client/pipewire.h" #include "pipewire/client/type.h" -#include "pipewire/server/core.h" -#include "pipewire/server/node.h" #include "pipewire/server/node-factory.h" -#include "pipewire/server/client.h" #include "pipewire/server/client-node.h" -#include "pipewire/server/module.h" -#include "spa/monitor.h" /** Initializes the type system * \param type a type structure diff --git a/pipewire/client/type.h b/pipewire/client/type.h index 97e1f0852..70f3f8bec 100644 --- a/pipewire/client/type.h +++ b/pipewire/client/type.h @@ -44,6 +44,8 @@ extern "C" { * \sa pw_proxy, pw_resource */ struct pw_interface { + const char *type; /**< interface type */ + uint32_t version; /**< version */ uint32_t n_methods; /**< number of methods in the interface */ const void *methods; /**< method implementations of the interface */ uint32_t n_events; /**< number of events in the interface */ diff --git a/pipewire/modules/module-autolink.c b/pipewire/modules/module-autolink.c index c0772083c..78c0bb3a6 100644 --- a/pipewire/modules/module-autolink.c +++ b/pipewire/modules/module-autolink.c @@ -42,7 +42,7 @@ struct client_info { struct impl *impl; struct pw_client *client; struct spa_list link; - struct pw_listener resource_added; + struct pw_listener resource_impl; struct pw_listener resource_removed; struct spa_list node_list; }; @@ -98,7 +98,7 @@ static void client_info_free(struct client_info *cinfo) struct node_info *info, *tmp; spa_list_remove(&cinfo->link); - pw_signal_remove(&cinfo->resource_added); + pw_signal_remove(&cinfo->resource_impl); pw_signal_remove(&cinfo->resource_removed); spa_list_for_each_safe(info, tmp, &cinfo->node_list, link) @@ -278,10 +278,10 @@ on_node_added(struct impl *impl, } static void -on_resource_added(struct pw_listener *listener, - struct pw_client *client, struct pw_resource *resource) +on_resource_impl(struct pw_listener *listener, + struct pw_client *client, struct pw_resource *resource) { - struct client_info *cinfo = SPA_CONTAINER_OF(listener, struct client_info, resource_added); + struct client_info *cinfo = SPA_CONTAINER_OF(listener, struct client_info, resource_impl); struct impl *impl = cinfo->impl; if (resource->type == impl->core->type.client_node) { @@ -325,7 +325,7 @@ on_global_added(struct pw_listener *listener, struct pw_core *core, struct pw_gl spa_list_insert(impl->client_list.prev, &cinfo->link); - pw_signal_add(&client->resource_added, &cinfo->resource_added, on_resource_added); + pw_signal_add(&client->resource_impl, &cinfo->resource_impl, on_resource_impl); pw_signal_add(&client->resource_removed, &cinfo->resource_removed, on_resource_removed); diff --git a/pipewire/modules/module-flatpak.c b/pipewire/modules/module-flatpak.c index 52cc85bce..69fe6299d 100644 --- a/pipewire/modules/module-flatpak.c +++ b/pipewire/modules/module-flatpak.c @@ -57,7 +57,7 @@ struct client_info { const struct pw_core_methods *old_methods; struct pw_core_methods core_methods; struct spa_list async_pending; - struct pw_listener resource_added; + struct pw_listener resource_impl; struct pw_listener resource_removed; }; @@ -422,11 +422,11 @@ do_create_link(void *object, new_id); } -static void on_resource_added(struct pw_listener *listener, - struct pw_client *client, - struct pw_resource *resource) +static void on_resource_impl(struct pw_listener *listener, + struct pw_client *client, + struct pw_resource *resource) { - struct client_info *cinfo = SPA_CONTAINER_OF(listener, struct client_info, resource_added); + struct client_info *cinfo = SPA_CONTAINER_OF(listener, struct client_info, resource_impl); struct impl *impl = cinfo->impl; if (resource->type == impl->core->type.core) { @@ -455,7 +455,7 @@ on_global_added(struct pw_listener *listener, struct pw_core *core, struct pw_gl cinfo->is_sandboxed = true; spa_list_init(&cinfo->async_pending); - pw_signal_add(&client->resource_added, &cinfo->resource_added, on_resource_added); + pw_signal_add(&client->resource_impl, &cinfo->resource_impl, on_resource_impl); spa_list_insert(impl->client_list.prev, &cinfo->link); diff --git a/pipewire/modules/module-protocol-native.c b/pipewire/modules/module-protocol-native.c index cde6ca003..6b8ffbd11 100644 --- a/pipewire/modules/module-protocol-native.c +++ b/pipewire/modules/module-protocol-native.c @@ -89,15 +89,16 @@ struct native_client { struct pw_listener busy_changed; }; -static void client_destroy(struct native_client *this) +static void client_destroy(void *data) { + struct pw_client *client = data; + struct native_client *this = client->user_data; + pw_loop_destroy_source(this->impl->core->main_loop->loop, this->source); - pw_client_destroy(this->client); spa_list_remove(&this->link); pw_connection_destroy(this->connection); close(this->fd); - free(this); } static void @@ -126,14 +127,14 @@ process_messages(struct native_client *client) if (opcode >= resource->iface->n_methods) { pw_log_error("protocol-native %p: invalid method %u %u", client->impl, id, opcode); - client_destroy(client); + pw_client_destroy(c); break; } demarshal = resource->iface->methods; if (!demarshal[opcode] || !demarshal[opcode] (resource, message, size)) { pw_log_error("protocol-native %p: invalid message received %u %u", client->impl, id, opcode); - client_destroy(client); + pw_client_destroy(c); break; } if (c->busy) { @@ -146,7 +147,9 @@ static void on_resource_added(struct pw_listener *listener, struct pw_client *client, struct pw_resource *resource) { - pw_protocol_native_server_setup(resource); + resource->iface = pw_protocol_get_interface(client->protocol, + spa_type_map_get_type(client->core->type.map, resource->type), + true); } static void @@ -183,7 +186,7 @@ connection_data(struct spa_loop_utils *utils, if (mask & (SPA_IO_ERR | SPA_IO_HUP)) { pw_log_error("protocol-native %p: got connection error", client->impl); - client_destroy(client); + pw_client_destroy(client->client); return; } @@ -198,10 +201,21 @@ static struct native_client *client_new(struct impl *impl, int fd) socklen_t len; struct ucred ucred, *ucredp; - this = calloc(1, sizeof(struct native_client)); - if (this == NULL) - goto no_native_client; + len = sizeof(ucred); + if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &len) < 0) { + pw_log_error("no peercred: %m"); + ucredp = NULL; + } else { + ucredp = &ucred; + } + client = pw_client_new(impl->core, ucredp, NULL, sizeof(struct native_client)); + if (client == NULL) + goto no_client; + + client->destroy = client_destroy; + + this = client->user_data; this->impl = impl; this->fd = fd; this->source = pw_loop_add_io(impl->core->main_loop->loop, @@ -214,18 +228,7 @@ static struct native_client *client_new(struct impl *impl, int fd) if (this->connection == NULL) goto no_connection; - len = sizeof(ucred); - if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &len) < 0) { - pw_log_error("no peercred: %m"); - ucredp = NULL; - } else { - ucredp = &ucred; - } - - client = pw_client_new(impl->core, ucredp, NULL); - if (client == NULL) - goto no_client; - + client->protocol = pw_protocol_get(PW_TYPE_PROTOCOL__Native); client->protocol_private = this->connection; this->client = client; @@ -236,15 +239,14 @@ static struct native_client *client_new(struct impl *impl, int fd) pw_signal_add(&client->busy_changed, &this->busy_changed, on_busy_changed); pw_global_bind(impl->core->global, client, 0, 0); + return this; - no_client: - pw_connection_destroy(this->connection); no_connection: pw_loop_destroy_source(impl->core->main_loop->loop, this->source); no_source: free(this); - no_native_client: + no_client: return NULL; } @@ -461,6 +463,8 @@ static void pw_protocol_native_destroy(struct impl *impl) bool pipewire__module_init(struct pw_module *module, const char *args) { + pw_protocol_native_server_init(); + pw_protocol_native_new(module->core, NULL); return true; } diff --git a/pipewire/server/client-node.c b/pipewire/server/client-node.c index da8c11b83..83a64bf6e 100644 --- a/pipewire/server/client-node.c +++ b/pipewire/server/client-node.c @@ -1169,13 +1169,17 @@ struct pw_client_node *pw_client_node_new(struct pw_client *client, this->resource = pw_resource_new(client, id, - client->core->type.client_node, - this, - &client_node_methods, - (pw_destroy_t) client_node_resource_destroy); + client->core->type.client_node, 0); + if (this->resource == NULL) goto error_no_resource; + pw_resource_set_implementation(this->resource, + this, + PW_VERSION_CLIENT_NODE, + &client_node_methods, + (pw_destroy_t) client_node_resource_destroy); + impl->proxy.resource = this->resource; pw_signal_add(&this->node->free_signal, &impl->node_free, on_node_free); diff --git a/pipewire/server/client-node.h b/pipewire/server/client-node.h index 129c3f4bb..fc8fb99e9 100644 --- a/pipewire/server/client-node.h +++ b/pipewire/server/client-node.h @@ -26,7 +26,7 @@ extern "C" { #endif -#define PIPEWIRE_TYPE__ClientNode "PipeWire:Object:ClientNode" +#define PIPEWIRE_TYPE__ClientNode PIPEWIRE_TYPE_NODE_BASE "Client" #define PIPEWIRE_TYPE_CLIENT_NODE_BASE PIPEWIRE_TYPE__ClientNode ":" /** \class pw_client_node diff --git a/pipewire/server/client.c b/pipewire/server/client.c index 748b92b71..e1b034947 100644 --- a/pipewire/server/client.c +++ b/pipewire/server/client.c @@ -43,10 +43,12 @@ client_bind_func(struct pw_global *global, struct pw_client *client, uint32_t ve struct pw_client *this = global->object; struct pw_resource *resource; - resource = pw_resource_new(client, id, global->type, global->object, NULL, client_unbind_func); + resource = pw_resource_new(client, id, global->type, 0); if (resource == NULL) goto no_mem; + pw_resource_set_implementation(resource, global->object, PW_VERSION_CLIENT, NULL, client_unbind_func); + pw_log_debug("client %p: bound to %d", global->object, resource->id); spa_list_insert(this->resource_list.prev, &resource->link); @@ -73,12 +75,14 @@ client_bind_func(struct pw_global *global, struct pw_client *client, uint32_t ve * \memberof pw_client */ struct pw_client *pw_client_new(struct pw_core *core, - struct ucred *ucred, struct pw_properties *properties) + struct ucred *ucred, + struct pw_properties *properties, + size_t user_data_size) { struct pw_client *this; struct impl *impl; - impl = calloc(1, sizeof(struct impl)); + impl = calloc(1, sizeof(struct impl) + user_data_size); if (impl == NULL) return NULL; @@ -90,9 +94,13 @@ struct pw_client *pw_client_new(struct pw_core *core, this->ucred = *ucred; this->properties = properties; + if (user_data_size > 0) + this->user_data = SPA_MEMBER(impl, sizeof(struct impl), void); + spa_list_init(&this->resource_list); pw_signal_init(&this->properties_changed); pw_signal_init(&this->resource_added); + pw_signal_init(&this->resource_impl); pw_signal_init(&this->resource_removed); pw_signal_init(&this->busy_changed); @@ -143,6 +151,9 @@ void pw_client_destroy(struct pw_client *client) if (client->properties) pw_properties_free(client->properties); + if (client->destroy) + client->destroy(client); + free(impl); } diff --git a/pipewire/server/client.h b/pipewire/server/client.h index e08892616..c429e4419 100644 --- a/pipewire/server/client.h +++ b/pipewire/server/client.h @@ -86,8 +86,6 @@ struct pw_client { bool ucred_valid; /**< if the ucred member is valid */ struct ucred ucred; /**< ucred information */ - void *protocol_private; /**< private data for the protocol implementation */ - struct pw_resource *core_resource; /**< core resource object */ struct pw_map objects; /**< list of resource objects */ @@ -98,6 +96,9 @@ struct pw_client { /** Emited when a resource is added */ PW_SIGNAL(resource_added, (struct pw_listener *listener, struct pw_client *client, struct pw_resource *resource)); + /** Emited when a resource implementation is set */ + PW_SIGNAL(resource_impl, (struct pw_listener *listener, + struct pw_client *client, struct pw_resource *resource)); /** Emited when a resource is removed */ PW_SIGNAL(resource_removed, (struct pw_listener *listener, struct pw_client *client, struct pw_resource *resource)); @@ -109,11 +110,19 @@ struct pw_client { /** Emited when the client is destroyed */ PW_SIGNAL(destroy_signal, (struct pw_listener *listener, struct pw_client *client)); + + struct pw_protocol *protocol; /**< protocol in use */ + void *protocol_private; /**< private data for the protocol */ + + void *user_data; /**< extra user data */ + pw_destroy_t destroy; /**< function to clean up the object */ }; struct pw_client * pw_client_new(struct pw_core *core, - struct ucred *ucred, struct pw_properties *properties); + struct ucred *ucred, + struct pw_properties *properties, + size_t user_data_size); void pw_client_destroy(struct pw_client *client); diff --git a/pipewire/server/core.c b/pipewire/server/core.c index 5ba83cd2b..3d9e93af9 100644 --- a/pipewire/server/core.c +++ b/pipewire/server/core.c @@ -116,12 +116,16 @@ static void core_get_registry(void *object, uint32_t new_id) registry_resource = pw_resource_new(client, new_id, this->type.registry, - this, - ®istry_methods, - destroy_registry_resource); + 0); if (registry_resource == NULL) goto no_mem; + pw_resource_set_implementation(registry_resource, + this, + PW_VERSION_REGISTRY, + ®istry_methods, + destroy_registry_resource); + spa_list_insert(this->registry_resource_list.prev, ®istry_resource->link); spa_list_for_each(global, &this->global_list, link) { @@ -238,10 +242,13 @@ core_bind_func(struct pw_global *global, struct pw_client *client, uint32_t vers struct pw_core *this = global->object; struct pw_resource *resource; - resource = pw_resource_new(client, id, global->type, global->object, &core_methods, core_unbind_func); + resource = pw_resource_new(client, id, global->type, 0); if (resource == NULL) goto no_mem; + pw_resource_set_implementation(resource, global->object, + PW_VERSION_CORE, &core_methods, core_unbind_func); + spa_list_insert(this->resource_list.prev, &resource->link); client->core_resource = resource; diff --git a/pipewire/server/link.c b/pipewire/server/link.c index 91598250e..858bdf6b3 100644 --- a/pipewire/server/link.c +++ b/pipewire/server/link.c @@ -834,10 +834,12 @@ link_bind_func(struct pw_global *global, struct pw_client *client, uint32_t vers struct impl *impl = SPA_CONTAINER_OF(this, struct impl, this); struct pw_resource *resource; - resource = pw_resource_new(client, id, global->type, global->object, NULL, link_unbind_func); + resource = pw_resource_new(client, id, global->type, 0); + if (resource == NULL) goto no_mem; + pw_resource_set_implementation(resource, global->object, PW_VERSION_LINK, NULL, link_unbind_func); impl->refcount++; pw_log_debug("link %p: bound to %d", global->object, resource->id); diff --git a/pipewire/server/module.c b/pipewire/server/module.c index d945d3ae5..d9075ea25 100644 --- a/pipewire/server/module.c +++ b/pipewire/server/module.c @@ -92,10 +92,12 @@ module_bind_func(struct pw_global *global, struct pw_client *client, uint32_t ve struct pw_module *this = global->object; struct pw_resource *resource; - resource = pw_resource_new(client, id, global->type, global->object, NULL, NULL); + resource = pw_resource_new(client, id, global->type, 0); if (resource == NULL) goto no_mem; + pw_resource_set_implementation(resource, global->object, PW_VERSION_MODULE, NULL, NULL); + pw_log_debug("module %p: bound to %d", global->object, resource->id); this->info.change_mask = ~0; diff --git a/pipewire/server/node.c b/pipewire/server/node.c index 7f405ebac..25c4486c1 100644 --- a/pipewire/server/node.c +++ b/pipewire/server/node.c @@ -475,10 +475,12 @@ node_bind_func(struct pw_global *global, struct pw_client *client, uint32_t vers struct pw_node *this = global->object; struct pw_resource *resource; - resource = pw_resource_new(client, id, global->type, global->object, NULL, node_unbind_func); + resource = pw_resource_new(client, id, global->type, 0); if (resource == NULL) goto no_mem; + pw_resource_set_implementation(resource, global->object, PW_VERSION_NODE, NULL, node_unbind_func); + pw_log_debug("node %p: bound to %d", this, resource->id); spa_list_insert(this->resource_list.prev, &resource->link); diff --git a/pipewire/server/protocol-native.c b/pipewire/server/protocol-native.c index b214ca74e..a96aad359 100644 --- a/pipewire/server/protocol-native.c +++ b/pipewire/server/protocol-native.c @@ -883,6 +883,8 @@ static const struct pw_core_events pw_protocol_native_server_core_events = { }; const struct pw_interface pw_protocol_native_server_core_interface = { + PIPEWIRE_TYPE__Core, + PW_VERSION_CORE, PW_CORE_METHOD_NUM, pw_protocol_native_server_core_demarshal, PW_CORE_EVENT_NUM, &pw_protocol_native_server_core_events, }; @@ -897,6 +899,8 @@ static const struct pw_registry_events pw_protocol_native_server_registry_events }; const struct pw_interface pw_protocol_native_server_registry_interface = { + PIPEWIRE_TYPE__Registry, + PW_VERSION_REGISTRY, PW_REGISTRY_METHOD_NUM, pw_protocol_native_server_registry_demarshal, PW_REGISTRY_EVENT_NUM, &pw_protocol_native_server_registry_events, }; @@ -906,6 +910,8 @@ static const struct pw_module_events pw_protocol_native_server_module_events = { }; const struct pw_interface pw_protocol_native_server_module_interface = { + PIPEWIRE_TYPE__Module, + PW_VERSION_MODULE, 0, NULL, PW_MODULE_EVENT_NUM, &pw_protocol_native_server_module_events, }; @@ -915,6 +921,8 @@ static const struct pw_node_events pw_protocol_native_server_node_events = { }; const struct pw_interface pw_protocol_native_server_node_interface = { + PIPEWIRE_TYPE__Node, + PW_VERSION_NODE, 0, NULL, PW_NODE_EVENT_NUM, &pw_protocol_native_server_node_events, }; @@ -924,6 +932,8 @@ static const struct pw_client_events pw_protocol_native_server_client_events = { }; const struct pw_interface pw_protocol_native_server_client_interface = { + PIPEWIRE_TYPE__Client, + PW_VERSION_CLIENT, 0, NULL, PW_CLIENT_EVENT_NUM, &pw_protocol_native_server_client_events, }; @@ -951,6 +961,8 @@ static const struct pw_client_node_events pw_protocol_native_server_client_node_ }; const struct pw_interface pw_protocol_native_server_client_node_interface = { + PIPEWIRE_TYPE_NODE_BASE "Client", + PW_VERSION_CLIENT_NODE, PW_CLIENT_NODE_METHOD_NUM, &pw_protocol_native_server_client_node_demarshal, PW_CLIENT_NODE_EVENT_NUM, &pw_protocol_native_server_client_node_events, }; @@ -960,29 +972,43 @@ static const struct pw_link_events pw_protocol_native_server_link_events = { }; const struct pw_interface pw_protocol_native_server_link_interface = { + PIPEWIRE_TYPE__Link, + PW_VERSION_LINK, 0, NULL, PW_LINK_EVENT_NUM, &pw_protocol_native_server_link_events, }; -bool pw_protocol_native_server_setup(struct pw_resource *resource) +void pw_protocol_native_server_init(void) { - const struct pw_interface *iface; - if (resource->type == resource->core->type.core) { - iface = &pw_protocol_native_server_core_interface; - } else if (resource->type == resource->core->type.registry) { - iface = &pw_protocol_native_server_registry_interface; - } else if (resource->type == resource->core->type.module) { - iface = &pw_protocol_native_server_module_interface; - } else if (resource->type == resource->core->type.node) { - iface = &pw_protocol_native_server_node_interface; - } else if (resource->type == resource->core->type.client) { - iface = &pw_protocol_native_server_client_interface; - } else if (resource->type == resource->core->type.client_node) { - iface = &pw_protocol_native_server_client_node_interface; - } else if (resource->type == resource->core->type.link) { - iface = &pw_protocol_native_server_link_interface; - } else - return false; - resource->iface = iface; - return true; + static bool init = false; + struct pw_protocol *protocol; + + if (init) + return; + + protocol = pw_protocol_get(PW_TYPE_PROTOCOL__Native); + + pw_protocol_add_interfaces(protocol, + NULL, + &pw_protocol_native_server_core_interface); + pw_protocol_add_interfaces(protocol, + NULL, + &pw_protocol_native_server_registry_interface); + pw_protocol_add_interfaces(protocol, + NULL, + &pw_protocol_native_server_module_interface); + pw_protocol_add_interfaces(protocol, + NULL, + &pw_protocol_native_server_node_interface); + pw_protocol_add_interfaces(protocol, + NULL, + &pw_protocol_native_server_client_node_interface); + pw_protocol_add_interfaces(protocol, + NULL, + &pw_protocol_native_server_client_interface); + pw_protocol_add_interfaces(protocol, + NULL, + &pw_protocol_native_server_link_interface); + + init = true; } diff --git a/pipewire/server/protocol-native.h b/pipewire/server/protocol-native.h index 5c6dbada1..26b3d1838 100644 --- a/pipewire/server/protocol-native.h +++ b/pipewire/server/protocol-native.h @@ -19,4 +19,4 @@ #include "pipewire/client/pipewire.h" -bool pw_protocol_native_server_setup(struct pw_resource *resource); +void pw_protocol_native_server_init(void); diff --git a/pipewire/server/resource.c b/pipewire/server/resource.c index 7d88432df..84a8db0c5 100644 --- a/pipewire/server/resource.c +++ b/pipewire/server/resource.c @@ -31,14 +31,12 @@ struct impl { struct pw_resource *pw_resource_new(struct pw_client *client, uint32_t id, uint32_t type, - void *object, - const void *implementation, - pw_destroy_t destroy) + size_t user_data_size) { struct impl *impl; struct pw_resource *this; - impl = calloc(1, sizeof(struct impl)); + impl = calloc(1, sizeof(struct impl) + user_data_size); if (impl == NULL) return NULL; @@ -46,20 +44,20 @@ struct pw_resource *pw_resource_new(struct pw_client *client, this->core = client->core; this->client = client; this->type = type; - this->object = object; - this->implementation = implementation; - this->destroy = destroy; pw_signal_init(&this->destroy_signal); if (id == SPA_ID_INVALID) { - this->id = pw_map_insert_new(&client->objects, this); + id = pw_map_insert_new(&client->objects, this); } else if (!pw_map_insert_at(&client->objects, id, this)) goto in_use; this->id = id; - pw_log_debug("resource %p: new for client %p id %u", this, client, this->id); + if (user_data_size > 0) + this->user_data = SPA_MEMBER(impl, sizeof(struct impl), void); + + pw_log_debug("resource %p: new for client %p id %u", this, client, id); pw_signal_emit(&client->resource_added, client, this); return this; @@ -70,6 +68,24 @@ struct pw_resource *pw_resource_new(struct pw_client *client, return NULL; } +int +pw_resource_set_implementation(struct pw_resource *resource, + void *object, + uint32_t version, + const void *implementation, + pw_destroy_t destroy) +{ + struct pw_client *client = resource->client; + + resource->object = object; + resource->version = version; + resource->implementation = implementation; + resource->destroy = destroy; + pw_signal_emit(&client->resource_impl, client, resource); + + return SPA_RESULT_OK; +} + void pw_resource_destroy(struct pw_resource *resource) { struct pw_client *client = resource->client; diff --git a/pipewire/server/resource.h b/pipewire/server/resource.h index 0cd5aa7ff..4159e227a 100644 --- a/pipewire/server/resource.h +++ b/pipewire/server/resource.h @@ -64,25 +64,32 @@ struct pw_resource { uint32_t id; /**< per client unique id, index in client objects */ uint32_t type; /**< type id of the object */ - void *object; /**< pointer to the object */ - pw_destroy_t destroy; /**< function to clean up the object */ - const struct pw_interface *iface; /**< protocol specific interface functions */ - const void *implementation; /**< implementation */ - void *access_private; /**< private data for access control */ + void *object; /**< pointer to the object */ + uint32_t version; /**< interface version */ + const void *implementation; /**< method implementation */ + pw_destroy_t destroy; /**< function to clean up the object */ /** Emited when the resource is destroyed */ PW_SIGNAL(destroy_signal, (struct pw_listener *listener, struct pw_resource *resource)); + + void *access_private; /**< private data for access control */ + void *user_data; /**< extra user data */ }; struct pw_resource * pw_resource_new(struct pw_client *client, uint32_t id, uint32_t type, - void *object, - const void *implementation, - pw_destroy_t destroy); + size_t user_data_size); + +int +pw_resource_set_implementation(struct pw_resource *resource, + void *object, + uint32_t version, + const void *implementation, + pw_destroy_t destroy); void pw_resource_destroy(struct pw_resource *resource);