1 From 3d186f7b97c508cc16955a96a69ee5d6c9db57dc Mon Sep 17 00:00:00 2001
2 From: George Kiagiadakis <george.kiagiadakis@collabora.com>
3 Date: Thu, 23 May 2019 18:59:05 +0300
4 Subject: [PATCH 1/2] extensions: implement Endpoint & ClientEndpoint
7 The ClientEndpoint interface allows session managers to register
8 endpoint objects on pipewire.
9 The Endpoint interface allows other clients to interact with
10 endpoints provided by the session manager.
12 src/extensions/client-endpoint.h | 106 ++++
13 src/extensions/endpoint.h | 237 +++++++++
14 src/extensions/meson.build | 2 +
15 src/modules/meson.build | 12 +
16 src/modules/module-endpoint.c | 137 +++++
17 src/modules/module-endpoint/endpoint-impl.c | 428 ++++++++++++++++
18 src/modules/module-endpoint/endpoint-impl.h | 52 ++
19 src/modules/module-endpoint/protocol-native.c | 472 ++++++++++++++++++
20 src/pipewire/pipewire.c | 2 +
21 src/pipewire/type.h | 3 +-
22 10 files changed, 1450 insertions(+), 1 deletion(-)
23 create mode 100644 src/extensions/client-endpoint.h
24 create mode 100644 src/extensions/endpoint.h
25 create mode 100644 src/modules/module-endpoint.c
26 create mode 100644 src/modules/module-endpoint/endpoint-impl.c
27 create mode 100644 src/modules/module-endpoint/endpoint-impl.h
28 create mode 100644 src/modules/module-endpoint/protocol-native.c
30 diff --git a/src/extensions/client-endpoint.h b/src/extensions/client-endpoint.h
32 index 00000000..0389893c
34 +++ b/src/extensions/client-endpoint.h
38 + * Copyright © 2019 Collabora Ltd.
39 + * @author George Kiagiadakis <george.kiagiadakis@collabora.com>
41 + * Permission is hereby granted, free of charge, to any person obtaining a
42 + * copy of this software and associated documentation files (the "Software"),
43 + * to deal in the Software without restriction, including without limitation
44 + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
45 + * and/or sell copies of the Software, and to permit persons to whom the
46 + * Software is furnished to do so, subject to the following conditions:
48 + * The above copyright notice and this permission notice (including the next
49 + * paragraph) shall be included in all copies or substantial portions of the
52 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
53 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
54 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
55 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
56 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
57 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
58 + * DEALINGS IN THE SOFTWARE.
61 +#ifndef PIPEWIRE_EXT_CLIENT_ENDPOINT_H
62 +#define PIPEWIRE_EXT_CLIENT_ENDPOINT_H
64 +#include "endpoint.h"
70 +struct pw_client_endpoint_proxy;
72 +#define PW_VERSION_CLIENT_ENDPOINT 0
73 +#define PW_EXTENSION_MODULE_CLIENT_ENDPOINT PIPEWIRE_MODULE_PREFIX "module-endpoint"
75 +#define PW_CLIENT_ENDPOINT_PROXY_METHOD_UPDATE 0
76 +#define PW_CLIENT_ENDPOINT_PROXY_METHOD_NUM 1
78 +struct pw_client_endpoint_proxy_methods {
79 +#define PW_VERSION_CLIENT_ENDPOINT_PROXY_METHODS 0
83 + * Update endpoint info
85 + int (*update) (void *object,
86 +#define PW_CLIENT_ENDPOINT_UPDATE_PARAMS (1 << 0)
87 +#define PW_CLIENT_ENDPOINT_UPDATE_PARAMS_INCREMENTAL (1 << 1)
88 +#define PW_CLIENT_ENDPOINT_UPDATE_INFO (1 << 2)
89 + uint32_t change_mask,
91 + const struct spa_pod **params,
92 + const struct pw_endpoint_info *info);
96 +pw_client_endpoint_proxy_update(struct pw_client_endpoint_proxy *p,
97 + uint32_t change_mask,
99 + const struct spa_pod **params,
100 + struct pw_endpoint_info *info)
102 + return pw_proxy_do((struct pw_proxy*)p,
103 + struct pw_client_endpoint_proxy_methods, update,
104 + change_mask, n_params, params, info);
107 +#define PW_CLIENT_ENDPOINT_PROXY_EVENT_SET_PARAM 0
108 +#define PW_CLIENT_ENDPOINT_PROXY_EVENT_NUM 1
110 +struct pw_client_endpoint_proxy_events {
111 +#define PW_VERSION_CLIENT_ENDPOINT_PROXY_EVENTS 0
115 + * Set a parameter on the endpoint
117 + * \param id the parameter id to set
118 + * \param flags extra parameter flags
119 + * \param param the parameter to set
121 + void (*set_param) (void *object, uint32_t id, uint32_t flags,
122 + const struct spa_pod *param);
126 +pw_client_endpoint_proxy_add_listener(struct pw_client_endpoint_proxy *p,
127 + struct spa_hook *listener,
128 + const struct pw_client_endpoint_proxy_events *events,
131 + pw_proxy_add_proxy_listener((struct pw_proxy*)p, listener, events, data);
134 +#define pw_client_endpoint_resource_set_param(r,...) \
135 + pw_resource_notify(r,struct pw_client_endpoint_proxy_events,set_param,__VA_ARGS__)
141 +#endif /* PIPEWIRE_EXT_CLIENT_ENDPOINT_H */
142 diff --git a/src/extensions/endpoint.h b/src/extensions/endpoint.h
144 index 00000000..3b84dd49
146 +++ b/src/extensions/endpoint.h
150 + * Copyright © 2019 Collabora Ltd.
151 + * @author George Kiagiadakis <george.kiagiadakis@collabora.com>
153 + * Permission is hereby granted, free of charge, to any person obtaining a
154 + * copy of this software and associated documentation files (the "Software"),
155 + * to deal in the Software without restriction, including without limitation
156 + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
157 + * and/or sell copies of the Software, and to permit persons to whom the
158 + * Software is furnished to do so, subject to the following conditions:
160 + * The above copyright notice and this permission notice (including the next
161 + * paragraph) shall be included in all copies or substantial portions of the
164 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
165 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
166 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
167 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
168 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
169 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
170 + * DEALINGS IN THE SOFTWARE.
173 +#ifndef PIPEWIRE_EXT_ENDPOINT_H
174 +#define PIPEWIRE_EXT_ENDPOINT_H
176 +#include <spa/utils/defs.h>
177 +#include <spa/utils/type-info.h>
178 +#include <pipewire/proxy.h>
184 +struct pw_endpoint_proxy;
186 +#define PW_VERSION_ENDPOINT 0
187 +#define PW_EXTENSION_MODULE_ENDPOINT PIPEWIRE_MODULE_PREFIX "module-endpoint"
189 +/* extending enum spa_param_type */
190 +enum endpoint_param_type {
191 + PW_ENDPOINT_PARAM_EnumControl = 0x1000,
192 + PW_ENDPOINT_PARAM_Control,
193 + PW_ENDPOINT_PARAM_EnumStream,
196 +enum endpoint_param_object_type {
197 + PW_ENDPOINT_OBJECT_ParamControl = PW_TYPE_FIRST + SPA_TYPE_OBJECT_START + 0x1001,
198 + PW_ENDPOINT_OBJECT_ParamStream,
201 +/** properties for PW_ENDPOINT_OBJECT_ParamControl */
202 +enum endpoint_param_control {
203 + PW_ENDPOINT_PARAM_CONTROL_START, /**< object id, one of enum endpoint_param_type */
204 + PW_ENDPOINT_PARAM_CONTROL_id, /**< control id (Int) */
205 + PW_ENDPOINT_PARAM_CONTROL_stream_id, /**< stream id (Int) */
206 + PW_ENDPOINT_PARAM_CONTROL_name, /**< control name (String) */
207 + PW_ENDPOINT_PARAM_CONTROL_type, /**< control type (Range) */
208 + PW_ENDPOINT_PARAM_CONTROL_value, /**< control value */
211 +/** properties for PW_ENDPOINT_OBJECT_ParamStream */
212 +enum endpoint_param_stream {
213 + PW_ENDPOINT_PARAM_STREAM_START, /**< object id, one of enum endpoint_param_type */
214 + PW_ENDPOINT_PARAM_STREAM_id, /**< stream id (Int) */
215 + PW_ENDPOINT_PARAM_STREAM_name, /**< stream name (String) */
218 +static const struct spa_type_info endpoint_param_type_info[] = {
219 + { PW_ENDPOINT_PARAM_EnumControl, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_ID_BASE "EnumControl", NULL },
220 + { PW_ENDPOINT_PARAM_Control, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_ID_BASE "Control", NULL },
221 + { PW_ENDPOINT_PARAM_EnumStream, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_ID_BASE "EnumStream", NULL },
222 + { 0, 0, NULL, NULL },
225 +#define PW_ENDPOINT_TYPE_INFO_ParamControl SPA_TYPE_INFO_PARAM_BASE "ParamControl"
226 +#define PW_ENDPOINT_TYPE_INFO_PARAM_CONTROL_BASE PW_ENDPOINT_TYPE_INFO_ParamControl ":"
228 +static const struct spa_type_info endpoint_param_control_info[] = {
229 + { PW_ENDPOINT_PARAM_CONTROL_START, SPA_TYPE_Id, PW_ENDPOINT_TYPE_INFO_PARAM_CONTROL_BASE, spa_type_param, },
230 + { PW_ENDPOINT_PARAM_CONTROL_id, SPA_TYPE_Int, PW_ENDPOINT_TYPE_INFO_PARAM_CONTROL_BASE "id", NULL },
231 + { PW_ENDPOINT_PARAM_CONTROL_stream_id, SPA_TYPE_Int, PW_ENDPOINT_TYPE_INFO_PARAM_CONTROL_BASE "streamId", NULL },
232 + { PW_ENDPOINT_PARAM_CONTROL_name, SPA_TYPE_String, PW_ENDPOINT_TYPE_INFO_PARAM_CONTROL_BASE "name", NULL },
233 + { PW_ENDPOINT_PARAM_CONTROL_type, SPA_TYPE_Pod, PW_ENDPOINT_TYPE_INFO_PARAM_CONTROL_BASE "type", NULL },
234 + { PW_ENDPOINT_PARAM_CONTROL_value, SPA_TYPE_Struct, PW_ENDPOINT_TYPE_INFO_PARAM_CONTROL_BASE "labels", NULL },
235 + { 0, 0, NULL, NULL },
238 +#define PW_ENDPOINT_TYPE_INFO_ParamStream SPA_TYPE_INFO_PARAM_BASE "ParamStream"
239 +#define PW_ENDPOINT_TYPE_INFO_PARAM_STREAM_BASE PW_ENDPOINT_TYPE_INFO_ParamStream ":"
241 +static const struct spa_type_info endpoint_param_stream_info[] = {
242 + { PW_ENDPOINT_PARAM_STREAM_START, SPA_TYPE_Id, PW_ENDPOINT_TYPE_INFO_PARAM_STREAM_BASE, spa_type_param, },
243 + { PW_ENDPOINT_PARAM_STREAM_id, SPA_TYPE_Int, PW_ENDPOINT_TYPE_INFO_PARAM_STREAM_BASE "id", NULL },
244 + { PW_ENDPOINT_PARAM_STREAM_name, SPA_TYPE_String, PW_ENDPOINT_TYPE_INFO_PARAM_STREAM_BASE "name", NULL },
245 + { 0, 0, NULL, NULL },
248 +static const struct spa_type_info endpoint_param_object_type_info[] = {
249 + { PW_ENDPOINT_OBJECT_ParamControl, SPA_TYPE_Object, SPA_TYPE_INFO_OBJECT_BASE "ParamControl", endpoint_param_control_info, },
250 + { PW_ENDPOINT_OBJECT_ParamStream, SPA_TYPE_Object, SPA_TYPE_INFO_OBJECT_BASE "ParamStream", endpoint_param_stream_info },
251 + { 0, 0, NULL, NULL },
254 +struct pw_endpoint_info {
255 + uint32_t id; /**< id of the global */
256 +#define PW_ENDPOINT_CHANGE_MASK_PARAMS (1 << 0)
257 +#define PW_ENDPOINT_CHANGE_MASK_PROPS (1 << 1)
258 + uint32_t change_mask; /**< bitfield of changed fields since last call */
259 + uint32_t n_params; /**< number of items in \a params */
260 + struct spa_param_info *params; /**< parameters */
261 + struct spa_dict *props; /**< extra properties */
264 +#define PW_ENDPOINT_PROXY_METHOD_SUBSCRIBE_PARAMS 0
265 +#define PW_ENDPOINT_PROXY_METHOD_ENUM_PARAMS 1
266 +#define PW_ENDPOINT_PROXY_METHOD_SET_PARAM 2
267 +#define PW_ENDPOINT_PROXY_METHOD_NUM 3
269 +struct pw_endpoint_proxy_methods {
270 +#define PW_VERSION_ENDPOINT_PROXY_METHODS 0
274 + * Subscribe to parameter changes
276 + * Automatically emit param events for the given ids when
277 + * they are changed.
279 + * \param ids an array of param ids
280 + * \param n_ids the number of ids in \a ids
282 + int (*subscribe_params) (void *object, uint32_t *ids, uint32_t n_ids);
285 + * Enumerate endpoint parameters
287 + * Start enumeration of endpoint parameters. For each param, a
288 + * param event will be emited.
290 + * \param seq a sequence number to place in the reply
291 + * \param id the parameter id to enum or SPA_ID_INVALID for all
292 + * \param start the start index or 0 for the first param
293 + * \param num the maximum number of params to retrieve
294 + * \param filter a param filter or NULL
296 + int (*enum_params) (void *object, int seq,
297 + uint32_t id, uint32_t start, uint32_t num,
298 + const struct spa_pod *filter);
301 + * Set a parameter on the endpoint
303 + * \param id the parameter id to set
304 + * \param flags extra parameter flags
305 + * \param param the parameter to set
307 + int (*set_param) (void *object, uint32_t id, uint32_t flags,
308 + const struct spa_pod *param);
312 +pw_endpoint_proxy_subscribe_params(struct pw_endpoint_proxy *p, uint32_t *ids, uint32_t n_ids)
314 + return pw_proxy_do((struct pw_proxy*)p, struct pw_endpoint_proxy_methods,
315 + subscribe_params, ids, n_ids);
319 +pw_endpoint_proxy_enum_params(struct pw_endpoint_proxy *p, int seq,
320 + uint32_t id, uint32_t start, uint32_t num,
321 + const struct spa_pod *filter)
323 + return pw_proxy_do((struct pw_proxy*)p, struct pw_endpoint_proxy_methods,
324 + enum_params, seq, id, start, num, filter);
328 +pw_endpoint_proxy_set_param(struct pw_endpoint_proxy *p, uint32_t id,
329 + uint32_t flags, const struct spa_pod *param)
331 + return pw_proxy_do((struct pw_proxy*)p, struct pw_endpoint_proxy_methods,
332 + set_param, id, flags, param);
335 +#define PW_ENDPOINT_PROXY_EVENT_INFO 0
336 +#define PW_ENDPOINT_PROXY_EVENT_PARAM 1
337 +#define PW_ENDPOINT_PROXY_EVENT_NUM 2
339 +struct pw_endpoint_proxy_events {
340 +#define PW_VERSION_ENDPOINT_PROXY_EVENTS 0
344 + * Notify endpoint info
346 + * \param info info about the endpoint
348 + void (*info) (void *object, const struct pw_endpoint_info * info);
351 + * Notify an endpoint param
353 + * Event emited as a result of the enum_params method.
355 + * \param seq the sequence number of the request
356 + * \param id the param id
357 + * \param index the param index
358 + * \param next the param index of the next param
359 + * \param param the parameter
361 + void (*param) (void *object, int seq, uint32_t id,
362 + uint32_t index, uint32_t next,
363 + const struct spa_pod *param);
367 +pw_endpoint_proxy_add_listener(struct pw_endpoint_proxy *p,
368 + struct spa_hook *listener,
369 + const struct pw_endpoint_proxy_events *events,
372 + pw_proxy_add_proxy_listener((struct pw_proxy*)p, listener, events, data);
375 +#define pw_endpoint_resource_info(r,...) \
376 + pw_resource_notify(r,struct pw_endpoint_proxy_events,info,__VA_ARGS__)
377 +#define pw_endpoint_resource_param(r,...) \
378 + pw_resource_notify(r,struct pw_endpoint_proxy_events,param,__VA_ARGS__)
384 +#endif /* PIPEWIRE_EXT_ENDPOINT_H */
385 diff --git a/src/extensions/meson.build b/src/extensions/meson.build
386 index a7f5d3cb..9f690caf 100644
387 --- a/src/extensions/meson.build
388 +++ b/src/extensions/meson.build
390 pipewire_ext_headers = [
391 + 'client-endpoint.h',
397 diff --git a/src/modules/meson.build b/src/modules/meson.build
398 index 98bc3864..572f1b6b 100644
399 --- a/src/modules/meson.build
400 +++ b/src/modules/meson.build
401 @@ -37,6 +37,18 @@ pipewire_module_client_node = shared_library('pipewire-module-client-node',
402 dependencies : [mathlib, dl_lib, pipewire_dep],
405 +pipewire_module_endpoint = shared_library('pipewire-module-endpoint',
406 + [ 'module-endpoint.c',
407 + 'module-endpoint/endpoint-impl.c',
408 + 'module-endpoint/protocol-native.c',
410 + c_args : pipewire_module_c_args,
411 + include_directories : [configinc, spa_inc],
413 + install_dir : modules_install_dir,
414 + dependencies : [mathlib, dl_lib, pipewire_dep],
417 pipewire_module_link_factory = shared_library('pipewire-module-link-factory',
418 [ 'module-link-factory.c' ],
419 c_args : pipewire_module_c_args,
420 diff --git a/src/modules/module-endpoint.c b/src/modules/module-endpoint.c
422 index 00000000..d830de1b
424 +++ b/src/modules/module-endpoint.c
428 + * Copyright © 2019 Collabora Ltd.
429 + * @author George Kiagiadakis <george.kiagiadakis@collabora.com>
431 + * Permission is hereby granted, free of charge, to any person obtaining a
432 + * copy of this software and associated documentation files (the "Software"),
433 + * to deal in the Software without restriction, including without limitation
434 + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
435 + * and/or sell copies of the Software, and to permit persons to whom the
436 + * Software is furnished to do so, subject to the following conditions:
438 + * The above copyright notice and this permission notice (including the next
439 + * paragraph) shall be included in all copies or substantial portions of the
442 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
443 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
444 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
445 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
446 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
447 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
448 + * DEALINGS IN THE SOFTWARE.
453 +#include "module-endpoint/endpoint-impl.h"
455 +struct pw_protocol *pw_protocol_native_ext_endpoint_init(struct pw_core *core);
457 +static const struct spa_dict_item module_props[] = {
458 + { PW_MODULE_PROP_AUTHOR, "George Kiagiadakis <george.kiagiadakis@collabora.com>" },
459 + { PW_MODULE_PROP_DESCRIPTION, "Allows clients to interract with session manager endpoints" },
460 + { PW_MODULE_PROP_VERSION, PACKAGE_VERSION },
463 +struct factory_data {
464 + struct pw_factory *this;
465 + struct pw_properties *properties;
467 + struct pw_module *module;
468 + struct spa_hook module_listener;
471 +static void *create_object(void *_data,
472 + struct pw_resource *resource,
475 + struct pw_properties *properties,
479 + struct pw_resource *endpoint_resource;
480 + struct pw_global *parent;
481 + struct pw_client *client = pw_resource_get_client(resource);
483 + endpoint_resource = pw_resource_new(client, new_id, PW_PERM_RWX, type, version, 0);
484 + if (endpoint_resource == NULL)
487 + parent = pw_client_get_global(client);
489 + result = pw_client_endpoint_new(endpoint_resource, parent, properties);
490 + if (result == NULL)
496 + pw_log_error("can't create endpoint");
497 + pw_resource_error(resource, -ENOMEM, "can't create endpoint: no memory");
499 + pw_properties_free(properties);
503 +static const struct pw_factory_implementation impl_factory = {
504 + PW_VERSION_FACTORY_IMPLEMENTATION,
505 + .create_object = create_object,
508 +static void module_destroy(void *data)
510 + struct factory_data *d = data;
512 + spa_hook_remove(&d->module_listener);
515 + pw_properties_free(d->properties);
517 + pw_factory_destroy(d->this);
520 +static const struct pw_module_events module_events = {
521 + PW_VERSION_MODULE_EVENTS,
522 + .destroy = module_destroy,
525 +static int module_init(struct pw_module *module, struct pw_properties *properties)
527 + struct pw_core *core = pw_module_get_core(module);
528 + struct pw_factory *factory;
529 + struct factory_data *data;
531 + factory = pw_factory_new(core,
533 + PW_TYPE_INTERFACE_ClientEndpoint,
534 + PW_VERSION_CLIENT_ENDPOINT,
537 + if (factory == NULL)
540 + data = pw_factory_get_user_data(factory);
541 + data->this = factory;
542 + data->module = module;
543 + data->properties = properties;
545 + pw_log_debug("module-endpoint %p: new", module);
547 + pw_factory_set_implementation(factory, &impl_factory, data);
548 + pw_factory_register(factory, NULL, pw_module_get_global(module), NULL);
550 + pw_protocol_native_ext_endpoint_init(core);
552 + pw_module_add_listener(module, &data->module_listener, &module_events, data);
553 + pw_module_update_properties(module, &SPA_DICT_INIT_ARRAY(module_props));
559 +int pipewire__module_init(struct pw_module *module, const char *args)
561 + return module_init(module, NULL);
563 diff --git a/src/modules/module-endpoint/endpoint-impl.c b/src/modules/module-endpoint/endpoint-impl.c
565 index 00000000..252eeca1
567 +++ b/src/modules/module-endpoint/endpoint-impl.c
571 + * Copyright © 2019 Collabora Ltd.
572 + * @author George Kiagiadakis <george.kiagiadakis@collabora.com>
574 + * Permission is hereby granted, free of charge, to any person obtaining a
575 + * copy of this software and associated documentation files (the "Software"),
576 + * to deal in the Software without restriction, including without limitation
577 + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
578 + * and/or sell copies of the Software, and to permit persons to whom the
579 + * Software is furnished to do so, subject to the following conditions:
581 + * The above copyright notice and this permission notice (including the next
582 + * paragraph) shall be included in all copies or substantial portions of the
585 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
586 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
587 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
588 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
589 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
590 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
591 + * DEALINGS IN THE SOFTWARE.
594 +#include "endpoint-impl.h"
595 +#include <pipewire/private.h>
596 +#include <spa/pod/filter.h>
597 +#include <spa/pod/compare.h>
599 +struct pw_endpoint {
600 + struct pw_core *core;
601 + struct pw_global *global;
602 + struct pw_global *parent;
604 + struct pw_client_endpoint *client_ep;
607 + struct spa_pod **params;
609 + struct pw_endpoint_info info;
610 + struct pw_properties *props;
613 +struct pw_client_endpoint {
614 + struct pw_resource *owner_resource;
615 + struct spa_hook owner_resource_listener;
617 + struct pw_endpoint endpoint;
620 +struct resource_data {
621 + struct pw_endpoint *endpoint;
622 + struct pw_client_endpoint *client_ep;
624 + struct spa_hook resource_listener;
626 + uint32_t n_subscribe_ids;
627 + uint32_t subscribe_ids[32];
631 +endpoint_enum_params (void *object, int seq,
632 + uint32_t id, uint32_t start, uint32_t num,
633 + const struct spa_pod *filter)
635 + struct pw_resource *resource = object;
636 + struct resource_data *data = pw_resource_get_user_data(resource);
637 + struct pw_endpoint *this = data->endpoint;
638 + struct spa_pod *result;
639 + struct spa_pod *param;
640 + uint8_t buffer[1024];
641 + struct spa_pod_builder b = { 0 };
643 + uint32_t next = start;
644 + uint32_t count = 0;
648 + if (index >= this->n_params)
651 + param = this->params[index];
653 + if (param == NULL || !spa_pod_is_object_id(param, id))
656 + spa_pod_builder_init(&b, buffer, sizeof(buffer));
657 + if (spa_pod_filter(&b, &result, param, filter) != 0)
660 + pw_log_debug("endpoint %p: %d param %u", this, seq, index);
662 + pw_endpoint_resource_param(resource, seq, id, index, next, result);
664 + if (++count == num)
671 +endpoint_subscribe_params (void *object, uint32_t *ids, uint32_t n_ids)
673 + struct pw_resource *resource = object;
674 + struct resource_data *data = pw_resource_get_user_data(resource);
677 + n_ids = SPA_MIN(n_ids, SPA_N_ELEMENTS(data->subscribe_ids));
678 + data->n_subscribe_ids = n_ids;
680 + for (i = 0; i < n_ids; i++) {
681 + data->subscribe_ids[i] = ids[i];
682 + pw_log_debug("endpoint %p: resource %d subscribe param %u",
683 + data->endpoint, resource->id, ids[i]);
684 + endpoint_enum_params(resource, 1, ids[i], 0, UINT32_MAX, NULL);
690 +endpoint_set_param (void *object, uint32_t id, uint32_t flags,
691 + const struct spa_pod *param)
693 + struct pw_resource *resource = object;
694 + struct resource_data *data = pw_resource_get_user_data(resource);
695 + struct pw_client_endpoint *client_ep = data->client_ep;
697 + pw_client_endpoint_resource_set_param(client_ep->owner_resource,
703 +static const struct pw_endpoint_proxy_methods endpoint_methods = {
704 + PW_VERSION_ENDPOINT_PROXY_METHODS,
705 + .subscribe_params = endpoint_subscribe_params,
706 + .enum_params = endpoint_enum_params,
707 + .set_param = endpoint_set_param,
711 +endpoint_unbind(void *data)
713 + struct pw_resource *resource = data;
714 + spa_list_remove(&resource->link);
717 +static const struct pw_resource_events resource_events = {
718 + PW_VERSION_RESOURCE_EVENTS,
719 + .destroy = endpoint_unbind,
723 +endpoint_bind(void *_data, struct pw_client *client, uint32_t permissions,
724 + uint32_t version, uint32_t id)
726 + struct pw_endpoint *this = _data;
727 + struct pw_global *global = this->global;
728 + struct pw_resource *resource;
729 + struct resource_data *data;
731 + resource = pw_resource_new(client, id, permissions, global->type, version, sizeof(*data));
732 + if (resource == NULL)
735 + data = pw_resource_get_user_data(resource);
736 + data->endpoint = this;
737 + data->client_ep = this->client_ep;
738 + pw_resource_add_listener(resource, &data->resource_listener, &resource_events, resource);
740 + pw_resource_set_implementation(resource, &endpoint_methods, resource);
742 + pw_log_debug("endpoint %p: bound to %d", this, resource->id);
744 + spa_list_append(&global->resource_list, &resource->link);
746 + this->info.change_mask = PW_ENDPOINT_CHANGE_MASK_PARAMS |
747 + PW_ENDPOINT_CHANGE_MASK_PROPS;
748 + pw_endpoint_resource_info(resource, &this->info);
749 + this->info.change_mask = 0;
754 + pw_log_error("can't create node resource");
759 +pw_endpoint_init(struct pw_endpoint *this,
760 + struct pw_core *core,
761 + struct pw_client *owner,
762 + struct pw_global *parent,
763 + struct pw_properties *properties)
765 + struct pw_properties *props = NULL;
767 + pw_log_debug("endpoint %p: new", this);
770 + this->parent = parent;
772 + props = properties ? properties : pw_properties_new(NULL, NULL);
776 + this->props = pw_properties_copy (props);
780 + this->global = pw_global_new (core,
781 + PW_TYPE_INTERFACE_Endpoint,
782 + PW_VERSION_ENDPOINT,
783 + props, endpoint_bind, this);
787 + this->info.id = this->global->id;
788 + this->info.props = &this->props->dict;
790 + return pw_global_register(this->global, owner, parent);
793 + pw_log_error("can't create endpoint - out of memory");
794 + if (props && !properties)
795 + pw_properties_free(props);
797 + pw_properties_free(this->props);
802 +pw_endpoint_clear(struct pw_endpoint *this)
806 + pw_log_debug("endpoint %p: destroy", this);
808 + pw_global_destroy(this->global);
810 + for (i = 0; i < this->n_params; i++)
811 + free(this->params[i]);
812 + free(this->params);
814 + free(this->info.params);
817 + pw_properties_free(this->props);
821 +endpoint_notify_subscribed(struct pw_endpoint *this,
822 + uint32_t index, uint32_t next)
824 + struct pw_global *global = this->global;
825 + struct pw_resource *resource;
826 + struct resource_data *data;
827 + struct spa_pod *param = this->params[index];
831 + if (!param || !spa_pod_is_object (param))
834 + id = SPA_POD_OBJECT_ID (param);
836 + spa_list_for_each(resource, &global->resource_list, link) {
837 + data = pw_resource_get_user_data(resource);
838 + for (i = 0; i < data->n_subscribe_ids; i++) {
839 + if (data->subscribe_ids[i] == id) {
840 + pw_endpoint_resource_param(resource, 1, id,
841 + index, next, param);
848 +client_endpoint_update(void *object,
849 + uint32_t change_mask,
851 + const struct spa_pod **params,
852 + const struct pw_endpoint_info *info)
854 + struct pw_client_endpoint *cliep = object;
855 + struct pw_endpoint *this = &cliep->endpoint;
857 + if (change_mask & PW_CLIENT_ENDPOINT_UPDATE_PARAMS) {
860 + pw_log_debug("endpoint %p: update %d params", this, n_params);
862 + for (i = 0; i < this->n_params; i++)
863 + free(this->params[i]);
864 + this->n_params = n_params;
865 + this->params = realloc(this->params, this->n_params * sizeof(struct spa_pod *));
867 + for (i = 0; i < this->n_params; i++) {
868 + this->params[i] = params[i] ? spa_pod_copy(params[i]) : NULL;
869 + endpoint_notify_subscribed(this, i, i+1);
872 + else if (change_mask & PW_CLIENT_ENDPOINT_UPDATE_PARAMS_INCREMENTAL) {
874 + const struct spa_pod_prop *pold, *pnew;
876 + pw_log_debug("endpoint %p: update %d params incremental", this, n_params);
878 + for (i = 0; i < this->n_params; i++) {
879 + /* we only support incremental updates for controls */
880 + if (!spa_pod_is_object_id (this->params[i], PW_ENDPOINT_PARAM_Control))
883 + for (j = 0; j < n_params; j++) {
884 + if (!spa_pod_is_object_id (params[j], PW_ENDPOINT_PARAM_Control)) {
885 + pw_log_warn ("endpoint %p: ignoring incremental update "
886 + "on non-control param", this);
890 + pold = spa_pod_object_find_prop (
891 + (const struct spa_pod_object *) this->params[i],
892 + NULL, PW_ENDPOINT_PARAM_CONTROL_id);
893 + pnew = spa_pod_object_find_prop (
894 + (const struct spa_pod_object *) params[j],
895 + NULL, PW_ENDPOINT_PARAM_CONTROL_id);
897 + if (pold && pnew && spa_pod_compare (&pold->value, &pnew->value) == 0) {
898 + free (this->params[i]);
899 + this->params[i] = spa_pod_copy (params[j]);
900 + endpoint_notify_subscribed(this, i, UINT32_MAX);
906 + if (change_mask & PW_CLIENT_ENDPOINT_UPDATE_INFO) {
907 + struct pw_global *global = this->global;
908 + struct pw_resource *resource;
910 + if (info->change_mask & PW_ENDPOINT_CHANGE_MASK_PARAMS) {
911 + size_t size = info->n_params * sizeof(struct spa_param_info);
912 + free(this->info.params);
913 + this->info.params = malloc(size);
914 + this->info.n_params = info->n_params;
915 + memcpy(this->info.params, info->params, size);
918 + if (info->change_mask & PW_ENDPOINT_CHANGE_MASK_PROPS) {
919 + pw_properties_update(this->props, info->props);
922 + this->info.change_mask = info->change_mask;
923 + spa_list_for_each(resource, &global->resource_list, link) {
924 + pw_endpoint_resource_info(resource, &this->info);
926 + this->info.change_mask = 0;
932 +static struct pw_client_endpoint_proxy_methods client_endpoint_methods = {
933 + PW_VERSION_CLIENT_ENDPOINT_PROXY_METHODS,
934 + .update = client_endpoint_update,
938 +client_endpoint_resource_destroy(void *data)
940 + struct pw_client_endpoint *this = data;
942 + pw_log_debug("client-endpoint %p: destroy", this);
944 + pw_endpoint_clear(&this->endpoint);
946 + this->owner_resource = NULL;
947 + spa_hook_remove(&this->owner_resource_listener);
951 +static const struct pw_resource_events owner_resource_events = {
952 + PW_VERSION_RESOURCE_EVENTS,
953 + .destroy = client_endpoint_resource_destroy,
956 +struct pw_client_endpoint *
957 +pw_client_endpoint_new(struct pw_resource *owner_resource,
958 + struct pw_global *parent,
959 + struct pw_properties *properties)
961 + struct pw_client_endpoint *this;
962 + struct pw_client *owner = pw_resource_get_client(owner_resource);
963 + struct pw_core *core = pw_client_get_core(owner);
965 + this = calloc(1, sizeof(struct pw_client_endpoint));
969 + pw_log_debug("client-endpoint %p: new", this);
971 + if (pw_endpoint_init(&this->endpoint, core, owner, parent, properties) < 0)
972 + goto error_no_endpoint;
973 + this->endpoint.client_ep = this;
975 + this->owner_resource = owner_resource;
976 + pw_resource_add_listener(this->owner_resource,
977 + &this->owner_resource_listener,
978 + &owner_resource_events,
980 + pw_resource_set_implementation(this->owner_resource,
981 + &client_endpoint_methods,
987 + pw_resource_destroy(owner_resource);
993 +pw_client_endpoint_destroy(struct pw_client_endpoint *this)
995 + pw_resource_destroy(this->owner_resource);
997 diff --git a/src/modules/module-endpoint/endpoint-impl.h b/src/modules/module-endpoint/endpoint-impl.h
999 index 00000000..059aa904
1001 +++ b/src/modules/module-endpoint/endpoint-impl.h
1005 + * Copyright © 2019 Collabora Ltd.
1006 + * @author George Kiagiadakis <george.kiagiadakis@collabora.com>
1008 + * Permission is hereby granted, free of charge, to any person obtaining a
1009 + * copy of this software and associated documentation files (the "Software"),
1010 + * to deal in the Software without restriction, including without limitation
1011 + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
1012 + * and/or sell copies of the Software, and to permit persons to whom the
1013 + * Software is furnished to do so, subject to the following conditions:
1015 + * The above copyright notice and this permission notice (including the next
1016 + * paragraph) shall be included in all copies or substantial portions of the
1019 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1020 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1021 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
1022 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1023 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
1024 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
1025 + * DEALINGS IN THE SOFTWARE.
1028 +#ifndef PIPEWIRE_ENDPOINT_IMPL_H
1029 +#define PIPEWIRE_ENDPOINT_IMPL_H
1031 +#include <pipewire/pipewire.h>
1032 +#include <extensions/endpoint.h>
1033 +#include <extensions/client-endpoint.h>
1039 +struct pw_endpoint;
1040 +struct pw_client_endpoint;
1042 +struct pw_client_endpoint *
1043 +pw_client_endpoint_new(struct pw_resource *resource,
1044 + struct pw_global *parent,
1045 + struct pw_properties *properties);
1048 +pw_client_endpoint_destroy(struct pw_client_endpoint *endpoint);
1054 +#endif /* PIPEWIRE_ENDPOINT_IMPL_H */
1055 diff --git a/src/modules/module-endpoint/protocol-native.c b/src/modules/module-endpoint/protocol-native.c
1056 new file mode 100644
1057 index 00000000..a41d3119
1059 +++ b/src/modules/module-endpoint/protocol-native.c
1063 + * Copyright © 2019 Collabora Ltd.
1064 + * @author George Kiagiadakis <george.kiagiadakis@collabora.com>
1066 + * Permission is hereby granted, free of charge, to any person obtaining a
1067 + * copy of this software and associated documentation files (the "Software"),
1068 + * to deal in the Software without restriction, including without limitation
1069 + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
1070 + * and/or sell copies of the Software, and to permit persons to whom the
1071 + * Software is furnished to do so, subject to the following conditions:
1073 + * The above copyright notice and this permission notice (including the next
1074 + * paragraph) shall be included in all copies or substantial portions of the
1077 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1078 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1079 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
1080 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1081 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
1082 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
1083 + * DEALINGS IN THE SOFTWARE.
1086 +#include <pipewire/pipewire.h>
1087 +#include <spa/pod/parser.h>
1089 +#include <extensions/client-endpoint.h>
1090 +#include <extensions/endpoint.h>
1091 +#include <extensions/protocol-native.h>
1094 +serialize_pw_endpoint_info(struct spa_pod_builder *b,
1095 + const struct pw_endpoint_info *info)
1097 + struct spa_pod_frame f;
1098 + uint32_t i, n_props;
1100 + n_props = info->props ? info->props->n_items : 0;
1102 + spa_pod_builder_push_struct(b, &f);
1103 + spa_pod_builder_add(b,
1104 + SPA_POD_Id(info->id),
1105 + SPA_POD_Int(info->change_mask),
1106 + SPA_POD_Int(info->n_params),
1107 + SPA_POD_Int(n_props),
1110 + for (i = 0; i < info->n_params; i++) {
1111 + spa_pod_builder_add(b,
1112 + SPA_POD_Id(info->params[i].id),
1113 + SPA_POD_Int(info->params[i].flags), NULL);
1116 + for (i = 0; i < n_props; i++) {
1117 + spa_pod_builder_add(b,
1118 + SPA_POD_String(info->props->items[i].key),
1119 + SPA_POD_String(info->props->items[i].value),
1123 + spa_pod_builder_pop(b, &f);
1126 +/* macro because of alloca() */
1127 +#define deserialize_pw_endpoint_info(p, f, info) \
1129 + if (spa_pod_parser_push_struct(p, f) < 0 || \
1130 + spa_pod_parser_get(p, \
1131 + SPA_POD_Id(&(info)->id), \
1132 + SPA_POD_Int(&(info)->change_mask), \
1133 + SPA_POD_Int(&(info)->n_params), \
1134 + SPA_POD_Int(&(info)->props->n_items), \
1138 + if ((info)->n_params > 0) \
1139 + (info)->params = alloca((info)->n_params * sizeof(struct spa_param_info)); \
1140 + if ((info)->props->n_items > 0) \
1141 + (info)->props->items = alloca((info)->props->n_items * sizeof(struct spa_dict_item)); \
1143 + for (i = 0; i < (info)->n_params; i++) { \
1144 + if (spa_pod_parser_get(p, \
1145 + SPA_POD_Id(&(info)->params[i].id), \
1146 + SPA_POD_Int(&(info)->params[i].flags), \
1151 + for (i = 0; i < (info)->props->n_items; i++) { \
1152 + if (spa_pod_parser_get(p, \
1153 + SPA_POD_String(&(info)->props->items[i].key), \
1154 + SPA_POD_String(&(info)->props->items[i].value), \
1159 + spa_pod_parser_pop(p, f); \
1163 +endpoint_marshal_subscribe_params(void *object, uint32_t *ids, uint32_t n_ids)
1165 + struct pw_proxy *proxy = object;
1166 + struct spa_pod_builder *b;
1168 + b = pw_protocol_native_begin_proxy(proxy,
1169 + PW_ENDPOINT_PROXY_METHOD_SUBSCRIBE_PARAMS, NULL);
1171 + spa_pod_builder_add_struct(b,
1172 + SPA_POD_Array(sizeof(uint32_t), SPA_TYPE_Id, n_ids, ids));
1174 + return pw_protocol_native_end_proxy(proxy, b);
1178 +endpoint_demarshal_subscribe_params(void *object, const struct pw_protocol_native_message *msg)
1180 + struct pw_resource *resource = object;
1181 + struct spa_pod_parser prs;
1182 + uint32_t csize, ctype, n_ids;
1185 + spa_pod_parser_init(&prs, msg->data, msg->size);
1186 + if (spa_pod_parser_get_struct(&prs,
1187 + SPA_POD_Array(&csize, &ctype, &n_ids, &ids)) < 0)
1190 + if (ctype != SPA_TYPE_Id)
1193 + return pw_resource_do(resource, struct pw_endpoint_proxy_methods,
1194 + subscribe_params, 0, ids, n_ids);
1198 +endpoint_marshal_enum_params(void *object, int seq, uint32_t id,
1199 + uint32_t index, uint32_t num, const struct spa_pod *filter)
1201 + struct pw_proxy *proxy = object;
1202 + struct spa_pod_builder *b;
1204 + b = pw_protocol_native_begin_proxy(proxy,
1205 + PW_ENDPOINT_PROXY_METHOD_ENUM_PARAMS, NULL);
1207 + spa_pod_builder_add_struct(b,
1210 + SPA_POD_Int(index),
1212 + SPA_POD_Pod(filter));
1214 + return pw_protocol_native_end_proxy(proxy, b);
1218 +endpoint_demarshal_enum_params(void *object, const struct pw_protocol_native_message *msg)
1220 + struct pw_resource *resource = object;
1221 + struct spa_pod_parser prs;
1222 + uint32_t id, index, num;
1224 + struct spa_pod *filter;
1226 + spa_pod_parser_init(&prs, msg->data, msg->size);
1227 + if (spa_pod_parser_get_struct(&prs,
1228 + SPA_POD_Int(&seq),
1230 + SPA_POD_Int(&index),
1231 + SPA_POD_Int(&num),
1232 + SPA_POD_Pod(&filter)) < 0)
1235 + return pw_resource_do(resource, struct pw_endpoint_proxy_methods,
1236 + enum_params, 0, seq, id, index, num, filter);
1240 +endpoint_marshal_set_param(void *object, uint32_t id, uint32_t flags,
1241 + const struct spa_pod *param)
1243 + struct pw_proxy *proxy = object;
1244 + struct spa_pod_builder *b;
1246 + b = pw_protocol_native_begin_proxy(proxy,
1247 + PW_ENDPOINT_PROXY_METHOD_SET_PARAM, NULL);
1249 + spa_pod_builder_add_struct(b,
1251 + SPA_POD_Int(flags),
1252 + SPA_POD_Pod(param));
1253 + return pw_protocol_native_end_proxy(proxy, b);
1257 +endpoint_demarshal_set_param(void *object, const struct pw_protocol_native_message *msg)
1259 + struct pw_resource *resource = object;
1260 + struct spa_pod_parser prs;
1261 + uint32_t id, flags;
1262 + struct spa_pod *param;
1264 + spa_pod_parser_init(&prs, msg->data, msg->size);
1265 + if (spa_pod_parser_get_struct(&prs,
1267 + SPA_POD_Int(&flags),
1268 + SPA_POD_Pod(¶m)) < 0)
1271 + return pw_resource_do(resource, struct pw_endpoint_proxy_methods,
1272 + set_param, 0, id, flags, param);
1276 +endpoint_marshal_info(void *object, const struct pw_endpoint_info *info)
1278 + struct pw_resource *resource = object;
1279 + struct spa_pod_builder *b;
1281 + b = pw_protocol_native_begin_resource(resource,
1282 + PW_ENDPOINT_PROXY_EVENT_INFO, NULL);
1283 + serialize_pw_endpoint_info (b, info);
1284 + pw_protocol_native_end_resource(resource, b);
1288 +endpoint_demarshal_info(void *object, const struct pw_protocol_native_message *msg)
1290 + struct pw_proxy *proxy = object;
1291 + struct spa_pod_parser prs;
1292 + struct spa_pod_frame f;
1293 + struct spa_dict props = SPA_DICT_INIT(NULL, 0);
1294 + struct pw_endpoint_info info = { .props = &props };
1297 + spa_pod_parser_init(&prs, msg->data, msg->size);
1299 + deserialize_pw_endpoint_info(&prs, &f, &info);
1301 + return pw_proxy_notify(proxy, struct pw_endpoint_proxy_events,
1306 +endpoint_marshal_param(void *object, int seq, uint32_t id,
1307 + uint32_t index, uint32_t next, const struct spa_pod *param)
1309 + struct pw_resource *resource = object;
1310 + struct spa_pod_builder *b;
1312 + b = pw_protocol_native_begin_resource(resource,
1313 + PW_ENDPOINT_PROXY_EVENT_PARAM, NULL);
1315 + spa_pod_builder_add_struct(b,
1318 + SPA_POD_Int(index),
1319 + SPA_POD_Int(next),
1320 + SPA_POD_Pod(param));
1322 + pw_protocol_native_end_resource(resource, b);
1326 +endpoint_demarshal_param(void *object, const struct pw_protocol_native_message *msg)
1328 + struct pw_proxy *proxy = object;
1329 + struct spa_pod_parser prs;
1330 + uint32_t id, index, next;
1332 + struct spa_pod *param;
1334 + spa_pod_parser_init(&prs, msg->data, msg->size);
1335 + if (spa_pod_parser_get_struct(&prs,
1336 + SPA_POD_Int(&seq),
1338 + SPA_POD_Int(&index),
1339 + SPA_POD_Int(&next),
1340 + SPA_POD_Pod(¶m)) < 0)
1343 + return pw_proxy_notify(proxy, struct pw_endpoint_proxy_events, param, 0,
1344 + seq, id, index, next, param);
1347 +static const struct pw_endpoint_proxy_methods pw_protocol_native_endpoint_method_marshal = {
1348 + PW_VERSION_ENDPOINT_PROXY_METHODS,
1349 + &endpoint_marshal_subscribe_params,
1350 + &endpoint_marshal_enum_params,
1351 + &endpoint_marshal_set_param,
1354 +static const struct pw_protocol_native_demarshal pw_protocol_native_endpoint_method_demarshal[] = {
1355 + { &endpoint_demarshal_subscribe_params, 0 },
1356 + { &endpoint_demarshal_enum_params, 0 },
1357 + { &endpoint_demarshal_set_param, 0 }
1360 +static const struct pw_endpoint_proxy_events pw_protocol_native_endpoint_event_marshal = {
1361 + PW_VERSION_ENDPOINT_PROXY_EVENTS,
1362 + &endpoint_marshal_info,
1363 + &endpoint_marshal_param,
1366 +static const struct pw_protocol_native_demarshal pw_protocol_native_endpoint_event_demarshal[] = {
1367 + { &endpoint_demarshal_info, 0 },
1368 + { &endpoint_demarshal_param, 0 }
1371 +static const struct pw_protocol_marshal pw_protocol_native_endpoint_marshal = {
1372 + PW_TYPE_INTERFACE_Endpoint,
1373 + PW_VERSION_ENDPOINT,
1374 + PW_ENDPOINT_PROXY_METHOD_NUM,
1375 + PW_ENDPOINT_PROXY_EVENT_NUM,
1376 + &pw_protocol_native_endpoint_method_marshal,
1377 + &pw_protocol_native_endpoint_method_demarshal,
1378 + &pw_protocol_native_endpoint_event_marshal,
1379 + &pw_protocol_native_endpoint_event_demarshal,
1384 +client_endpoint_marshal_update(
1386 + uint32_t change_mask,
1387 + uint32_t n_params,
1388 + const struct spa_pod **params,
1389 + const struct pw_endpoint_info *info)
1391 + struct pw_proxy *proxy = object;
1392 + struct spa_pod_builder *b;
1393 + struct spa_pod_frame f;
1396 + b = pw_protocol_native_begin_proxy(proxy,
1397 + PW_CLIENT_ENDPOINT_PROXY_METHOD_UPDATE, NULL);
1399 + spa_pod_builder_push_struct(b, &f);
1400 + spa_pod_builder_add(b,
1401 + SPA_POD_Int(change_mask),
1402 + SPA_POD_Int(n_params), NULL);
1404 + for (i = 0; i < n_params; i++)
1405 + spa_pod_builder_add(b, SPA_POD_Pod(params[i]), NULL);
1407 + if (change_mask & PW_CLIENT_ENDPOINT_UPDATE_INFO)
1408 + serialize_pw_endpoint_info(b, info);
1410 + spa_pod_builder_pop(b, &f);
1412 + return pw_protocol_native_end_proxy(proxy, b);
1416 +client_endpoint_demarshal_update(void *object,
1417 + const struct pw_protocol_native_message *msg)
1419 + struct pw_resource *resource = object;
1420 + struct spa_pod_parser prs;
1421 + struct spa_pod_frame f[2];
1422 + uint32_t change_mask, n_params;
1423 + const struct spa_pod **params = NULL;
1424 + struct spa_dict props = SPA_DICT_INIT(NULL, 0);
1425 + struct pw_endpoint_info info = { .props = &props };
1428 + spa_pod_parser_init(&prs, msg->data, msg->size);
1429 + if (spa_pod_parser_push_struct(&prs, &f[0]) < 0 ||
1430 + spa_pod_parser_get(&prs,
1431 + SPA_POD_Int(&change_mask),
1432 + SPA_POD_Int(&n_params), NULL) < 0)
1436 + params = alloca(n_params * sizeof(struct spa_pod *));
1437 + for (i = 0; i < n_params; i++)
1438 + if (spa_pod_parser_get(&prs,
1439 + SPA_POD_PodObject(¶ms[i]), NULL) < 0)
1442 + if (change_mask & PW_CLIENT_ENDPOINT_UPDATE_INFO)
1443 + deserialize_pw_endpoint_info(&prs, &f[1], &info);
1445 + pw_resource_do(resource, struct pw_client_endpoint_proxy_methods,
1446 + update, 0, change_mask, n_params, params, &info);
1451 +client_endpoint_marshal_set_param (void *object,
1452 + uint32_t id, uint32_t flags,
1453 + const struct spa_pod *param)
1455 + struct pw_resource *resource = object;
1456 + struct spa_pod_builder *b;
1458 + b = pw_protocol_native_begin_resource(resource,
1459 + PW_CLIENT_ENDPOINT_PROXY_EVENT_SET_PARAM, NULL);
1461 + spa_pod_builder_add_struct(b,
1463 + SPA_POD_Int(flags),
1464 + SPA_POD_Pod(param));
1466 + pw_protocol_native_end_resource(resource, b);
1470 +client_endpoint_demarshal_set_param(void *object,
1471 + const struct pw_protocol_native_message *msg)
1473 + struct pw_proxy *proxy = object;
1474 + struct spa_pod_parser prs;
1475 + uint32_t id, flags;
1476 + const struct spa_pod *param = NULL;
1478 + spa_pod_parser_init(&prs, msg->data, msg->size);
1479 + if (spa_pod_parser_get_struct(&prs,
1481 + SPA_POD_Int(&flags),
1482 + SPA_POD_PodObject(¶m)) < 0)
1485 + pw_proxy_notify(proxy, struct pw_client_endpoint_proxy_events,
1486 + set_param, 0, id, flags, param);
1490 +static const struct pw_client_endpoint_proxy_methods pw_protocol_native_client_endpoint_method_marshal = {
1491 + PW_VERSION_CLIENT_ENDPOINT_PROXY_METHODS,
1492 + &client_endpoint_marshal_update,
1495 +static const struct pw_protocol_native_demarshal pw_protocol_native_client_endpoint_method_demarshal[] = {
1496 + { &client_endpoint_demarshal_update, 0 }
1499 +static const struct pw_client_endpoint_proxy_events pw_protocol_native_client_endpoint_event_marshal = {
1500 + PW_VERSION_CLIENT_ENDPOINT_PROXY_EVENTS,
1501 + &client_endpoint_marshal_set_param,
1504 +static const struct pw_protocol_native_demarshal pw_protocol_native_client_endpoint_event_demarshal[] = {
1505 + { &client_endpoint_demarshal_set_param, 0 }
1508 +static const struct pw_protocol_marshal pw_protocol_native_client_endpoint_marshal = {
1509 + PW_TYPE_INTERFACE_ClientEndpoint,
1510 + PW_VERSION_CLIENT_ENDPOINT,
1511 + PW_CLIENT_ENDPOINT_PROXY_METHOD_NUM,
1512 + PW_CLIENT_ENDPOINT_PROXY_EVENT_NUM,
1513 + &pw_protocol_native_client_endpoint_method_marshal,
1514 + &pw_protocol_native_client_endpoint_method_demarshal,
1515 + &pw_protocol_native_client_endpoint_event_marshal,
1516 + &pw_protocol_native_client_endpoint_event_demarshal,
1519 +struct pw_protocol *pw_protocol_native_ext_endpoint_init(struct pw_core *core)
1521 + struct pw_protocol *protocol;
1523 + protocol = pw_core_find_protocol(core, PW_TYPE_INFO_PROTOCOL_Native);
1525 + if (protocol == NULL)
1528 + pw_protocol_add_marshal(protocol, &pw_protocol_native_client_endpoint_marshal);
1529 + pw_protocol_add_marshal(protocol, &pw_protocol_native_endpoint_marshal);
1533 diff --git a/src/pipewire/pipewire.c b/src/pipewire/pipewire.c
1534 index a8752438..bbbf9420 100644
1535 --- a/src/pipewire/pipewire.c
1536 +++ b/src/pipewire/pipewire.c
1537 @@ -647,6 +647,8 @@ static const struct spa_type_info type_info[] = {
1538 { PW_TYPE_INTERFACE_Module, SPA_TYPE_Pointer, PW_TYPE_INFO_INTERFACE_BASE "Module", NULL },
1539 { PW_TYPE_INTERFACE_ClientNode, SPA_TYPE_Pointer, PW_TYPE_INFO_INTERFACE_BASE "ClientNode", NULL },
1540 { PW_TYPE_INTERFACE_Device, SPA_TYPE_Pointer, PW_TYPE_INFO_INTERFACE_BASE "Device", NULL },
1541 + { PW_TYPE_INTERFACE_Endpoint, SPA_TYPE_Pointer, PW_TYPE_INFO_INTERFACE_BASE "Endpoint", NULL},
1542 + { PW_TYPE_INTERFACE_ClientEndpoint, SPA_TYPE_Pointer, PW_TYPE_INFO_INTERFACE_BASE "ClientEndpoint", NULL},
1543 { SPA_ID_INVALID, SPA_ID_INVALID, "spa_types", spa_types },
1544 { 0, 0, NULL, NULL },
1546 diff --git a/src/pipewire/type.h b/src/pipewire/type.h
1547 index a1b205f7..39544913 100644
1548 --- a/src/pipewire/type.h
1549 +++ b/src/pipewire/type.h
1550 @@ -48,7 +48,8 @@ enum {
1552 PW_TYPE_INTERFACE_EXTENSIONS = PW_TYPE_INTERFACE_START + 0x1000,
1553 PW_TYPE_INTERFACE_ClientNode,
1555 + PW_TYPE_INTERFACE_Endpoint,
1556 + PW_TYPE_INTERFACE_ClientEndpoint,
1559 #define PW_TYPE_INFO_BASE "PipeWire:"