1 From 5afe82a430642c2f7e116941709a624b8fd73011 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] extensions: implement Endpoint & ClientEndpoint interfaces
6 The ClientEndpoint interface allows session managers to register
7 endpoint objects on pipewire.
8 The Endpoint interface allows other clients to interact with
9 endpoints provided by the session manager.
11 Upstream-Status: Pending
13 src/extensions/client-endpoint.h | 106 ++++
14 src/extensions/endpoint.h | 237 +++++++++
15 src/extensions/meson.build | 2 +
16 src/modules/meson.build | 12 +
17 src/modules/module-endpoint.c | 137 +++++
18 src/modules/module-endpoint/endpoint-impl.c | 428 ++++++++++++++++
19 src/modules/module-endpoint/endpoint-impl.h | 52 ++
20 src/modules/module-endpoint/protocol-native.c | 472 ++++++++++++++++++
21 src/pipewire/pipewire.c | 2 +
22 src/pipewire/type.h | 3 +-
23 10 files changed, 1450 insertions(+), 1 deletion(-)
24 create mode 100644 src/extensions/client-endpoint.h
25 create mode 100644 src/extensions/endpoint.h
26 create mode 100644 src/modules/module-endpoint.c
27 create mode 100644 src/modules/module-endpoint/endpoint-impl.c
28 create mode 100644 src/modules/module-endpoint/endpoint-impl.h
29 create mode 100644 src/modules/module-endpoint/protocol-native.c
31 diff --git a/src/extensions/client-endpoint.h b/src/extensions/client-endpoint.h
33 index 00000000..0389893c
35 +++ b/src/extensions/client-endpoint.h
39 + * Copyright © 2019 Collabora Ltd.
40 + * @author George Kiagiadakis <george.kiagiadakis@collabora.com>
42 + * Permission is hereby granted, free of charge, to any person obtaining a
43 + * copy of this software and associated documentation files (the "Software"),
44 + * to deal in the Software without restriction, including without limitation
45 + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
46 + * and/or sell copies of the Software, and to permit persons to whom the
47 + * Software is furnished to do so, subject to the following conditions:
49 + * The above copyright notice and this permission notice (including the next
50 + * paragraph) shall be included in all copies or substantial portions of the
53 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
54 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
55 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
56 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
57 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
58 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
59 + * DEALINGS IN THE SOFTWARE.
62 +#ifndef PIPEWIRE_EXT_CLIENT_ENDPOINT_H
63 +#define PIPEWIRE_EXT_CLIENT_ENDPOINT_H
65 +#include "endpoint.h"
71 +struct pw_client_endpoint_proxy;
73 +#define PW_VERSION_CLIENT_ENDPOINT 0
74 +#define PW_EXTENSION_MODULE_CLIENT_ENDPOINT PIPEWIRE_MODULE_PREFIX "module-endpoint"
76 +#define PW_CLIENT_ENDPOINT_PROXY_METHOD_UPDATE 0
77 +#define PW_CLIENT_ENDPOINT_PROXY_METHOD_NUM 1
79 +struct pw_client_endpoint_proxy_methods {
80 +#define PW_VERSION_CLIENT_ENDPOINT_PROXY_METHODS 0
84 + * Update endpoint info
86 + int (*update) (void *object,
87 +#define PW_CLIENT_ENDPOINT_UPDATE_PARAMS (1 << 0)
88 +#define PW_CLIENT_ENDPOINT_UPDATE_PARAMS_INCREMENTAL (1 << 1)
89 +#define PW_CLIENT_ENDPOINT_UPDATE_INFO (1 << 2)
90 + uint32_t change_mask,
92 + const struct spa_pod **params,
93 + const struct pw_endpoint_info *info);
97 +pw_client_endpoint_proxy_update(struct pw_client_endpoint_proxy *p,
98 + uint32_t change_mask,
100 + const struct spa_pod **params,
101 + struct pw_endpoint_info *info)
103 + return pw_proxy_do((struct pw_proxy*)p,
104 + struct pw_client_endpoint_proxy_methods, update,
105 + change_mask, n_params, params, info);
108 +#define PW_CLIENT_ENDPOINT_PROXY_EVENT_SET_PARAM 0
109 +#define PW_CLIENT_ENDPOINT_PROXY_EVENT_NUM 1
111 +struct pw_client_endpoint_proxy_events {
112 +#define PW_VERSION_CLIENT_ENDPOINT_PROXY_EVENTS 0
116 + * Set a parameter on the endpoint
118 + * \param id the parameter id to set
119 + * \param flags extra parameter flags
120 + * \param param the parameter to set
122 + void (*set_param) (void *object, uint32_t id, uint32_t flags,
123 + const struct spa_pod *param);
127 +pw_client_endpoint_proxy_add_listener(struct pw_client_endpoint_proxy *p,
128 + struct spa_hook *listener,
129 + const struct pw_client_endpoint_proxy_events *events,
132 + pw_proxy_add_proxy_listener((struct pw_proxy*)p, listener, events, data);
135 +#define pw_client_endpoint_resource_set_param(r,...) \
136 + pw_resource_notify(r,struct pw_client_endpoint_proxy_events,set_param,__VA_ARGS__)
142 +#endif /* PIPEWIRE_EXT_CLIENT_ENDPOINT_H */
143 diff --git a/src/extensions/endpoint.h b/src/extensions/endpoint.h
145 index 00000000..211c0895
147 +++ b/src/extensions/endpoint.h
151 + * Copyright © 2019 Collabora Ltd.
152 + * @author George Kiagiadakis <george.kiagiadakis@collabora.com>
154 + * Permission is hereby granted, free of charge, to any person obtaining a
155 + * copy of this software and associated documentation files (the "Software"),
156 + * to deal in the Software without restriction, including without limitation
157 + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
158 + * and/or sell copies of the Software, and to permit persons to whom the
159 + * Software is furnished to do so, subject to the following conditions:
161 + * The above copyright notice and this permission notice (including the next
162 + * paragraph) shall be included in all copies or substantial portions of the
165 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
166 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
167 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
168 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
169 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
170 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
171 + * DEALINGS IN THE SOFTWARE.
174 +#ifndef PIPEWIRE_EXT_ENDPOINT_H
175 +#define PIPEWIRE_EXT_ENDPOINT_H
177 +#include <spa/utils/defs.h>
178 +#include <spa/utils/type-info.h>
179 +#include <pipewire/proxy.h>
185 +struct pw_endpoint_proxy;
187 +#define PW_VERSION_ENDPOINT 0
188 +#define PW_EXTENSION_MODULE_ENDPOINT PIPEWIRE_MODULE_PREFIX "module-endpoint"
190 +/* extending enum spa_param_type */
191 +enum endpoint_param_type {
192 + PW_ENDPOINT_PARAM_EnumControl = 0x1000,
193 + PW_ENDPOINT_PARAM_Control,
194 + PW_ENDPOINT_PARAM_EnumStream,
197 +enum endpoint_param_object_type {
198 + PW_ENDPOINT_OBJECT_ParamControl = PW_TYPE_FIRST + SPA_TYPE_OBJECT_START + 0x1001,
199 + PW_ENDPOINT_OBJECT_ParamStream,
202 +/** properties for PW_ENDPOINT_OBJECT_ParamControl */
203 +enum endpoint_param_control {
204 + PW_ENDPOINT_PARAM_CONTROL_START, /**< object id, one of enum endpoint_param_type */
205 + PW_ENDPOINT_PARAM_CONTROL_id, /**< control id (Int) */
206 + PW_ENDPOINT_PARAM_CONTROL_stream_id, /**< stream id (Int) */
207 + PW_ENDPOINT_PARAM_CONTROL_name, /**< control name (String) */
208 + PW_ENDPOINT_PARAM_CONTROL_type, /**< control type (Range) */
209 + PW_ENDPOINT_PARAM_CONTROL_value, /**< control value */
212 +/** properties for PW_ENDPOINT_OBJECT_ParamStream */
213 +enum endpoint_param_stream {
214 + PW_ENDPOINT_PARAM_STREAM_START, /**< object id, one of enum endpoint_param_type */
215 + PW_ENDPOINT_PARAM_STREAM_id, /**< stream id (Int) */
216 + PW_ENDPOINT_PARAM_STREAM_name, /**< stream name (String) */
219 +static const struct spa_type_info endpoint_param_type_info[] = {
220 + { PW_ENDPOINT_PARAM_EnumControl, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_ID_BASE "EnumControl", NULL },
221 + { PW_ENDPOINT_PARAM_Control, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_ID_BASE "Control", NULL },
222 + { PW_ENDPOINT_PARAM_EnumStream, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_ID_BASE "EnumStream", NULL },
223 + { 0, 0, NULL, NULL },
226 +#define PW_ENDPOINT_TYPE_INFO_ParamControl SPA_TYPE_INFO_PARAM_BASE "ParamControl"
227 +#define PW_ENDPOINT_TYPE_INFO_PARAM_CONTROL_BASE PW_ENDPOINT_TYPE_INFO_ParamControl ":"
229 +static const struct spa_type_info endpoint_param_control_info[] = {
230 + { PW_ENDPOINT_PARAM_CONTROL_START, SPA_TYPE_Id, PW_ENDPOINT_TYPE_INFO_PARAM_CONTROL_BASE, spa_type_param, },
231 + { PW_ENDPOINT_PARAM_CONTROL_id, SPA_TYPE_Int, PW_ENDPOINT_TYPE_INFO_PARAM_CONTROL_BASE "id", NULL },
232 + { PW_ENDPOINT_PARAM_CONTROL_stream_id, SPA_TYPE_Int, PW_ENDPOINT_TYPE_INFO_PARAM_CONTROL_BASE "streamId", NULL },
233 + { PW_ENDPOINT_PARAM_CONTROL_name, SPA_TYPE_String, PW_ENDPOINT_TYPE_INFO_PARAM_CONTROL_BASE "name", NULL },
234 + { PW_ENDPOINT_PARAM_CONTROL_type, SPA_TYPE_Pod, PW_ENDPOINT_TYPE_INFO_PARAM_CONTROL_BASE "type", NULL },
235 + { PW_ENDPOINT_PARAM_CONTROL_value, SPA_TYPE_Struct, PW_ENDPOINT_TYPE_INFO_PARAM_CONTROL_BASE "value", NULL },
236 + { 0, 0, NULL, NULL },
239 +#define PW_ENDPOINT_TYPE_INFO_ParamStream SPA_TYPE_INFO_PARAM_BASE "ParamStream"
240 +#define PW_ENDPOINT_TYPE_INFO_PARAM_STREAM_BASE PW_ENDPOINT_TYPE_INFO_ParamStream ":"
242 +static const struct spa_type_info endpoint_param_stream_info[] = {
243 + { PW_ENDPOINT_PARAM_STREAM_START, SPA_TYPE_Id, PW_ENDPOINT_TYPE_INFO_PARAM_STREAM_BASE, spa_type_param, },
244 + { PW_ENDPOINT_PARAM_STREAM_id, SPA_TYPE_Int, PW_ENDPOINT_TYPE_INFO_PARAM_STREAM_BASE "id", NULL },
245 + { PW_ENDPOINT_PARAM_STREAM_name, SPA_TYPE_String, PW_ENDPOINT_TYPE_INFO_PARAM_STREAM_BASE "name", NULL },
246 + { 0, 0, NULL, NULL },
249 +static const struct spa_type_info endpoint_param_object_type_info[] = {
250 + { PW_ENDPOINT_OBJECT_ParamControl, SPA_TYPE_Object, SPA_TYPE_INFO_OBJECT_BASE "ParamControl", endpoint_param_control_info, },
251 + { PW_ENDPOINT_OBJECT_ParamStream, SPA_TYPE_Object, SPA_TYPE_INFO_OBJECT_BASE "ParamStream", endpoint_param_stream_info },
252 + { 0, 0, NULL, NULL },
255 +struct pw_endpoint_info {
256 + uint32_t id; /**< id of the global */
257 +#define PW_ENDPOINT_CHANGE_MASK_PARAMS (1 << 0)
258 +#define PW_ENDPOINT_CHANGE_MASK_PROPS (1 << 1)
259 + uint32_t change_mask; /**< bitfield of changed fields since last call */
260 + uint32_t n_params; /**< number of items in \a params */
261 + struct spa_param_info *params; /**< parameters */
262 + struct spa_dict *props; /**< extra properties */
265 +#define PW_ENDPOINT_PROXY_METHOD_SUBSCRIBE_PARAMS 0
266 +#define PW_ENDPOINT_PROXY_METHOD_ENUM_PARAMS 1
267 +#define PW_ENDPOINT_PROXY_METHOD_SET_PARAM 2
268 +#define PW_ENDPOINT_PROXY_METHOD_NUM 3
270 +struct pw_endpoint_proxy_methods {
271 +#define PW_VERSION_ENDPOINT_PROXY_METHODS 0
275 + * Subscribe to parameter changes
277 + * Automatically emit param events for the given ids when
278 + * they are changed.
280 + * \param ids an array of param ids
281 + * \param n_ids the number of ids in \a ids
283 + int (*subscribe_params) (void *object, uint32_t *ids, uint32_t n_ids);
286 + * Enumerate endpoint parameters
288 + * Start enumeration of endpoint parameters. For each param, a
289 + * param event will be emited.
291 + * \param seq a sequence number to place in the reply
292 + * \param id the parameter id to enum or SPA_ID_INVALID for all
293 + * \param start the start index or 0 for the first param
294 + * \param num the maximum number of params to retrieve
295 + * \param filter a param filter or NULL
297 + int (*enum_params) (void *object, int seq,
298 + uint32_t id, uint32_t start, uint32_t num,
299 + const struct spa_pod *filter);
302 + * Set a parameter on the endpoint
304 + * \param id the parameter id to set
305 + * \param flags extra parameter flags
306 + * \param param the parameter to set
308 + int (*set_param) (void *object, uint32_t id, uint32_t flags,
309 + const struct spa_pod *param);
313 +pw_endpoint_proxy_subscribe_params(struct pw_endpoint_proxy *p, uint32_t *ids, uint32_t n_ids)
315 + return pw_proxy_do((struct pw_proxy*)p, struct pw_endpoint_proxy_methods,
316 + subscribe_params, ids, n_ids);
320 +pw_endpoint_proxy_enum_params(struct pw_endpoint_proxy *p, int seq,
321 + uint32_t id, uint32_t start, uint32_t num,
322 + const struct spa_pod *filter)
324 + return pw_proxy_do((struct pw_proxy*)p, struct pw_endpoint_proxy_methods,
325 + enum_params, seq, id, start, num, filter);
329 +pw_endpoint_proxy_set_param(struct pw_endpoint_proxy *p, uint32_t id,
330 + uint32_t flags, const struct spa_pod *param)
332 + return pw_proxy_do((struct pw_proxy*)p, struct pw_endpoint_proxy_methods,
333 + set_param, id, flags, param);
336 +#define PW_ENDPOINT_PROXY_EVENT_INFO 0
337 +#define PW_ENDPOINT_PROXY_EVENT_PARAM 1
338 +#define PW_ENDPOINT_PROXY_EVENT_NUM 2
340 +struct pw_endpoint_proxy_events {
341 +#define PW_VERSION_ENDPOINT_PROXY_EVENTS 0
345 + * Notify endpoint info
347 + * \param info info about the endpoint
349 + void (*info) (void *object, const struct pw_endpoint_info * info);
352 + * Notify an endpoint param
354 + * Event emited as a result of the enum_params method.
356 + * \param seq the sequence number of the request
357 + * \param id the param id
358 + * \param index the param index
359 + * \param next the param index of the next param
360 + * \param param the parameter
362 + void (*param) (void *object, int seq, uint32_t id,
363 + uint32_t index, uint32_t next,
364 + const struct spa_pod *param);
368 +pw_endpoint_proxy_add_listener(struct pw_endpoint_proxy *p,
369 + struct spa_hook *listener,
370 + const struct pw_endpoint_proxy_events *events,
373 + pw_proxy_add_proxy_listener((struct pw_proxy*)p, listener, events, data);
376 +#define pw_endpoint_resource_info(r,...) \
377 + pw_resource_notify(r,struct pw_endpoint_proxy_events,info,__VA_ARGS__)
378 +#define pw_endpoint_resource_param(r,...) \
379 + pw_resource_notify(r,struct pw_endpoint_proxy_events,param,__VA_ARGS__)
385 +#endif /* PIPEWIRE_EXT_ENDPOINT_H */
386 diff --git a/src/extensions/meson.build b/src/extensions/meson.build
387 index a7f5d3cb..9f690caf 100644
388 --- a/src/extensions/meson.build
389 +++ b/src/extensions/meson.build
391 pipewire_ext_headers = [
392 + 'client-endpoint.h',
398 diff --git a/src/modules/meson.build b/src/modules/meson.build
399 index 98bc3864..572f1b6b 100644
400 --- a/src/modules/meson.build
401 +++ b/src/modules/meson.build
402 @@ -37,6 +37,18 @@ pipewire_module_client_node = shared_library('pipewire-module-client-node',
403 dependencies : [mathlib, dl_lib, pipewire_dep],
406 +pipewire_module_endpoint = shared_library('pipewire-module-endpoint',
407 + [ 'module-endpoint.c',
408 + 'module-endpoint/endpoint-impl.c',
409 + 'module-endpoint/protocol-native.c',
411 + c_args : pipewire_module_c_args,
412 + include_directories : [configinc, spa_inc],
414 + install_dir : modules_install_dir,
415 + dependencies : [mathlib, dl_lib, pipewire_dep],
418 pipewire_module_link_factory = shared_library('pipewire-module-link-factory',
419 [ 'module-link-factory.c' ],
420 c_args : pipewire_module_c_args,
421 diff --git a/src/modules/module-endpoint.c b/src/modules/module-endpoint.c
423 index 00000000..d830de1b
425 +++ b/src/modules/module-endpoint.c
429 + * Copyright © 2019 Collabora Ltd.
430 + * @author George Kiagiadakis <george.kiagiadakis@collabora.com>
432 + * Permission is hereby granted, free of charge, to any person obtaining a
433 + * copy of this software and associated documentation files (the "Software"),
434 + * to deal in the Software without restriction, including without limitation
435 + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
436 + * and/or sell copies of the Software, and to permit persons to whom the
437 + * Software is furnished to do so, subject to the following conditions:
439 + * The above copyright notice and this permission notice (including the next
440 + * paragraph) shall be included in all copies or substantial portions of the
443 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
444 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
445 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
446 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
447 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
448 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
449 + * DEALINGS IN THE SOFTWARE.
454 +#include "module-endpoint/endpoint-impl.h"
456 +struct pw_protocol *pw_protocol_native_ext_endpoint_init(struct pw_core *core);
458 +static const struct spa_dict_item module_props[] = {
459 + { PW_MODULE_PROP_AUTHOR, "George Kiagiadakis <george.kiagiadakis@collabora.com>" },
460 + { PW_MODULE_PROP_DESCRIPTION, "Allows clients to interract with session manager endpoints" },
461 + { PW_MODULE_PROP_VERSION, PACKAGE_VERSION },
464 +struct factory_data {
465 + struct pw_factory *this;
466 + struct pw_properties *properties;
468 + struct pw_module *module;
469 + struct spa_hook module_listener;
472 +static void *create_object(void *_data,
473 + struct pw_resource *resource,
476 + struct pw_properties *properties,
480 + struct pw_resource *endpoint_resource;
481 + struct pw_global *parent;
482 + struct pw_client *client = pw_resource_get_client(resource);
484 + endpoint_resource = pw_resource_new(client, new_id, PW_PERM_RWX, type, version, 0);
485 + if (endpoint_resource == NULL)
488 + parent = pw_client_get_global(client);
490 + result = pw_client_endpoint_new(endpoint_resource, parent, properties);
491 + if (result == NULL)
497 + pw_log_error("can't create endpoint");
498 + pw_resource_error(resource, -ENOMEM, "can't create endpoint: no memory");
500 + pw_properties_free(properties);
504 +static const struct pw_factory_implementation impl_factory = {
505 + PW_VERSION_FACTORY_IMPLEMENTATION,
506 + .create_object = create_object,
509 +static void module_destroy(void *data)
511 + struct factory_data *d = data;
513 + spa_hook_remove(&d->module_listener);
516 + pw_properties_free(d->properties);
518 + pw_factory_destroy(d->this);
521 +static const struct pw_module_events module_events = {
522 + PW_VERSION_MODULE_EVENTS,
523 + .destroy = module_destroy,
526 +static int module_init(struct pw_module *module, struct pw_properties *properties)
528 + struct pw_core *core = pw_module_get_core(module);
529 + struct pw_factory *factory;
530 + struct factory_data *data;
532 + factory = pw_factory_new(core,
534 + PW_TYPE_INTERFACE_ClientEndpoint,
535 + PW_VERSION_CLIENT_ENDPOINT,
538 + if (factory == NULL)
541 + data = pw_factory_get_user_data(factory);
542 + data->this = factory;
543 + data->module = module;
544 + data->properties = properties;
546 + pw_log_debug("module-endpoint %p: new", module);
548 + pw_factory_set_implementation(factory, &impl_factory, data);
549 + pw_factory_register(factory, NULL, pw_module_get_global(module), NULL);
551 + pw_protocol_native_ext_endpoint_init(core);
553 + pw_module_add_listener(module, &data->module_listener, &module_events, data);
554 + pw_module_update_properties(module, &SPA_DICT_INIT_ARRAY(module_props));
560 +int pipewire__module_init(struct pw_module *module, const char *args)
562 + return module_init(module, NULL);
564 diff --git a/src/modules/module-endpoint/endpoint-impl.c b/src/modules/module-endpoint/endpoint-impl.c
566 index 00000000..252eeca1
568 +++ b/src/modules/module-endpoint/endpoint-impl.c
572 + * Copyright © 2019 Collabora Ltd.
573 + * @author George Kiagiadakis <george.kiagiadakis@collabora.com>
575 + * Permission is hereby granted, free of charge, to any person obtaining a
576 + * copy of this software and associated documentation files (the "Software"),
577 + * to deal in the Software without restriction, including without limitation
578 + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
579 + * and/or sell copies of the Software, and to permit persons to whom the
580 + * Software is furnished to do so, subject to the following conditions:
582 + * The above copyright notice and this permission notice (including the next
583 + * paragraph) shall be included in all copies or substantial portions of the
586 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
587 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
588 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
589 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
590 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
591 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
592 + * DEALINGS IN THE SOFTWARE.
595 +#include "endpoint-impl.h"
596 +#include <pipewire/private.h>
597 +#include <spa/pod/filter.h>
598 +#include <spa/pod/compare.h>
600 +struct pw_endpoint {
601 + struct pw_core *core;
602 + struct pw_global *global;
603 + struct pw_global *parent;
605 + struct pw_client_endpoint *client_ep;
608 + struct spa_pod **params;
610 + struct pw_endpoint_info info;
611 + struct pw_properties *props;
614 +struct pw_client_endpoint {
615 + struct pw_resource *owner_resource;
616 + struct spa_hook owner_resource_listener;
618 + struct pw_endpoint endpoint;
621 +struct resource_data {
622 + struct pw_endpoint *endpoint;
623 + struct pw_client_endpoint *client_ep;
625 + struct spa_hook resource_listener;
627 + uint32_t n_subscribe_ids;
628 + uint32_t subscribe_ids[32];
632 +endpoint_enum_params (void *object, int seq,
633 + uint32_t id, uint32_t start, uint32_t num,
634 + const struct spa_pod *filter)
636 + struct pw_resource *resource = object;
637 + struct resource_data *data = pw_resource_get_user_data(resource);
638 + struct pw_endpoint *this = data->endpoint;
639 + struct spa_pod *result;
640 + struct spa_pod *param;
641 + uint8_t buffer[1024];
642 + struct spa_pod_builder b = { 0 };
644 + uint32_t next = start;
645 + uint32_t count = 0;
649 + if (index >= this->n_params)
652 + param = this->params[index];
654 + if (param == NULL || !spa_pod_is_object_id(param, id))
657 + spa_pod_builder_init(&b, buffer, sizeof(buffer));
658 + if (spa_pod_filter(&b, &result, param, filter) != 0)
661 + pw_log_debug("endpoint %p: %d param %u", this, seq, index);
663 + pw_endpoint_resource_param(resource, seq, id, index, next, result);
665 + if (++count == num)
672 +endpoint_subscribe_params (void *object, uint32_t *ids, uint32_t n_ids)
674 + struct pw_resource *resource = object;
675 + struct resource_data *data = pw_resource_get_user_data(resource);
678 + n_ids = SPA_MIN(n_ids, SPA_N_ELEMENTS(data->subscribe_ids));
679 + data->n_subscribe_ids = n_ids;
681 + for (i = 0; i < n_ids; i++) {
682 + data->subscribe_ids[i] = ids[i];
683 + pw_log_debug("endpoint %p: resource %d subscribe param %u",
684 + data->endpoint, resource->id, ids[i]);
685 + endpoint_enum_params(resource, 1, ids[i], 0, UINT32_MAX, NULL);
691 +endpoint_set_param (void *object, uint32_t id, uint32_t flags,
692 + const struct spa_pod *param)
694 + struct pw_resource *resource = object;
695 + struct resource_data *data = pw_resource_get_user_data(resource);
696 + struct pw_client_endpoint *client_ep = data->client_ep;
698 + pw_client_endpoint_resource_set_param(client_ep->owner_resource,
704 +static const struct pw_endpoint_proxy_methods endpoint_methods = {
705 + PW_VERSION_ENDPOINT_PROXY_METHODS,
706 + .subscribe_params = endpoint_subscribe_params,
707 + .enum_params = endpoint_enum_params,
708 + .set_param = endpoint_set_param,
712 +endpoint_unbind(void *data)
714 + struct pw_resource *resource = data;
715 + spa_list_remove(&resource->link);
718 +static const struct pw_resource_events resource_events = {
719 + PW_VERSION_RESOURCE_EVENTS,
720 + .destroy = endpoint_unbind,
724 +endpoint_bind(void *_data, struct pw_client *client, uint32_t permissions,
725 + uint32_t version, uint32_t id)
727 + struct pw_endpoint *this = _data;
728 + struct pw_global *global = this->global;
729 + struct pw_resource *resource;
730 + struct resource_data *data;
732 + resource = pw_resource_new(client, id, permissions, global->type, version, sizeof(*data));
733 + if (resource == NULL)
736 + data = pw_resource_get_user_data(resource);
737 + data->endpoint = this;
738 + data->client_ep = this->client_ep;
739 + pw_resource_add_listener(resource, &data->resource_listener, &resource_events, resource);
741 + pw_resource_set_implementation(resource, &endpoint_methods, resource);
743 + pw_log_debug("endpoint %p: bound to %d", this, resource->id);
745 + spa_list_append(&global->resource_list, &resource->link);
747 + this->info.change_mask = PW_ENDPOINT_CHANGE_MASK_PARAMS |
748 + PW_ENDPOINT_CHANGE_MASK_PROPS;
749 + pw_endpoint_resource_info(resource, &this->info);
750 + this->info.change_mask = 0;
755 + pw_log_error("can't create node resource");
760 +pw_endpoint_init(struct pw_endpoint *this,
761 + struct pw_core *core,
762 + struct pw_client *owner,
763 + struct pw_global *parent,
764 + struct pw_properties *properties)
766 + struct pw_properties *props = NULL;
768 + pw_log_debug("endpoint %p: new", this);
771 + this->parent = parent;
773 + props = properties ? properties : pw_properties_new(NULL, NULL);
777 + this->props = pw_properties_copy (props);
781 + this->global = pw_global_new (core,
782 + PW_TYPE_INTERFACE_Endpoint,
783 + PW_VERSION_ENDPOINT,
784 + props, endpoint_bind, this);
788 + this->info.id = this->global->id;
789 + this->info.props = &this->props->dict;
791 + return pw_global_register(this->global, owner, parent);
794 + pw_log_error("can't create endpoint - out of memory");
795 + if (props && !properties)
796 + pw_properties_free(props);
798 + pw_properties_free(this->props);
803 +pw_endpoint_clear(struct pw_endpoint *this)
807 + pw_log_debug("endpoint %p: destroy", this);
809 + pw_global_destroy(this->global);
811 + for (i = 0; i < this->n_params; i++)
812 + free(this->params[i]);
813 + free(this->params);
815 + free(this->info.params);
818 + pw_properties_free(this->props);
822 +endpoint_notify_subscribed(struct pw_endpoint *this,
823 + uint32_t index, uint32_t next)
825 + struct pw_global *global = this->global;
826 + struct pw_resource *resource;
827 + struct resource_data *data;
828 + struct spa_pod *param = this->params[index];
832 + if (!param || !spa_pod_is_object (param))
835 + id = SPA_POD_OBJECT_ID (param);
837 + spa_list_for_each(resource, &global->resource_list, link) {
838 + data = pw_resource_get_user_data(resource);
839 + for (i = 0; i < data->n_subscribe_ids; i++) {
840 + if (data->subscribe_ids[i] == id) {
841 + pw_endpoint_resource_param(resource, 1, id,
842 + index, next, param);
849 +client_endpoint_update(void *object,
850 + uint32_t change_mask,
852 + const struct spa_pod **params,
853 + const struct pw_endpoint_info *info)
855 + struct pw_client_endpoint *cliep = object;
856 + struct pw_endpoint *this = &cliep->endpoint;
858 + if (change_mask & PW_CLIENT_ENDPOINT_UPDATE_PARAMS) {
861 + pw_log_debug("endpoint %p: update %d params", this, n_params);
863 + for (i = 0; i < this->n_params; i++)
864 + free(this->params[i]);
865 + this->n_params = n_params;
866 + this->params = realloc(this->params, this->n_params * sizeof(struct spa_pod *));
868 + for (i = 0; i < this->n_params; i++) {
869 + this->params[i] = params[i] ? spa_pod_copy(params[i]) : NULL;
870 + endpoint_notify_subscribed(this, i, i+1);
873 + else if (change_mask & PW_CLIENT_ENDPOINT_UPDATE_PARAMS_INCREMENTAL) {
875 + const struct spa_pod_prop *pold, *pnew;
877 + pw_log_debug("endpoint %p: update %d params incremental", this, n_params);
879 + for (i = 0; i < this->n_params; i++) {
880 + /* we only support incremental updates for controls */
881 + if (!spa_pod_is_object_id (this->params[i], PW_ENDPOINT_PARAM_Control))
884 + for (j = 0; j < n_params; j++) {
885 + if (!spa_pod_is_object_id (params[j], PW_ENDPOINT_PARAM_Control)) {
886 + pw_log_warn ("endpoint %p: ignoring incremental update "
887 + "on non-control param", this);
891 + pold = spa_pod_object_find_prop (
892 + (const struct spa_pod_object *) this->params[i],
893 + NULL, PW_ENDPOINT_PARAM_CONTROL_id);
894 + pnew = spa_pod_object_find_prop (
895 + (const struct spa_pod_object *) params[j],
896 + NULL, PW_ENDPOINT_PARAM_CONTROL_id);
898 + if (pold && pnew && spa_pod_compare (&pold->value, &pnew->value) == 0) {
899 + free (this->params[i]);
900 + this->params[i] = spa_pod_copy (params[j]);
901 + endpoint_notify_subscribed(this, i, UINT32_MAX);
907 + if (change_mask & PW_CLIENT_ENDPOINT_UPDATE_INFO) {
908 + struct pw_global *global = this->global;
909 + struct pw_resource *resource;
911 + if (info->change_mask & PW_ENDPOINT_CHANGE_MASK_PARAMS) {
912 + size_t size = info->n_params * sizeof(struct spa_param_info);
913 + free(this->info.params);
914 + this->info.params = malloc(size);
915 + this->info.n_params = info->n_params;
916 + memcpy(this->info.params, info->params, size);
919 + if (info->change_mask & PW_ENDPOINT_CHANGE_MASK_PROPS) {
920 + pw_properties_update(this->props, info->props);
923 + this->info.change_mask = info->change_mask;
924 + spa_list_for_each(resource, &global->resource_list, link) {
925 + pw_endpoint_resource_info(resource, &this->info);
927 + this->info.change_mask = 0;
933 +static struct pw_client_endpoint_proxy_methods client_endpoint_methods = {
934 + PW_VERSION_CLIENT_ENDPOINT_PROXY_METHODS,
935 + .update = client_endpoint_update,
939 +client_endpoint_resource_destroy(void *data)
941 + struct pw_client_endpoint *this = data;
943 + pw_log_debug("client-endpoint %p: destroy", this);
945 + pw_endpoint_clear(&this->endpoint);
947 + this->owner_resource = NULL;
948 + spa_hook_remove(&this->owner_resource_listener);
952 +static const struct pw_resource_events owner_resource_events = {
953 + PW_VERSION_RESOURCE_EVENTS,
954 + .destroy = client_endpoint_resource_destroy,
957 +struct pw_client_endpoint *
958 +pw_client_endpoint_new(struct pw_resource *owner_resource,
959 + struct pw_global *parent,
960 + struct pw_properties *properties)
962 + struct pw_client_endpoint *this;
963 + struct pw_client *owner = pw_resource_get_client(owner_resource);
964 + struct pw_core *core = pw_client_get_core(owner);
966 + this = calloc(1, sizeof(struct pw_client_endpoint));
970 + pw_log_debug("client-endpoint %p: new", this);
972 + if (pw_endpoint_init(&this->endpoint, core, owner, parent, properties) < 0)
973 + goto error_no_endpoint;
974 + this->endpoint.client_ep = this;
976 + this->owner_resource = owner_resource;
977 + pw_resource_add_listener(this->owner_resource,
978 + &this->owner_resource_listener,
979 + &owner_resource_events,
981 + pw_resource_set_implementation(this->owner_resource,
982 + &client_endpoint_methods,
988 + pw_resource_destroy(owner_resource);
994 +pw_client_endpoint_destroy(struct pw_client_endpoint *this)
996 + pw_resource_destroy(this->owner_resource);
998 diff --git a/src/modules/module-endpoint/endpoint-impl.h b/src/modules/module-endpoint/endpoint-impl.h
1000 index 00000000..059aa904
1002 +++ b/src/modules/module-endpoint/endpoint-impl.h
1006 + * Copyright © 2019 Collabora Ltd.
1007 + * @author George Kiagiadakis <george.kiagiadakis@collabora.com>
1009 + * Permission is hereby granted, free of charge, to any person obtaining a
1010 + * copy of this software and associated documentation files (the "Software"),
1011 + * to deal in the Software without restriction, including without limitation
1012 + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
1013 + * and/or sell copies of the Software, and to permit persons to whom the
1014 + * Software is furnished to do so, subject to the following conditions:
1016 + * The above copyright notice and this permission notice (including the next
1017 + * paragraph) shall be included in all copies or substantial portions of the
1020 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1021 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1022 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
1023 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1024 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
1025 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
1026 + * DEALINGS IN THE SOFTWARE.
1029 +#ifndef PIPEWIRE_ENDPOINT_IMPL_H
1030 +#define PIPEWIRE_ENDPOINT_IMPL_H
1032 +#include <pipewire/pipewire.h>
1033 +#include <extensions/endpoint.h>
1034 +#include <extensions/client-endpoint.h>
1040 +struct pw_endpoint;
1041 +struct pw_client_endpoint;
1043 +struct pw_client_endpoint *
1044 +pw_client_endpoint_new(struct pw_resource *resource,
1045 + struct pw_global *parent,
1046 + struct pw_properties *properties);
1049 +pw_client_endpoint_destroy(struct pw_client_endpoint *endpoint);
1055 +#endif /* PIPEWIRE_ENDPOINT_IMPL_H */
1056 diff --git a/src/modules/module-endpoint/protocol-native.c b/src/modules/module-endpoint/protocol-native.c
1057 new file mode 100644
1058 index 00000000..a41d3119
1060 +++ b/src/modules/module-endpoint/protocol-native.c
1064 + * Copyright © 2019 Collabora Ltd.
1065 + * @author George Kiagiadakis <george.kiagiadakis@collabora.com>
1067 + * Permission is hereby granted, free of charge, to any person obtaining a
1068 + * copy of this software and associated documentation files (the "Software"),
1069 + * to deal in the Software without restriction, including without limitation
1070 + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
1071 + * and/or sell copies of the Software, and to permit persons to whom the
1072 + * Software is furnished to do so, subject to the following conditions:
1074 + * The above copyright notice and this permission notice (including the next
1075 + * paragraph) shall be included in all copies or substantial portions of the
1078 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1079 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1080 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
1081 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1082 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
1083 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
1084 + * DEALINGS IN THE SOFTWARE.
1087 +#include <pipewire/pipewire.h>
1088 +#include <spa/pod/parser.h>
1090 +#include <extensions/client-endpoint.h>
1091 +#include <extensions/endpoint.h>
1092 +#include <extensions/protocol-native.h>
1095 +serialize_pw_endpoint_info(struct spa_pod_builder *b,
1096 + const struct pw_endpoint_info *info)
1098 + struct spa_pod_frame f;
1099 + uint32_t i, n_props;
1101 + n_props = info->props ? info->props->n_items : 0;
1103 + spa_pod_builder_push_struct(b, &f);
1104 + spa_pod_builder_add(b,
1105 + SPA_POD_Id(info->id),
1106 + SPA_POD_Int(info->change_mask),
1107 + SPA_POD_Int(info->n_params),
1108 + SPA_POD_Int(n_props),
1111 + for (i = 0; i < info->n_params; i++) {
1112 + spa_pod_builder_add(b,
1113 + SPA_POD_Id(info->params[i].id),
1114 + SPA_POD_Int(info->params[i].flags), NULL);
1117 + for (i = 0; i < n_props; i++) {
1118 + spa_pod_builder_add(b,
1119 + SPA_POD_String(info->props->items[i].key),
1120 + SPA_POD_String(info->props->items[i].value),
1124 + spa_pod_builder_pop(b, &f);
1127 +/* macro because of alloca() */
1128 +#define deserialize_pw_endpoint_info(p, f, info) \
1130 + if (spa_pod_parser_push_struct(p, f) < 0 || \
1131 + spa_pod_parser_get(p, \
1132 + SPA_POD_Id(&(info)->id), \
1133 + SPA_POD_Int(&(info)->change_mask), \
1134 + SPA_POD_Int(&(info)->n_params), \
1135 + SPA_POD_Int(&(info)->props->n_items), \
1139 + if ((info)->n_params > 0) \
1140 + (info)->params = alloca((info)->n_params * sizeof(struct spa_param_info)); \
1141 + if ((info)->props->n_items > 0) \
1142 + (info)->props->items = alloca((info)->props->n_items * sizeof(struct spa_dict_item)); \
1144 + for (i = 0; i < (info)->n_params; i++) { \
1145 + if (spa_pod_parser_get(p, \
1146 + SPA_POD_Id(&(info)->params[i].id), \
1147 + SPA_POD_Int(&(info)->params[i].flags), \
1152 + for (i = 0; i < (info)->props->n_items; i++) { \
1153 + if (spa_pod_parser_get(p, \
1154 + SPA_POD_String(&(info)->props->items[i].key), \
1155 + SPA_POD_String(&(info)->props->items[i].value), \
1160 + spa_pod_parser_pop(p, f); \
1164 +endpoint_marshal_subscribe_params(void *object, uint32_t *ids, uint32_t n_ids)
1166 + struct pw_proxy *proxy = object;
1167 + struct spa_pod_builder *b;
1169 + b = pw_protocol_native_begin_proxy(proxy,
1170 + PW_ENDPOINT_PROXY_METHOD_SUBSCRIBE_PARAMS, NULL);
1172 + spa_pod_builder_add_struct(b,
1173 + SPA_POD_Array(sizeof(uint32_t), SPA_TYPE_Id, n_ids, ids));
1175 + return pw_protocol_native_end_proxy(proxy, b);
1179 +endpoint_demarshal_subscribe_params(void *object, const struct pw_protocol_native_message *msg)
1181 + struct pw_resource *resource = object;
1182 + struct spa_pod_parser prs;
1183 + uint32_t csize, ctype, n_ids;
1186 + spa_pod_parser_init(&prs, msg->data, msg->size);
1187 + if (spa_pod_parser_get_struct(&prs,
1188 + SPA_POD_Array(&csize, &ctype, &n_ids, &ids)) < 0)
1191 + if (ctype != SPA_TYPE_Id)
1194 + return pw_resource_do(resource, struct pw_endpoint_proxy_methods,
1195 + subscribe_params, 0, ids, n_ids);
1199 +endpoint_marshal_enum_params(void *object, int seq, uint32_t id,
1200 + uint32_t index, uint32_t num, const struct spa_pod *filter)
1202 + struct pw_proxy *proxy = object;
1203 + struct spa_pod_builder *b;
1205 + b = pw_protocol_native_begin_proxy(proxy,
1206 + PW_ENDPOINT_PROXY_METHOD_ENUM_PARAMS, NULL);
1208 + spa_pod_builder_add_struct(b,
1211 + SPA_POD_Int(index),
1213 + SPA_POD_Pod(filter));
1215 + return pw_protocol_native_end_proxy(proxy, b);
1219 +endpoint_demarshal_enum_params(void *object, const struct pw_protocol_native_message *msg)
1221 + struct pw_resource *resource = object;
1222 + struct spa_pod_parser prs;
1223 + uint32_t id, index, num;
1225 + struct spa_pod *filter;
1227 + spa_pod_parser_init(&prs, msg->data, msg->size);
1228 + if (spa_pod_parser_get_struct(&prs,
1229 + SPA_POD_Int(&seq),
1231 + SPA_POD_Int(&index),
1232 + SPA_POD_Int(&num),
1233 + SPA_POD_Pod(&filter)) < 0)
1236 + return pw_resource_do(resource, struct pw_endpoint_proxy_methods,
1237 + enum_params, 0, seq, id, index, num, filter);
1241 +endpoint_marshal_set_param(void *object, uint32_t id, uint32_t flags,
1242 + const struct spa_pod *param)
1244 + struct pw_proxy *proxy = object;
1245 + struct spa_pod_builder *b;
1247 + b = pw_protocol_native_begin_proxy(proxy,
1248 + PW_ENDPOINT_PROXY_METHOD_SET_PARAM, NULL);
1250 + spa_pod_builder_add_struct(b,
1252 + SPA_POD_Int(flags),
1253 + SPA_POD_Pod(param));
1254 + return pw_protocol_native_end_proxy(proxy, b);
1258 +endpoint_demarshal_set_param(void *object, const struct pw_protocol_native_message *msg)
1260 + struct pw_resource *resource = object;
1261 + struct spa_pod_parser prs;
1262 + uint32_t id, flags;
1263 + struct spa_pod *param;
1265 + spa_pod_parser_init(&prs, msg->data, msg->size);
1266 + if (spa_pod_parser_get_struct(&prs,
1268 + SPA_POD_Int(&flags),
1269 + SPA_POD_Pod(¶m)) < 0)
1272 + return pw_resource_do(resource, struct pw_endpoint_proxy_methods,
1273 + set_param, 0, id, flags, param);
1277 +endpoint_marshal_info(void *object, const struct pw_endpoint_info *info)
1279 + struct pw_resource *resource = object;
1280 + struct spa_pod_builder *b;
1282 + b = pw_protocol_native_begin_resource(resource,
1283 + PW_ENDPOINT_PROXY_EVENT_INFO, NULL);
1284 + serialize_pw_endpoint_info (b, info);
1285 + pw_protocol_native_end_resource(resource, b);
1289 +endpoint_demarshal_info(void *object, const struct pw_protocol_native_message *msg)
1291 + struct pw_proxy *proxy = object;
1292 + struct spa_pod_parser prs;
1293 + struct spa_pod_frame f;
1294 + struct spa_dict props = SPA_DICT_INIT(NULL, 0);
1295 + struct pw_endpoint_info info = { .props = &props };
1298 + spa_pod_parser_init(&prs, msg->data, msg->size);
1300 + deserialize_pw_endpoint_info(&prs, &f, &info);
1302 + return pw_proxy_notify(proxy, struct pw_endpoint_proxy_events,
1307 +endpoint_marshal_param(void *object, int seq, uint32_t id,
1308 + uint32_t index, uint32_t next, const struct spa_pod *param)
1310 + struct pw_resource *resource = object;
1311 + struct spa_pod_builder *b;
1313 + b = pw_protocol_native_begin_resource(resource,
1314 + PW_ENDPOINT_PROXY_EVENT_PARAM, NULL);
1316 + spa_pod_builder_add_struct(b,
1319 + SPA_POD_Int(index),
1320 + SPA_POD_Int(next),
1321 + SPA_POD_Pod(param));
1323 + pw_protocol_native_end_resource(resource, b);
1327 +endpoint_demarshal_param(void *object, const struct pw_protocol_native_message *msg)
1329 + struct pw_proxy *proxy = object;
1330 + struct spa_pod_parser prs;
1331 + uint32_t id, index, next;
1333 + struct spa_pod *param;
1335 + spa_pod_parser_init(&prs, msg->data, msg->size);
1336 + if (spa_pod_parser_get_struct(&prs,
1337 + SPA_POD_Int(&seq),
1339 + SPA_POD_Int(&index),
1340 + SPA_POD_Int(&next),
1341 + SPA_POD_Pod(¶m)) < 0)
1344 + return pw_proxy_notify(proxy, struct pw_endpoint_proxy_events, param, 0,
1345 + seq, id, index, next, param);
1348 +static const struct pw_endpoint_proxy_methods pw_protocol_native_endpoint_method_marshal = {
1349 + PW_VERSION_ENDPOINT_PROXY_METHODS,
1350 + &endpoint_marshal_subscribe_params,
1351 + &endpoint_marshal_enum_params,
1352 + &endpoint_marshal_set_param,
1355 +static const struct pw_protocol_native_demarshal pw_protocol_native_endpoint_method_demarshal[] = {
1356 + { &endpoint_demarshal_subscribe_params, 0 },
1357 + { &endpoint_demarshal_enum_params, 0 },
1358 + { &endpoint_demarshal_set_param, 0 }
1361 +static const struct pw_endpoint_proxy_events pw_protocol_native_endpoint_event_marshal = {
1362 + PW_VERSION_ENDPOINT_PROXY_EVENTS,
1363 + &endpoint_marshal_info,
1364 + &endpoint_marshal_param,
1367 +static const struct pw_protocol_native_demarshal pw_protocol_native_endpoint_event_demarshal[] = {
1368 + { &endpoint_demarshal_info, 0 },
1369 + { &endpoint_demarshal_param, 0 }
1372 +static const struct pw_protocol_marshal pw_protocol_native_endpoint_marshal = {
1373 + PW_TYPE_INTERFACE_Endpoint,
1374 + PW_VERSION_ENDPOINT,
1375 + PW_ENDPOINT_PROXY_METHOD_NUM,
1376 + PW_ENDPOINT_PROXY_EVENT_NUM,
1377 + &pw_protocol_native_endpoint_method_marshal,
1378 + &pw_protocol_native_endpoint_method_demarshal,
1379 + &pw_protocol_native_endpoint_event_marshal,
1380 + &pw_protocol_native_endpoint_event_demarshal,
1385 +client_endpoint_marshal_update(
1387 + uint32_t change_mask,
1388 + uint32_t n_params,
1389 + const struct spa_pod **params,
1390 + const struct pw_endpoint_info *info)
1392 + struct pw_proxy *proxy = object;
1393 + struct spa_pod_builder *b;
1394 + struct spa_pod_frame f;
1397 + b = pw_protocol_native_begin_proxy(proxy,
1398 + PW_CLIENT_ENDPOINT_PROXY_METHOD_UPDATE, NULL);
1400 + spa_pod_builder_push_struct(b, &f);
1401 + spa_pod_builder_add(b,
1402 + SPA_POD_Int(change_mask),
1403 + SPA_POD_Int(n_params), NULL);
1405 + for (i = 0; i < n_params; i++)
1406 + spa_pod_builder_add(b, SPA_POD_Pod(params[i]), NULL);
1408 + if (change_mask & PW_CLIENT_ENDPOINT_UPDATE_INFO)
1409 + serialize_pw_endpoint_info(b, info);
1411 + spa_pod_builder_pop(b, &f);
1413 + return pw_protocol_native_end_proxy(proxy, b);
1417 +client_endpoint_demarshal_update(void *object,
1418 + const struct pw_protocol_native_message *msg)
1420 + struct pw_resource *resource = object;
1421 + struct spa_pod_parser prs;
1422 + struct spa_pod_frame f[2];
1423 + uint32_t change_mask, n_params;
1424 + const struct spa_pod **params = NULL;
1425 + struct spa_dict props = SPA_DICT_INIT(NULL, 0);
1426 + struct pw_endpoint_info info = { .props = &props };
1429 + spa_pod_parser_init(&prs, msg->data, msg->size);
1430 + if (spa_pod_parser_push_struct(&prs, &f[0]) < 0 ||
1431 + spa_pod_parser_get(&prs,
1432 + SPA_POD_Int(&change_mask),
1433 + SPA_POD_Int(&n_params), NULL) < 0)
1437 + params = alloca(n_params * sizeof(struct spa_pod *));
1438 + for (i = 0; i < n_params; i++)
1439 + if (spa_pod_parser_get(&prs,
1440 + SPA_POD_PodObject(¶ms[i]), NULL) < 0)
1443 + if (change_mask & PW_CLIENT_ENDPOINT_UPDATE_INFO)
1444 + deserialize_pw_endpoint_info(&prs, &f[1], &info);
1446 + pw_resource_do(resource, struct pw_client_endpoint_proxy_methods,
1447 + update, 0, change_mask, n_params, params, &info);
1452 +client_endpoint_marshal_set_param (void *object,
1453 + uint32_t id, uint32_t flags,
1454 + const struct spa_pod *param)
1456 + struct pw_resource *resource = object;
1457 + struct spa_pod_builder *b;
1459 + b = pw_protocol_native_begin_resource(resource,
1460 + PW_CLIENT_ENDPOINT_PROXY_EVENT_SET_PARAM, NULL);
1462 + spa_pod_builder_add_struct(b,
1464 + SPA_POD_Int(flags),
1465 + SPA_POD_Pod(param));
1467 + pw_protocol_native_end_resource(resource, b);
1471 +client_endpoint_demarshal_set_param(void *object,
1472 + const struct pw_protocol_native_message *msg)
1474 + struct pw_proxy *proxy = object;
1475 + struct spa_pod_parser prs;
1476 + uint32_t id, flags;
1477 + const struct spa_pod *param = NULL;
1479 + spa_pod_parser_init(&prs, msg->data, msg->size);
1480 + if (spa_pod_parser_get_struct(&prs,
1482 + SPA_POD_Int(&flags),
1483 + SPA_POD_PodObject(¶m)) < 0)
1486 + pw_proxy_notify(proxy, struct pw_client_endpoint_proxy_events,
1487 + set_param, 0, id, flags, param);
1491 +static const struct pw_client_endpoint_proxy_methods pw_protocol_native_client_endpoint_method_marshal = {
1492 + PW_VERSION_CLIENT_ENDPOINT_PROXY_METHODS,
1493 + &client_endpoint_marshal_update,
1496 +static const struct pw_protocol_native_demarshal pw_protocol_native_client_endpoint_method_demarshal[] = {
1497 + { &client_endpoint_demarshal_update, 0 }
1500 +static const struct pw_client_endpoint_proxy_events pw_protocol_native_client_endpoint_event_marshal = {
1501 + PW_VERSION_CLIENT_ENDPOINT_PROXY_EVENTS,
1502 + &client_endpoint_marshal_set_param,
1505 +static const struct pw_protocol_native_demarshal pw_protocol_native_client_endpoint_event_demarshal[] = {
1506 + { &client_endpoint_demarshal_set_param, 0 }
1509 +static const struct pw_protocol_marshal pw_protocol_native_client_endpoint_marshal = {
1510 + PW_TYPE_INTERFACE_ClientEndpoint,
1511 + PW_VERSION_CLIENT_ENDPOINT,
1512 + PW_CLIENT_ENDPOINT_PROXY_METHOD_NUM,
1513 + PW_CLIENT_ENDPOINT_PROXY_EVENT_NUM,
1514 + &pw_protocol_native_client_endpoint_method_marshal,
1515 + &pw_protocol_native_client_endpoint_method_demarshal,
1516 + &pw_protocol_native_client_endpoint_event_marshal,
1517 + &pw_protocol_native_client_endpoint_event_demarshal,
1520 +struct pw_protocol *pw_protocol_native_ext_endpoint_init(struct pw_core *core)
1522 + struct pw_protocol *protocol;
1524 + protocol = pw_core_find_protocol(core, PW_TYPE_INFO_PROTOCOL_Native);
1526 + if (protocol == NULL)
1529 + pw_protocol_add_marshal(protocol, &pw_protocol_native_client_endpoint_marshal);
1530 + pw_protocol_add_marshal(protocol, &pw_protocol_native_endpoint_marshal);
1534 diff --git a/src/pipewire/pipewire.c b/src/pipewire/pipewire.c
1535 index a8752438..bbbf9420 100644
1536 --- a/src/pipewire/pipewire.c
1537 +++ b/src/pipewire/pipewire.c
1538 @@ -647,6 +647,8 @@ static const struct spa_type_info type_info[] = {
1539 { PW_TYPE_INTERFACE_Module, SPA_TYPE_Pointer, PW_TYPE_INFO_INTERFACE_BASE "Module", NULL },
1540 { PW_TYPE_INTERFACE_ClientNode, SPA_TYPE_Pointer, PW_TYPE_INFO_INTERFACE_BASE "ClientNode", NULL },
1541 { PW_TYPE_INTERFACE_Device, SPA_TYPE_Pointer, PW_TYPE_INFO_INTERFACE_BASE "Device", NULL },
1542 + { PW_TYPE_INTERFACE_Endpoint, SPA_TYPE_Pointer, PW_TYPE_INFO_INTERFACE_BASE "Endpoint", NULL},
1543 + { PW_TYPE_INTERFACE_ClientEndpoint, SPA_TYPE_Pointer, PW_TYPE_INFO_INTERFACE_BASE "ClientEndpoint", NULL},
1544 { SPA_ID_INVALID, SPA_ID_INVALID, "spa_types", spa_types },
1545 { 0, 0, NULL, NULL },
1547 diff --git a/src/pipewire/type.h b/src/pipewire/type.h
1548 index a1b205f7..39544913 100644
1549 --- a/src/pipewire/type.h
1550 +++ b/src/pipewire/type.h
1551 @@ -48,7 +48,8 @@ enum {
1553 PW_TYPE_INTERFACE_EXTENSIONS = PW_TYPE_INTERFACE_START + 0x1000,
1554 PW_TYPE_INTERFACE_ClientNode,
1556 + PW_TYPE_INTERFACE_Endpoint,
1557 + PW_TYPE_INTERFACE_ClientEndpoint,
1560 #define PW_TYPE_INFO_BASE "PipeWire:"