From 5e28b182790ce38cb769949a5f2f9c649b6978c6 Mon Sep 17 00:00:00 2001 From: Jan-Simon Möller Date: Fri, 7 Jun 2019 13:35:14 +0200 Subject: pipewire recipe plumbing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This does enhance the recipes for pipewire and wireplumber in 2 ways: a) we add a separate package for the configuration and make it replaceable w/o recompiling pipewire or wireplumber itself b) this in turn makes the recipes not AGL specific and upstreamable as-is. v2: enhanced config recipes v3 & v4: fix typo Bug-AGL: SPEC-2473 Change-Id: I1f6f32d7cc64d9424706ca6bc87550f5e2c6d359 Signed-off-by: Jan-Simon Möller --- .../packagegroups/packagegroup-pipewire.bb | 1 - ...implement-Endpoint-ClientEndpoint-interfa.patch | 1562 -------------------- .../0001-spa-include-install-missing-headers.patch | 40 - ...i-add-support-for-printing-endpoint-info-.patch | 148 -- .../pipewire/pipewire-conf-agl/pipewire.conf | 10 + .../pipewire/pipewire-conf-agl_git.bb | 30 + .../recipes-multimedia/pipewire/pipewire.conf | 10 - .../recipes-multimedia/pipewire/pipewire.inc | 29 +- ...implement-Endpoint-ClientEndpoint-interfa.patch | 1562 ++++++++++++++++++++ .../0001-spa-include-install-missing-headers.patch | 40 + ...i-add-support-for-printing-endpoint-info-.patch | 148 ++ .../recipes-multimedia/pipewire/pipewire_git.bb | 6 +- .../wireplumber/wireplumber_git.bb | 12 +- 13 files changed, 1818 insertions(+), 1780 deletions(-) delete mode 100644 meta-pipewire/recipes-multimedia/pipewire/0001-extensions-implement-Endpoint-ClientEndpoint-interfa.patch delete mode 100644 meta-pipewire/recipes-multimedia/pipewire/0001-spa-include-install-missing-headers.patch delete mode 100644 meta-pipewire/recipes-multimedia/pipewire/0002-pipewire-cli-add-support-for-printing-endpoint-info-.patch create mode 100644 meta-pipewire/recipes-multimedia/pipewire/pipewire-conf-agl/pipewire.conf create mode 100644 meta-pipewire/recipes-multimedia/pipewire/pipewire-conf-agl_git.bb delete mode 100644 meta-pipewire/recipes-multimedia/pipewire/pipewire.conf create mode 100644 meta-pipewire/recipes-multimedia/pipewire/pipewire/0001-extensions-implement-Endpoint-ClientEndpoint-interfa.patch create mode 100644 meta-pipewire/recipes-multimedia/pipewire/pipewire/0001-spa-include-install-missing-headers.patch create mode 100644 meta-pipewire/recipes-multimedia/pipewire/pipewire/0002-pipewire-cli-add-support-for-printing-endpoint-info-.patch (limited to 'meta-pipewire') diff --git a/meta-pipewire/recipes-core/packagegroups/packagegroup-pipewire.bb b/meta-pipewire/recipes-core/packagegroups/packagegroup-pipewire.bb index b831ef38..7958c732 100644 --- a/meta-pipewire/recipes-core/packagegroups/packagegroup-pipewire.bb +++ b/meta-pipewire/recipes-core/packagegroups/packagegroup-pipewire.bb @@ -11,5 +11,4 @@ PACKAGES = "\ RDEPENDS_${PN} += "\ pipewire \ pipewire-alsa \ - wireplumber \ " diff --git a/meta-pipewire/recipes-multimedia/pipewire/0001-extensions-implement-Endpoint-ClientEndpoint-interfa.patch b/meta-pipewire/recipes-multimedia/pipewire/0001-extensions-implement-Endpoint-ClientEndpoint-interfa.patch deleted file mode 100644 index b78a9096..00000000 --- a/meta-pipewire/recipes-multimedia/pipewire/0001-extensions-implement-Endpoint-ClientEndpoint-interfa.patch +++ /dev/null @@ -1,1562 +0,0 @@ -From 3d186f7b97c508cc16955a96a69ee5d6c9db57dc Mon Sep 17 00:00:00 2001 -From: George Kiagiadakis -Date: Thu, 23 May 2019 18:59:05 +0300 -Subject: [PATCH 1/2] extensions: implement Endpoint & ClientEndpoint - interfaces - -The ClientEndpoint interface allows session managers to register -endpoint objects on pipewire. -The Endpoint interface allows other clients to interact with -endpoints provided by the session manager. ---- - src/extensions/client-endpoint.h | 106 ++++ - src/extensions/endpoint.h | 237 +++++++++ - src/extensions/meson.build | 2 + - src/modules/meson.build | 12 + - src/modules/module-endpoint.c | 137 +++++ - src/modules/module-endpoint/endpoint-impl.c | 428 ++++++++++++++++ - src/modules/module-endpoint/endpoint-impl.h | 52 ++ - src/modules/module-endpoint/protocol-native.c | 472 ++++++++++++++++++ - src/pipewire/pipewire.c | 2 + - src/pipewire/type.h | 3 +- - 10 files changed, 1450 insertions(+), 1 deletion(-) - create mode 100644 src/extensions/client-endpoint.h - create mode 100644 src/extensions/endpoint.h - create mode 100644 src/modules/module-endpoint.c - create mode 100644 src/modules/module-endpoint/endpoint-impl.c - create mode 100644 src/modules/module-endpoint/endpoint-impl.h - create mode 100644 src/modules/module-endpoint/protocol-native.c - -diff --git a/src/extensions/client-endpoint.h b/src/extensions/client-endpoint.h -new file mode 100644 -index 00000000..0389893c ---- /dev/null -+++ b/src/extensions/client-endpoint.h -@@ -0,0 +1,106 @@ -+/* PipeWire -+ * -+ * Copyright © 2019 Collabora Ltd. -+ * @author George Kiagiadakis -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a -+ * copy of this software and associated documentation files (the "Software"), -+ * to deal in the Software without restriction, including without limitation -+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, -+ * and/or sell copies of the Software, and to permit persons to whom the -+ * Software is furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice (including the next -+ * paragraph) shall be included in all copies or substantial portions of the -+ * Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -+ * DEALINGS IN THE SOFTWARE. -+ */ -+ -+#ifndef PIPEWIRE_EXT_CLIENT_ENDPOINT_H -+#define PIPEWIRE_EXT_CLIENT_ENDPOINT_H -+ -+#include "endpoint.h" -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+struct pw_client_endpoint_proxy; -+ -+#define PW_VERSION_CLIENT_ENDPOINT 0 -+#define PW_EXTENSION_MODULE_CLIENT_ENDPOINT PIPEWIRE_MODULE_PREFIX "module-endpoint" -+ -+#define PW_CLIENT_ENDPOINT_PROXY_METHOD_UPDATE 0 -+#define PW_CLIENT_ENDPOINT_PROXY_METHOD_NUM 1 -+ -+struct pw_client_endpoint_proxy_methods { -+#define PW_VERSION_CLIENT_ENDPOINT_PROXY_METHODS 0 -+ uint32_t version; -+ -+ /** -+ * Update endpoint info -+ */ -+ int (*update) (void *object, -+#define PW_CLIENT_ENDPOINT_UPDATE_PARAMS (1 << 0) -+#define PW_CLIENT_ENDPOINT_UPDATE_PARAMS_INCREMENTAL (1 << 1) -+#define PW_CLIENT_ENDPOINT_UPDATE_INFO (1 << 2) -+ uint32_t change_mask, -+ uint32_t n_params, -+ const struct spa_pod **params, -+ const struct pw_endpoint_info *info); -+}; -+ -+static inline int -+pw_client_endpoint_proxy_update(struct pw_client_endpoint_proxy *p, -+ uint32_t change_mask, -+ uint32_t n_params, -+ const struct spa_pod **params, -+ struct pw_endpoint_info *info) -+{ -+ return pw_proxy_do((struct pw_proxy*)p, -+ struct pw_client_endpoint_proxy_methods, update, -+ change_mask, n_params, params, info); -+} -+ -+#define PW_CLIENT_ENDPOINT_PROXY_EVENT_SET_PARAM 0 -+#define PW_CLIENT_ENDPOINT_PROXY_EVENT_NUM 1 -+ -+struct pw_client_endpoint_proxy_events { -+#define PW_VERSION_CLIENT_ENDPOINT_PROXY_EVENTS 0 -+ uint32_t version; -+ -+ /** -+ * Set a parameter on the endpoint -+ * -+ * \param id the parameter id to set -+ * \param flags extra parameter flags -+ * \param param the parameter to set -+ */ -+ void (*set_param) (void *object, uint32_t id, uint32_t flags, -+ const struct spa_pod *param); -+}; -+ -+static inline void -+pw_client_endpoint_proxy_add_listener(struct pw_client_endpoint_proxy *p, -+ struct spa_hook *listener, -+ const struct pw_client_endpoint_proxy_events *events, -+ void *data) -+{ -+ pw_proxy_add_proxy_listener((struct pw_proxy*)p, listener, events, data); -+} -+ -+#define pw_client_endpoint_resource_set_param(r,...) \ -+ pw_resource_notify(r,struct pw_client_endpoint_proxy_events,set_param,__VA_ARGS__) -+ -+#ifdef __cplusplus -+} /* extern "C" */ -+#endif -+ -+#endif /* PIPEWIRE_EXT_CLIENT_ENDPOINT_H */ -diff --git a/src/extensions/endpoint.h b/src/extensions/endpoint.h -new file mode 100644 -index 00000000..3b84dd49 ---- /dev/null -+++ b/src/extensions/endpoint.h -@@ -0,0 +1,237 @@ -+/* PipeWire -+ * -+ * Copyright © 2019 Collabora Ltd. -+ * @author George Kiagiadakis -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a -+ * copy of this software and associated documentation files (the "Software"), -+ * to deal in the Software without restriction, including without limitation -+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, -+ * and/or sell copies of the Software, and to permit persons to whom the -+ * Software is furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice (including the next -+ * paragraph) shall be included in all copies or substantial portions of the -+ * Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -+ * DEALINGS IN THE SOFTWARE. -+ */ -+ -+#ifndef PIPEWIRE_EXT_ENDPOINT_H -+#define PIPEWIRE_EXT_ENDPOINT_H -+ -+#include -+#include -+#include -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+struct pw_endpoint_proxy; -+ -+#define PW_VERSION_ENDPOINT 0 -+#define PW_EXTENSION_MODULE_ENDPOINT PIPEWIRE_MODULE_PREFIX "module-endpoint" -+ -+/* extending enum spa_param_type */ -+enum endpoint_param_type { -+ PW_ENDPOINT_PARAM_EnumControl = 0x1000, -+ PW_ENDPOINT_PARAM_Control, -+ PW_ENDPOINT_PARAM_EnumStream, -+}; -+ -+enum endpoint_param_object_type { -+ PW_ENDPOINT_OBJECT_ParamControl = PW_TYPE_FIRST + SPA_TYPE_OBJECT_START + 0x1001, -+ PW_ENDPOINT_OBJECT_ParamStream, -+}; -+ -+/** properties for PW_ENDPOINT_OBJECT_ParamControl */ -+enum endpoint_param_control { -+ PW_ENDPOINT_PARAM_CONTROL_START, /**< object id, one of enum endpoint_param_type */ -+ PW_ENDPOINT_PARAM_CONTROL_id, /**< control id (Int) */ -+ PW_ENDPOINT_PARAM_CONTROL_stream_id, /**< stream id (Int) */ -+ PW_ENDPOINT_PARAM_CONTROL_name, /**< control name (String) */ -+ PW_ENDPOINT_PARAM_CONTROL_type, /**< control type (Range) */ -+ PW_ENDPOINT_PARAM_CONTROL_value, /**< control value */ -+}; -+ -+/** properties for PW_ENDPOINT_OBJECT_ParamStream */ -+enum endpoint_param_stream { -+ PW_ENDPOINT_PARAM_STREAM_START, /**< object id, one of enum endpoint_param_type */ -+ PW_ENDPOINT_PARAM_STREAM_id, /**< stream id (Int) */ -+ PW_ENDPOINT_PARAM_STREAM_name, /**< stream name (String) */ -+}; -+ -+static const struct spa_type_info endpoint_param_type_info[] = { -+ { PW_ENDPOINT_PARAM_EnumControl, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_ID_BASE "EnumControl", NULL }, -+ { PW_ENDPOINT_PARAM_Control, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_ID_BASE "Control", NULL }, -+ { PW_ENDPOINT_PARAM_EnumStream, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_ID_BASE "EnumStream", NULL }, -+ { 0, 0, NULL, NULL }, -+}; -+ -+#define PW_ENDPOINT_TYPE_INFO_ParamControl SPA_TYPE_INFO_PARAM_BASE "ParamControl" -+#define PW_ENDPOINT_TYPE_INFO_PARAM_CONTROL_BASE PW_ENDPOINT_TYPE_INFO_ParamControl ":" -+ -+static const struct spa_type_info endpoint_param_control_info[] = { -+ { PW_ENDPOINT_PARAM_CONTROL_START, SPA_TYPE_Id, PW_ENDPOINT_TYPE_INFO_PARAM_CONTROL_BASE, spa_type_param, }, -+ { PW_ENDPOINT_PARAM_CONTROL_id, SPA_TYPE_Int, PW_ENDPOINT_TYPE_INFO_PARAM_CONTROL_BASE "id", NULL }, -+ { PW_ENDPOINT_PARAM_CONTROL_stream_id, SPA_TYPE_Int, PW_ENDPOINT_TYPE_INFO_PARAM_CONTROL_BASE "streamId", NULL }, -+ { PW_ENDPOINT_PARAM_CONTROL_name, SPA_TYPE_String, PW_ENDPOINT_TYPE_INFO_PARAM_CONTROL_BASE "name", NULL }, -+ { PW_ENDPOINT_PARAM_CONTROL_type, SPA_TYPE_Pod, PW_ENDPOINT_TYPE_INFO_PARAM_CONTROL_BASE "type", NULL }, -+ { PW_ENDPOINT_PARAM_CONTROL_value, SPA_TYPE_Struct, PW_ENDPOINT_TYPE_INFO_PARAM_CONTROL_BASE "labels", NULL }, -+ { 0, 0, NULL, NULL }, -+}; -+ -+#define PW_ENDPOINT_TYPE_INFO_ParamStream SPA_TYPE_INFO_PARAM_BASE "ParamStream" -+#define PW_ENDPOINT_TYPE_INFO_PARAM_STREAM_BASE PW_ENDPOINT_TYPE_INFO_ParamStream ":" -+ -+static const struct spa_type_info endpoint_param_stream_info[] = { -+ { PW_ENDPOINT_PARAM_STREAM_START, SPA_TYPE_Id, PW_ENDPOINT_TYPE_INFO_PARAM_STREAM_BASE, spa_type_param, }, -+ { PW_ENDPOINT_PARAM_STREAM_id, SPA_TYPE_Int, PW_ENDPOINT_TYPE_INFO_PARAM_STREAM_BASE "id", NULL }, -+ { PW_ENDPOINT_PARAM_STREAM_name, SPA_TYPE_String, PW_ENDPOINT_TYPE_INFO_PARAM_STREAM_BASE "name", NULL }, -+ { 0, 0, NULL, NULL }, -+}; -+ -+static const struct spa_type_info endpoint_param_object_type_info[] = { -+ { PW_ENDPOINT_OBJECT_ParamControl, SPA_TYPE_Object, SPA_TYPE_INFO_OBJECT_BASE "ParamControl", endpoint_param_control_info, }, -+ { PW_ENDPOINT_OBJECT_ParamStream, SPA_TYPE_Object, SPA_TYPE_INFO_OBJECT_BASE "ParamStream", endpoint_param_stream_info }, -+ { 0, 0, NULL, NULL }, -+}; -+ -+struct pw_endpoint_info { -+ uint32_t id; /**< id of the global */ -+#define PW_ENDPOINT_CHANGE_MASK_PARAMS (1 << 0) -+#define PW_ENDPOINT_CHANGE_MASK_PROPS (1 << 1) -+ uint32_t change_mask; /**< bitfield of changed fields since last call */ -+ uint32_t n_params; /**< number of items in \a params */ -+ struct spa_param_info *params; /**< parameters */ -+ struct spa_dict *props; /**< extra properties */ -+}; -+ -+#define PW_ENDPOINT_PROXY_METHOD_SUBSCRIBE_PARAMS 0 -+#define PW_ENDPOINT_PROXY_METHOD_ENUM_PARAMS 1 -+#define PW_ENDPOINT_PROXY_METHOD_SET_PARAM 2 -+#define PW_ENDPOINT_PROXY_METHOD_NUM 3 -+ -+struct pw_endpoint_proxy_methods { -+#define PW_VERSION_ENDPOINT_PROXY_METHODS 0 -+ uint32_t version; -+ -+ /** -+ * Subscribe to parameter changes -+ * -+ * Automatically emit param events for the given ids when -+ * they are changed. -+ * -+ * \param ids an array of param ids -+ * \param n_ids the number of ids in \a ids -+ */ -+ int (*subscribe_params) (void *object, uint32_t *ids, uint32_t n_ids); -+ -+ /** -+ * Enumerate endpoint parameters -+ * -+ * Start enumeration of endpoint parameters. For each param, a -+ * param event will be emited. -+ * -+ * \param seq a sequence number to place in the reply -+ * \param id the parameter id to enum or SPA_ID_INVALID for all -+ * \param start the start index or 0 for the first param -+ * \param num the maximum number of params to retrieve -+ * \param filter a param filter or NULL -+ */ -+ int (*enum_params) (void *object, int seq, -+ uint32_t id, uint32_t start, uint32_t num, -+ const struct spa_pod *filter); -+ -+ /** -+ * Set a parameter on the endpoint -+ * -+ * \param id the parameter id to set -+ * \param flags extra parameter flags -+ * \param param the parameter to set -+ */ -+ int (*set_param) (void *object, uint32_t id, uint32_t flags, -+ const struct spa_pod *param); -+}; -+ -+static inline int -+pw_endpoint_proxy_subscribe_params(struct pw_endpoint_proxy *p, uint32_t *ids, uint32_t n_ids) -+{ -+ return pw_proxy_do((struct pw_proxy*)p, struct pw_endpoint_proxy_methods, -+ subscribe_params, ids, n_ids); -+} -+ -+static inline int -+pw_endpoint_proxy_enum_params(struct pw_endpoint_proxy *p, int seq, -+ uint32_t id, uint32_t start, uint32_t num, -+ const struct spa_pod *filter) -+{ -+ return pw_proxy_do((struct pw_proxy*)p, struct pw_endpoint_proxy_methods, -+ enum_params, seq, id, start, num, filter); -+} -+ -+static inline int -+pw_endpoint_proxy_set_param(struct pw_endpoint_proxy *p, uint32_t id, -+ uint32_t flags, const struct spa_pod *param) -+{ -+ return pw_proxy_do((struct pw_proxy*)p, struct pw_endpoint_proxy_methods, -+ set_param, id, flags, param); -+} -+ -+#define PW_ENDPOINT_PROXY_EVENT_INFO 0 -+#define PW_ENDPOINT_PROXY_EVENT_PARAM 1 -+#define PW_ENDPOINT_PROXY_EVENT_NUM 2 -+ -+struct pw_endpoint_proxy_events { -+#define PW_VERSION_ENDPOINT_PROXY_EVENTS 0 -+ uint32_t version; -+ -+ /** -+ * Notify endpoint info -+ * -+ * \param info info about the endpoint -+ */ -+ void (*info) (void *object, const struct pw_endpoint_info * info); -+ -+ /** -+ * Notify an endpoint param -+ * -+ * Event emited as a result of the enum_params method. -+ * -+ * \param seq the sequence number of the request -+ * \param id the param id -+ * \param index the param index -+ * \param next the param index of the next param -+ * \param param the parameter -+ */ -+ void (*param) (void *object, int seq, uint32_t id, -+ uint32_t index, uint32_t next, -+ const struct spa_pod *param); -+}; -+ -+static inline void -+pw_endpoint_proxy_add_listener(struct pw_endpoint_proxy *p, -+ struct spa_hook *listener, -+ const struct pw_endpoint_proxy_events *events, -+ void *data) -+{ -+ pw_proxy_add_proxy_listener((struct pw_proxy*)p, listener, events, data); -+} -+ -+#define pw_endpoint_resource_info(r,...) \ -+ pw_resource_notify(r,struct pw_endpoint_proxy_events,info,__VA_ARGS__) -+#define pw_endpoint_resource_param(r,...) \ -+ pw_resource_notify(r,struct pw_endpoint_proxy_events,param,__VA_ARGS__) -+ -+#ifdef __cplusplus -+} /* extern "C" */ -+#endif -+ -+#endif /* PIPEWIRE_EXT_ENDPOINT_H */ -diff --git a/src/extensions/meson.build b/src/extensions/meson.build -index a7f5d3cb..9f690caf 100644 ---- a/src/extensions/meson.build -+++ b/src/extensions/meson.build -@@ -1,5 +1,7 @@ - pipewire_ext_headers = [ -+ 'client-endpoint.h', - 'client-node.h', -+ 'endpoint.h', - 'protocol-native.h', - ] - -diff --git a/src/modules/meson.build b/src/modules/meson.build -index 98bc3864..572f1b6b 100644 ---- a/src/modules/meson.build -+++ b/src/modules/meson.build -@@ -37,6 +37,18 @@ pipewire_module_client_node = shared_library('pipewire-module-client-node', - dependencies : [mathlib, dl_lib, pipewire_dep], - ) - -+pipewire_module_endpoint = shared_library('pipewire-module-endpoint', -+ [ 'module-endpoint.c', -+ 'module-endpoint/endpoint-impl.c', -+ 'module-endpoint/protocol-native.c', -+ ], -+ c_args : pipewire_module_c_args, -+ include_directories : [configinc, spa_inc], -+ install : true, -+ install_dir : modules_install_dir, -+ dependencies : [mathlib, dl_lib, pipewire_dep], -+) -+ - pipewire_module_link_factory = shared_library('pipewire-module-link-factory', - [ 'module-link-factory.c' ], - c_args : pipewire_module_c_args, -diff --git a/src/modules/module-endpoint.c b/src/modules/module-endpoint.c -new file mode 100644 -index 00000000..d830de1b ---- /dev/null -+++ b/src/modules/module-endpoint.c -@@ -0,0 +1,137 @@ -+/* PipeWire -+ * -+ * Copyright © 2019 Collabora Ltd. -+ * @author George Kiagiadakis -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a -+ * copy of this software and associated documentation files (the "Software"), -+ * to deal in the Software without restriction, including without limitation -+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, -+ * and/or sell copies of the Software, and to permit persons to whom the -+ * Software is furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice (including the next -+ * paragraph) shall be included in all copies or substantial portions of the -+ * Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -+ * DEALINGS IN THE SOFTWARE. -+ */ -+ -+#include "config.h" -+ -+#include "module-endpoint/endpoint-impl.h" -+ -+struct pw_protocol *pw_protocol_native_ext_endpoint_init(struct pw_core *core); -+ -+static const struct spa_dict_item module_props[] = { -+ { PW_MODULE_PROP_AUTHOR, "George Kiagiadakis " }, -+ { PW_MODULE_PROP_DESCRIPTION, "Allows clients to interract with session manager endpoints" }, -+ { PW_MODULE_PROP_VERSION, PACKAGE_VERSION }, -+}; -+ -+struct factory_data { -+ struct pw_factory *this; -+ struct pw_properties *properties; -+ -+ struct pw_module *module; -+ struct spa_hook module_listener; -+}; -+ -+static void *create_object(void *_data, -+ struct pw_resource *resource, -+ uint32_t type, -+ uint32_t version, -+ struct pw_properties *properties, -+ uint32_t new_id) -+{ -+ void *result; -+ struct pw_resource *endpoint_resource; -+ struct pw_global *parent; -+ struct pw_client *client = pw_resource_get_client(resource); -+ -+ endpoint_resource = pw_resource_new(client, new_id, PW_PERM_RWX, type, version, 0); -+ if (endpoint_resource == NULL) -+ goto no_mem; -+ -+ parent = pw_client_get_global(client); -+ -+ result = pw_client_endpoint_new(endpoint_resource, parent, properties); -+ if (result == NULL) -+ goto no_mem; -+ -+ return result; -+ -+ no_mem: -+ pw_log_error("can't create endpoint"); -+ pw_resource_error(resource, -ENOMEM, "can't create endpoint: no memory"); -+ if (properties) -+ pw_properties_free(properties); -+ return NULL; -+} -+ -+static const struct pw_factory_implementation impl_factory = { -+ PW_VERSION_FACTORY_IMPLEMENTATION, -+ .create_object = create_object, -+}; -+ -+static void module_destroy(void *data) -+{ -+ struct factory_data *d = data; -+ -+ spa_hook_remove(&d->module_listener); -+ -+ if (d->properties) -+ pw_properties_free(d->properties); -+ -+ pw_factory_destroy(d->this); -+} -+ -+static const struct pw_module_events module_events = { -+ PW_VERSION_MODULE_EVENTS, -+ .destroy = module_destroy, -+}; -+ -+static int module_init(struct pw_module *module, struct pw_properties *properties) -+{ -+ struct pw_core *core = pw_module_get_core(module); -+ struct pw_factory *factory; -+ struct factory_data *data; -+ -+ factory = pw_factory_new(core, -+ "client-endpoint", -+ PW_TYPE_INTERFACE_ClientEndpoint, -+ PW_VERSION_CLIENT_ENDPOINT, -+ NULL, -+ sizeof(*data)); -+ if (factory == NULL) -+ return -ENOMEM; -+ -+ data = pw_factory_get_user_data(factory); -+ data->this = factory; -+ data->module = module; -+ data->properties = properties; -+ -+ pw_log_debug("module-endpoint %p: new", module); -+ -+ pw_factory_set_implementation(factory, &impl_factory, data); -+ pw_factory_register(factory, NULL, pw_module_get_global(module), NULL); -+ -+ pw_protocol_native_ext_endpoint_init(core); -+ -+ pw_module_add_listener(module, &data->module_listener, &module_events, data); -+ pw_module_update_properties(module, &SPA_DICT_INIT_ARRAY(module_props)); -+ -+ return 0; -+} -+ -+SPA_EXPORT -+int pipewire__module_init(struct pw_module *module, const char *args) -+{ -+ return module_init(module, NULL); -+} -diff --git a/src/modules/module-endpoint/endpoint-impl.c b/src/modules/module-endpoint/endpoint-impl.c -new file mode 100644 -index 00000000..252eeca1 ---- /dev/null -+++ b/src/modules/module-endpoint/endpoint-impl.c -@@ -0,0 +1,428 @@ -+/* PipeWire -+ * -+ * Copyright © 2019 Collabora Ltd. -+ * @author George Kiagiadakis -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a -+ * copy of this software and associated documentation files (the "Software"), -+ * to deal in the Software without restriction, including without limitation -+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, -+ * and/or sell copies of the Software, and to permit persons to whom the -+ * Software is furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice (including the next -+ * paragraph) shall be included in all copies or substantial portions of the -+ * Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -+ * DEALINGS IN THE SOFTWARE. -+ */ -+ -+#include "endpoint-impl.h" -+#include -+#include -+#include -+ -+struct pw_endpoint { -+ struct pw_core *core; -+ struct pw_global *global; -+ struct pw_global *parent; -+ -+ struct pw_client_endpoint *client_ep; -+ -+ uint32_t n_params; -+ struct spa_pod **params; -+ -+ struct pw_endpoint_info info; -+ struct pw_properties *props; -+}; -+ -+struct pw_client_endpoint { -+ struct pw_resource *owner_resource; -+ struct spa_hook owner_resource_listener; -+ -+ struct pw_endpoint endpoint; -+}; -+ -+struct resource_data { -+ struct pw_endpoint *endpoint; -+ struct pw_client_endpoint *client_ep; -+ -+ struct spa_hook resource_listener; -+ -+ uint32_t n_subscribe_ids; -+ uint32_t subscribe_ids[32]; -+}; -+ -+static int -+endpoint_enum_params (void *object, int seq, -+ uint32_t id, uint32_t start, uint32_t num, -+ const struct spa_pod *filter) -+{ -+ struct pw_resource *resource = object; -+ struct resource_data *data = pw_resource_get_user_data(resource); -+ struct pw_endpoint *this = data->endpoint; -+ struct spa_pod *result; -+ struct spa_pod *param; -+ uint8_t buffer[1024]; -+ struct spa_pod_builder b = { 0 }; -+ uint32_t index; -+ uint32_t next = start; -+ uint32_t count = 0; -+ -+ while (true) { -+ index = next++; -+ if (index >= this->n_params) -+ break; -+ -+ param = this->params[index]; -+ -+ if (param == NULL || !spa_pod_is_object_id(param, id)) -+ continue; -+ -+ spa_pod_builder_init(&b, buffer, sizeof(buffer)); -+ if (spa_pod_filter(&b, &result, param, filter) != 0) -+ continue; -+ -+ pw_log_debug("endpoint %p: %d param %u", this, seq, index); -+ -+ pw_endpoint_resource_param(resource, seq, id, index, next, result); -+ -+ if (++count == num) -+ break; -+ } -+ return 0; -+} -+ -+static int -+endpoint_subscribe_params (void *object, uint32_t *ids, uint32_t n_ids) -+{ -+ struct pw_resource *resource = object; -+ struct resource_data *data = pw_resource_get_user_data(resource); -+ uint32_t i; -+ -+ n_ids = SPA_MIN(n_ids, SPA_N_ELEMENTS(data->subscribe_ids)); -+ data->n_subscribe_ids = n_ids; -+ -+ for (i = 0; i < n_ids; i++) { -+ data->subscribe_ids[i] = ids[i]; -+ pw_log_debug("endpoint %p: resource %d subscribe param %u", -+ data->endpoint, resource->id, ids[i]); -+ endpoint_enum_params(resource, 1, ids[i], 0, UINT32_MAX, NULL); -+ } -+ return 0; -+} -+ -+static int -+endpoint_set_param (void *object, uint32_t id, uint32_t flags, -+ const struct spa_pod *param) -+{ -+ struct pw_resource *resource = object; -+ struct resource_data *data = pw_resource_get_user_data(resource); -+ struct pw_client_endpoint *client_ep = data->client_ep; -+ -+ pw_client_endpoint_resource_set_param(client_ep->owner_resource, -+ id, flags, param); -+ -+ return 0; -+} -+ -+static const struct pw_endpoint_proxy_methods endpoint_methods = { -+ PW_VERSION_ENDPOINT_PROXY_METHODS, -+ .subscribe_params = endpoint_subscribe_params, -+ .enum_params = endpoint_enum_params, -+ .set_param = endpoint_set_param, -+}; -+ -+static void -+endpoint_unbind(void *data) -+{ -+ struct pw_resource *resource = data; -+ spa_list_remove(&resource->link); -+} -+ -+static const struct pw_resource_events resource_events = { -+ PW_VERSION_RESOURCE_EVENTS, -+ .destroy = endpoint_unbind, -+}; -+ -+static int -+endpoint_bind(void *_data, struct pw_client *client, uint32_t permissions, -+ uint32_t version, uint32_t id) -+{ -+ struct pw_endpoint *this = _data; -+ struct pw_global *global = this->global; -+ struct pw_resource *resource; -+ struct resource_data *data; -+ -+ resource = pw_resource_new(client, id, permissions, global->type, version, sizeof(*data)); -+ if (resource == NULL) -+ goto no_mem; -+ -+ data = pw_resource_get_user_data(resource); -+ data->endpoint = this; -+ data->client_ep = this->client_ep; -+ pw_resource_add_listener(resource, &data->resource_listener, &resource_events, resource); -+ -+ pw_resource_set_implementation(resource, &endpoint_methods, resource); -+ -+ pw_log_debug("endpoint %p: bound to %d", this, resource->id); -+ -+ spa_list_append(&global->resource_list, &resource->link); -+ -+ this->info.change_mask = PW_ENDPOINT_CHANGE_MASK_PARAMS | -+ PW_ENDPOINT_CHANGE_MASK_PROPS; -+ pw_endpoint_resource_info(resource, &this->info); -+ this->info.change_mask = 0; -+ -+ return 0; -+ -+ no_mem: -+ pw_log_error("can't create node resource"); -+ return -ENOMEM; -+} -+ -+static int -+pw_endpoint_init(struct pw_endpoint *this, -+ struct pw_core *core, -+ struct pw_client *owner, -+ struct pw_global *parent, -+ struct pw_properties *properties) -+{ -+ struct pw_properties *props = NULL; -+ -+ pw_log_debug("endpoint %p: new", this); -+ -+ this->core = core; -+ this->parent = parent; -+ -+ props = properties ? properties : pw_properties_new(NULL, NULL); -+ if (!props) -+ goto no_mem; -+ -+ this->props = pw_properties_copy (props); -+ if (!this->props) -+ goto no_mem; -+ -+ this->global = pw_global_new (core, -+ PW_TYPE_INTERFACE_Endpoint, -+ PW_VERSION_ENDPOINT, -+ props, endpoint_bind, this); -+ if (!this->global) -+ goto no_mem; -+ -+ this->info.id = this->global->id; -+ this->info.props = &this->props->dict; -+ -+ return pw_global_register(this->global, owner, parent); -+ -+ no_mem: -+ pw_log_error("can't create endpoint - out of memory"); -+ if (props && !properties) -+ pw_properties_free(props); -+ if (this->props) -+ pw_properties_free(this->props); -+ return -ENOMEM; -+} -+ -+static void -+pw_endpoint_clear(struct pw_endpoint *this) -+{ -+ uint32_t i; -+ -+ pw_log_debug("endpoint %p: destroy", this); -+ -+ pw_global_destroy(this->global); -+ -+ for (i = 0; i < this->n_params; i++) -+ free(this->params[i]); -+ free(this->params); -+ -+ free(this->info.params); -+ -+ if (this->props) -+ pw_properties_free(this->props); -+} -+ -+static void -+endpoint_notify_subscribed(struct pw_endpoint *this, -+ uint32_t index, uint32_t next) -+{ -+ struct pw_global *global = this->global; -+ struct pw_resource *resource; -+ struct resource_data *data; -+ struct spa_pod *param = this->params[index]; -+ uint32_t id; -+ uint32_t i; -+ -+ if (!param || !spa_pod_is_object (param)) -+ return; -+ -+ id = SPA_POD_OBJECT_ID (param); -+ -+ spa_list_for_each(resource, &global->resource_list, link) { -+ data = pw_resource_get_user_data(resource); -+ for (i = 0; i < data->n_subscribe_ids; i++) { -+ if (data->subscribe_ids[i] == id) { -+ pw_endpoint_resource_param(resource, 1, id, -+ index, next, param); -+ } -+ } -+ } -+} -+ -+static int -+client_endpoint_update(void *object, -+ uint32_t change_mask, -+ uint32_t n_params, -+ const struct spa_pod **params, -+ const struct pw_endpoint_info *info) -+{ -+ struct pw_client_endpoint *cliep = object; -+ struct pw_endpoint *this = &cliep->endpoint; -+ -+ if (change_mask & PW_CLIENT_ENDPOINT_UPDATE_PARAMS) { -+ uint32_t i; -+ -+ pw_log_debug("endpoint %p: update %d params", this, n_params); -+ -+ for (i = 0; i < this->n_params; i++) -+ free(this->params[i]); -+ this->n_params = n_params; -+ this->params = realloc(this->params, this->n_params * sizeof(struct spa_pod *)); -+ -+ for (i = 0; i < this->n_params; i++) { -+ this->params[i] = params[i] ? spa_pod_copy(params[i]) : NULL; -+ endpoint_notify_subscribed(this, i, i+1); -+ } -+ } -+ else if (change_mask & PW_CLIENT_ENDPOINT_UPDATE_PARAMS_INCREMENTAL) { -+ uint32_t i, j; -+ const struct spa_pod_prop *pold, *pnew; -+ -+ pw_log_debug("endpoint %p: update %d params incremental", this, n_params); -+ -+ for (i = 0; i < this->n_params; i++) { -+ /* we only support incremental updates for controls */ -+ if (!spa_pod_is_object_id (this->params[i], PW_ENDPOINT_PARAM_Control)) -+ continue; -+ -+ for (j = 0; j < n_params; j++) { -+ if (!spa_pod_is_object_id (params[j], PW_ENDPOINT_PARAM_Control)) { -+ pw_log_warn ("endpoint %p: ignoring incremental update " -+ "on non-control param", this); -+ continue; -+ } -+ -+ pold = spa_pod_object_find_prop ( -+ (const struct spa_pod_object *) this->params[i], -+ NULL, PW_ENDPOINT_PARAM_CONTROL_id); -+ pnew = spa_pod_object_find_prop ( -+ (const struct spa_pod_object *) params[j], -+ NULL, PW_ENDPOINT_PARAM_CONTROL_id); -+ -+ if (pold && pnew && spa_pod_compare (&pold->value, &pnew->value) == 0) { -+ free (this->params[i]); -+ this->params[i] = spa_pod_copy (params[j]); -+ endpoint_notify_subscribed(this, i, UINT32_MAX); -+ } -+ } -+ } -+ } -+ -+ if (change_mask & PW_CLIENT_ENDPOINT_UPDATE_INFO) { -+ struct pw_global *global = this->global; -+ struct pw_resource *resource; -+ -+ if (info->change_mask & PW_ENDPOINT_CHANGE_MASK_PARAMS) { -+ size_t size = info->n_params * sizeof(struct spa_param_info); -+ free(this->info.params); -+ this->info.params = malloc(size); -+ this->info.n_params = info->n_params; -+ memcpy(this->info.params, info->params, size); -+ } -+ -+ if (info->change_mask & PW_ENDPOINT_CHANGE_MASK_PROPS) { -+ pw_properties_update(this->props, info->props); -+ } -+ -+ this->info.change_mask = info->change_mask; -+ spa_list_for_each(resource, &global->resource_list, link) { -+ pw_endpoint_resource_info(resource, &this->info); -+ } -+ this->info.change_mask = 0; -+ } -+ -+ return 0; -+} -+ -+static struct pw_client_endpoint_proxy_methods client_endpoint_methods = { -+ PW_VERSION_CLIENT_ENDPOINT_PROXY_METHODS, -+ .update = client_endpoint_update, -+}; -+ -+static void -+client_endpoint_resource_destroy(void *data) -+{ -+ struct pw_client_endpoint *this = data; -+ -+ pw_log_debug("client-endpoint %p: destroy", this); -+ -+ pw_endpoint_clear(&this->endpoint); -+ -+ this->owner_resource = NULL; -+ spa_hook_remove(&this->owner_resource_listener); -+ free(this); -+} -+ -+static const struct pw_resource_events owner_resource_events = { -+ PW_VERSION_RESOURCE_EVENTS, -+ .destroy = client_endpoint_resource_destroy, -+}; -+ -+struct pw_client_endpoint * -+pw_client_endpoint_new(struct pw_resource *owner_resource, -+ struct pw_global *parent, -+ struct pw_properties *properties) -+{ -+ struct pw_client_endpoint *this; -+ struct pw_client *owner = pw_resource_get_client(owner_resource); -+ struct pw_core *core = pw_client_get_core(owner); -+ -+ this = calloc(1, sizeof(struct pw_client_endpoint)); -+ if (this == NULL) -+ return NULL; -+ -+ pw_log_debug("client-endpoint %p: new", this); -+ -+ if (pw_endpoint_init(&this->endpoint, core, owner, parent, properties) < 0) -+ goto error_no_endpoint; -+ this->endpoint.client_ep = this; -+ -+ this->owner_resource = owner_resource; -+ pw_resource_add_listener(this->owner_resource, -+ &this->owner_resource_listener, -+ &owner_resource_events, -+ this); -+ pw_resource_set_implementation(this->owner_resource, -+ &client_endpoint_methods, -+ this); -+ -+ return this; -+ -+ error_no_endpoint: -+ pw_resource_destroy(owner_resource); -+ free(this); -+ return NULL; -+} -+ -+void -+pw_client_endpoint_destroy(struct pw_client_endpoint *this) -+{ -+ pw_resource_destroy(this->owner_resource); -+} -diff --git a/src/modules/module-endpoint/endpoint-impl.h b/src/modules/module-endpoint/endpoint-impl.h -new file mode 100644 -index 00000000..059aa904 ---- /dev/null -+++ b/src/modules/module-endpoint/endpoint-impl.h -@@ -0,0 +1,52 @@ -+/* PipeWire -+ * -+ * Copyright © 2019 Collabora Ltd. -+ * @author George Kiagiadakis -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a -+ * copy of this software and associated documentation files (the "Software"), -+ * to deal in the Software without restriction, including without limitation -+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, -+ * and/or sell copies of the Software, and to permit persons to whom the -+ * Software is furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice (including the next -+ * paragraph) shall be included in all copies or substantial portions of the -+ * Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -+ * DEALINGS IN THE SOFTWARE. -+ */ -+ -+#ifndef PIPEWIRE_ENDPOINT_IMPL_H -+#define PIPEWIRE_ENDPOINT_IMPL_H -+ -+#include -+#include -+#include -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+struct pw_endpoint; -+struct pw_client_endpoint; -+ -+struct pw_client_endpoint * -+pw_client_endpoint_new(struct pw_resource *resource, -+ struct pw_global *parent, -+ struct pw_properties *properties); -+ -+void -+pw_client_endpoint_destroy(struct pw_client_endpoint *endpoint); -+ -+#ifdef __cplusplus -+} -+#endif -+ -+#endif /* PIPEWIRE_ENDPOINT_IMPL_H */ -diff --git a/src/modules/module-endpoint/protocol-native.c b/src/modules/module-endpoint/protocol-native.c -new file mode 100644 -index 00000000..a41d3119 ---- /dev/null -+++ b/src/modules/module-endpoint/protocol-native.c -@@ -0,0 +1,472 @@ -+/* PipeWire -+ * -+ * Copyright © 2019 Collabora Ltd. -+ * @author George Kiagiadakis -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a -+ * copy of this software and associated documentation files (the "Software"), -+ * to deal in the Software without restriction, including without limitation -+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, -+ * and/or sell copies of the Software, and to permit persons to whom the -+ * Software is furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice (including the next -+ * paragraph) shall be included in all copies or substantial portions of the -+ * Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -+ * DEALINGS IN THE SOFTWARE. -+ */ -+ -+#include -+#include -+ -+#include -+#include -+#include -+ -+static void -+serialize_pw_endpoint_info(struct spa_pod_builder *b, -+ const struct pw_endpoint_info *info) -+{ -+ struct spa_pod_frame f; -+ uint32_t i, n_props; -+ -+ n_props = info->props ? info->props->n_items : 0; -+ -+ spa_pod_builder_push_struct(b, &f); -+ spa_pod_builder_add(b, -+ SPA_POD_Id(info->id), -+ SPA_POD_Int(info->change_mask), -+ SPA_POD_Int(info->n_params), -+ SPA_POD_Int(n_props), -+ NULL); -+ -+ for (i = 0; i < info->n_params; i++) { -+ spa_pod_builder_add(b, -+ SPA_POD_Id(info->params[i].id), -+ SPA_POD_Int(info->params[i].flags), NULL); -+ } -+ -+ for (i = 0; i < n_props; i++) { -+ spa_pod_builder_add(b, -+ SPA_POD_String(info->props->items[i].key), -+ SPA_POD_String(info->props->items[i].value), -+ NULL); -+ } -+ -+ spa_pod_builder_pop(b, &f); -+} -+ -+/* macro because of alloca() */ -+#define deserialize_pw_endpoint_info(p, f, info) \ -+do { \ -+ if (spa_pod_parser_push_struct(p, f) < 0 || \ -+ spa_pod_parser_get(p, \ -+ SPA_POD_Id(&(info)->id), \ -+ SPA_POD_Int(&(info)->change_mask), \ -+ SPA_POD_Int(&(info)->n_params), \ -+ SPA_POD_Int(&(info)->props->n_items), \ -+ NULL) < 0) \ -+ return -EINVAL; \ -+ \ -+ if ((info)->n_params > 0) \ -+ (info)->params = alloca((info)->n_params * sizeof(struct spa_param_info)); \ -+ if ((info)->props->n_items > 0) \ -+ (info)->props->items = alloca((info)->props->n_items * sizeof(struct spa_dict_item)); \ -+ \ -+ for (i = 0; i < (info)->n_params; i++) { \ -+ if (spa_pod_parser_get(p, \ -+ SPA_POD_Id(&(info)->params[i].id), \ -+ SPA_POD_Int(&(info)->params[i].flags), \ -+ NULL) < 0) \ -+ return -EINVAL; \ -+ } \ -+ \ -+ for (i = 0; i < (info)->props->n_items; i++) { \ -+ if (spa_pod_parser_get(p, \ -+ SPA_POD_String(&(info)->props->items[i].key), \ -+ SPA_POD_String(&(info)->props->items[i].value), \ -+ NULL) < 0) \ -+ return -EINVAL; \ -+ } \ -+ \ -+ spa_pod_parser_pop(p, f); \ -+} while(0) -+ -+static int -+endpoint_marshal_subscribe_params(void *object, uint32_t *ids, uint32_t n_ids) -+{ -+ struct pw_proxy *proxy = object; -+ struct spa_pod_builder *b; -+ -+ b = pw_protocol_native_begin_proxy(proxy, -+ PW_ENDPOINT_PROXY_METHOD_SUBSCRIBE_PARAMS, NULL); -+ -+ spa_pod_builder_add_struct(b, -+ SPA_POD_Array(sizeof(uint32_t), SPA_TYPE_Id, n_ids, ids)); -+ -+ return pw_protocol_native_end_proxy(proxy, b); -+} -+ -+static int -+endpoint_demarshal_subscribe_params(void *object, const struct pw_protocol_native_message *msg) -+{ -+ struct pw_resource *resource = object; -+ struct spa_pod_parser prs; -+ uint32_t csize, ctype, n_ids; -+ uint32_t *ids; -+ -+ spa_pod_parser_init(&prs, msg->data, msg->size); -+ if (spa_pod_parser_get_struct(&prs, -+ SPA_POD_Array(&csize, &ctype, &n_ids, &ids)) < 0) -+ return -EINVAL; -+ -+ if (ctype != SPA_TYPE_Id) -+ return -EINVAL; -+ -+ return pw_resource_do(resource, struct pw_endpoint_proxy_methods, -+ subscribe_params, 0, ids, n_ids); -+} -+ -+static int -+endpoint_marshal_enum_params(void *object, int seq, uint32_t id, -+ uint32_t index, uint32_t num, const struct spa_pod *filter) -+{ -+ struct pw_proxy *proxy = object; -+ struct spa_pod_builder *b; -+ -+ b = pw_protocol_native_begin_proxy(proxy, -+ PW_ENDPOINT_PROXY_METHOD_ENUM_PARAMS, NULL); -+ -+ spa_pod_builder_add_struct(b, -+ SPA_POD_Int(seq), -+ SPA_POD_Id(id), -+ SPA_POD_Int(index), -+ SPA_POD_Int(num), -+ SPA_POD_Pod(filter)); -+ -+ return pw_protocol_native_end_proxy(proxy, b); -+} -+ -+static int -+endpoint_demarshal_enum_params(void *object, const struct pw_protocol_native_message *msg) -+{ -+ struct pw_resource *resource = object; -+ struct spa_pod_parser prs; -+ uint32_t id, index, num; -+ int seq; -+ struct spa_pod *filter; -+ -+ spa_pod_parser_init(&prs, msg->data, msg->size); -+ if (spa_pod_parser_get_struct(&prs, -+ SPA_POD_Int(&seq), -+ SPA_POD_Id(&id), -+ SPA_POD_Int(&index), -+ SPA_POD_Int(&num), -+ SPA_POD_Pod(&filter)) < 0) -+ return -EINVAL; -+ -+ return pw_resource_do(resource, struct pw_endpoint_proxy_methods, -+ enum_params, 0, seq, id, index, num, filter); -+} -+ -+static int -+endpoint_marshal_set_param(void *object, uint32_t id, uint32_t flags, -+ const struct spa_pod *param) -+{ -+ struct pw_proxy *proxy = object; -+ struct spa_pod_builder *b; -+ -+ b = pw_protocol_native_begin_proxy(proxy, -+ PW_ENDPOINT_PROXY_METHOD_SET_PARAM, NULL); -+ -+ spa_pod_builder_add_struct(b, -+ SPA_POD_Id(id), -+ SPA_POD_Int(flags), -+ SPA_POD_Pod(param)); -+ return pw_protocol_native_end_proxy(proxy, b); -+} -+ -+static int -+endpoint_demarshal_set_param(void *object, const struct pw_protocol_native_message *msg) -+{ -+ struct pw_resource *resource = object; -+ struct spa_pod_parser prs; -+ uint32_t id, flags; -+ struct spa_pod *param; -+ -+ spa_pod_parser_init(&prs, msg->data, msg->size); -+ if (spa_pod_parser_get_struct(&prs, -+ SPA_POD_Id(&id), -+ SPA_POD_Int(&flags), -+ SPA_POD_Pod(¶m)) < 0) -+ return -EINVAL; -+ -+ return pw_resource_do(resource, struct pw_endpoint_proxy_methods, -+ set_param, 0, id, flags, param); -+} -+ -+static void -+endpoint_marshal_info(void *object, const struct pw_endpoint_info *info) -+{ -+ struct pw_resource *resource = object; -+ struct spa_pod_builder *b; -+ -+ b = pw_protocol_native_begin_resource(resource, -+ PW_ENDPOINT_PROXY_EVENT_INFO, NULL); -+ serialize_pw_endpoint_info (b, info); -+ pw_protocol_native_end_resource(resource, b); -+} -+ -+static int -+endpoint_demarshal_info(void *object, const struct pw_protocol_native_message *msg) -+{ -+ struct pw_proxy *proxy = object; -+ struct spa_pod_parser prs; -+ struct spa_pod_frame f; -+ struct spa_dict props = SPA_DICT_INIT(NULL, 0); -+ struct pw_endpoint_info info = { .props = &props }; -+ uint32_t i; -+ -+ spa_pod_parser_init(&prs, msg->data, msg->size); -+ -+ deserialize_pw_endpoint_info(&prs, &f, &info); -+ -+ return pw_proxy_notify(proxy, struct pw_endpoint_proxy_events, -+ info, 0, &info); -+} -+ -+static void -+endpoint_marshal_param(void *object, int seq, uint32_t id, -+ uint32_t index, uint32_t next, const struct spa_pod *param) -+{ -+ struct pw_resource *resource = object; -+ struct spa_pod_builder *b; -+ -+ b = pw_protocol_native_begin_resource(resource, -+ PW_ENDPOINT_PROXY_EVENT_PARAM, NULL); -+ -+ spa_pod_builder_add_struct(b, -+ SPA_POD_Int(seq), -+ SPA_POD_Id(id), -+ SPA_POD_Int(index), -+ SPA_POD_Int(next), -+ SPA_POD_Pod(param)); -+ -+ pw_protocol_native_end_resource(resource, b); -+} -+ -+static int -+endpoint_demarshal_param(void *object, const struct pw_protocol_native_message *msg) -+{ -+ struct pw_proxy *proxy = object; -+ struct spa_pod_parser prs; -+ uint32_t id, index, next; -+ int seq; -+ struct spa_pod *param; -+ -+ spa_pod_parser_init(&prs, msg->data, msg->size); -+ if (spa_pod_parser_get_struct(&prs, -+ SPA_POD_Int(&seq), -+ SPA_POD_Id(&id), -+ SPA_POD_Int(&index), -+ SPA_POD_Int(&next), -+ SPA_POD_Pod(¶m)) < 0) -+ return -EINVAL; -+ -+ return pw_proxy_notify(proxy, struct pw_endpoint_proxy_events, param, 0, -+ seq, id, index, next, param); -+} -+ -+static const struct pw_endpoint_proxy_methods pw_protocol_native_endpoint_method_marshal = { -+ PW_VERSION_ENDPOINT_PROXY_METHODS, -+ &endpoint_marshal_subscribe_params, -+ &endpoint_marshal_enum_params, -+ &endpoint_marshal_set_param, -+}; -+ -+static const struct pw_protocol_native_demarshal pw_protocol_native_endpoint_method_demarshal[] = { -+ { &endpoint_demarshal_subscribe_params, 0 }, -+ { &endpoint_demarshal_enum_params, 0 }, -+ { &endpoint_demarshal_set_param, 0 } -+}; -+ -+static const struct pw_endpoint_proxy_events pw_protocol_native_endpoint_event_marshal = { -+ PW_VERSION_ENDPOINT_PROXY_EVENTS, -+ &endpoint_marshal_info, -+ &endpoint_marshal_param, -+}; -+ -+static const struct pw_protocol_native_demarshal pw_protocol_native_endpoint_event_demarshal[] = { -+ { &endpoint_demarshal_info, 0 }, -+ { &endpoint_demarshal_param, 0 } -+}; -+ -+static const struct pw_protocol_marshal pw_protocol_native_endpoint_marshal = { -+ PW_TYPE_INTERFACE_Endpoint, -+ PW_VERSION_ENDPOINT, -+ PW_ENDPOINT_PROXY_METHOD_NUM, -+ PW_ENDPOINT_PROXY_EVENT_NUM, -+ &pw_protocol_native_endpoint_method_marshal, -+ &pw_protocol_native_endpoint_method_demarshal, -+ &pw_protocol_native_endpoint_event_marshal, -+ &pw_protocol_native_endpoint_event_demarshal, -+}; -+ -+ -+static int -+client_endpoint_marshal_update( -+ void *object, -+ uint32_t change_mask, -+ uint32_t n_params, -+ const struct spa_pod **params, -+ const struct pw_endpoint_info *info) -+{ -+ struct pw_proxy *proxy = object; -+ struct spa_pod_builder *b; -+ struct spa_pod_frame f; -+ uint32_t i; -+ -+ b = pw_protocol_native_begin_proxy(proxy, -+ PW_CLIENT_ENDPOINT_PROXY_METHOD_UPDATE, NULL); -+ -+ spa_pod_builder_push_struct(b, &f); -+ spa_pod_builder_add(b, -+ SPA_POD_Int(change_mask), -+ SPA_POD_Int(n_params), NULL); -+ -+ for (i = 0; i < n_params; i++) -+ spa_pod_builder_add(b, SPA_POD_Pod(params[i]), NULL); -+ -+ if (change_mask & PW_CLIENT_ENDPOINT_UPDATE_INFO) -+ serialize_pw_endpoint_info(b, info); -+ -+ spa_pod_builder_pop(b, &f); -+ -+ return pw_protocol_native_end_proxy(proxy, b); -+} -+ -+static int -+client_endpoint_demarshal_update(void *object, -+ const struct pw_protocol_native_message *msg) -+{ -+ struct pw_resource *resource = object; -+ struct spa_pod_parser prs; -+ struct spa_pod_frame f[2]; -+ uint32_t change_mask, n_params; -+ const struct spa_pod **params = NULL; -+ struct spa_dict props = SPA_DICT_INIT(NULL, 0); -+ struct pw_endpoint_info info = { .props = &props }; -+ uint32_t i; -+ -+ spa_pod_parser_init(&prs, msg->data, msg->size); -+ if (spa_pod_parser_push_struct(&prs, &f[0]) < 0 || -+ spa_pod_parser_get(&prs, -+ SPA_POD_Int(&change_mask), -+ SPA_POD_Int(&n_params), NULL) < 0) -+ return -EINVAL; -+ -+ if (n_params > 0) -+ params = alloca(n_params * sizeof(struct spa_pod *)); -+ for (i = 0; i < n_params; i++) -+ if (spa_pod_parser_get(&prs, -+ SPA_POD_PodObject(¶ms[i]), NULL) < 0) -+ return -EINVAL; -+ -+ if (change_mask & PW_CLIENT_ENDPOINT_UPDATE_INFO) -+ deserialize_pw_endpoint_info(&prs, &f[1], &info); -+ -+ pw_resource_do(resource, struct pw_client_endpoint_proxy_methods, -+ update, 0, change_mask, n_params, params, &info); -+ return 0; -+} -+ -+static void -+client_endpoint_marshal_set_param (void *object, -+ uint32_t id, uint32_t flags, -+ const struct spa_pod *param) -+{ -+ struct pw_resource *resource = object; -+ struct spa_pod_builder *b; -+ -+ b = pw_protocol_native_begin_resource(resource, -+ PW_CLIENT_ENDPOINT_PROXY_EVENT_SET_PARAM, NULL); -+ -+ spa_pod_builder_add_struct(b, -+ SPA_POD_Id(id), -+ SPA_POD_Int(flags), -+ SPA_POD_Pod(param)); -+ -+ pw_protocol_native_end_resource(resource, b); -+} -+ -+static int -+client_endpoint_demarshal_set_param(void *object, -+ const struct pw_protocol_native_message *msg) -+{ -+ struct pw_proxy *proxy = object; -+ struct spa_pod_parser prs; -+ uint32_t id, flags; -+ const struct spa_pod *param = NULL; -+ -+ spa_pod_parser_init(&prs, msg->data, msg->size); -+ if (spa_pod_parser_get_struct(&prs, -+ SPA_POD_Id(&id), -+ SPA_POD_Int(&flags), -+ SPA_POD_PodObject(¶m)) < 0) -+ return -EINVAL; -+ -+ pw_proxy_notify(proxy, struct pw_client_endpoint_proxy_events, -+ set_param, 0, id, flags, param); -+ return 0; -+} -+ -+static const struct pw_client_endpoint_proxy_methods pw_protocol_native_client_endpoint_method_marshal = { -+ PW_VERSION_CLIENT_ENDPOINT_PROXY_METHODS, -+ &client_endpoint_marshal_update, -+}; -+ -+static const struct pw_protocol_native_demarshal pw_protocol_native_client_endpoint_method_demarshal[] = { -+ { &client_endpoint_demarshal_update, 0 } -+}; -+ -+static const struct pw_client_endpoint_proxy_events pw_protocol_native_client_endpoint_event_marshal = { -+ PW_VERSION_CLIENT_ENDPOINT_PROXY_EVENTS, -+ &client_endpoint_marshal_set_param, -+}; -+ -+static const struct pw_protocol_native_demarshal pw_protocol_native_client_endpoint_event_demarshal[] = { -+ { &client_endpoint_demarshal_set_param, 0 } -+}; -+ -+static const struct pw_protocol_marshal pw_protocol_native_client_endpoint_marshal = { -+ PW_TYPE_INTERFACE_ClientEndpoint, -+ PW_VERSION_CLIENT_ENDPOINT, -+ PW_CLIENT_ENDPOINT_PROXY_METHOD_NUM, -+ PW_CLIENT_ENDPOINT_PROXY_EVENT_NUM, -+ &pw_protocol_native_client_endpoint_method_marshal, -+ &pw_protocol_native_client_endpoint_method_demarshal, -+ &pw_protocol_native_client_endpoint_event_marshal, -+ &pw_protocol_native_client_endpoint_event_demarshal, -+}; -+ -+struct pw_protocol *pw_protocol_native_ext_endpoint_init(struct pw_core *core) -+{ -+ struct pw_protocol *protocol; -+ -+ protocol = pw_core_find_protocol(core, PW_TYPE_INFO_PROTOCOL_Native); -+ -+ if (protocol == NULL) -+ return NULL; -+ -+ pw_protocol_add_marshal(protocol, &pw_protocol_native_client_endpoint_marshal); -+ pw_protocol_add_marshal(protocol, &pw_protocol_native_endpoint_marshal); -+ -+ return protocol; -+} -diff --git a/src/pipewire/pipewire.c b/src/pipewire/pipewire.c -index a8752438..bbbf9420 100644 ---- a/src/pipewire/pipewire.c -+++ b/src/pipewire/pipewire.c -@@ -647,6 +647,8 @@ static const struct spa_type_info type_info[] = { - { PW_TYPE_INTERFACE_Module, SPA_TYPE_Pointer, PW_TYPE_INFO_INTERFACE_BASE "Module", NULL }, - { PW_TYPE_INTERFACE_ClientNode, SPA_TYPE_Pointer, PW_TYPE_INFO_INTERFACE_BASE "ClientNode", NULL }, - { PW_TYPE_INTERFACE_Device, SPA_TYPE_Pointer, PW_TYPE_INFO_INTERFACE_BASE "Device", NULL }, -+ { PW_TYPE_INTERFACE_Endpoint, SPA_TYPE_Pointer, PW_TYPE_INFO_INTERFACE_BASE "Endpoint", NULL}, -+ { PW_TYPE_INTERFACE_ClientEndpoint, SPA_TYPE_Pointer, PW_TYPE_INFO_INTERFACE_BASE "ClientEndpoint", NULL}, - { SPA_ID_INVALID, SPA_ID_INVALID, "spa_types", spa_types }, - { 0, 0, NULL, NULL }, - }; -diff --git a/src/pipewire/type.h b/src/pipewire/type.h -index a1b205f7..39544913 100644 ---- a/src/pipewire/type.h -+++ b/src/pipewire/type.h -@@ -48,7 +48,8 @@ enum { - /* extensions */ - PW_TYPE_INTERFACE_EXTENSIONS = PW_TYPE_INTERFACE_START + 0x1000, - PW_TYPE_INTERFACE_ClientNode, -- -+ PW_TYPE_INTERFACE_Endpoint, -+ PW_TYPE_INTERFACE_ClientEndpoint, - }; - - #define PW_TYPE_INFO_BASE "PipeWire:" --- -2.20.1 - diff --git a/meta-pipewire/recipes-multimedia/pipewire/0001-spa-include-install-missing-headers.patch b/meta-pipewire/recipes-multimedia/pipewire/0001-spa-include-install-missing-headers.patch deleted file mode 100644 index 01efe773..00000000 --- a/meta-pipewire/recipes-multimedia/pipewire/0001-spa-include-install-missing-headers.patch +++ /dev/null @@ -1,40 +0,0 @@ -From 14893ae87ab0b15b7e438779433c4973c797c5f5 Mon Sep 17 00:00:00 2001 -From: George Kiagiadakis -Date: Wed, 29 May 2019 12:09:13 +0300 -Subject: [PATCH] spa/include: install missing headers - ---- - spa/include/spa/meson.build | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/spa/include/spa/meson.build b/spa/include/spa/meson.build -index c9d07659..c079a1a2 100644 ---- a/spa/include/spa/meson.build -+++ b/spa/include/spa/meson.build -@@ -39,6 +39,7 @@ spa_monitor_headers = [ - 'monitor/device.h', - 'monitor/monitor.h', - 'monitor/type-info.h', -+ 'monitor/utils.h', - ] - - install_headers(spa_monitor_headers, -@@ -50,6 +51,7 @@ spa_node_headers = [ - 'node/io.h', - 'node/node.h', - 'node/type-info.h', -+ 'node/utils.h', - ] - - install_headers(spa_node_headers, -@@ -97,6 +99,7 @@ spa_utils_headers = [ - 'utils/dict.h', - 'utils/hook.h', - 'utils/list.h', -+ 'utils/result.h', - 'utils/ringbuffer.h', - 'utils/type.h', - 'utils/type-info.h', --- -2.20.1 - diff --git a/meta-pipewire/recipes-multimedia/pipewire/0002-pipewire-cli-add-support-for-printing-endpoint-info-.patch b/meta-pipewire/recipes-multimedia/pipewire/0002-pipewire-cli-add-support-for-printing-endpoint-info-.patch deleted file mode 100644 index 008c15f9..00000000 --- a/meta-pipewire/recipes-multimedia/pipewire/0002-pipewire-cli-add-support-for-printing-endpoint-info-.patch +++ /dev/null @@ -1,148 +0,0 @@ -From e76140c534dde71424eb9abd1dde69cf14152da5 Mon Sep 17 00:00:00 2001 -From: George Kiagiadakis -Date: Tue, 28 May 2019 11:46:36 +0300 -Subject: [PATCH 2/2] pipewire-cli: add support for printing endpoint info & - params - -Note that you have to run: - load-module libpipewire-module-endpoint -before trying to query any endpoints ---- - src/tools/pipewire-cli.c | 78 +++++++++++++++++++++++++++++++++++++++- - 1 file changed, 77 insertions(+), 1 deletion(-) - -diff --git a/src/tools/pipewire-cli.c b/src/tools/pipewire-cli.c -index 521739f6..9511db82 100644 ---- a/src/tools/pipewire-cli.c -+++ b/src/tools/pipewire-cli.c -@@ -38,6 +38,8 @@ - #include - #include - -+#include -+ - static const char WHITESPACE[] = " \t"; - - struct remote_data; -@@ -176,8 +178,12 @@ static void print_params(struct spa_param_info *params, uint32_t n_params, char - return; - } - for (i = 0; i < n_params; i++) { -+ const struct spa_type_info *type_info = spa_type_param; -+ if (params[i].id >= PW_ENDPOINT_PARAM_EnumControl) -+ type_info = endpoint_param_type_info; -+ - fprintf(stdout, "%c\t %d (%s) %c%c\n", mark, params[i].id, -- spa_debug_type_find_name(spa_type_param, params[i].id), -+ spa_debug_type_find_name(type_info, params[i].id), - params[i].flags & SPA_PARAM_INFO_READ ? 'r' : '-', - params[i].flags & SPA_PARAM_INFO_WRITE ? 'w' : '-'); - } -@@ -641,6 +647,16 @@ static void info_device(struct proxy_data *pd) - info->change_mask = 0; - } - -+static void info_endpoint(struct proxy_data *pd) -+{ -+ struct pw_endpoint_info *info = pd->info; -+ -+ info_global(pd); -+ print_properties(info->props, MARK_CHANGE(1), true); -+ print_params(info->params, info->n_params, MARK_CHANGE(0), true); -+ info->change_mask = 0; -+} -+ - static void core_event_info(void *object, const struct pw_core_info *info) - { - struct proxy_data *pd = object; -@@ -708,6 +724,9 @@ static void event_param(void *object, int seq, uint32_t id, - - if (spa_pod_is_object_type(param, SPA_TYPE_OBJECT_Format)) - spa_debug_format(2, NULL, param); -+ else if (spa_pod_is_object_type(param, PW_ENDPOINT_OBJECT_ParamControl) || -+ spa_pod_is_object_type(param, PW_ENDPOINT_OBJECT_ParamStream)) -+ spa_debug_pod(2, endpoint_param_object_type_info, param); - else - spa_debug_pod(2, NULL, param); - } -@@ -842,6 +861,53 @@ static const struct pw_device_proxy_events device_events = { - .param = event_param - }; - -+static void endpoint_info_free(struct pw_endpoint_info *info) -+{ -+ free(info->params); -+ if (info->props) -+ pw_properties_free ((struct pw_properties *)info->props); -+ free(info); -+} -+ -+static void endpoint_event_info(void *object, -+ const struct pw_endpoint_info *update) -+{ -+ struct proxy_data *pd = object; -+ struct remote_data *rd = pd->rd; -+ struct pw_endpoint_info *info = pd->info; -+ -+ if (!info) { -+ info = pd->info = calloc(1, sizeof(*info)); -+ info->id = update->id; -+ } -+ if (update->change_mask & PW_ENDPOINT_CHANGE_MASK_PARAMS) { -+ info->n_params = update->n_params; -+ free(info->params); -+ info->params = malloc(info->n_params * sizeof(struct spa_param_info)); -+ memcpy(info->params, update->params, -+ info->n_params * sizeof(struct spa_param_info)); -+ } -+ if (update->change_mask & PW_ENDPOINT_CHANGE_MASK_PROPS) { -+ if (info->props) -+ pw_properties_free ((struct pw_properties *)info->props); -+ info->props = -+ (struct spa_dict *) pw_properties_new_dict (update->props); -+ } -+ -+ if (pd->global == NULL) -+ pd->global = pw_map_lookup(&rd->globals, info->id); -+ if (pd->global && pd->global->info_pending) { -+ info_endpoint(pd); -+ pd->global->info_pending = false; -+ } -+} -+ -+static const struct pw_endpoint_proxy_events endpoint_events = { -+ PW_VERSION_ENDPOINT_PROXY_EVENTS, -+ .info = endpoint_event_info, -+ .param = event_param -+}; -+ - static void - destroy_proxy (void *data) - { -@@ -928,6 +994,12 @@ static bool bind_global(struct remote_data *rd, struct global *global, char **er - destroy = (pw_destroy_t) pw_link_info_free; - info_func = info_link; - break; -+ case PW_TYPE_INTERFACE_Endpoint: -+ events = &endpoint_events; -+ client_version = PW_VERSION_ENDPOINT; -+ destroy = (pw_destroy_t) endpoint_info_free; -+ info_func = info_endpoint; -+ break; - default: - asprintf(error, "unsupported type %s", spa_debug_type_find_name(pw_type_info(), global->type)); - return false; -@@ -1201,6 +1273,10 @@ static bool do_enum_params(struct data *data, const char *cmd, char *args, char - pw_device_proxy_enum_params((struct pw_device_proxy*)global->proxy, 0, - param_id, 0, 0, NULL); - break; -+ case PW_TYPE_INTERFACE_Endpoint: -+ pw_endpoint_proxy_enum_params((struct pw_endpoint_proxy*)global->proxy, 0, -+ param_id, 0, 0, NULL); -+ break; - default: - asprintf(error, "enum-params not implemented on object %d", atoi(a[0])); - return false; --- -2.20.1 - diff --git a/meta-pipewire/recipes-multimedia/pipewire/pipewire-conf-agl/pipewire.conf b/meta-pipewire/recipes-multimedia/pipewire/pipewire-conf-agl/pipewire.conf new file mode 100644 index 00000000..d09ee8ed --- /dev/null +++ b/meta-pipewire/recipes-multimedia/pipewire/pipewire-conf-agl/pipewire.conf @@ -0,0 +1,10 @@ +# daemon config file for PipeWire version "0.2.9" +# distributed by Automotive Grade Linux +load-module libpipewire-module-protocol-native +load-module libpipewire-module-spa-monitor alsa/libspa-alsa alsa-monitor alsa +load-module libpipewire-module-client-node +load-module libpipewire-module-access +load-module libpipewire-module-audio-dsp +load-module libpipewire-module-link-factory +load-module libpipewire-module-endpoint +exec /usr/bin/wireplumber diff --git a/meta-pipewire/recipes-multimedia/pipewire/pipewire-conf-agl_git.bb b/meta-pipewire/recipes-multimedia/pipewire/pipewire-conf-agl_git.bb new file mode 100644 index 00000000..50b207df --- /dev/null +++ b/meta-pipewire/recipes-multimedia/pipewire/pipewire-conf-agl_git.bb @@ -0,0 +1,30 @@ +SUMMARY = "AGL configuration file for pipewire" +HOMEPAGE = "https://pipewire.org" +BUGTRACKER = "https://jira.automotivelinux.org" +AUTHOR = "George Kiagiadakis " +SECTION = "multimedia" + +LICENSE = "MIT" + +SRC_URI = " \ + file://pipewire.conf \ + " + +do_configure[noexec] = "1" +do_compile[noexec] = "1" + +do_install_append() { + # if we are distributing our own configuration file, + # replace the one installed by pipewire + install -d ${D}/${sysconfdir}/pipewire/ + install -m 0644 ${WORKDIR}/pipewire.conf ${D}${sysconfdir}/pipewire/pipewire.conf +} + +FILES_${PN} = "\ + ${sysconfdir}/pipewire/pipewire.conf \ +" +CONFFILES_${PN} += "\ + ${sysconfdir}/pipewire/pipewire.conf \ +" + +RPROVIDES_${PN} += "virtual/pipewire-config" diff --git a/meta-pipewire/recipes-multimedia/pipewire/pipewire.conf b/meta-pipewire/recipes-multimedia/pipewire/pipewire.conf deleted file mode 100644 index d09ee8ed..00000000 --- a/meta-pipewire/recipes-multimedia/pipewire/pipewire.conf +++ /dev/null @@ -1,10 +0,0 @@ -# daemon config file for PipeWire version "0.2.9" -# distributed by Automotive Grade Linux -load-module libpipewire-module-protocol-native -load-module libpipewire-module-spa-monitor alsa/libspa-alsa alsa-monitor alsa -load-module libpipewire-module-client-node -load-module libpipewire-module-access -load-module libpipewire-module-audio-dsp -load-module libpipewire-module-link-factory -load-module libpipewire-module-endpoint -exec /usr/bin/wireplumber diff --git a/meta-pipewire/recipes-multimedia/pipewire/pipewire.inc b/meta-pipewire/recipes-multimedia/pipewire/pipewire.inc index c1916c10..f7a6136d 100644 --- a/meta-pipewire/recipes-multimedia/pipewire/pipewire.inc +++ b/meta-pipewire/recipes-multimedia/pipewire/pipewire.inc @@ -49,13 +49,6 @@ PACKAGECONFIG[gstreamer] = "-Dgstreamer=true,-Dgstreamer=false,glib-2.0 gstreame PACKAGECONFIG[manpages] = "-Dman=true,-Dman=false,libxml-parser-perl-native" do_install_append() { - # if we are distributing our own configuration file, - # replace the one installed by pipewire - if [ -f ${WORKDIR}/pipewire.conf ] - then - install -m 0644 ${WORKDIR}/pipewire.conf ${D}${sysconfdir}/pipewire/pipewire.conf - fi - # only install the alsa config file if the alsa-lib plugin has been built # this avoids creating the pipewire-alsa package when the pipewire-alsa # feature is not enabled @@ -66,24 +59,21 @@ do_install_append() { fi } -PACKAGES += "\ - lib${PN} \ - lib${PN}-modules \ +PACKAGES =+ "\ ${PN}-spa-plugins \ ${PN}-alsa \ ${PN}-pulseaudio \ ${PN}-jack \ + ${PN}-config \ gstreamer${GST_VER}-${PN} \ + lib${PN} \ + lib${PN}-modules \ " FILES_${PN} = "\ ${bindir}/pipewire* \ - ${sysconfdir}/pipewire/pipewire.conf \ ${systemd_user_unitdir}/* \ " -CONFFILES_${PN} += "\ - ${sysconfdir}/pipewire/pipewire.conf \ -" FILES_lib${PN} = "\ ${libdir}/libpipewire-*.so.* \ @@ -112,3 +102,14 @@ FILES_gstreamer${GST_VER}-${PN} = "\ " RDEPENDS_lib${PN} += "lib${PN}-modules ${PN}-spa-plugins" + +# The default pipewire config. +# Replace in your own package using +# "virtual/pipewire-config" +FILES_${PN}-config = "\ + ${sysconfdir}/pipewire/pipewire.conf \ +" +CONFFILES_${PN}-config += "\ + ${sysconfdir}/pipewire/pipewire.conf \ +" +RPROVIDES_${PN}-config += "virtual/pipewire-config" diff --git a/meta-pipewire/recipes-multimedia/pipewire/pipewire/0001-extensions-implement-Endpoint-ClientEndpoint-interfa.patch b/meta-pipewire/recipes-multimedia/pipewire/pipewire/0001-extensions-implement-Endpoint-ClientEndpoint-interfa.patch new file mode 100644 index 00000000..b78a9096 --- /dev/null +++ b/meta-pipewire/recipes-multimedia/pipewire/pipewire/0001-extensions-implement-Endpoint-ClientEndpoint-interfa.patch @@ -0,0 +1,1562 @@ +From 3d186f7b97c508cc16955a96a69ee5d6c9db57dc Mon Sep 17 00:00:00 2001 +From: George Kiagiadakis +Date: Thu, 23 May 2019 18:59:05 +0300 +Subject: [PATCH 1/2] extensions: implement Endpoint & ClientEndpoint + interfaces + +The ClientEndpoint interface allows session managers to register +endpoint objects on pipewire. +The Endpoint interface allows other clients to interact with +endpoints provided by the session manager. +--- + src/extensions/client-endpoint.h | 106 ++++ + src/extensions/endpoint.h | 237 +++++++++ + src/extensions/meson.build | 2 + + src/modules/meson.build | 12 + + src/modules/module-endpoint.c | 137 +++++ + src/modules/module-endpoint/endpoint-impl.c | 428 ++++++++++++++++ + src/modules/module-endpoint/endpoint-impl.h | 52 ++ + src/modules/module-endpoint/protocol-native.c | 472 ++++++++++++++++++ + src/pipewire/pipewire.c | 2 + + src/pipewire/type.h | 3 +- + 10 files changed, 1450 insertions(+), 1 deletion(-) + create mode 100644 src/extensions/client-endpoint.h + create mode 100644 src/extensions/endpoint.h + create mode 100644 src/modules/module-endpoint.c + create mode 100644 src/modules/module-endpoint/endpoint-impl.c + create mode 100644 src/modules/module-endpoint/endpoint-impl.h + create mode 100644 src/modules/module-endpoint/protocol-native.c + +diff --git a/src/extensions/client-endpoint.h b/src/extensions/client-endpoint.h +new file mode 100644 +index 00000000..0389893c +--- /dev/null ++++ b/src/extensions/client-endpoint.h +@@ -0,0 +1,106 @@ ++/* PipeWire ++ * ++ * Copyright © 2019 Collabora Ltd. ++ * @author George Kiagiadakis ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Software"), ++ * to deal in the Software without restriction, including without limitation ++ * the rights to use, copy, modify, merge, publish, distribute, sublicense, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice (including the next ++ * paragraph) shall be included in all copies or substantial portions of the ++ * Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ */ ++ ++#ifndef PIPEWIRE_EXT_CLIENT_ENDPOINT_H ++#define PIPEWIRE_EXT_CLIENT_ENDPOINT_H ++ ++#include "endpoint.h" ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++struct pw_client_endpoint_proxy; ++ ++#define PW_VERSION_CLIENT_ENDPOINT 0 ++#define PW_EXTENSION_MODULE_CLIENT_ENDPOINT PIPEWIRE_MODULE_PREFIX "module-endpoint" ++ ++#define PW_CLIENT_ENDPOINT_PROXY_METHOD_UPDATE 0 ++#define PW_CLIENT_ENDPOINT_PROXY_METHOD_NUM 1 ++ ++struct pw_client_endpoint_proxy_methods { ++#define PW_VERSION_CLIENT_ENDPOINT_PROXY_METHODS 0 ++ uint32_t version; ++ ++ /** ++ * Update endpoint info ++ */ ++ int (*update) (void *object, ++#define PW_CLIENT_ENDPOINT_UPDATE_PARAMS (1 << 0) ++#define PW_CLIENT_ENDPOINT_UPDATE_PARAMS_INCREMENTAL (1 << 1) ++#define PW_CLIENT_ENDPOINT_UPDATE_INFO (1 << 2) ++ uint32_t change_mask, ++ uint32_t n_params, ++ const struct spa_pod **params, ++ const struct pw_endpoint_info *info); ++}; ++ ++static inline int ++pw_client_endpoint_proxy_update(struct pw_client_endpoint_proxy *p, ++ uint32_t change_mask, ++ uint32_t n_params, ++ const struct spa_pod **params, ++ struct pw_endpoint_info *info) ++{ ++ return pw_proxy_do((struct pw_proxy*)p, ++ struct pw_client_endpoint_proxy_methods, update, ++ change_mask, n_params, params, info); ++} ++ ++#define PW_CLIENT_ENDPOINT_PROXY_EVENT_SET_PARAM 0 ++#define PW_CLIENT_ENDPOINT_PROXY_EVENT_NUM 1 ++ ++struct pw_client_endpoint_proxy_events { ++#define PW_VERSION_CLIENT_ENDPOINT_PROXY_EVENTS 0 ++ uint32_t version; ++ ++ /** ++ * Set a parameter on the endpoint ++ * ++ * \param id the parameter id to set ++ * \param flags extra parameter flags ++ * \param param the parameter to set ++ */ ++ void (*set_param) (void *object, uint32_t id, uint32_t flags, ++ const struct spa_pod *param); ++}; ++ ++static inline void ++pw_client_endpoint_proxy_add_listener(struct pw_client_endpoint_proxy *p, ++ struct spa_hook *listener, ++ const struct pw_client_endpoint_proxy_events *events, ++ void *data) ++{ ++ pw_proxy_add_proxy_listener((struct pw_proxy*)p, listener, events, data); ++} ++ ++#define pw_client_endpoint_resource_set_param(r,...) \ ++ pw_resource_notify(r,struct pw_client_endpoint_proxy_events,set_param,__VA_ARGS__) ++ ++#ifdef __cplusplus ++} /* extern "C" */ ++#endif ++ ++#endif /* PIPEWIRE_EXT_CLIENT_ENDPOINT_H */ +diff --git a/src/extensions/endpoint.h b/src/extensions/endpoint.h +new file mode 100644 +index 00000000..3b84dd49 +--- /dev/null ++++ b/src/extensions/endpoint.h +@@ -0,0 +1,237 @@ ++/* PipeWire ++ * ++ * Copyright © 2019 Collabora Ltd. ++ * @author George Kiagiadakis ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Software"), ++ * to deal in the Software without restriction, including without limitation ++ * the rights to use, copy, modify, merge, publish, distribute, sublicense, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice (including the next ++ * paragraph) shall be included in all copies or substantial portions of the ++ * Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ */ ++ ++#ifndef PIPEWIRE_EXT_ENDPOINT_H ++#define PIPEWIRE_EXT_ENDPOINT_H ++ ++#include ++#include ++#include ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++struct pw_endpoint_proxy; ++ ++#define PW_VERSION_ENDPOINT 0 ++#define PW_EXTENSION_MODULE_ENDPOINT PIPEWIRE_MODULE_PREFIX "module-endpoint" ++ ++/* extending enum spa_param_type */ ++enum endpoint_param_type { ++ PW_ENDPOINT_PARAM_EnumControl = 0x1000, ++ PW_ENDPOINT_PARAM_Control, ++ PW_ENDPOINT_PARAM_EnumStream, ++}; ++ ++enum endpoint_param_object_type { ++ PW_ENDPOINT_OBJECT_ParamControl = PW_TYPE_FIRST + SPA_TYPE_OBJECT_START + 0x1001, ++ PW_ENDPOINT_OBJECT_ParamStream, ++}; ++ ++/** properties for PW_ENDPOINT_OBJECT_ParamControl */ ++enum endpoint_param_control { ++ PW_ENDPOINT_PARAM_CONTROL_START, /**< object id, one of enum endpoint_param_type */ ++ PW_ENDPOINT_PARAM_CONTROL_id, /**< control id (Int) */ ++ PW_ENDPOINT_PARAM_CONTROL_stream_id, /**< stream id (Int) */ ++ PW_ENDPOINT_PARAM_CONTROL_name, /**< control name (String) */ ++ PW_ENDPOINT_PARAM_CONTROL_type, /**< control type (Range) */ ++ PW_ENDPOINT_PARAM_CONTROL_value, /**< control value */ ++}; ++ ++/** properties for PW_ENDPOINT_OBJECT_ParamStream */ ++enum endpoint_param_stream { ++ PW_ENDPOINT_PARAM_STREAM_START, /**< object id, one of enum endpoint_param_type */ ++ PW_ENDPOINT_PARAM_STREAM_id, /**< stream id (Int) */ ++ PW_ENDPOINT_PARAM_STREAM_name, /**< stream name (String) */ ++}; ++ ++static const struct spa_type_info endpoint_param_type_info[] = { ++ { PW_ENDPOINT_PARAM_EnumControl, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_ID_BASE "EnumControl", NULL }, ++ { PW_ENDPOINT_PARAM_Control, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_ID_BASE "Control", NULL }, ++ { PW_ENDPOINT_PARAM_EnumStream, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_ID_BASE "EnumStream", NULL }, ++ { 0, 0, NULL, NULL }, ++}; ++ ++#define PW_ENDPOINT_TYPE_INFO_ParamControl SPA_TYPE_INFO_PARAM_BASE "ParamControl" ++#define PW_ENDPOINT_TYPE_INFO_PARAM_CONTROL_BASE PW_ENDPOINT_TYPE_INFO_ParamControl ":" ++ ++static const struct spa_type_info endpoint_param_control_info[] = { ++ { PW_ENDPOINT_PARAM_CONTROL_START, SPA_TYPE_Id, PW_ENDPOINT_TYPE_INFO_PARAM_CONTROL_BASE, spa_type_param, }, ++ { PW_ENDPOINT_PARAM_CONTROL_id, SPA_TYPE_Int, PW_ENDPOINT_TYPE_INFO_PARAM_CONTROL_BASE "id", NULL }, ++ { PW_ENDPOINT_PARAM_CONTROL_stream_id, SPA_TYPE_Int, PW_ENDPOINT_TYPE_INFO_PARAM_CONTROL_BASE "streamId", NULL }, ++ { PW_ENDPOINT_PARAM_CONTROL_name, SPA_TYPE_String, PW_ENDPOINT_TYPE_INFO_PARAM_CONTROL_BASE "name", NULL }, ++ { PW_ENDPOINT_PARAM_CONTROL_type, SPA_TYPE_Pod, PW_ENDPOINT_TYPE_INFO_PARAM_CONTROL_BASE "type", NULL }, ++ { PW_ENDPOINT_PARAM_CONTROL_value, SPA_TYPE_Struct, PW_ENDPOINT_TYPE_INFO_PARAM_CONTROL_BASE "labels", NULL }, ++ { 0, 0, NULL, NULL }, ++}; ++ ++#define PW_ENDPOINT_TYPE_INFO_ParamStream SPA_TYPE_INFO_PARAM_BASE "ParamStream" ++#define PW_ENDPOINT_TYPE_INFO_PARAM_STREAM_BASE PW_ENDPOINT_TYPE_INFO_ParamStream ":" ++ ++static const struct spa_type_info endpoint_param_stream_info[] = { ++ { PW_ENDPOINT_PARAM_STREAM_START, SPA_TYPE_Id, PW_ENDPOINT_TYPE_INFO_PARAM_STREAM_BASE, spa_type_param, }, ++ { PW_ENDPOINT_PARAM_STREAM_id, SPA_TYPE_Int, PW_ENDPOINT_TYPE_INFO_PARAM_STREAM_BASE "id", NULL }, ++ { PW_ENDPOINT_PARAM_STREAM_name, SPA_TYPE_String, PW_ENDPOINT_TYPE_INFO_PARAM_STREAM_BASE "name", NULL }, ++ { 0, 0, NULL, NULL }, ++}; ++ ++static const struct spa_type_info endpoint_param_object_type_info[] = { ++ { PW_ENDPOINT_OBJECT_ParamControl, SPA_TYPE_Object, SPA_TYPE_INFO_OBJECT_BASE "ParamControl", endpoint_param_control_info, }, ++ { PW_ENDPOINT_OBJECT_ParamStream, SPA_TYPE_Object, SPA_TYPE_INFO_OBJECT_BASE "ParamStream", endpoint_param_stream_info }, ++ { 0, 0, NULL, NULL }, ++}; ++ ++struct pw_endpoint_info { ++ uint32_t id; /**< id of the global */ ++#define PW_ENDPOINT_CHANGE_MASK_PARAMS (1 << 0) ++#define PW_ENDPOINT_CHANGE_MASK_PROPS (1 << 1) ++ uint32_t change_mask; /**< bitfield of changed fields since last call */ ++ uint32_t n_params; /**< number of items in \a params */ ++ struct spa_param_info *params; /**< parameters */ ++ struct spa_dict *props; /**< extra properties */ ++}; ++ ++#define PW_ENDPOINT_PROXY_METHOD_SUBSCRIBE_PARAMS 0 ++#define PW_ENDPOINT_PROXY_METHOD_ENUM_PARAMS 1 ++#define PW_ENDPOINT_PROXY_METHOD_SET_PARAM 2 ++#define PW_ENDPOINT_PROXY_METHOD_NUM 3 ++ ++struct pw_endpoint_proxy_methods { ++#define PW_VERSION_ENDPOINT_PROXY_METHODS 0 ++ uint32_t version; ++ ++ /** ++ * Subscribe to parameter changes ++ * ++ * Automatically emit param events for the given ids when ++ * they are changed. ++ * ++ * \param ids an array of param ids ++ * \param n_ids the number of ids in \a ids ++ */ ++ int (*subscribe_params) (void *object, uint32_t *ids, uint32_t n_ids); ++ ++ /** ++ * Enumerate endpoint parameters ++ * ++ * Start enumeration of endpoint parameters. For each param, a ++ * param event will be emited. ++ * ++ * \param seq a sequence number to place in the reply ++ * \param id the parameter id to enum or SPA_ID_INVALID for all ++ * \param start the start index or 0 for the first param ++ * \param num the maximum number of params to retrieve ++ * \param filter a param filter or NULL ++ */ ++ int (*enum_params) (void *object, int seq, ++ uint32_t id, uint32_t start, uint32_t num, ++ const struct spa_pod *filter); ++ ++ /** ++ * Set a parameter on the endpoint ++ * ++ * \param id the parameter id to set ++ * \param flags extra parameter flags ++ * \param param the parameter to set ++ */ ++ int (*set_param) (void *object, uint32_t id, uint32_t flags, ++ const struct spa_pod *param); ++}; ++ ++static inline int ++pw_endpoint_proxy_subscribe_params(struct pw_endpoint_proxy *p, uint32_t *ids, uint32_t n_ids) ++{ ++ return pw_proxy_do((struct pw_proxy*)p, struct pw_endpoint_proxy_methods, ++ subscribe_params, ids, n_ids); ++} ++ ++static inline int ++pw_endpoint_proxy_enum_params(struct pw_endpoint_proxy *p, int seq, ++ uint32_t id, uint32_t start, uint32_t num, ++ const struct spa_pod *filter) ++{ ++ return pw_proxy_do((struct pw_proxy*)p, struct pw_endpoint_proxy_methods, ++ enum_params, seq, id, start, num, filter); ++} ++ ++static inline int ++pw_endpoint_proxy_set_param(struct pw_endpoint_proxy *p, uint32_t id, ++ uint32_t flags, const struct spa_pod *param) ++{ ++ return pw_proxy_do((struct pw_proxy*)p, struct pw_endpoint_proxy_methods, ++ set_param, id, flags, param); ++} ++ ++#define PW_ENDPOINT_PROXY_EVENT_INFO 0 ++#define PW_ENDPOINT_PROXY_EVENT_PARAM 1 ++#define PW_ENDPOINT_PROXY_EVENT_NUM 2 ++ ++struct pw_endpoint_proxy_events { ++#define PW_VERSION_ENDPOINT_PROXY_EVENTS 0 ++ uint32_t version; ++ ++ /** ++ * Notify endpoint info ++ * ++ * \param info info about the endpoint ++ */ ++ void (*info) (void *object, const struct pw_endpoint_info * info); ++ ++ /** ++ * Notify an endpoint param ++ * ++ * Event emited as a result of the enum_params method. ++ * ++ * \param seq the sequence number of the request ++ * \param id the param id ++ * \param index the param index ++ * \param next the param index of the next param ++ * \param param the parameter ++ */ ++ void (*param) (void *object, int seq, uint32_t id, ++ uint32_t index, uint32_t next, ++ const struct spa_pod *param); ++}; ++ ++static inline void ++pw_endpoint_proxy_add_listener(struct pw_endpoint_proxy *p, ++ struct spa_hook *listener, ++ const struct pw_endpoint_proxy_events *events, ++ void *data) ++{ ++ pw_proxy_add_proxy_listener((struct pw_proxy*)p, listener, events, data); ++} ++ ++#define pw_endpoint_resource_info(r,...) \ ++ pw_resource_notify(r,struct pw_endpoint_proxy_events,info,__VA_ARGS__) ++#define pw_endpoint_resource_param(r,...) \ ++ pw_resource_notify(r,struct pw_endpoint_proxy_events,param,__VA_ARGS__) ++ ++#ifdef __cplusplus ++} /* extern "C" */ ++#endif ++ ++#endif /* PIPEWIRE_EXT_ENDPOINT_H */ +diff --git a/src/extensions/meson.build b/src/extensions/meson.build +index a7f5d3cb..9f690caf 100644 +--- a/src/extensions/meson.build ++++ b/src/extensions/meson.build +@@ -1,5 +1,7 @@ + pipewire_ext_headers = [ ++ 'client-endpoint.h', + 'client-node.h', ++ 'endpoint.h', + 'protocol-native.h', + ] + +diff --git a/src/modules/meson.build b/src/modules/meson.build +index 98bc3864..572f1b6b 100644 +--- a/src/modules/meson.build ++++ b/src/modules/meson.build +@@ -37,6 +37,18 @@ pipewire_module_client_node = shared_library('pipewire-module-client-node', + dependencies : [mathlib, dl_lib, pipewire_dep], + ) + ++pipewire_module_endpoint = shared_library('pipewire-module-endpoint', ++ [ 'module-endpoint.c', ++ 'module-endpoint/endpoint-impl.c', ++ 'module-endpoint/protocol-native.c', ++ ], ++ c_args : pipewire_module_c_args, ++ include_directories : [configinc, spa_inc], ++ install : true, ++ install_dir : modules_install_dir, ++ dependencies : [mathlib, dl_lib, pipewire_dep], ++) ++ + pipewire_module_link_factory = shared_library('pipewire-module-link-factory', + [ 'module-link-factory.c' ], + c_args : pipewire_module_c_args, +diff --git a/src/modules/module-endpoint.c b/src/modules/module-endpoint.c +new file mode 100644 +index 00000000..d830de1b +--- /dev/null ++++ b/src/modules/module-endpoint.c +@@ -0,0 +1,137 @@ ++/* PipeWire ++ * ++ * Copyright © 2019 Collabora Ltd. ++ * @author George Kiagiadakis ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Software"), ++ * to deal in the Software without restriction, including without limitation ++ * the rights to use, copy, modify, merge, publish, distribute, sublicense, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice (including the next ++ * paragraph) shall be included in all copies or substantial portions of the ++ * Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ */ ++ ++#include "config.h" ++ ++#include "module-endpoint/endpoint-impl.h" ++ ++struct pw_protocol *pw_protocol_native_ext_endpoint_init(struct pw_core *core); ++ ++static const struct spa_dict_item module_props[] = { ++ { PW_MODULE_PROP_AUTHOR, "George Kiagiadakis " }, ++ { PW_MODULE_PROP_DESCRIPTION, "Allows clients to interract with session manager endpoints" }, ++ { PW_MODULE_PROP_VERSION, PACKAGE_VERSION }, ++}; ++ ++struct factory_data { ++ struct pw_factory *this; ++ struct pw_properties *properties; ++ ++ struct pw_module *module; ++ struct spa_hook module_listener; ++}; ++ ++static void *create_object(void *_data, ++ struct pw_resource *resource, ++ uint32_t type, ++ uint32_t version, ++ struct pw_properties *properties, ++ uint32_t new_id) ++{ ++ void *result; ++ struct pw_resource *endpoint_resource; ++ struct pw_global *parent; ++ struct pw_client *client = pw_resource_get_client(resource); ++ ++ endpoint_resource = pw_resource_new(client, new_id, PW_PERM_RWX, type, version, 0); ++ if (endpoint_resource == NULL) ++ goto no_mem; ++ ++ parent = pw_client_get_global(client); ++ ++ result = pw_client_endpoint_new(endpoint_resource, parent, properties); ++ if (result == NULL) ++ goto no_mem; ++ ++ return result; ++ ++ no_mem: ++ pw_log_error("can't create endpoint"); ++ pw_resource_error(resource, -ENOMEM, "can't create endpoint: no memory"); ++ if (properties) ++ pw_properties_free(properties); ++ return NULL; ++} ++ ++static const struct pw_factory_implementation impl_factory = { ++ PW_VERSION_FACTORY_IMPLEMENTATION, ++ .create_object = create_object, ++}; ++ ++static void module_destroy(void *data) ++{ ++ struct factory_data *d = data; ++ ++ spa_hook_remove(&d->module_listener); ++ ++ if (d->properties) ++ pw_properties_free(d->properties); ++ ++ pw_factory_destroy(d->this); ++} ++ ++static const struct pw_module_events module_events = { ++ PW_VERSION_MODULE_EVENTS, ++ .destroy = module_destroy, ++}; ++ ++static int module_init(struct pw_module *module, struct pw_properties *properties) ++{ ++ struct pw_core *core = pw_module_get_core(module); ++ struct pw_factory *factory; ++ struct factory_data *data; ++ ++ factory = pw_factory_new(core, ++ "client-endpoint", ++ PW_TYPE_INTERFACE_ClientEndpoint, ++ PW_VERSION_CLIENT_ENDPOINT, ++ NULL, ++ sizeof(*data)); ++ if (factory == NULL) ++ return -ENOMEM; ++ ++ data = pw_factory_get_user_data(factory); ++ data->this = factory; ++ data->module = module; ++ data->properties = properties; ++ ++ pw_log_debug("module-endpoint %p: new", module); ++ ++ pw_factory_set_implementation(factory, &impl_factory, data); ++ pw_factory_register(factory, NULL, pw_module_get_global(module), NULL); ++ ++ pw_protocol_native_ext_endpoint_init(core); ++ ++ pw_module_add_listener(module, &data->module_listener, &module_events, data); ++ pw_module_update_properties(module, &SPA_DICT_INIT_ARRAY(module_props)); ++ ++ return 0; ++} ++ ++SPA_EXPORT ++int pipewire__module_init(struct pw_module *module, const char *args) ++{ ++ return module_init(module, NULL); ++} +diff --git a/src/modules/module-endpoint/endpoint-impl.c b/src/modules/module-endpoint/endpoint-impl.c +new file mode 100644 +index 00000000..252eeca1 +--- /dev/null ++++ b/src/modules/module-endpoint/endpoint-impl.c +@@ -0,0 +1,428 @@ ++/* PipeWire ++ * ++ * Copyright © 2019 Collabora Ltd. ++ * @author George Kiagiadakis ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Software"), ++ * to deal in the Software without restriction, including without limitation ++ * the rights to use, copy, modify, merge, publish, distribute, sublicense, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice (including the next ++ * paragraph) shall be included in all copies or substantial portions of the ++ * Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ */ ++ ++#include "endpoint-impl.h" ++#include ++#include ++#include ++ ++struct pw_endpoint { ++ struct pw_core *core; ++ struct pw_global *global; ++ struct pw_global *parent; ++ ++ struct pw_client_endpoint *client_ep; ++ ++ uint32_t n_params; ++ struct spa_pod **params; ++ ++ struct pw_endpoint_info info; ++ struct pw_properties *props; ++}; ++ ++struct pw_client_endpoint { ++ struct pw_resource *owner_resource; ++ struct spa_hook owner_resource_listener; ++ ++ struct pw_endpoint endpoint; ++}; ++ ++struct resource_data { ++ struct pw_endpoint *endpoint; ++ struct pw_client_endpoint *client_ep; ++ ++ struct spa_hook resource_listener; ++ ++ uint32_t n_subscribe_ids; ++ uint32_t subscribe_ids[32]; ++}; ++ ++static int ++endpoint_enum_params (void *object, int seq, ++ uint32_t id, uint32_t start, uint32_t num, ++ const struct spa_pod *filter) ++{ ++ struct pw_resource *resource = object; ++ struct resource_data *data = pw_resource_get_user_data(resource); ++ struct pw_endpoint *this = data->endpoint; ++ struct spa_pod *result; ++ struct spa_pod *param; ++ uint8_t buffer[1024]; ++ struct spa_pod_builder b = { 0 }; ++ uint32_t index; ++ uint32_t next = start; ++ uint32_t count = 0; ++ ++ while (true) { ++ index = next++; ++ if (index >= this->n_params) ++ break; ++ ++ param = this->params[index]; ++ ++ if (param == NULL || !spa_pod_is_object_id(param, id)) ++ continue; ++ ++ spa_pod_builder_init(&b, buffer, sizeof(buffer)); ++ if (spa_pod_filter(&b, &result, param, filter) != 0) ++ continue; ++ ++ pw_log_debug("endpoint %p: %d param %u", this, seq, index); ++ ++ pw_endpoint_resource_param(resource, seq, id, index, next, result); ++ ++ if (++count == num) ++ break; ++ } ++ return 0; ++} ++ ++static int ++endpoint_subscribe_params (void *object, uint32_t *ids, uint32_t n_ids) ++{ ++ struct pw_resource *resource = object; ++ struct resource_data *data = pw_resource_get_user_data(resource); ++ uint32_t i; ++ ++ n_ids = SPA_MIN(n_ids, SPA_N_ELEMENTS(data->subscribe_ids)); ++ data->n_subscribe_ids = n_ids; ++ ++ for (i = 0; i < n_ids; i++) { ++ data->subscribe_ids[i] = ids[i]; ++ pw_log_debug("endpoint %p: resource %d subscribe param %u", ++ data->endpoint, resource->id, ids[i]); ++ endpoint_enum_params(resource, 1, ids[i], 0, UINT32_MAX, NULL); ++ } ++ return 0; ++} ++ ++static int ++endpoint_set_param (void *object, uint32_t id, uint32_t flags, ++ const struct spa_pod *param) ++{ ++ struct pw_resource *resource = object; ++ struct resource_data *data = pw_resource_get_user_data(resource); ++ struct pw_client_endpoint *client_ep = data->client_ep; ++ ++ pw_client_endpoint_resource_set_param(client_ep->owner_resource, ++ id, flags, param); ++ ++ return 0; ++} ++ ++static const struct pw_endpoint_proxy_methods endpoint_methods = { ++ PW_VERSION_ENDPOINT_PROXY_METHODS, ++ .subscribe_params = endpoint_subscribe_params, ++ .enum_params = endpoint_enum_params, ++ .set_param = endpoint_set_param, ++}; ++ ++static void ++endpoint_unbind(void *data) ++{ ++ struct pw_resource *resource = data; ++ spa_list_remove(&resource->link); ++} ++ ++static const struct pw_resource_events resource_events = { ++ PW_VERSION_RESOURCE_EVENTS, ++ .destroy = endpoint_unbind, ++}; ++ ++static int ++endpoint_bind(void *_data, struct pw_client *client, uint32_t permissions, ++ uint32_t version, uint32_t id) ++{ ++ struct pw_endpoint *this = _data; ++ struct pw_global *global = this->global; ++ struct pw_resource *resource; ++ struct resource_data *data; ++ ++ resource = pw_resource_new(client, id, permissions, global->type, version, sizeof(*data)); ++ if (resource == NULL) ++ goto no_mem; ++ ++ data = pw_resource_get_user_data(resource); ++ data->endpoint = this; ++ data->client_ep = this->client_ep; ++ pw_resource_add_listener(resource, &data->resource_listener, &resource_events, resource); ++ ++ pw_resource_set_implementation(resource, &endpoint_methods, resource); ++ ++ pw_log_debug("endpoint %p: bound to %d", this, resource->id); ++ ++ spa_list_append(&global->resource_list, &resource->link); ++ ++ this->info.change_mask = PW_ENDPOINT_CHANGE_MASK_PARAMS | ++ PW_ENDPOINT_CHANGE_MASK_PROPS; ++ pw_endpoint_resource_info(resource, &this->info); ++ this->info.change_mask = 0; ++ ++ return 0; ++ ++ no_mem: ++ pw_log_error("can't create node resource"); ++ return -ENOMEM; ++} ++ ++static int ++pw_endpoint_init(struct pw_endpoint *this, ++ struct pw_core *core, ++ struct pw_client *owner, ++ struct pw_global *parent, ++ struct pw_properties *properties) ++{ ++ struct pw_properties *props = NULL; ++ ++ pw_log_debug("endpoint %p: new", this); ++ ++ this->core = core; ++ this->parent = parent; ++ ++ props = properties ? properties : pw_properties_new(NULL, NULL); ++ if (!props) ++ goto no_mem; ++ ++ this->props = pw_properties_copy (props); ++ if (!this->props) ++ goto no_mem; ++ ++ this->global = pw_global_new (core, ++ PW_TYPE_INTERFACE_Endpoint, ++ PW_VERSION_ENDPOINT, ++ props, endpoint_bind, this); ++ if (!this->global) ++ goto no_mem; ++ ++ this->info.id = this->global->id; ++ this->info.props = &this->props->dict; ++ ++ return pw_global_register(this->global, owner, parent); ++ ++ no_mem: ++ pw_log_error("can't create endpoint - out of memory"); ++ if (props && !properties) ++ pw_properties_free(props); ++ if (this->props) ++ pw_properties_free(this->props); ++ return -ENOMEM; ++} ++ ++static void ++pw_endpoint_clear(struct pw_endpoint *this) ++{ ++ uint32_t i; ++ ++ pw_log_debug("endpoint %p: destroy", this); ++ ++ pw_global_destroy(this->global); ++ ++ for (i = 0; i < this->n_params; i++) ++ free(this->params[i]); ++ free(this->params); ++ ++ free(this->info.params); ++ ++ if (this->props) ++ pw_properties_free(this->props); ++} ++ ++static void ++endpoint_notify_subscribed(struct pw_endpoint *this, ++ uint32_t index, uint32_t next) ++{ ++ struct pw_global *global = this->global; ++ struct pw_resource *resource; ++ struct resource_data *data; ++ struct spa_pod *param = this->params[index]; ++ uint32_t id; ++ uint32_t i; ++ ++ if (!param || !spa_pod_is_object (param)) ++ return; ++ ++ id = SPA_POD_OBJECT_ID (param); ++ ++ spa_list_for_each(resource, &global->resource_list, link) { ++ data = pw_resource_get_user_data(resource); ++ for (i = 0; i < data->n_subscribe_ids; i++) { ++ if (data->subscribe_ids[i] == id) { ++ pw_endpoint_resource_param(resource, 1, id, ++ index, next, param); ++ } ++ } ++ } ++} ++ ++static int ++client_endpoint_update(void *object, ++ uint32_t change_mask, ++ uint32_t n_params, ++ const struct spa_pod **params, ++ const struct pw_endpoint_info *info) ++{ ++ struct pw_client_endpoint *cliep = object; ++ struct pw_endpoint *this = &cliep->endpoint; ++ ++ if (change_mask & PW_CLIENT_ENDPOINT_UPDATE_PARAMS) { ++ uint32_t i; ++ ++ pw_log_debug("endpoint %p: update %d params", this, n_params); ++ ++ for (i = 0; i < this->n_params; i++) ++ free(this->params[i]); ++ this->n_params = n_params; ++ this->params = realloc(this->params, this->n_params * sizeof(struct spa_pod *)); ++ ++ for (i = 0; i < this->n_params; i++) { ++ this->params[i] = params[i] ? spa_pod_copy(params[i]) : NULL; ++ endpoint_notify_subscribed(this, i, i+1); ++ } ++ } ++ else if (change_mask & PW_CLIENT_ENDPOINT_UPDATE_PARAMS_INCREMENTAL) { ++ uint32_t i, j; ++ const struct spa_pod_prop *pold, *pnew; ++ ++ pw_log_debug("endpoint %p: update %d params incremental", this, n_params); ++ ++ for (i = 0; i < this->n_params; i++) { ++ /* we only support incremental updates for controls */ ++ if (!spa_pod_is_object_id (this->params[i], PW_ENDPOINT_PARAM_Control)) ++ continue; ++ ++ for (j = 0; j < n_params; j++) { ++ if (!spa_pod_is_object_id (params[j], PW_ENDPOINT_PARAM_Control)) { ++ pw_log_warn ("endpoint %p: ignoring incremental update " ++ "on non-control param", this); ++ continue; ++ } ++ ++ pold = spa_pod_object_find_prop ( ++ (const struct spa_pod_object *) this->params[i], ++ NULL, PW_ENDPOINT_PARAM_CONTROL_id); ++ pnew = spa_pod_object_find_prop ( ++ (const struct spa_pod_object *) params[j], ++ NULL, PW_ENDPOINT_PARAM_CONTROL_id); ++ ++ if (pold && pnew && spa_pod_compare (&pold->value, &pnew->value) == 0) { ++ free (this->params[i]); ++ this->params[i] = spa_pod_copy (params[j]); ++ endpoint_notify_subscribed(this, i, UINT32_MAX); ++ } ++ } ++ } ++ } ++ ++ if (change_mask & PW_CLIENT_ENDPOINT_UPDATE_INFO) { ++ struct pw_global *global = this->global; ++ struct pw_resource *resource; ++ ++ if (info->change_mask & PW_ENDPOINT_CHANGE_MASK_PARAMS) { ++ size_t size = info->n_params * sizeof(struct spa_param_info); ++ free(this->info.params); ++ this->info.params = malloc(size); ++ this->info.n_params = info->n_params; ++ memcpy(this->info.params, info->params, size); ++ } ++ ++ if (info->change_mask & PW_ENDPOINT_CHANGE_MASK_PROPS) { ++ pw_properties_update(this->props, info->props); ++ } ++ ++ this->info.change_mask = info->change_mask; ++ spa_list_for_each(resource, &global->resource_list, link) { ++ pw_endpoint_resource_info(resource, &this->info); ++ } ++ this->info.change_mask = 0; ++ } ++ ++ return 0; ++} ++ ++static struct pw_client_endpoint_proxy_methods client_endpoint_methods = { ++ PW_VERSION_CLIENT_ENDPOINT_PROXY_METHODS, ++ .update = client_endpoint_update, ++}; ++ ++static void ++client_endpoint_resource_destroy(void *data) ++{ ++ struct pw_client_endpoint *this = data; ++ ++ pw_log_debug("client-endpoint %p: destroy", this); ++ ++ pw_endpoint_clear(&this->endpoint); ++ ++ this->owner_resource = NULL; ++ spa_hook_remove(&this->owner_resource_listener); ++ free(this); ++} ++ ++static const struct pw_resource_events owner_resource_events = { ++ PW_VERSION_RESOURCE_EVENTS, ++ .destroy = client_endpoint_resource_destroy, ++}; ++ ++struct pw_client_endpoint * ++pw_client_endpoint_new(struct pw_resource *owner_resource, ++ struct pw_global *parent, ++ struct pw_properties *properties) ++{ ++ struct pw_client_endpoint *this; ++ struct pw_client *owner = pw_resource_get_client(owner_resource); ++ struct pw_core *core = pw_client_get_core(owner); ++ ++ this = calloc(1, sizeof(struct pw_client_endpoint)); ++ if (this == NULL) ++ return NULL; ++ ++ pw_log_debug("client-endpoint %p: new", this); ++ ++ if (pw_endpoint_init(&this->endpoint, core, owner, parent, properties) < 0) ++ goto error_no_endpoint; ++ this->endpoint.client_ep = this; ++ ++ this->owner_resource = owner_resource; ++ pw_resource_add_listener(this->owner_resource, ++ &this->owner_resource_listener, ++ &owner_resource_events, ++ this); ++ pw_resource_set_implementation(this->owner_resource, ++ &client_endpoint_methods, ++ this); ++ ++ return this; ++ ++ error_no_endpoint: ++ pw_resource_destroy(owner_resource); ++ free(this); ++ return NULL; ++} ++ ++void ++pw_client_endpoint_destroy(struct pw_client_endpoint *this) ++{ ++ pw_resource_destroy(this->owner_resource); ++} +diff --git a/src/modules/module-endpoint/endpoint-impl.h b/src/modules/module-endpoint/endpoint-impl.h +new file mode 100644 +index 00000000..059aa904 +--- /dev/null ++++ b/src/modules/module-endpoint/endpoint-impl.h +@@ -0,0 +1,52 @@ ++/* PipeWire ++ * ++ * Copyright © 2019 Collabora Ltd. ++ * @author George Kiagiadakis ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Software"), ++ * to deal in the Software without restriction, including without limitation ++ * the rights to use, copy, modify, merge, publish, distribute, sublicense, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice (including the next ++ * paragraph) shall be included in all copies or substantial portions of the ++ * Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ */ ++ ++#ifndef PIPEWIRE_ENDPOINT_IMPL_H ++#define PIPEWIRE_ENDPOINT_IMPL_H ++ ++#include ++#include ++#include ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++struct pw_endpoint; ++struct pw_client_endpoint; ++ ++struct pw_client_endpoint * ++pw_client_endpoint_new(struct pw_resource *resource, ++ struct pw_global *parent, ++ struct pw_properties *properties); ++ ++void ++pw_client_endpoint_destroy(struct pw_client_endpoint *endpoint); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* PIPEWIRE_ENDPOINT_IMPL_H */ +diff --git a/src/modules/module-endpoint/protocol-native.c b/src/modules/module-endpoint/protocol-native.c +new file mode 100644 +index 00000000..a41d3119 +--- /dev/null ++++ b/src/modules/module-endpoint/protocol-native.c +@@ -0,0 +1,472 @@ ++/* PipeWire ++ * ++ * Copyright © 2019 Collabora Ltd. ++ * @author George Kiagiadakis ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Software"), ++ * to deal in the Software without restriction, including without limitation ++ * the rights to use, copy, modify, merge, publish, distribute, sublicense, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice (including the next ++ * paragraph) shall be included in all copies or substantial portions of the ++ * Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ */ ++ ++#include ++#include ++ ++#include ++#include ++#include ++ ++static void ++serialize_pw_endpoint_info(struct spa_pod_builder *b, ++ const struct pw_endpoint_info *info) ++{ ++ struct spa_pod_frame f; ++ uint32_t i, n_props; ++ ++ n_props = info->props ? info->props->n_items : 0; ++ ++ spa_pod_builder_push_struct(b, &f); ++ spa_pod_builder_add(b, ++ SPA_POD_Id(info->id), ++ SPA_POD_Int(info->change_mask), ++ SPA_POD_Int(info->n_params), ++ SPA_POD_Int(n_props), ++ NULL); ++ ++ for (i = 0; i < info->n_params; i++) { ++ spa_pod_builder_add(b, ++ SPA_POD_Id(info->params[i].id), ++ SPA_POD_Int(info->params[i].flags), NULL); ++ } ++ ++ for (i = 0; i < n_props; i++) { ++ spa_pod_builder_add(b, ++ SPA_POD_String(info->props->items[i].key), ++ SPA_POD_String(info->props->items[i].value), ++ NULL); ++ } ++ ++ spa_pod_builder_pop(b, &f); ++} ++ ++/* macro because of alloca() */ ++#define deserialize_pw_endpoint_info(p, f, info) \ ++do { \ ++ if (spa_pod_parser_push_struct(p, f) < 0 || \ ++ spa_pod_parser_get(p, \ ++ SPA_POD_Id(&(info)->id), \ ++ SPA_POD_Int(&(info)->change_mask), \ ++ SPA_POD_Int(&(info)->n_params), \ ++ SPA_POD_Int(&(info)->props->n_items), \ ++ NULL) < 0) \ ++ return -EINVAL; \ ++ \ ++ if ((info)->n_params > 0) \ ++ (info)->params = alloca((info)->n_params * sizeof(struct spa_param_info)); \ ++ if ((info)->props->n_items > 0) \ ++ (info)->props->items = alloca((info)->props->n_items * sizeof(struct spa_dict_item)); \ ++ \ ++ for (i = 0; i < (info)->n_params; i++) { \ ++ if (spa_pod_parser_get(p, \ ++ SPA_POD_Id(&(info)->params[i].id), \ ++ SPA_POD_Int(&(info)->params[i].flags), \ ++ NULL) < 0) \ ++ return -EINVAL; \ ++ } \ ++ \ ++ for (i = 0; i < (info)->props->n_items; i++) { \ ++ if (spa_pod_parser_get(p, \ ++ SPA_POD_String(&(info)->props->items[i].key), \ ++ SPA_POD_String(&(info)->props->items[i].value), \ ++ NULL) < 0) \ ++ return -EINVAL; \ ++ } \ ++ \ ++ spa_pod_parser_pop(p, f); \ ++} while(0) ++ ++static int ++endpoint_marshal_subscribe_params(void *object, uint32_t *ids, uint32_t n_ids) ++{ ++ struct pw_proxy *proxy = object; ++ struct spa_pod_builder *b; ++ ++ b = pw_protocol_native_begin_proxy(proxy, ++ PW_ENDPOINT_PROXY_METHOD_SUBSCRIBE_PARAMS, NULL); ++ ++ spa_pod_builder_add_struct(b, ++ SPA_POD_Array(sizeof(uint32_t), SPA_TYPE_Id, n_ids, ids)); ++ ++ return pw_protocol_native_end_proxy(proxy, b); ++} ++ ++static int ++endpoint_demarshal_subscribe_params(void *object, const struct pw_protocol_native_message *msg) ++{ ++ struct pw_resource *resource = object; ++ struct spa_pod_parser prs; ++ uint32_t csize, ctype, n_ids; ++ uint32_t *ids; ++ ++ spa_pod_parser_init(&prs, msg->data, msg->size); ++ if (spa_pod_parser_get_struct(&prs, ++ SPA_POD_Array(&csize, &ctype, &n_ids, &ids)) < 0) ++ return -EINVAL; ++ ++ if (ctype != SPA_TYPE_Id) ++ return -EINVAL; ++ ++ return pw_resource_do(resource, struct pw_endpoint_proxy_methods, ++ subscribe_params, 0, ids, n_ids); ++} ++ ++static int ++endpoint_marshal_enum_params(void *object, int seq, uint32_t id, ++ uint32_t index, uint32_t num, const struct spa_pod *filter) ++{ ++ struct pw_proxy *proxy = object; ++ struct spa_pod_builder *b; ++ ++ b = pw_protocol_native_begin_proxy(proxy, ++ PW_ENDPOINT_PROXY_METHOD_ENUM_PARAMS, NULL); ++ ++ spa_pod_builder_add_struct(b, ++ SPA_POD_Int(seq), ++ SPA_POD_Id(id), ++ SPA_POD_Int(index), ++ SPA_POD_Int(num), ++ SPA_POD_Pod(filter)); ++ ++ return pw_protocol_native_end_proxy(proxy, b); ++} ++ ++static int ++endpoint_demarshal_enum_params(void *object, const struct pw_protocol_native_message *msg) ++{ ++ struct pw_resource *resource = object; ++ struct spa_pod_parser prs; ++ uint32_t id, index, num; ++ int seq; ++ struct spa_pod *filter; ++ ++ spa_pod_parser_init(&prs, msg->data, msg->size); ++ if (spa_pod_parser_get_struct(&prs, ++ SPA_POD_Int(&seq), ++ SPA_POD_Id(&id), ++ SPA_POD_Int(&index), ++ SPA_POD_Int(&num), ++ SPA_POD_Pod(&filter)) < 0) ++ return -EINVAL; ++ ++ return pw_resource_do(resource, struct pw_endpoint_proxy_methods, ++ enum_params, 0, seq, id, index, num, filter); ++} ++ ++static int ++endpoint_marshal_set_param(void *object, uint32_t id, uint32_t flags, ++ const struct spa_pod *param) ++{ ++ struct pw_proxy *proxy = object; ++ struct spa_pod_builder *b; ++ ++ b = pw_protocol_native_begin_proxy(proxy, ++ PW_ENDPOINT_PROXY_METHOD_SET_PARAM, NULL); ++ ++ spa_pod_builder_add_struct(b, ++ SPA_POD_Id(id), ++ SPA_POD_Int(flags), ++ SPA_POD_Pod(param)); ++ return pw_protocol_native_end_proxy(proxy, b); ++} ++ ++static int ++endpoint_demarshal_set_param(void *object, const struct pw_protocol_native_message *msg) ++{ ++ struct pw_resource *resource = object; ++ struct spa_pod_parser prs; ++ uint32_t id, flags; ++ struct spa_pod *param; ++ ++ spa_pod_parser_init(&prs, msg->data, msg->size); ++ if (spa_pod_parser_get_struct(&prs, ++ SPA_POD_Id(&id), ++ SPA_POD_Int(&flags), ++ SPA_POD_Pod(¶m)) < 0) ++ return -EINVAL; ++ ++ return pw_resource_do(resource, struct pw_endpoint_proxy_methods, ++ set_param, 0, id, flags, param); ++} ++ ++static void ++endpoint_marshal_info(void *object, const struct pw_endpoint_info *info) ++{ ++ struct pw_resource *resource = object; ++ struct spa_pod_builder *b; ++ ++ b = pw_protocol_native_begin_resource(resource, ++ PW_ENDPOINT_PROXY_EVENT_INFO, NULL); ++ serialize_pw_endpoint_info (b, info); ++ pw_protocol_native_end_resource(resource, b); ++} ++ ++static int ++endpoint_demarshal_info(void *object, const struct pw_protocol_native_message *msg) ++{ ++ struct pw_proxy *proxy = object; ++ struct spa_pod_parser prs; ++ struct spa_pod_frame f; ++ struct spa_dict props = SPA_DICT_INIT(NULL, 0); ++ struct pw_endpoint_info info = { .props = &props }; ++ uint32_t i; ++ ++ spa_pod_parser_init(&prs, msg->data, msg->size); ++ ++ deserialize_pw_endpoint_info(&prs, &f, &info); ++ ++ return pw_proxy_notify(proxy, struct pw_endpoint_proxy_events, ++ info, 0, &info); ++} ++ ++static void ++endpoint_marshal_param(void *object, int seq, uint32_t id, ++ uint32_t index, uint32_t next, const struct spa_pod *param) ++{ ++ struct pw_resource *resource = object; ++ struct spa_pod_builder *b; ++ ++ b = pw_protocol_native_begin_resource(resource, ++ PW_ENDPOINT_PROXY_EVENT_PARAM, NULL); ++ ++ spa_pod_builder_add_struct(b, ++ SPA_POD_Int(seq), ++ SPA_POD_Id(id), ++ SPA_POD_Int(index), ++ SPA_POD_Int(next), ++ SPA_POD_Pod(param)); ++ ++ pw_protocol_native_end_resource(resource, b); ++} ++ ++static int ++endpoint_demarshal_param(void *object, const struct pw_protocol_native_message *msg) ++{ ++ struct pw_proxy *proxy = object; ++ struct spa_pod_parser prs; ++ uint32_t id, index, next; ++ int seq; ++ struct spa_pod *param; ++ ++ spa_pod_parser_init(&prs, msg->data, msg->size); ++ if (spa_pod_parser_get_struct(&prs, ++ SPA_POD_Int(&seq), ++ SPA_POD_Id(&id), ++ SPA_POD_Int(&index), ++ SPA_POD_Int(&next), ++ SPA_POD_Pod(¶m)) < 0) ++ return -EINVAL; ++ ++ return pw_proxy_notify(proxy, struct pw_endpoint_proxy_events, param, 0, ++ seq, id, index, next, param); ++} ++ ++static const struct pw_endpoint_proxy_methods pw_protocol_native_endpoint_method_marshal = { ++ PW_VERSION_ENDPOINT_PROXY_METHODS, ++ &endpoint_marshal_subscribe_params, ++ &endpoint_marshal_enum_params, ++ &endpoint_marshal_set_param, ++}; ++ ++static const struct pw_protocol_native_demarshal pw_protocol_native_endpoint_method_demarshal[] = { ++ { &endpoint_demarshal_subscribe_params, 0 }, ++ { &endpoint_demarshal_enum_params, 0 }, ++ { &endpoint_demarshal_set_param, 0 } ++}; ++ ++static const struct pw_endpoint_proxy_events pw_protocol_native_endpoint_event_marshal = { ++ PW_VERSION_ENDPOINT_PROXY_EVENTS, ++ &endpoint_marshal_info, ++ &endpoint_marshal_param, ++}; ++ ++static const struct pw_protocol_native_demarshal pw_protocol_native_endpoint_event_demarshal[] = { ++ { &endpoint_demarshal_info, 0 }, ++ { &endpoint_demarshal_param, 0 } ++}; ++ ++static const struct pw_protocol_marshal pw_protocol_native_endpoint_marshal = { ++ PW_TYPE_INTERFACE_Endpoint, ++ PW_VERSION_ENDPOINT, ++ PW_ENDPOINT_PROXY_METHOD_NUM, ++ PW_ENDPOINT_PROXY_EVENT_NUM, ++ &pw_protocol_native_endpoint_method_marshal, ++ &pw_protocol_native_endpoint_method_demarshal, ++ &pw_protocol_native_endpoint_event_marshal, ++ &pw_protocol_native_endpoint_event_demarshal, ++}; ++ ++ ++static int ++client_endpoint_marshal_update( ++ void *object, ++ uint32_t change_mask, ++ uint32_t n_params, ++ const struct spa_pod **params, ++ const struct pw_endpoint_info *info) ++{ ++ struct pw_proxy *proxy = object; ++ struct spa_pod_builder *b; ++ struct spa_pod_frame f; ++ uint32_t i; ++ ++ b = pw_protocol_native_begin_proxy(proxy, ++ PW_CLIENT_ENDPOINT_PROXY_METHOD_UPDATE, NULL); ++ ++ spa_pod_builder_push_struct(b, &f); ++ spa_pod_builder_add(b, ++ SPA_POD_Int(change_mask), ++ SPA_POD_Int(n_params), NULL); ++ ++ for (i = 0; i < n_params; i++) ++ spa_pod_builder_add(b, SPA_POD_Pod(params[i]), NULL); ++ ++ if (change_mask & PW_CLIENT_ENDPOINT_UPDATE_INFO) ++ serialize_pw_endpoint_info(b, info); ++ ++ spa_pod_builder_pop(b, &f); ++ ++ return pw_protocol_native_end_proxy(proxy, b); ++} ++ ++static int ++client_endpoint_demarshal_update(void *object, ++ const struct pw_protocol_native_message *msg) ++{ ++ struct pw_resource *resource = object; ++ struct spa_pod_parser prs; ++ struct spa_pod_frame f[2]; ++ uint32_t change_mask, n_params; ++ const struct spa_pod **params = NULL; ++ struct spa_dict props = SPA_DICT_INIT(NULL, 0); ++ struct pw_endpoint_info info = { .props = &props }; ++ uint32_t i; ++ ++ spa_pod_parser_init(&prs, msg->data, msg->size); ++ if (spa_pod_parser_push_struct(&prs, &f[0]) < 0 || ++ spa_pod_parser_get(&prs, ++ SPA_POD_Int(&change_mask), ++ SPA_POD_Int(&n_params), NULL) < 0) ++ return -EINVAL; ++ ++ if (n_params > 0) ++ params = alloca(n_params * sizeof(struct spa_pod *)); ++ for (i = 0; i < n_params; i++) ++ if (spa_pod_parser_get(&prs, ++ SPA_POD_PodObject(¶ms[i]), NULL) < 0) ++ return -EINVAL; ++ ++ if (change_mask & PW_CLIENT_ENDPOINT_UPDATE_INFO) ++ deserialize_pw_endpoint_info(&prs, &f[1], &info); ++ ++ pw_resource_do(resource, struct pw_client_endpoint_proxy_methods, ++ update, 0, change_mask, n_params, params, &info); ++ return 0; ++} ++ ++static void ++client_endpoint_marshal_set_param (void *object, ++ uint32_t id, uint32_t flags, ++ const struct spa_pod *param) ++{ ++ struct pw_resource *resource = object; ++ struct spa_pod_builder *b; ++ ++ b = pw_protocol_native_begin_resource(resource, ++ PW_CLIENT_ENDPOINT_PROXY_EVENT_SET_PARAM, NULL); ++ ++ spa_pod_builder_add_struct(b, ++ SPA_POD_Id(id), ++ SPA_POD_Int(flags), ++ SPA_POD_Pod(param)); ++ ++ pw_protocol_native_end_resource(resource, b); ++} ++ ++static int ++client_endpoint_demarshal_set_param(void *object, ++ const struct pw_protocol_native_message *msg) ++{ ++ struct pw_proxy *proxy = object; ++ struct spa_pod_parser prs; ++ uint32_t id, flags; ++ const struct spa_pod *param = NULL; ++ ++ spa_pod_parser_init(&prs, msg->data, msg->size); ++ if (spa_pod_parser_get_struct(&prs, ++ SPA_POD_Id(&id), ++ SPA_POD_Int(&flags), ++ SPA_POD_PodObject(¶m)) < 0) ++ return -EINVAL; ++ ++ pw_proxy_notify(proxy, struct pw_client_endpoint_proxy_events, ++ set_param, 0, id, flags, param); ++ return 0; ++} ++ ++static const struct pw_client_endpoint_proxy_methods pw_protocol_native_client_endpoint_method_marshal = { ++ PW_VERSION_CLIENT_ENDPOINT_PROXY_METHODS, ++ &client_endpoint_marshal_update, ++}; ++ ++static const struct pw_protocol_native_demarshal pw_protocol_native_client_endpoint_method_demarshal[] = { ++ { &client_endpoint_demarshal_update, 0 } ++}; ++ ++static const struct pw_client_endpoint_proxy_events pw_protocol_native_client_endpoint_event_marshal = { ++ PW_VERSION_CLIENT_ENDPOINT_PROXY_EVENTS, ++ &client_endpoint_marshal_set_param, ++}; ++ ++static const struct pw_protocol_native_demarshal pw_protocol_native_client_endpoint_event_demarshal[] = { ++ { &client_endpoint_demarshal_set_param, 0 } ++}; ++ ++static const struct pw_protocol_marshal pw_protocol_native_client_endpoint_marshal = { ++ PW_TYPE_INTERFACE_ClientEndpoint, ++ PW_VERSION_CLIENT_ENDPOINT, ++ PW_CLIENT_ENDPOINT_PROXY_METHOD_NUM, ++ PW_CLIENT_ENDPOINT_PROXY_EVENT_NUM, ++ &pw_protocol_native_client_endpoint_method_marshal, ++ &pw_protocol_native_client_endpoint_method_demarshal, ++ &pw_protocol_native_client_endpoint_event_marshal, ++ &pw_protocol_native_client_endpoint_event_demarshal, ++}; ++ ++struct pw_protocol *pw_protocol_native_ext_endpoint_init(struct pw_core *core) ++{ ++ struct pw_protocol *protocol; ++ ++ protocol = pw_core_find_protocol(core, PW_TYPE_INFO_PROTOCOL_Native); ++ ++ if (protocol == NULL) ++ return NULL; ++ ++ pw_protocol_add_marshal(protocol, &pw_protocol_native_client_endpoint_marshal); ++ pw_protocol_add_marshal(protocol, &pw_protocol_native_endpoint_marshal); ++ ++ return protocol; ++} +diff --git a/src/pipewire/pipewire.c b/src/pipewire/pipewire.c +index a8752438..bbbf9420 100644 +--- a/src/pipewire/pipewire.c ++++ b/src/pipewire/pipewire.c +@@ -647,6 +647,8 @@ static const struct spa_type_info type_info[] = { + { PW_TYPE_INTERFACE_Module, SPA_TYPE_Pointer, PW_TYPE_INFO_INTERFACE_BASE "Module", NULL }, + { PW_TYPE_INTERFACE_ClientNode, SPA_TYPE_Pointer, PW_TYPE_INFO_INTERFACE_BASE "ClientNode", NULL }, + { PW_TYPE_INTERFACE_Device, SPA_TYPE_Pointer, PW_TYPE_INFO_INTERFACE_BASE "Device", NULL }, ++ { PW_TYPE_INTERFACE_Endpoint, SPA_TYPE_Pointer, PW_TYPE_INFO_INTERFACE_BASE "Endpoint", NULL}, ++ { PW_TYPE_INTERFACE_ClientEndpoint, SPA_TYPE_Pointer, PW_TYPE_INFO_INTERFACE_BASE "ClientEndpoint", NULL}, + { SPA_ID_INVALID, SPA_ID_INVALID, "spa_types", spa_types }, + { 0, 0, NULL, NULL }, + }; +diff --git a/src/pipewire/type.h b/src/pipewire/type.h +index a1b205f7..39544913 100644 +--- a/src/pipewire/type.h ++++ b/src/pipewire/type.h +@@ -48,7 +48,8 @@ enum { + /* extensions */ + PW_TYPE_INTERFACE_EXTENSIONS = PW_TYPE_INTERFACE_START + 0x1000, + PW_TYPE_INTERFACE_ClientNode, +- ++ PW_TYPE_INTERFACE_Endpoint, ++ PW_TYPE_INTERFACE_ClientEndpoint, + }; + + #define PW_TYPE_INFO_BASE "PipeWire:" +-- +2.20.1 + diff --git a/meta-pipewire/recipes-multimedia/pipewire/pipewire/0001-spa-include-install-missing-headers.patch b/meta-pipewire/recipes-multimedia/pipewire/pipewire/0001-spa-include-install-missing-headers.patch new file mode 100644 index 00000000..01efe773 --- /dev/null +++ b/meta-pipewire/recipes-multimedia/pipewire/pipewire/0001-spa-include-install-missing-headers.patch @@ -0,0 +1,40 @@ +From 14893ae87ab0b15b7e438779433c4973c797c5f5 Mon Sep 17 00:00:00 2001 +From: George Kiagiadakis +Date: Wed, 29 May 2019 12:09:13 +0300 +Subject: [PATCH] spa/include: install missing headers + +--- + spa/include/spa/meson.build | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/spa/include/spa/meson.build b/spa/include/spa/meson.build +index c9d07659..c079a1a2 100644 +--- a/spa/include/spa/meson.build ++++ b/spa/include/spa/meson.build +@@ -39,6 +39,7 @@ spa_monitor_headers = [ + 'monitor/device.h', + 'monitor/monitor.h', + 'monitor/type-info.h', ++ 'monitor/utils.h', + ] + + install_headers(spa_monitor_headers, +@@ -50,6 +51,7 @@ spa_node_headers = [ + 'node/io.h', + 'node/node.h', + 'node/type-info.h', ++ 'node/utils.h', + ] + + install_headers(spa_node_headers, +@@ -97,6 +99,7 @@ spa_utils_headers = [ + 'utils/dict.h', + 'utils/hook.h', + 'utils/list.h', ++ 'utils/result.h', + 'utils/ringbuffer.h', + 'utils/type.h', + 'utils/type-info.h', +-- +2.20.1 + diff --git a/meta-pipewire/recipes-multimedia/pipewire/pipewire/0002-pipewire-cli-add-support-for-printing-endpoint-info-.patch b/meta-pipewire/recipes-multimedia/pipewire/pipewire/0002-pipewire-cli-add-support-for-printing-endpoint-info-.patch new file mode 100644 index 00000000..008c15f9 --- /dev/null +++ b/meta-pipewire/recipes-multimedia/pipewire/pipewire/0002-pipewire-cli-add-support-for-printing-endpoint-info-.patch @@ -0,0 +1,148 @@ +From e76140c534dde71424eb9abd1dde69cf14152da5 Mon Sep 17 00:00:00 2001 +From: George Kiagiadakis +Date: Tue, 28 May 2019 11:46:36 +0300 +Subject: [PATCH 2/2] pipewire-cli: add support for printing endpoint info & + params + +Note that you have to run: + load-module libpipewire-module-endpoint +before trying to query any endpoints +--- + src/tools/pipewire-cli.c | 78 +++++++++++++++++++++++++++++++++++++++- + 1 file changed, 77 insertions(+), 1 deletion(-) + +diff --git a/src/tools/pipewire-cli.c b/src/tools/pipewire-cli.c +index 521739f6..9511db82 100644 +--- a/src/tools/pipewire-cli.c ++++ b/src/tools/pipewire-cli.c +@@ -38,6 +38,8 @@ + #include + #include + ++#include ++ + static const char WHITESPACE[] = " \t"; + + struct remote_data; +@@ -176,8 +178,12 @@ static void print_params(struct spa_param_info *params, uint32_t n_params, char + return; + } + for (i = 0; i < n_params; i++) { ++ const struct spa_type_info *type_info = spa_type_param; ++ if (params[i].id >= PW_ENDPOINT_PARAM_EnumControl) ++ type_info = endpoint_param_type_info; ++ + fprintf(stdout, "%c\t %d (%s) %c%c\n", mark, params[i].id, +- spa_debug_type_find_name(spa_type_param, params[i].id), ++ spa_debug_type_find_name(type_info, params[i].id), + params[i].flags & SPA_PARAM_INFO_READ ? 'r' : '-', + params[i].flags & SPA_PARAM_INFO_WRITE ? 'w' : '-'); + } +@@ -641,6 +647,16 @@ static void info_device(struct proxy_data *pd) + info->change_mask = 0; + } + ++static void info_endpoint(struct proxy_data *pd) ++{ ++ struct pw_endpoint_info *info = pd->info; ++ ++ info_global(pd); ++ print_properties(info->props, MARK_CHANGE(1), true); ++ print_params(info->params, info->n_params, MARK_CHANGE(0), true); ++ info->change_mask = 0; ++} ++ + static void core_event_info(void *object, const struct pw_core_info *info) + { + struct proxy_data *pd = object; +@@ -708,6 +724,9 @@ static void event_param(void *object, int seq, uint32_t id, + + if (spa_pod_is_object_type(param, SPA_TYPE_OBJECT_Format)) + spa_debug_format(2, NULL, param); ++ else if (spa_pod_is_object_type(param, PW_ENDPOINT_OBJECT_ParamControl) || ++ spa_pod_is_object_type(param, PW_ENDPOINT_OBJECT_ParamStream)) ++ spa_debug_pod(2, endpoint_param_object_type_info, param); + else + spa_debug_pod(2, NULL, param); + } +@@ -842,6 +861,53 @@ static const struct pw_device_proxy_events device_events = { + .param = event_param + }; + ++static void endpoint_info_free(struct pw_endpoint_info *info) ++{ ++ free(info->params); ++ if (info->props) ++ pw_properties_free ((struct pw_properties *)info->props); ++ free(info); ++} ++ ++static void endpoint_event_info(void *object, ++ const struct pw_endpoint_info *update) ++{ ++ struct proxy_data *pd = object; ++ struct remote_data *rd = pd->rd; ++ struct pw_endpoint_info *info = pd->info; ++ ++ if (!info) { ++ info = pd->info = calloc(1, sizeof(*info)); ++ info->id = update->id; ++ } ++ if (update->change_mask & PW_ENDPOINT_CHANGE_MASK_PARAMS) { ++ info->n_params = update->n_params; ++ free(info->params); ++ info->params = malloc(info->n_params * sizeof(struct spa_param_info)); ++ memcpy(info->params, update->params, ++ info->n_params * sizeof(struct spa_param_info)); ++ } ++ if (update->change_mask & PW_ENDPOINT_CHANGE_MASK_PROPS) { ++ if (info->props) ++ pw_properties_free ((struct pw_properties *)info->props); ++ info->props = ++ (struct spa_dict *) pw_properties_new_dict (update->props); ++ } ++ ++ if (pd->global == NULL) ++ pd->global = pw_map_lookup(&rd->globals, info->id); ++ if (pd->global && pd->global->info_pending) { ++ info_endpoint(pd); ++ pd->global->info_pending = false; ++ } ++} ++ ++static const struct pw_endpoint_proxy_events endpoint_events = { ++ PW_VERSION_ENDPOINT_PROXY_EVENTS, ++ .info = endpoint_event_info, ++ .param = event_param ++}; ++ + static void + destroy_proxy (void *data) + { +@@ -928,6 +994,12 @@ static bool bind_global(struct remote_data *rd, struct global *global, char **er + destroy = (pw_destroy_t) pw_link_info_free; + info_func = info_link; + break; ++ case PW_TYPE_INTERFACE_Endpoint: ++ events = &endpoint_events; ++ client_version = PW_VERSION_ENDPOINT; ++ destroy = (pw_destroy_t) endpoint_info_free; ++ info_func = info_endpoint; ++ break; + default: + asprintf(error, "unsupported type %s", spa_debug_type_find_name(pw_type_info(), global->type)); + return false; +@@ -1201,6 +1273,10 @@ static bool do_enum_params(struct data *data, const char *cmd, char *args, char + pw_device_proxy_enum_params((struct pw_device_proxy*)global->proxy, 0, + param_id, 0, 0, NULL); + break; ++ case PW_TYPE_INTERFACE_Endpoint: ++ pw_endpoint_proxy_enum_params((struct pw_endpoint_proxy*)global->proxy, 0, ++ param_id, 0, 0, NULL); ++ break; + default: + asprintf(error, "enum-params not implemented on object %d", atoi(a[0])); + return false; +-- +2.20.1 + diff --git a/meta-pipewire/recipes-multimedia/pipewire/pipewire_git.bb b/meta-pipewire/recipes-multimedia/pipewire/pipewire_git.bb index 65efe214..84e76883 100644 --- a/meta-pipewire/recipes-multimedia/pipewire/pipewire_git.bb +++ b/meta-pipewire/recipes-multimedia/pipewire/pipewire_git.bb @@ -1,16 +1,14 @@ require pipewire.inc -FILESEXTRAPATHS_prepend := "${THISDIR}:" - SRC_URI = "gitsm://github.com/PipeWire/pipewire;protocol=https;branch=work \ file://0001-spa-include-install-missing-headers.patch \ file://0001-extensions-implement-Endpoint-ClientEndpoint-interfa.patch \ file://0002-pipewire-cli-add-support-for-printing-endpoint-info-.patch \ - file://pipewire.conf \ " + SRCREV = "4be788962e60891237f1f018627bf709ae3981e6" PV = "0.2.90+git${SRCPV}-1" S = "${WORKDIR}/git" -RDEPENDS_${PN} += "wireplumber" +RDEPENDS_${PN} += "virtual/pipewire-sessionmanager virtual/pipewire-config" diff --git a/meta-pipewire/recipes-multimedia/wireplumber/wireplumber_git.bb b/meta-pipewire/recipes-multimedia/wireplumber/wireplumber_git.bb index daf0a38a..df5e93df 100644 --- a/meta-pipewire/recipes-multimedia/wireplumber/wireplumber_git.bb +++ b/meta-pipewire/recipes-multimedia/wireplumber/wireplumber_git.bb @@ -17,10 +17,20 @@ SRCREV = "36bc1795ca2626cde5cbd5ec6afae50e5496bd08" PV = "0.0+git${SRCPV}" S = "${WORKDIR}/git" +PACKAGES =+ "${PN}-config" + FILES_${PN} += "\ ${libdir}/wireplumber-*/* \ +" +RPROVIDES_${PN} += "virtual/pipewire-sessionmanager" +RDEPENDS_${PN} += "virtual/wireplumber-config" + + +FILES_${PN}-config += "\ ${sysconfdir}/wireplumber/* \ " -CONFFILES_${PN} += "\ +CONFFILES_${PN}-config += "\ ${sysconfdir}/wireplumber/* \ " + +RPROVIDES_${PN}-config += "virtual/wireplumber-config" -- cgit 1.2.3-korg