wireplumber: update to latest master
[AGL/meta-agl-devel.git] / meta-pipewire / recipes-multimedia / pipewire / pipewire / 0009-extensions-implement-new-session-manager-extension.patch
1 From cc47e191c42b836811c5fca1122505375a4e080b 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 new session manager extension
5
6 This extension, implemented in module-session-manager, implements
7 a set of objects that are useful for session managers.
8
9 Upstream-Status: Pending
10 ---
11  src/extensions/meson.build                    |    9 +
12  src/extensions/session-manager.h              |   34 +
13  .../session-manager/impl-interfaces.h         |  329 +++
14  src/extensions/session-manager/interfaces.h   |  465 ++++
15  src/extensions/session-manager/introspect.h   |  131 +
16  src/extensions/session-manager/keys.h         |   40 +
17  src/modules/meson.build                       |   17 +
18  src/modules/module-session-manager.c          |   56 +
19  .../module-session-manager/client-endpoint.c  |  270 +++
20  .../module-session-manager/client-endpoint.h  |   60 +
21  .../module-session-manager/client-session.c   |  270 +++
22  .../module-session-manager/client-session.h   |   62 +
23  .../module-session-manager/endpoint-link.c    |  359 +++
24  .../module-session-manager/endpoint-link.h    |   64 +
25  .../module-session-manager/endpoint-stream.c  |  329 +++
26  .../module-session-manager/endpoint-stream.h  |   64 +
27  src/modules/module-session-manager/endpoint.c |  343 +++
28  src/modules/module-session-manager/endpoint.h |   61 +
29  .../module-session-manager/protocol-native.c  | 2125 +++++++++++++++++
30  src/modules/module-session-manager/session.c  |  341 +++
31  src/modules/module-session-manager/session.h  |   61 +
32  src/pipewire/pipewire.c                       |    6 +
33  src/pipewire/type.h                           |    7 +-
34  23 files changed, 5502 insertions(+), 1 deletion(-)
35  create mode 100644 src/extensions/session-manager.h
36  create mode 100644 src/extensions/session-manager/impl-interfaces.h
37  create mode 100644 src/extensions/session-manager/interfaces.h
38  create mode 100644 src/extensions/session-manager/introspect.h
39  create mode 100644 src/extensions/session-manager/keys.h
40  create mode 100644 src/modules/module-session-manager.c
41  create mode 100644 src/modules/module-session-manager/client-endpoint.c
42  create mode 100644 src/modules/module-session-manager/client-endpoint.h
43  create mode 100644 src/modules/module-session-manager/client-session.c
44  create mode 100644 src/modules/module-session-manager/client-session.h
45  create mode 100644 src/modules/module-session-manager/endpoint-link.c
46  create mode 100644 src/modules/module-session-manager/endpoint-link.h
47  create mode 100644 src/modules/module-session-manager/endpoint-stream.c
48  create mode 100644 src/modules/module-session-manager/endpoint-stream.h
49  create mode 100644 src/modules/module-session-manager/endpoint.c
50  create mode 100644 src/modules/module-session-manager/endpoint.h
51  create mode 100644 src/modules/module-session-manager/protocol-native.c
52  create mode 100644 src/modules/module-session-manager/session.c
53  create mode 100644 src/modules/module-session-manager/session.h
54
55 diff --git a/src/extensions/meson.build b/src/extensions/meson.build
56 index a7f5d3cb..95377faa 100644
57 --- a/src/extensions/meson.build
58 +++ b/src/extensions/meson.build
59 @@ -1,6 +1,15 @@
60 +pipewire_ext_sm_headers = [
61 +  'session-manager/impl-interfaces.h',
62 +  'session-manager/interfaces.h',
63 +  'session-manager/introspect.h',
64 +  'session-manager/keys.h',
65 +]
66 +
67  pipewire_ext_headers = [
68    'client-node.h',
69    'protocol-native.h',
70 +  'session-manager.h',
71  ]
72  
73 +install_headers(pipewire_ext_sm_headers, subdir : 'pipewire/extensions/session-manager')
74  install_headers(pipewire_ext_headers, subdir : 'pipewire/extensions')
75 diff --git a/src/extensions/session-manager.h b/src/extensions/session-manager.h
76 new file mode 100644
77 index 00000000..95e759b0
78 --- /dev/null
79 +++ b/src/extensions/session-manager.h
80 @@ -0,0 +1,34 @@
81 +/* PipeWire
82 + *
83 + * Copyright © 2019 Collabora Ltd.
84 + *   @author George Kiagiadakis <george.kiagiadakis@collabora.com>
85 + *
86 + * Permission is hereby granted, free of charge, to any person obtaining a
87 + * copy of this software and associated documentation files (the "Software"),
88 + * to deal in the Software without restriction, including without limitation
89 + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
90 + * and/or sell copies of the Software, and to permit persons to whom the
91 + * Software is furnished to do so, subject to the following conditions:
92 + *
93 + * The above copyright notice and this permission notice (including the next
94 + * paragraph) shall be included in all copies or substantial portions of the
95 + * Software.
96 + *
97 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
98 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
99 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
100 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
101 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
102 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
103 + * DEALINGS IN THE SOFTWARE.
104 + */
105 +
106 +#ifndef PIPEWIRE_EXT_SESSION_MANAGER_H
107 +#define PIPEWIRE_EXT_SESSION_MANAGER_H
108 +
109 +#include "session-manager/introspect.h"
110 +#include "session-manager/interfaces.h"
111 +#include "session-manager/impl-interfaces.h"
112 +#include "session-manager/keys.h"
113 +
114 +#endif /* PIPEWIRE_EXT_SESSION_MANAGER_H */
115 diff --git a/src/extensions/session-manager/impl-interfaces.h b/src/extensions/session-manager/impl-interfaces.h
116 new file mode 100644
117 index 00000000..66daa0b9
118 --- /dev/null
119 +++ b/src/extensions/session-manager/impl-interfaces.h
120 @@ -0,0 +1,329 @@
121 +/* PipeWire
122 + *
123 + * Copyright © 2019 Collabora Ltd.
124 + *   @author George Kiagiadakis <george.kiagiadakis@collabora.com>
125 + *
126 + * Permission is hereby granted, free of charge, to any person obtaining a
127 + * copy of this software and associated documentation files (the "Software"),
128 + * to deal in the Software without restriction, including without limitation
129 + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
130 + * and/or sell copies of the Software, and to permit persons to whom the
131 + * Software is furnished to do so, subject to the following conditions:
132 + *
133 + * The above copyright notice and this permission notice (including the next
134 + * paragraph) shall be included in all copies or substantial portions of the
135 + * Software.
136 + *
137 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
138 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
139 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
140 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
141 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
142 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
143 + * DEALINGS IN THE SOFTWARE.
144 + */
145 +
146 +#ifndef PIPEWIRE_EXT_SESSION_MANAGER_IMPL_INTERFACES_H
147 +#define PIPEWIRE_EXT_SESSION_MANAGER_IMPL_INTERFACES_H
148 +
149 +#include <spa/utils/defs.h>
150 +#include <spa/utils/hook.h>
151 +#include <errno.h>
152 +
153 +#include "introspect.h"
154 +
155 +#ifdef __cplusplus
156 +extern "C" {
157 +#endif
158 +
159 +#define PW_VERSION_CLIENT_ENDPOINT_PROXY 0
160 +struct pw_client_endpoint_proxy { struct spa_interface iface; };
161 +
162 +#define PW_CLIENT_ENDPOINT_PROXY_EVENT_SET_ID                  0
163 +#define PW_CLIENT_ENDPOINT_PROXY_EVENT_SET_SESSION_ID          1
164 +#define PW_CLIENT_ENDPOINT_PROXY_EVENT_SET_PARAM               2
165 +#define PW_CLIENT_ENDPOINT_PROXY_EVENT_STREAM_SET_PARAM                3
166 +#define PW_CLIENT_ENDPOINT_PROXY_EVENT_NUM                     4
167 +
168 +struct pw_client_endpoint_proxy_events {
169 +#define PW_VERSION_CLIENT_ENDPOINT_PROXY_EVENTS                0
170 +       uint32_t version;               /**< version of this structure */
171 +
172 +       /**
173 +        * Sets the id of the \a endpoint.
174 +        *
175 +        * On endpoint implementations, this is called by the server to notify
176 +        * the implementation of the assigned global id of the endpoint. The
177 +        * implementation is obliged to set this id in the
178 +        * #struct pw_endpoint_info \a id field. The implementation should also
179 +        * not emit the info() event before this method is called.
180 +        *
181 +        * \param endpoint a #pw_endpoint
182 +        * \param id the global id assigned to this endpoint
183 +        *
184 +        * \return 0 on success
185 +        *         -EINVAL when the id has already been set
186 +        *         -ENOTSUP on the server-side endpoint implementation
187 +        */
188 +       int (*set_id) (void *endpoint, uint32_t id);
189 +
190 +       /**
191 +        * Sets the session id of the \a endpoint.
192 +        *
193 +        * On endpoints that are not session masters, this method notifies
194 +        * the implementation that it has been associated with a session.
195 +        * The implementation is obliged to set this id in the
196 +        * #struct pw_endpoint_info \a session_id field.
197 +        *
198 +        * \param endpoint a #pw_endpoint
199 +        * \param id the session id associated with this endpoint
200 +        *
201 +        * \return 0 on success
202 +        *         -EINVAL when the session id has already been set
203 +        *         -ENOTSUP when the endpoint is a session master
204 +        */
205 +       int (*set_session_id) (void *endpoint, uint32_t session_id);
206 +
207 +       /**
208 +        * Set the configurable parameter in \a endpoint.
209 +        *
210 +        * Usually, \a param will be obtained from enum_params and then
211 +        * modified but it is also possible to set another spa_pod
212 +        * as long as its keys and types match a supported object.
213 +        *
214 +        * Objects with property keys that are not known are ignored.
215 +        *
216 +        * This function must be called from the main thread.
217 +        *
218 +        * \param endpoint a #struct pw_endpoint
219 +        * \param id the parameter id to configure
220 +        * \param flags additional flags
221 +        * \param param the parameter to configure
222 +        *
223 +        * \return 0 on success
224 +        *         -EINVAL when \a endpoint is NULL
225 +        *         -ENOTSUP when there are no parameters implemented on \a endpoint
226 +        *         -ENOENT the parameter is unknown
227 +        */
228 +       int (*set_param) (void *endpoint,
229 +                         uint32_t id, uint32_t flags,
230 +                         const struct spa_pod *param);
231 +
232 +       /**
233 +        * Set a parameter on \a stream_id of \a endpoint.
234 +        *
235 +        * When \a param is NULL, the parameter will be unset.
236 +        *
237 +        * This function must be called from the main thread.
238 +        *
239 +        * \param endpoint a #struct pw_endpoint
240 +        * \param stream_id the stream to configure
241 +        * \param id the parameter id to set
242 +        * \param flags optional flags
243 +        * \param param a #struct spa_pod with the parameter to set
244 +        * \return 0 on success
245 +        *         1 on success, the value of \a param might have been
246 +        *                changed depending on \a flags and the final value can
247 +        *                be found by doing stream_enum_params.
248 +        *         -EINVAL when \a endpoint is NULL or invalid arguments are given
249 +        *         -ESRCH when the type or size of a property is not correct.
250 +        *         -ENOENT when the param id is not found
251 +        */
252 +       int (*stream_set_param) (void *endpoint, uint32_t stream_id,
253 +                                uint32_t id, uint32_t flags,
254 +                                const struct spa_pod *param);
255 +};
256 +
257 +#define PW_CLIENT_ENDPOINT_PROXY_METHOD_ADD_LISTENER   0
258 +#define PW_CLIENT_ENDPOINT_PROXY_METHOD_UPDATE         1
259 +#define PW_CLIENT_ENDPOINT_PROXY_METHOD_STREAM_UPDATE  2
260 +#define PW_CLIENT_ENDPOINT_PROXY_METHOD_NUM            3
261 +
262 +struct pw_client_endpoint_proxy_methods {
263 +#define PW_VERSION_CLIENT_ENDPOINT_PROXY_METHODS       0
264 +       uint32_t version;               /**< version of this structure */
265 +
266 +       int (*add_listener) (void *object,
267 +                       struct spa_hook *listener,
268 +                       const struct pw_client_endpoint_proxy_events *events,
269 +                       void *data);
270 +
271 +       /** Update endpoint information */
272 +       int (*update) (void *object,
273 +#define PW_CLIENT_ENDPOINT_UPDATE_PARAMS       (1 << 0)
274 +#define PW_CLIENT_ENDPOINT_UPDATE_INFO         (1 << 1)
275 +                       uint32_t change_mask,
276 +                       uint32_t n_params,
277 +                       const struct spa_pod **params,
278 +                       const struct pw_endpoint_info *info);
279 +
280 +       /** Update stream information */
281 +       int (*stream_update) (void *object,
282 +                               uint32_t stream_id,
283 +#define PW_CLIENT_ENDPOINT_STREAM_UPDATE_PARAMS                (1 << 0)
284 +#define PW_CLIENT_ENDPOINT_STREAM_UPDATE_INFO          (1 << 1)
285 +#define PW_CLIENT_ENDPOINT_STREAM_UPDATE_DESTROYED     (1 << 2)
286 +                               uint32_t change_mask,
287 +                               uint32_t n_params,
288 +                               const struct spa_pod **params,
289 +                               const struct pw_endpoint_stream_info *info);
290 +};
291 +
292 +#define pw_client_endpoint_proxy_method(o,method,version,...)          \
293 +({                                                                     \
294 +       int _res = -ENOTSUP;                                            \
295 +       struct pw_client_endpoint_proxy *_p = o;                        \
296 +       spa_interface_call_res(&_p->iface,                              \
297 +                       struct pw_client_endpoint_proxy_methods, _res,  \
298 +                       method, version, ##__VA_ARGS__);                \
299 +       _res;                                                           \
300 +})
301 +
302 +#define pw_client_endpoint_proxy_add_listener(o,...)   pw_client_endpoint_proxy_method(o,add_listener,0,__VA_ARGS__)
303 +#define pw_client_endpoint_proxy_update(o,...)         pw_client_endpoint_proxy_method(o,update,0,__VA_ARGS__)
304 +#define pw_client_endpoint_proxy_stream_update(o,...)  pw_client_endpoint_proxy_method(o,stream_update,0,__VA_ARGS__)
305 +
306 +
307 +#define PW_VERSION_CLIENT_SESSION_PROXY 0
308 +struct pw_client_session_proxy { struct spa_interface iface; };
309 +
310 +#define PW_CLIENT_SESSION_PROXY_EVENT_SET_ID                   0
311 +#define PW_CLIENT_SESSION_PROXY_EVENT_SET_PARAM                        1
312 +#define PW_CLIENT_SESSION_PROXY_EVENT_LINK_SET_PARAM           2
313 +#define PW_CLIENT_SESSION_PROXY_EVENT_CREATE_LINK              3
314 +#define PW_CLIENT_SESSION_PROXY_EVENT_DESTROY_LINK             4
315 +#define PW_CLIENT_SESSION_PROXY_EVENT_LINK_REQUEST_STATE       5
316 +#define PW_CLIENT_SESSION_PROXY_EVENT_NUM                      6
317 +
318 +struct pw_client_session_proxy_events {
319 +#define PW_VERSION_CLIENT_SESSION_PROXY_EVENTS         0
320 +       uint32_t version;               /**< version of this structure */
321 +
322 +       /**
323 +        * Sets the id of the \a session.
324 +        *
325 +        * On session implementations, this is called by the server to notify
326 +        * the implementation of the assigned global id of the session. The
327 +        * implementation is obliged to set this id in the
328 +        * #struct pw_session_info \a id field. The implementation should also
329 +        * not emit the info() event before this method is called.
330 +        *
331 +        * \param session a #pw_session
332 +        * \param id the global id assigned to this session
333 +        *
334 +        * \return 0 on success
335 +        *         -EINVAL when the id has already been set
336 +        *         -ENOTSUP on the server-side session implementation
337 +        */
338 +       int (*set_id) (void *session, uint32_t id);
339 +
340 +       /**
341 +        * Set the configurable parameter in \a session.
342 +        *
343 +        * Usually, \a param will be obtained from enum_params and then
344 +        * modified but it is also possible to set another spa_pod
345 +        * as long as its keys and types match a supported object.
346 +        *
347 +        * Objects with property keys that are not known are ignored.
348 +        *
349 +        * This function must be called from the main thread.
350 +        *
351 +        * \param session a #struct pw_session
352 +        * \param id the parameter id to configure
353 +        * \param flags additional flags
354 +        * \param param the parameter to configure
355 +        *
356 +        * \return 0 on success
357 +        *         -EINVAL when \a session is NULL
358 +        *         -ENOTSUP when there are no parameters implemented on \a session
359 +        *         -ENOENT the parameter is unknown
360 +        */
361 +       int (*set_param) (void *session,
362 +                         uint32_t id, uint32_t flags,
363 +                         const struct spa_pod *param);
364 +
365 +       /**
366 +        * Set a parameter on \a link_id of \a session.
367 +        *
368 +        * When \a param is NULL, the parameter will be unset.
369 +        *
370 +        * This function must be called from the main thread.
371 +        *
372 +        * \param session a #struct pw_session
373 +        * \param link_id the link to configure
374 +        * \param id the parameter id to set
375 +        * \param flags optional flags
376 +        * \param param a #struct spa_pod with the parameter to set
377 +        * \return 0 on success
378 +        *         1 on success, the value of \a param might have been
379 +        *                changed depending on \a flags and the final value can
380 +        *                be found by doing link_enum_params.
381 +        *         -EINVAL when \a session is NULL or invalid arguments are given
382 +        *         -ESRCH when the type or size of a property is not correct.
383 +        *         -ENOENT when the param id is not found
384 +        */
385 +       int (*link_set_param) (void *session, uint32_t link_id,
386 +                              uint32_t id, uint32_t flags,
387 +                              const struct spa_pod *param);
388 +
389 +       int (*create_link) (void *session, const struct spa_dict *props);
390 +
391 +       int (*destroy_link) (void *session, uint32_t link_id);
392 +
393 +       int (*link_request_state) (void *session, uint32_t link_id, uint32_t state);
394 +};
395 +
396 +#define PW_CLIENT_SESSION_PROXY_METHOD_ADD_LISTENER    0
397 +#define PW_CLIENT_SESSION_PROXY_METHOD_UPDATE          1
398 +#define PW_CLIENT_SESSION_PROXY_METHOD_LINK_UPDATE     2
399 +#define PW_CLIENT_SESSION_PROXY_METHOD_NUM             3
400 +
401 +struct pw_client_session_proxy_methods {
402 +#define PW_VERSION_CLIENT_SESSION_PROXY_METHODS        0
403 +       uint32_t version;               /**< version of this structure */
404 +
405 +       int (*add_listener) (void *object,
406 +                       struct spa_hook *listener,
407 +                       const struct pw_client_session_proxy_events *events,
408 +                       void *data);
409 +
410 +       /** Update session information */
411 +       int (*update) (void *object,
412 +#define PW_CLIENT_SESSION_UPDATE_PARAMS                (1 << 0)
413 +#define PW_CLIENT_SESSION_UPDATE_INFO          (1 << 1)
414 +                       uint32_t change_mask,
415 +                       uint32_t n_params,
416 +                       const struct spa_pod **params,
417 +                       const struct pw_session_info *info);
418 +
419 +       /** Update link information */
420 +       int (*link_update) (void *object,
421 +                               uint32_t link_id,
422 +#define PW_CLIENT_SESSION_LINK_UPDATE_PARAMS           (1 << 0)
423 +#define PW_CLIENT_SESSION_LINK_UPDATE_INFO             (1 << 1)
424 +#define PW_CLIENT_SESSION_LINK_UPDATE_DESTROYED                (1 << 2)
425 +                               uint32_t change_mask,
426 +                               uint32_t n_params,
427 +                               const struct spa_pod **params,
428 +                               const struct pw_endpoint_link_info *info);
429 +};
430 +
431 +#define pw_client_session_proxy_method(o,method,version,...)           \
432 +({                                                                     \
433 +       int _res = -ENOTSUP;                                            \
434 +       struct pw_client_session_proxy *_p = o;                         \
435 +       spa_interface_call_res(&_p->iface,                              \
436 +                       struct pw_client_session_proxy_methods, _res,   \
437 +                       method, version, ##__VA_ARGS__);                \
438 +       _res;                                                           \
439 +})
440 +
441 +#define pw_client_session_proxy_add_listener(o,...)    pw_client_session_proxy_method(o,add_listener,0,__VA_ARGS__)
442 +#define pw_client_session_proxy_update(o,...)          pw_client_session_proxy_method(o,update,0,__VA_ARGS__)
443 +#define pw_client_session_proxy_link_update(o,...)     pw_client_session_proxy_method(o,link_update,0,__VA_ARGS__)
444 +
445 +#ifdef __cplusplus
446 +}  /* extern "C" */
447 +#endif
448 +
449 +#endif /* PIPEWIRE_EXT_SESSION_MANAGER_IMPL_INTERFACES_H */
450 diff --git a/src/extensions/session-manager/interfaces.h b/src/extensions/session-manager/interfaces.h
451 new file mode 100644
452 index 00000000..0651e8bf
453 --- /dev/null
454 +++ b/src/extensions/session-manager/interfaces.h
455 @@ -0,0 +1,465 @@
456 +/* PipeWire
457 + *
458 + * Copyright © 2019 Collabora Ltd.
459 + *   @author George Kiagiadakis <george.kiagiadakis@collabora.com>
460 + *
461 + * Permission is hereby granted, free of charge, to any person obtaining a
462 + * copy of this software and associated documentation files (the "Software"),
463 + * to deal in the Software without restriction, including without limitation
464 + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
465 + * and/or sell copies of the Software, and to permit persons to whom the
466 + * Software is furnished to do so, subject to the following conditions:
467 + *
468 + * The above copyright notice and this permission notice (including the next
469 + * paragraph) shall be included in all copies or substantial portions of the
470 + * Software.
471 + *
472 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
473 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
474 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
475 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
476 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
477 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
478 + * DEALINGS IN THE SOFTWARE.
479 + */
480 +
481 +#ifndef PIPEWIRE_EXT_SESSION_MANAGER_INTERFACES_H
482 +#define PIPEWIRE_EXT_SESSION_MANAGER_INTERFACES_H
483 +
484 +#include <spa/utils/defs.h>
485 +#include <spa/utils/hook.h>
486 +
487 +#include "introspect.h"
488 +
489 +#ifdef __cplusplus
490 +extern "C" {
491 +#endif
492 +
493 +#define PW_VERSION_SESSION_PROXY               0
494 +struct pw_session_proxy { struct spa_interface iface; };
495 +#define PW_VERSION_ENDPOINT_PROXY              0
496 +struct pw_endpoint_proxy { struct spa_interface iface; };
497 +#define PW_VERSION_ENDPOINT_STREAM_PROXY       0
498 +struct pw_endpoint_stream_proxy { struct spa_interface iface; };
499 +#define PW_VERSION_ENDPOINT_LINK_PROXY         0
500 +struct pw_endpoint_link_proxy { struct spa_interface iface; };
501 +
502 +/* Session */
503 +
504 +#define PW_SESSION_PROXY_EVENT_INFO            0
505 +#define PW_SESSION_PROXY_EVENT_PARAM           1
506 +#define PW_SESSION_PROXY_EVENT_NUM             2
507 +
508 +struct pw_session_proxy_events {
509 +#define PW_VERSION_SESSION_PROXY_EVENTS                0
510 +       uint32_t version;                       /**< version of this structure */
511 +
512 +       /**
513 +        * Notify session info
514 +        *
515 +        * \param info info about the session
516 +        */
517 +       void (*info) (void *object, const struct pw_session_info *info);
518 +
519 +       /**
520 +        * Notify a session param
521 +        *
522 +        * Event emited as a result of the enum_params method.
523 +        *
524 +        * \param seq the sequence number of the request
525 +        * \param id the param id
526 +        * \param index the param index
527 +        * \param next the param index of the next param
528 +        * \param param the parameter
529 +        */
530 +       void (*param) (void *object, int seq,
531 +                      uint32_t id, uint32_t index, uint32_t next,
532 +                      const struct spa_pod *param);
533 +};
534 +
535 +#define PW_SESSION_PROXY_METHOD_ADD_LISTENER           0
536 +#define PW_SESSION_PROXY_METHOD_SUBSCRIBE_PARAMS       1
537 +#define PW_SESSION_PROXY_METHOD_ENUM_PARAMS            2
538 +#define PW_SESSION_PROXY_METHOD_SET_PARAM              3
539 +#define PW_SESSION_PROXY_METHOD_CREATE_LINK            4
540 +#define PW_SESSION_PROXY_METHOD_NUM                    5
541 +
542 +struct pw_session_proxy_methods {
543 +#define PW_VERSION_SESSION_PROXY_METHODS       0
544 +       uint32_t version;                       /**< version of this structure */
545 +
546 +       int (*add_listener) (void *object,
547 +                       struct spa_hook *listener,
548 +                       const struct pw_session_proxy_events *events,
549 +                       void *data);
550 +
551 +       /**
552 +        * Subscribe to parameter changes
553 +        *
554 +        * Automatically emit param events for the given ids when
555 +        * they are changed.
556 +        *
557 +        * \param ids an array of param ids
558 +        * \param n_ids the number of ids in \a ids
559 +        */
560 +       int (*subscribe_params) (void *object, uint32_t *ids, uint32_t n_ids);
561 +
562 +       /**
563 +        * Enumerate session parameters
564 +        *
565 +        * Start enumeration of session parameters. For each param, a
566 +        * param event will be emited.
567 +        *
568 +        * \param seq a sequence number returned in the reply
569 +        * \param id the parameter id to enumerate
570 +        * \param start the start index or 0 for the first param
571 +        * \param num the maximum number of params to retrieve
572 +        * \param filter a param filter or NULL
573 +        */
574 +       int (*enum_params) (void *object, int seq,
575 +                       uint32_t id, uint32_t start, uint32_t num,
576 +                       const struct spa_pod *filter);
577 +
578 +       /**
579 +        * Set a parameter on the session
580 +        *
581 +        * \param id the parameter id to set
582 +        * \param flags extra parameter flags
583 +        * \param param the parameter to set
584 +        */
585 +       int (*set_param) (void *object, uint32_t id, uint32_t flags,
586 +                         const struct spa_pod *param);
587 +
588 +       int (*create_link) (void *object, const struct spa_dict *props);
589 +};
590 +
591 +#define pw_session_proxy_method(o,method,version,...)                  \
592 +({                                                                     \
593 +       int _res = -ENOTSUP;                                            \
594 +       struct pw_session_proxy *_p = o;                                        \
595 +       spa_interface_call_res(&_p->iface,                              \
596 +                       struct pw_session_proxy_methods, _res,          \
597 +                       method, version, ##__VA_ARGS__);                \
598 +       _res;                                                           \
599 +})
600 +
601 +#define pw_session_proxy_add_listener(c,...)           pw_session_proxy_method(c,add_listener,0,__VA_ARGS__)
602 +#define pw_session_proxy_subscribe_params(c,...)       pw_session_proxy_method(c,subscribe_params,0,__VA_ARGS__)
603 +#define pw_session_proxy_enum_params(c,...)            pw_session_proxy_method(c,enum_params,0,__VA_ARGS__)
604 +#define pw_session_proxy_create_link(c,...)            pw_session_proxy_method(c,create_link,0,__VA_ARGS__)
605 +
606 +/* Endpoint */
607 +
608 +#define PW_ENDPOINT_PROXY_EVENT_INFO           0
609 +#define PW_ENDPOINT_PROXY_EVENT_PARAM          1
610 +#define PW_ENDPOINT_PROXY_EVENT_NUM            2
611 +
612 +struct pw_endpoint_proxy_events {
613 +#define PW_VERSION_ENDPOINT_PROXY_EVENTS       0
614 +       uint32_t version;                       /**< version of this structure */
615 +
616 +       /**
617 +        * Notify endpoint info
618 +        *
619 +        * \param info info about the endpoint
620 +        */
621 +       void (*info) (void *object, const struct pw_endpoint_info *info);
622 +
623 +       /**
624 +        * Notify a endpoint param
625 +        *
626 +        * Event emited as a result of the enum_params method.
627 +        *
628 +        * \param seq the sequence number of the request
629 +        * \param id the param id
630 +        * \param index the param index
631 +        * \param next the param index of the next param
632 +        * \param param the parameter
633 +        */
634 +       void (*param) (void *object, int seq,
635 +                      uint32_t id, uint32_t index, uint32_t next,
636 +                      const struct spa_pod *param);
637 +};
638 +
639 +#define PW_ENDPOINT_PROXY_METHOD_ADD_LISTENER          0
640 +#define PW_ENDPOINT_PROXY_METHOD_SUBSCRIBE_PARAMS      1
641 +#define PW_ENDPOINT_PROXY_METHOD_ENUM_PARAMS           2
642 +#define PW_ENDPOINT_PROXY_METHOD_SET_PARAM             3
643 +#define PW_ENDPOINT_PROXY_METHOD_NUM                   4
644 +
645 +struct pw_endpoint_proxy_methods {
646 +#define PW_VERSION_ENDPOINT_PROXY_METHODS      0
647 +       uint32_t version;                       /**< version of this structure */
648 +
649 +       int (*add_listener) (void *object,
650 +                       struct spa_hook *listener,
651 +                       const struct pw_endpoint_proxy_events *events,
652 +                       void *data);
653 +
654 +       /**
655 +        * Subscribe to parameter changes
656 +        *
657 +        * Automatically emit param events for the given ids when
658 +        * they are changed.
659 +        *
660 +        * \param ids an array of param ids
661 +        * \param n_ids the number of ids in \a ids
662 +        */
663 +       int (*subscribe_params) (void *object, uint32_t *ids, uint32_t n_ids);
664 +
665 +       /**
666 +        * Enumerate endpoint parameters
667 +        *
668 +        * Start enumeration of endpoint parameters. For each param, a
669 +        * param event will be emited.
670 +        *
671 +        * \param seq a sequence number returned in the reply
672 +        * \param id the parameter id to enumerate
673 +        * \param start the start index or 0 for the first param
674 +        * \param num the maximum number of params to retrieve
675 +        * \param filter a param filter or NULL
676 +        */
677 +       int (*enum_params) (void *object, int seq,
678 +                       uint32_t id, uint32_t start, uint32_t num,
679 +                       const struct spa_pod *filter);
680 +
681 +       /**
682 +        * Set a parameter on the endpoint
683 +        *
684 +        * \param id the parameter id to set
685 +        * \param flags extra parameter flags
686 +        * \param param the parameter to set
687 +        */
688 +       int (*set_param) (void *object, uint32_t id, uint32_t flags,
689 +                         const struct spa_pod *param);
690 +};
691 +
692 +#define pw_endpoint_proxy_method(o,method,version,...)                 \
693 +({                                                                     \
694 +       int _res = -ENOTSUP;                                            \
695 +       struct pw_endpoint_proxy *_p = o;                                       \
696 +       spa_interface_call_res(&_p->iface,                              \
697 +                       struct pw_endpoint_proxy_methods, _res,         \
698 +                       method, version, ##__VA_ARGS__);                \
699 +       _res;                                                           \
700 +})
701 +
702 +#define pw_endpoint_proxy_add_listener(c,...)          pw_endpoint_proxy_method(c,add_listener,0,__VA_ARGS__)
703 +#define pw_endpoint_proxy_subscribe_params(c,...)      pw_endpoint_proxy_method(c,subscribe_params,0,__VA_ARGS__)
704 +#define pw_endpoint_proxy_enum_params(c,...)           pw_endpoint_proxy_method(c,enum_params,0,__VA_ARGS__)
705 +
706 +/* Endpoint Stream */
707 +
708 +#define PW_ENDPOINT_STREAM_PROXY_EVENT_INFO            0
709 +#define PW_ENDPOINT_STREAM_PROXY_EVENT_PARAM           1
710 +#define PW_ENDPOINT_STREAM_PROXY_EVENT_NUM             2
711 +
712 +struct pw_endpoint_stream_proxy_events {
713 +#define PW_VERSION_ENDPOINT_STREAM_PROXY_EVENTS        0
714 +       uint32_t version;                       /**< version of this structure */
715 +
716 +       /**
717 +        * Notify endpoint stream info
718 +        *
719 +        * \param info info about the endpoint stream
720 +        */
721 +       void (*info) (void *object, const struct pw_endpoint_stream_info *info);
722 +
723 +       /**
724 +        * Notify a endpoint stream param
725 +        *
726 +        * Event emited as a result of the enum_params method.
727 +        *
728 +        * \param seq the sequence number of the request
729 +        * \param id the param id
730 +        * \param index the param index
731 +        * \param next the param index of the next param
732 +        * \param param the parameter
733 +        */
734 +       void (*param) (void *object, int seq,
735 +                      uint32_t id, uint32_t index, uint32_t next,
736 +                      const struct spa_pod *param);
737 +};
738 +
739 +#define PW_ENDPOINT_STREAM_PROXY_METHOD_ADD_LISTENER           0
740 +#define PW_ENDPOINT_STREAM_PROXY_METHOD_SUBSCRIBE_PARAMS       1
741 +#define PW_ENDPOINT_STREAM_PROXY_METHOD_ENUM_PARAMS            2
742 +#define PW_ENDPOINT_STREAM_PROXY_METHOD_SET_PARAM              3
743 +#define PW_ENDPOINT_STREAM_PROXY_METHOD_NUM                    4
744 +
745 +struct pw_endpoint_stream_proxy_methods {
746 +#define PW_VERSION_ENDPOINT_STREAM_PROXY_METHODS       0
747 +       uint32_t version;                       /**< version of this structure */
748 +
749 +       int (*add_listener) (void *object,
750 +                       struct spa_hook *listener,
751 +                       const struct pw_endpoint_stream_proxy_events *events,
752 +                       void *data);
753 +
754 +       /**
755 +        * Subscribe to parameter changes
756 +        *
757 +        * Automatically emit param events for the given ids when
758 +        * they are changed.
759 +        *
760 +        * \param ids an array of param ids
761 +        * \param n_ids the number of ids in \a ids
762 +        */
763 +       int (*subscribe_params) (void *object, uint32_t *ids, uint32_t n_ids);
764 +
765 +       /**
766 +        * Enumerate stream parameters
767 +        *
768 +        * Start enumeration of stream parameters. For each param, a
769 +        * param event will be emited.
770 +        *
771 +        * \param seq a sequence number returned in the reply
772 +        * \param id the parameter id to enumerate
773 +        * \param start the start index or 0 for the first param
774 +        * \param num the maximum number of params to retrieve
775 +        * \param filter a param filter or NULL
776 +        */
777 +       int (*enum_params) (void *object, int seq,
778 +                       uint32_t id, uint32_t start, uint32_t num,
779 +                       const struct spa_pod *filter);
780 +
781 +       /**
782 +        * Set a parameter on the stream
783 +        *
784 +        * \param id the parameter id to set
785 +        * \param flags extra parameter flags
786 +        * \param param the parameter to set
787 +        */
788 +       int (*set_param) (void *object, uint32_t id, uint32_t flags,
789 +                         const struct spa_pod *param);
790 +};
791 +
792 +#define pw_endpoint_stream_proxy_method(o,method,version,...)                  \
793 +({                                                                     \
794 +       int _res = -ENOTSUP;                                            \
795 +       struct pw_endpoint_stream_proxy *_p = o;                                        \
796 +       spa_interface_call_res(&_p->iface,                              \
797 +                       struct pw_endpoint_stream_proxy_methods, _res,          \
798 +                       method, version, ##__VA_ARGS__);                \
799 +       _res;                                                           \
800 +})
801 +
802 +#define pw_endpoint_stream_proxy_add_listener(c,...)           pw_endpoint_stream_proxy_method(c,add_listener,0,__VA_ARGS__)
803 +#define pw_endpoint_stream_proxy_subscribe_params(c,...)       pw_endpoint_stream_proxy_method(c,subscribe_params,0,__VA_ARGS__)
804 +#define pw_endpoint_stream_proxy_enum_params(c,...)            pw_endpoint_stream_proxy_method(c,enum_params,0,__VA_ARGS__)
805 +
806 +/* Endpoint Link */
807 +
808 +#define PW_ENDPOINT_LINK_PROXY_EVENT_INFO              0
809 +#define PW_ENDPOINT_LINK_PROXY_EVENT_PARAM             1
810 +#define PW_ENDPOINT_LINK_PROXY_EVENT_NUM               2
811 +
812 +struct pw_endpoint_link_proxy_events {
813 +#define PW_VERSION_ENDPOINT_LINK_PROXY_EVENTS  0
814 +       uint32_t version;                       /**< version of this structure */
815 +
816 +       /**
817 +        * Notify endpoint link info
818 +        *
819 +        * \param info info about the endpoint link
820 +        */
821 +       void (*info) (void *object, const struct pw_endpoint_link_info *info);
822 +
823 +       /**
824 +        * Notify a endpoint link param
825 +        *
826 +        * Event emited as a result of the enum_params method.
827 +        *
828 +        * \param seq the sequence number of the request
829 +        * \param id the param id
830 +        * \param index the param index
831 +        * \param next the param index of the next param
832 +        * \param param the parameter
833 +        */
834 +       void (*param) (void *object, int seq,
835 +                      uint32_t id, uint32_t index, uint32_t next,
836 +                      const struct spa_pod *param);
837 +};
838 +
839 +#define PW_ENDPOINT_LINK_PROXY_METHOD_ADD_LISTENER             0
840 +#define PW_ENDPOINT_LINK_PROXY_METHOD_SUBSCRIBE_PARAMS         1
841 +#define PW_ENDPOINT_LINK_PROXY_METHOD_ENUM_PARAMS              2
842 +#define PW_ENDPOINT_LINK_PROXY_METHOD_SET_PARAM                        3
843 +#define PW_ENDPOINT_LINK_PROXY_METHOD_REQUEST_STATE            4
844 +#define PW_ENDPOINT_LINK_PROXY_METHOD_DESTROY                  5
845 +#define PW_ENDPOINT_LINK_PROXY_METHOD_NUM                      6
846 +
847 +struct pw_endpoint_link_proxy_methods {
848 +#define PW_VERSION_ENDPOINT_LINK_PROXY_METHODS 0
849 +       uint32_t version;                       /**< version of this structure */
850 +
851 +       int (*add_listener) (void *object,
852 +                       struct spa_hook *listener,
853 +                       const struct pw_endpoint_link_proxy_events *events,
854 +                       void *data);
855 +
856 +       /**
857 +        * Subscribe to parameter changes
858 +        *
859 +        * Automatically emit param events for the given ids when
860 +        * they are changed.
861 +        *
862 +        * \param ids an array of param ids
863 +        * \param n_ids the number of ids in \a ids
864 +        */
865 +       int (*subscribe_params) (void *object, uint32_t *ids, uint32_t n_ids);
866 +
867 +       /**
868 +        * Enumerate link parameters
869 +        *
870 +        * Start enumeration of link parameters. For each param, a
871 +        * param event will be emited.
872 +        *
873 +        * \param seq a sequence number returned in the reply
874 +        * \param id the parameter id to enumerate
875 +        * \param start the start index or 0 for the first param
876 +        * \param num the maximum number of params to retrieve
877 +        * \param filter a param filter or NULL
878 +        */
879 +       int (*enum_params) (void *object, int seq,
880 +                       uint32_t id, uint32_t start, uint32_t num,
881 +                       const struct spa_pod *filter);
882 +
883 +       /**
884 +        * Set a parameter on the link
885 +        *
886 +        * \param id the parameter id to set
887 +        * \param flags extra parameter flags
888 +        * \param param the parameter to set
889 +        */
890 +       int (*set_param) (void *object, uint32_t id, uint32_t flags,
891 +                         const struct spa_pod *param);
892 +
893 +       int (*request_state) (void *object, enum pw_endpoint_link_state state);
894 +
895 +       int (*destroy) (void *object);
896 +
897 +};
898 +
899 +#define pw_endpoint_link_proxy_method(o,method,version,...)                    \
900 +({                                                                     \
901 +       int _res = -ENOTSUP;                                            \
902 +       struct pw_endpoint_link_proxy *_p = o;                                  \
903 +       spa_interface_call_res(&_p->iface,                              \
904 +                       struct pw_endpoint_link_proxy_methods, _res,            \
905 +                       method, version, ##__VA_ARGS__);                \
906 +       _res;                                                           \
907 +})
908 +
909 +#define pw_endpoint_link_proxy_add_listener(c,...)     pw_endpoint_link_proxy_method(c,add_listener,0,__VA_ARGS__)
910 +#define pw_endpoint_link_proxy_subscribe_params(c,...) pw_endpoint_link_proxy_method(c,subscribe_params,0,__VA_ARGS__)
911 +#define pw_endpoint_link_proxy_enum_params(c,...)      pw_endpoint_link_proxy_method(c,enum_params,0,__VA_ARGS__)
912 +#define pw_endpoint_link_proxy_request_state(c,...)    pw_endpoint_link_proxy_method(c,request_state,0,__VA_ARGS__)
913 +#define pw_endpoint_link_proxy_destroy(c,...)          pw_endpoint_link_proxy_method(c,destroy,0,__VA_ARGS__)
914 +
915 +
916 +#ifdef __cplusplus
917 +}  /* extern "C" */
918 +#endif
919 +
920 +#endif /* PIPEWIRE_EXT_SESSION_MANAGER_INTERFACES_H */
921 diff --git a/src/extensions/session-manager/introspect.h b/src/extensions/session-manager/introspect.h
922 new file mode 100644
923 index 00000000..3b0e4113
924 --- /dev/null
925 +++ b/src/extensions/session-manager/introspect.h
926 @@ -0,0 +1,131 @@
927 +/* PipeWire
928 + *
929 + * Copyright © 2019 Collabora Ltd.
930 + *   @author George Kiagiadakis <george.kiagiadakis@collabora.com>
931 + *
932 + * Permission is hereby granted, free of charge, to any person obtaining a
933 + * copy of this software and associated documentation files (the "Software"),
934 + * to deal in the Software without restriction, including without limitation
935 + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
936 + * and/or sell copies of the Software, and to permit persons to whom the
937 + * Software is furnished to do so, subject to the following conditions:
938 + *
939 + * The above copyright notice and this permission notice (including the next
940 + * paragraph) shall be included in all copies or substantial portions of the
941 + * Software.
942 + *
943 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
944 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
945 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
946 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
947 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
948 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
949 + * DEALINGS IN THE SOFTWARE.
950 + */
951 +
952 +#ifndef PIPEWIRE_EXT_SESSION_MANAGER_INTROSPECT_H
953 +#define PIPEWIRE_EXT_SESSION_MANAGER_INTROSPECT_H
954 +
955 +#include <spa/utils/defs.h>
956 +#include <spa/utils/dict.h>
957 +#include <spa/param/param.h>
958 +
959 +#ifdef __cplusplus
960 +extern "C" {
961 +#endif
962 +
963 +#define PW_KEY_ENDPOINT_ID     "endpoint.id"
964 +#define PW_KEY_SESSION_ID      "session.id"
965 +
966 +enum pw_endpoint_direction {
967 +       PW_ENDPOINT_DIRECTION_SINK_INPUT = SPA_DIRECTION_INPUT,
968 +       PW_ENDPOINT_DIRECTION_SOURCE_OUTPUT = SPA_DIRECTION_OUTPUT,
969 +       PW_ENDPOINT_DIRECTION_SOURCE,
970 +       PW_ENDPOINT_DIRECTION_SINK,
971 +};
972 +
973 +enum pw_endpoint_link_state {
974 +       PW_ENDPOINT_LINK_STATE_ERROR = -1,
975 +       PW_ENDPOINT_LINK_STATE_PREPARING,
976 +       PW_ENDPOINT_LINK_STATE_INACTIVE,
977 +       PW_ENDPOINT_LINK_STATE_ACTIVE,
978 +};
979 +
980 +struct pw_session_info {
981 +#define PW_VERSION_SESSION_INFO                        0
982 +       uint32_t version;                       /**< version of this structure */
983 +       uint32_t id;                            /**< the session id (global) */
984 +#define PW_SESSION_CHANGE_MASK_PROPS           (1 << 0)
985 +#define PW_SESSION_CHANGE_MASK_PARAMS          (1 << 1)
986 +#define PW_SESSION_CHANGE_MASK_ALL             ((1 << 2)-1)
987 +       uint32_t change_mask;                   /**< bitfield of changed fields since last call */
988 +       struct spa_dict *props;                 /**< extra properties */
989 +       struct spa_param_info *params;          /**< parameters */
990 +       uint32_t n_params;                      /**< number of items in \a params */
991 +};
992 +
993 +struct pw_endpoint_info {
994 +#define PW_VERSION_ENDPOINT_INFO               0
995 +       uint32_t version;                       /**< version of this structure */
996 +       uint32_t id;                            /**< the endpoint id (global) */
997 +       char *name;                             /**< name of the endpoint */
998 +       char *media_class;                      /**< media class of the endpoint */
999 +       enum pw_endpoint_direction direction;   /**< direction of the endpoint */
1000 +#define PW_ENDPOINT_FLAG_PROVIDES_SESSION      (1 << 0)
1001 +       uint32_t flags;                         /**< additional flags */
1002 +#define PW_ENDPOINT_CHANGE_MASK_STREAMS                (1 << 0)
1003 +#define PW_ENDPOINT_CHANGE_MASK_SESSION                (1 << 1)
1004 +#define PW_ENDPOINT_CHANGE_MASK_PROPS          (1 << 2)
1005 +#define PW_ENDPOINT_CHANGE_MASK_PARAMS         (1 << 3)
1006 +#define PW_ENDPOINT_CHANGE_MASK_ALL            ((1 << 4)-1)
1007 +       uint32_t change_mask;                   /**< bitfield of changed fields since last call */
1008 +       uint32_t n_streams;                     /**< number of streams available */
1009 +       uint32_t session_id;                    /**< the id of the controlling session */
1010 +       struct spa_dict *props;                 /**< extra properties */
1011 +       struct spa_param_info *params;          /**< parameters */
1012 +       uint32_t n_params;                      /**< number of items in \a params */
1013 +};
1014 +
1015 +struct pw_endpoint_stream_info {
1016 +#define PW_VERSION_ENDPOINT_STREAM_INFO                0
1017 +       uint32_t version;                       /**< version of this structure */
1018 +       uint32_t id;                            /**< the stream id (local or global) */
1019 +       uint32_t endpoint_id;                   /**< the endpoint id (global) */
1020 +       char *name;                             /**< name of the stream */
1021 +#define PW_ENDPOINT_STREAM_CHANGE_MASK_LINK_PARAMS     (1 << 0)
1022 +#define PW_ENDPOINT_STREAM_CHANGE_MASK_PROPS           (1 << 1)
1023 +#define PW_ENDPOINT_STREAM_CHANGE_MASK_PARAMS          (1 << 2)
1024 +#define PW_ENDPOINT_STREAM_CHANGE_MASK_ALL             ((1 << 3)-1)
1025 +       uint32_t change_mask;                   /**< bitfield of changed fields since last call */
1026 +       struct spa_pod *link_params;            /**< information for linking this stream */
1027 +       struct spa_dict *props;                 /**< extra properties */
1028 +       struct spa_param_info *params;          /**< parameters */
1029 +       uint32_t n_params;                      /**< number of items in \a params */
1030 +};
1031 +
1032 +struct pw_endpoint_link_info {
1033 +#define PW_VERSION_ENDPOINT_LINK_INFO          0
1034 +       uint32_t version;                       /**< version of this structure */
1035 +       uint32_t id;                            /**< the link id (global) */
1036 +       uint32_t session_id;                    /**< the session id (global) */
1037 +       uint32_t output_endpoint_id;            /**< the output endpoint id (global) */
1038 +       uint32_t output_stream_id;              /**< the output stream id (local or global) */
1039 +       uint32_t input_endpoint_id;             /**< the input endpoint id (global) */
1040 +       uint32_t input_stream_id;               /**< the input stream id (local or global) */
1041 +#define PW_ENDPOINT_LINK_CHANGE_MASK_STATE     (1 << 0)
1042 +#define PW_ENDPOINT_LINK_CHANGE_MASK_PROPS     (1 << 1)
1043 +#define PW_ENDPOINT_LINK_CHANGE_MASK_PARAMS    (1 << 2)
1044 +#define PW_ENDPOINT_LINK_CHANGE_MASK_ALL       ((1 << 3)-1)
1045 +       uint32_t change_mask;                   /**< bitfield of changed fields since last call */
1046 +       enum pw_endpoint_link_state state;      /**< the state of the link */
1047 +       char *error;                            /**< error string if state == ERROR */
1048 +       struct spa_dict *props;                 /**< extra properties */
1049 +       struct spa_param_info *params;          /**< parameters */
1050 +       uint32_t n_params;                      /**< number of items in \a params */
1051 +};
1052 +
1053 +#ifdef __cplusplus
1054 +}  /* extern "C" */
1055 +#endif
1056 +
1057 +#endif /* PIPEWIRE_EXT_SESSION_MANAGER_INTROSPECT_H */
1058 diff --git a/src/extensions/session-manager/keys.h b/src/extensions/session-manager/keys.h
1059 new file mode 100644
1060 index 00000000..a7167510
1061 --- /dev/null
1062 +++ b/src/extensions/session-manager/keys.h
1063 @@ -0,0 +1,40 @@
1064 +/* PipeWire
1065 + *
1066 + * Copyright © 2019 Collabora Ltd.
1067 + *   @author George Kiagiadakis <george.kiagiadakis@collabora.com>
1068 + *
1069 + * Permission is hereby granted, free of charge, to any person obtaining a
1070 + * copy of this software and associated documentation files (the "Software"),
1071 + * to deal in the Software without restriction, including without limitation
1072 + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
1073 + * and/or sell copies of the Software, and to permit persons to whom the
1074 + * Software is furnished to do so, subject to the following conditions:
1075 + *
1076 + * The above copyright notice and this permission notice (including the next
1077 + * paragraph) shall be included in all copies or substantial portions of the
1078 + * Software.
1079 + *
1080 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1081 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1082 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1083 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1084 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
1085 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
1086 + * DEALINGS IN THE SOFTWARE.
1087 + */
1088 +
1089 +#ifndef PIPEWIRE_EXT_SESSION_MANAGER_KEYS_H
1090 +#define PIPEWIRE_EXT_SESSION_MANAGER_KEYS_H
1091 +
1092 +#ifdef __cplusplus
1093 +extern "C" {
1094 +#endif
1095 +
1096 +#define PW_KEY_ENDPOINT_ID     "endpoint.id"
1097 +#define PW_KEY_SESSION_ID      "session.id"
1098 +
1099 +#ifdef __cplusplus
1100 +}
1101 +#endif
1102 +
1103 +#endif /* PIPEWIRE_EXT_SESSION_MANAGER_KEYS_H */
1104 diff --git a/src/modules/meson.build b/src/modules/meson.build
1105 index bec6f558..23e8bba3 100644
1106 --- a/src/modules/meson.build
1107 +++ b/src/modules/meson.build
1108 @@ -99,3 +99,20 @@ pipewire_module_adapter = shared_library('pipewire-module-adapter',
1109    install_dir : modules_install_dir,
1110    dependencies : [mathlib, dl_lib, rt_lib, pipewire_dep],
1111  )
1112 +
1113 +pipewire_module_session_manager = shared_library('pipewire-module-session-manager',
1114 +  [ 'module-session-manager.c',
1115 +    'module-session-manager/client-endpoint.c',
1116 +    'module-session-manager/client-session.c',
1117 +    'module-session-manager/endpoint-link.c',
1118 +    'module-session-manager/endpoint-stream.c',
1119 +    'module-session-manager/endpoint.c',
1120 +    'module-session-manager/session.c',
1121 +    'module-session-manager/protocol-native.c',
1122 +  ],
1123 +  c_args : pipewire_module_c_args,
1124 +  include_directories : [configinc, spa_inc],
1125 +  install : true,
1126 +  install_dir : modules_install_dir,
1127 +  dependencies : [mathlib, dl_lib, pipewire_dep],
1128 +)
1129 diff --git a/src/modules/module-session-manager.c b/src/modules/module-session-manager.c
1130 new file mode 100644
1131 index 00000000..dbea3357
1132 --- /dev/null
1133 +++ b/src/modules/module-session-manager.c
1134 @@ -0,0 +1,56 @@
1135 +/* PipeWire
1136 + *
1137 + * Copyright © 2019 Collabora Ltd.
1138 + *   @author George Kiagiadakis <george.kiagiadakis@collabora.com>
1139 + *
1140 + * Permission is hereby granted, free of charge, to any person obtaining a
1141 + * copy of this software and associated documentation files (the "Software"),
1142 + * to deal in the Software without restriction, including without limitation
1143 + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
1144 + * and/or sell copies of the Software, and to permit persons to whom the
1145 + * Software is furnished to do so, subject to the following conditions:
1146 + *
1147 + * The above copyright notice and this permission notice (including the next
1148 + * paragraph) shall be included in all copies or substantial portions of the
1149 + * Software.
1150 + *
1151 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1152 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1153 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1154 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1155 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
1156 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
1157 + * DEALINGS IN THE SOFTWARE.
1158 + */
1159 +
1160 +#include "config.h"
1161 +
1162 +#include <pipewire/pipewire.h>
1163 +
1164 +/* client-endpoint.c */
1165 +int client_endpoint_factory_init(struct pw_module *module);
1166 +/* client-session.c */
1167 +int client_session_factory_init(struct pw_module *module);
1168 +/* protocol-native.c */
1169 +struct pw_protocol *pw_protocol_native_ext_session_manager_init(struct pw_core *core);
1170 +
1171 +static const struct spa_dict_item module_props[] = {
1172 +       { PW_KEY_MODULE_AUTHOR, "George Kiagiadakis <george.kiagiadakis@collabora.com>" },
1173 +       { PW_KEY_MODULE_DESCRIPTION, "Implements objects for session management" },
1174 +       { PW_KEY_MODULE_VERSION, PACKAGE_VERSION },
1175 +};
1176 +
1177 +SPA_EXPORT
1178 +int pipewire__module_init(struct pw_module *module, const char *args)
1179 +{
1180 +       struct pw_core *core = pw_module_get_core(module);
1181 +
1182 +       client_endpoint_factory_init(module);
1183 +       client_session_factory_init(module);
1184 +
1185 +       pw_protocol_native_ext_session_manager_init(core);
1186 +
1187 +       pw_module_update_properties(module, &SPA_DICT_INIT_ARRAY(module_props));
1188 +
1189 +       return 0;
1190 +}
1191 diff --git a/src/modules/module-session-manager/client-endpoint.c b/src/modules/module-session-manager/client-endpoint.c
1192 new file mode 100644
1193 index 00000000..0e501c9f
1194 --- /dev/null
1195 +++ b/src/modules/module-session-manager/client-endpoint.c
1196 @@ -0,0 +1,270 @@
1197 +/* PipeWire
1198 + *
1199 + * Copyright © 2019 Collabora Ltd.
1200 + *   @author George Kiagiadakis <george.kiagiadakis@collabora.com>
1201 + *
1202 + * Permission is hereby granted, free of charge, to any person obtaining a
1203 + * copy of this software and associated documentation files (the "Software"),
1204 + * to deal in the Software without restriction, including without limitation
1205 + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
1206 + * and/or sell copies of the Software, and to permit persons to whom the
1207 + * Software is furnished to do so, subject to the following conditions:
1208 + *
1209 + * The above copyright notice and this permission notice (including the next
1210 + * paragraph) shall be included in all copies or substantial portions of the
1211 + * Software.
1212 + *
1213 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1214 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1215 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1216 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1217 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
1218 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
1219 + * DEALINGS IN THE SOFTWARE.
1220 + */
1221 +
1222 +#include <stdbool.h>
1223 +#include <string.h>
1224 +
1225 +#include <pipewire/pipewire.h>
1226 +#include <extensions/session-manager.h>
1227 +
1228 +#include "client-endpoint.h"
1229 +#include "endpoint.h"
1230 +#include "endpoint-stream.h"
1231 +
1232 +#include <pipewire/private.h>
1233 +
1234 +#define NAME "client-endpoint"
1235 +
1236 +struct factory_data {
1237 +       struct pw_factory *factory;
1238 +       struct pw_module *module;
1239 +       struct spa_hook module_listener;
1240 +};
1241 +
1242 +static struct endpoint_stream *find_stream(struct client_endpoint *this, uint32_t id)
1243 +{
1244 +       struct endpoint_stream *s;
1245 +       spa_list_for_each(s, &this->streams, link) {
1246 +               if (s->id == id)
1247 +                       return s;
1248 +       }
1249 +       return NULL;
1250 +}
1251 +
1252 +static int client_endpoint_update(void *object,
1253 +                               uint32_t change_mask,
1254 +                               uint32_t n_params,
1255 +                               const struct spa_pod **params,
1256 +                               const struct pw_endpoint_info *info)
1257 +{
1258 +       struct client_endpoint *this = object;
1259 +       struct endpoint *endpoint = &this->endpoint;
1260 +
1261 +       return endpoint_update(endpoint, change_mask, n_params, params, info);
1262 +}
1263 +
1264 +static int client_endpoint_stream_update(void *object,
1265 +                               uint32_t stream_id,
1266 +                               uint32_t change_mask,
1267 +                               uint32_t n_params,
1268 +                               const struct spa_pod **params,
1269 +                               const struct pw_endpoint_stream_info *info)
1270 +{
1271 +       struct client_endpoint *this = object;
1272 +       struct endpoint *endpoint = &this->endpoint;
1273 +       struct endpoint_stream *stream = find_stream(this, stream_id);
1274 +       struct pw_properties *props = NULL;
1275 +
1276 +       if (!stream) {
1277 +               struct pw_core *core = pw_global_get_core(endpoint->global);
1278 +               const char *keys[] = {
1279 +                       PW_KEY_FACTORY_ID,
1280 +                       PW_KEY_CLIENT_ID,
1281 +                       PW_KEY_ENDPOINT_ID,
1282 +                       NULL
1283 +               };
1284 +
1285 +               stream = calloc(1, sizeof(struct endpoint_stream));
1286 +               if (!stream)
1287 +                       goto no_mem;
1288 +
1289 +               props = pw_properties_new(NULL, NULL);
1290 +               if (!props)
1291 +                       goto no_mem;
1292 +               pw_properties_copy_keys (endpoint->props, props, keys);
1293 +
1294 +               if (endpoint_stream_init(stream, stream_id, endpoint->info.id,
1295 +                                       this, core, props) < 0)
1296 +                       goto no_mem;
1297 +
1298 +               spa_list_append(&this->streams, &stream->link);
1299 +       }
1300 +       else if (change_mask & PW_CLIENT_ENDPOINT_STREAM_UPDATE_DESTROYED) {
1301 +               endpoint_stream_clear(stream);
1302 +               spa_list_remove(&stream->link);
1303 +               free(stream);
1304 +               stream = NULL;
1305 +       }
1306 +
1307 +       return stream ?
1308 +               endpoint_stream_update(stream, change_mask, n_params, params, info)
1309 +               : 0;
1310 +
1311 +       no_mem:
1312 +       if (props)
1313 +               pw_properties_free(props);
1314 +       free(stream);
1315 +       pw_log_error(NAME" %p: cannot update stream: no memory", this);
1316 +       pw_resource_error(this->resource, -ENOMEM,
1317 +               NAME" %p: cannot update stream: no memory", this);
1318 +       return -ENOMEM;
1319 +}
1320 +
1321 +static struct pw_client_endpoint_proxy_methods methods = {
1322 +       PW_VERSION_CLIENT_ENDPOINT_PROXY_METHODS,
1323 +       .update = client_endpoint_update,
1324 +       .stream_update = client_endpoint_stream_update,
1325 +};
1326 +
1327 +static void client_endpoint_destroy(void *data)
1328 +{
1329 +       struct client_endpoint *this = data;
1330 +       struct endpoint_stream *s;
1331 +
1332 +       pw_log_debug(NAME" %p: destroy", this);
1333 +
1334 +       spa_list_consume(s, &this->streams, link) {
1335 +               endpoint_stream_clear(s);
1336 +               spa_list_remove(&s->link);
1337 +               free(s);
1338 +       }
1339 +       endpoint_clear(&this->endpoint);
1340 +       spa_hook_remove(&this->resource_listener);
1341 +
1342 +       free(this);
1343 +}
1344 +
1345 +static const struct pw_resource_events resource_events = {
1346 +       PW_VERSION_RESOURCE_EVENTS,
1347 +       .destroy = client_endpoint_destroy,
1348 +};
1349 +
1350 +static void *create_object(void *data,
1351 +                          struct pw_resource *owner_resource,
1352 +                          uint32_t type,
1353 +                          uint32_t version,
1354 +                          struct pw_properties *properties,
1355 +                          uint32_t new_id)
1356 +{
1357 +       struct factory_data *d = data;
1358 +       struct pw_factory *factory = d->factory;
1359 +       struct client_endpoint *this;
1360 +       struct pw_client *owner = pw_resource_get_client(owner_resource);
1361 +       struct pw_core *core = pw_client_get_core(owner);
1362 +
1363 +       this = calloc(1, sizeof(struct client_endpoint));
1364 +       if (this == NULL)
1365 +               goto no_mem;
1366 +
1367 +       spa_list_init(&this->streams);
1368 +
1369 +       pw_log_debug(NAME" %p: new", this);
1370 +
1371 +       if (!properties)
1372 +               properties = pw_properties_new(NULL, NULL);
1373 +       if (!properties)
1374 +               goto no_mem;
1375 +
1376 +       pw_properties_setf(properties, PW_KEY_CLIENT_ID, "%d", owner->global->id);
1377 +       pw_properties_setf(properties, PW_KEY_FACTORY_ID, "%d", factory->global->id);
1378 +
1379 +       this->resource = pw_resource_new(owner, new_id, PW_PERM_RWX, type, version, 0);
1380 +       if (this->resource == NULL)
1381 +               goto no_mem;
1382 +
1383 +       if (endpoint_init(&this->endpoint, this, core, properties) < 0)
1384 +               goto no_mem;
1385 +
1386 +       pw_resource_add_listener(this->resource, &this->resource_listener,
1387 +                                &resource_events, this);
1388 +       pw_resource_add_object_listener(this->resource, &this->object_listener,
1389 +                                       &methods, this);
1390 +
1391 +       return this;
1392 +
1393 +      no_mem:
1394 +       if (properties)
1395 +               pw_properties_free(properties);
1396 +       if (this && this->resource)
1397 +               pw_resource_destroy(this->resource);
1398 +       free(this);
1399 +       pw_log_error("can't create client endpoint: no memory");
1400 +       pw_resource_error(owner_resource, -ENOMEM,
1401 +                       "can't create client endpoint: no memory");
1402 +       return NULL;
1403 +}
1404 +
1405 +static const struct pw_factory_implementation impl_factory = {
1406 +       PW_VERSION_FACTORY_IMPLEMENTATION,
1407 +       .create_object = create_object,
1408 +};
1409 +
1410 +static void module_destroy(void *data)
1411 +{
1412 +       struct factory_data *d = data;
1413 +
1414 +       spa_hook_remove(&d->module_listener);
1415 +       pw_factory_destroy(d->factory);
1416 +}
1417 +
1418 +static void module_registered(void *data)
1419 +{
1420 +       struct factory_data *d = data;
1421 +       struct pw_module *module = d->module;
1422 +       struct pw_factory *factory = d->factory;
1423 +       struct spa_dict_item items[1];
1424 +       char id[16];
1425 +       int res;
1426 +
1427 +       snprintf(id, sizeof(id), "%d", module->global->id);
1428 +       items[0] = SPA_DICT_ITEM_INIT(PW_KEY_MODULE_ID, id);
1429 +       pw_factory_update_properties(factory, &SPA_DICT_INIT(items, 1));
1430 +
1431 +       if ((res = pw_factory_register(factory, NULL)) < 0) {
1432 +               pw_log_error(NAME" %p: can't register factory: %s", factory, spa_strerror(res));
1433 +       }
1434 +}
1435 +
1436 +static const struct pw_module_events module_events = {
1437 +       PW_VERSION_MODULE_EVENTS,
1438 +       .destroy = module_destroy,
1439 +       .registered = module_registered,
1440 +};
1441 +
1442 +int client_endpoint_factory_init(struct pw_module *module)
1443 +{
1444 +       struct pw_core *core = pw_module_get_core(module);
1445 +       struct pw_factory *factory;
1446 +       struct factory_data *data;
1447 +
1448 +       factory = pw_factory_new(core,
1449 +                                "client-endpoint",
1450 +                                PW_TYPE_INTERFACE_ClientEndpoint,
1451 +                                PW_VERSION_CLIENT_ENDPOINT_PROXY,
1452 +                                NULL,
1453 +                                sizeof(*data));
1454 +       if (factory == NULL)
1455 +               return -ENOMEM;
1456 +
1457 +       data = pw_factory_get_user_data(factory);
1458 +       data->factory = factory;
1459 +       data->module = module;
1460 +
1461 +       pw_factory_set_implementation(factory, &impl_factory, data);
1462 +
1463 +       pw_module_add_listener(module, &data->module_listener, &module_events, data);
1464 +
1465 +       return 0;
1466 +}
1467 diff --git a/src/modules/module-session-manager/client-endpoint.h b/src/modules/module-session-manager/client-endpoint.h
1468 new file mode 100644
1469 index 00000000..394e9fa8
1470 --- /dev/null
1471 +++ b/src/modules/module-session-manager/client-endpoint.h
1472 @@ -0,0 +1,60 @@
1473 +/* PipeWire
1474 + *
1475 + * Copyright © 2019 Collabora Ltd.
1476 + *   @author George Kiagiadakis <george.kiagiadakis@collabora.com>
1477 + *
1478 + * Permission is hereby granted, free of charge, to any person obtaining a
1479 + * copy of this software and associated documentation files (the "Software"),
1480 + * to deal in the Software without restriction, including without limitation
1481 + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
1482 + * and/or sell copies of the Software, and to permit persons to whom the
1483 + * Software is furnished to do so, subject to the following conditions:
1484 + *
1485 + * The above copyright notice and this permission notice (including the next
1486 + * paragraph) shall be included in all copies or substantial portions of the
1487 + * Software.
1488 + *
1489 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1490 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1491 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1492 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1493 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
1494 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
1495 + * DEALINGS IN THE SOFTWARE.
1496 + */
1497 +
1498 +#ifndef MODULE_SESSION_MANAGER_CLIENT_ENDPOINT_H
1499 +#define MODULE_SESSION_MANAGER_CLIENT_ENDPOINT_H
1500 +
1501 +#include "endpoint.h"
1502 +
1503 +#ifdef __cplusplus
1504 +extern "C" {
1505 +#endif
1506 +
1507 +struct client_endpoint {
1508 +       struct pw_resource *resource;
1509 +       struct spa_hook resource_listener;
1510 +       struct spa_hook object_listener;
1511 +       struct endpoint endpoint;
1512 +       struct spa_list streams;
1513 +};
1514 +
1515 +#define pw_client_endpoint_resource(r,m,v,...) \
1516 +       pw_resource_call_res(r,struct pw_client_endpoint_proxy_events,m,v,__VA_ARGS__)
1517 +#define pw_client_endpoint_resource_set_id(r,...)      \
1518 +       pw_client_endpoint_resource(r,set_id,0,__VA_ARGS__)
1519 +#define pw_client_endpoint_resource_set_session_id(r,...)      \
1520 +       pw_client_endpoint_resource(r,set_session_id,0,__VA_ARGS__)
1521 +#define pw_client_endpoint_resource_set_param(r,...)   \
1522 +       pw_client_endpoint_resource(r,set_param,0,__VA_ARGS__)
1523 +#define pw_client_endpoint_resource_stream_set_param(r,...)    \
1524 +       pw_client_endpoint_resource(r,stream_set_param,0,__VA_ARGS__)
1525 +
1526 +int client_endpoint_factory_init(struct pw_module *module);
1527 +
1528 +#ifdef __cplusplus
1529 +}  /* extern "C" */
1530 +#endif
1531 +
1532 +#endif /* MODULE_SESSION_MANAGER_CLIENT_ENDPOINT_H */
1533 diff --git a/src/modules/module-session-manager/client-session.c b/src/modules/module-session-manager/client-session.c
1534 new file mode 100644
1535 index 00000000..9b20d833
1536 --- /dev/null
1537 +++ b/src/modules/module-session-manager/client-session.c
1538 @@ -0,0 +1,270 @@
1539 +/* PipeWire
1540 + *
1541 + * Copyright © 2019 Collabora Ltd.
1542 + *   @author George Kiagiadakis <george.kiagiadakis@collabora.com>
1543 + *
1544 + * Permission is hereby granted, free of charge, to any person obtaining a
1545 + * copy of this software and associated documentation files (the "Software"),
1546 + * to deal in the Software without restriction, including without limitation
1547 + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
1548 + * and/or sell copies of the Software, and to permit persons to whom the
1549 + * Software is furnished to do so, subject to the following conditions:
1550 + *
1551 + * The above copyright notice and this permission notice (including the next
1552 + * paragraph) shall be included in all copies or substantial portions of the
1553 + * Software.
1554 + *
1555 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1556 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1557 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1558 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1559 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
1560 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
1561 + * DEALINGS IN THE SOFTWARE.
1562 + */
1563 +
1564 +#include <stdbool.h>
1565 +#include <string.h>
1566 +
1567 +#include <pipewire/pipewire.h>
1568 +#include <extensions/session-manager.h>
1569 +
1570 +#include "client-session.h"
1571 +#include "session.h"
1572 +#include "endpoint-link.h"
1573 +
1574 +#include <pipewire/private.h>
1575 +
1576 +#define NAME "client-session"
1577 +
1578 +struct factory_data {
1579 +       struct pw_factory *factory;
1580 +       struct pw_module *module;
1581 +       struct spa_hook module_listener;
1582 +};
1583 +
1584 +static struct endpoint_link *find_link(struct client_session *this, uint32_t id)
1585 +{
1586 +       struct endpoint_link *l;
1587 +       spa_list_for_each(l, &this->links, link) {
1588 +               if (l->id == id)
1589 +                       return l;
1590 +       }
1591 +       return NULL;
1592 +}
1593 +
1594 +static int client_session_update(void *object,
1595 +                               uint32_t change_mask,
1596 +                               uint32_t n_params,
1597 +                               const struct spa_pod **params,
1598 +                               const struct pw_session_info *info)
1599 +{
1600 +       struct client_session *this = object;
1601 +       struct session *session = &this->session;
1602 +
1603 +       return session_update(session, change_mask, n_params, params, info);
1604 +}
1605 +
1606 +static int client_session_link_update(void *object,
1607 +                               uint32_t link_id,
1608 +                               uint32_t change_mask,
1609 +                               uint32_t n_params,
1610 +                               const struct spa_pod **params,
1611 +                               const struct pw_endpoint_link_info *info)
1612 +{
1613 +       struct client_session *this = object;
1614 +       struct session *session = &this->session;
1615 +       struct endpoint_link *link = find_link(this, link_id);
1616 +       struct pw_properties *props = NULL;
1617 +
1618 +       if (!link) {
1619 +               struct pw_core *core = pw_global_get_core(session->global);
1620 +               const char *keys[] = {
1621 +                       PW_KEY_FACTORY_ID,
1622 +                       PW_KEY_CLIENT_ID,
1623 +                       PW_KEY_SESSION_ID,
1624 +                       NULL
1625 +               };
1626 +
1627 +               link = calloc(1, sizeof(struct endpoint_link));
1628 +               if (!link)
1629 +                       goto no_mem;
1630 +
1631 +               props = pw_properties_new(NULL, NULL);
1632 +               if (!props)
1633 +                       goto no_mem;
1634 +               pw_properties_copy_keys (session->props, props, keys);
1635 +
1636 +               if (endpoint_link_init(link, link_id, session->info.id,
1637 +                                       this, core, props) < 0)
1638 +                       goto no_mem;
1639 +
1640 +               spa_list_append(&this->links, &link->link);
1641 +       }
1642 +       else if (change_mask & PW_CLIENT_SESSION_LINK_UPDATE_DESTROYED) {
1643 +               endpoint_link_clear(link);
1644 +               spa_list_remove(&link->link);
1645 +               free(link);
1646 +               link = NULL;
1647 +       }
1648 +
1649 +       return link ?
1650 +               endpoint_link_update(link, change_mask, n_params, params, info)
1651 +               : 0;
1652 +
1653 +       no_mem:
1654 +       if (props)
1655 +               pw_properties_free(props);
1656 +       free(link);
1657 +       pw_log_error(NAME" %p: cannot update link: no memory", this);
1658 +       pw_resource_error(this->resource, -ENOMEM,
1659 +               NAME" %p: cannot update link: no memory", this);
1660 +       return -ENOMEM;
1661 +}
1662 +
1663 +static struct pw_client_session_proxy_methods methods = {
1664 +       PW_VERSION_CLIENT_SESSION_PROXY_METHODS,
1665 +       .update = client_session_update,
1666 +       .link_update = client_session_link_update,
1667 +};
1668 +
1669 +static void client_session_destroy(void *data)
1670 +{
1671 +       struct client_session *this = data;
1672 +       struct endpoint_link *l;
1673 +
1674 +       pw_log_debug(NAME" %p: destroy", this);
1675 +
1676 +       spa_list_consume(l, &this->links, link) {
1677 +               endpoint_link_clear(l);
1678 +               spa_list_remove(&l->link);
1679 +               free(l);
1680 +       }
1681 +       session_clear(&this->session);
1682 +       spa_hook_remove(&this->resource_listener);
1683 +
1684 +       free(this);
1685 +}
1686 +
1687 +static const struct pw_resource_events resource_events = {
1688 +       PW_VERSION_RESOURCE_EVENTS,
1689 +       .destroy = client_session_destroy,
1690 +};
1691 +
1692 +static void *create_object(void *data,
1693 +                          struct pw_resource *owner_resource,
1694 +                          uint32_t type,
1695 +                          uint32_t version,
1696 +                          struct pw_properties *properties,
1697 +                          uint32_t new_id)
1698 +{
1699 +       struct factory_data *d = data;
1700 +       struct pw_factory *factory = d->factory;
1701 +       struct client_session *this;
1702 +       struct pw_client *owner = pw_resource_get_client(owner_resource);
1703 +       struct pw_core *core = pw_client_get_core(owner);
1704 +
1705 +       this = calloc(1, sizeof(struct client_session));
1706 +       if (this == NULL)
1707 +               goto no_mem;
1708 +
1709 +       spa_list_init(&this->links);
1710 +
1711 +       pw_log_debug(NAME" %p: new", this);
1712 +
1713 +       if (!properties)
1714 +               properties = pw_properties_new(NULL, NULL);
1715 +       if (!properties)
1716 +               goto no_mem;
1717 +
1718 +       pw_properties_setf(properties, PW_KEY_CLIENT_ID, "%d", owner->global->id);
1719 +       pw_properties_setf(properties, PW_KEY_FACTORY_ID, "%d", factory->global->id);
1720 +
1721 +       this->resource = pw_resource_new(owner, new_id, PW_PERM_RWX, type, version, 0);
1722 +       if (this->resource == NULL)
1723 +               goto no_mem;
1724 +
1725 +       if (session_init(&this->session, this, core, properties) < 0)
1726 +               goto no_mem;
1727 +
1728 +       pw_resource_add_listener(this->resource, &this->resource_listener,
1729 +                                &resource_events, this);
1730 +       pw_resource_add_object_listener(this->resource, &this->object_listener,
1731 +                                       &methods, this);
1732 +
1733 +       return this;
1734 +
1735 +      no_mem:
1736 +       if (properties)
1737 +               pw_properties_free(properties);
1738 +       if (this && this->resource)
1739 +               pw_resource_destroy(this->resource);
1740 +       free(this);
1741 +       pw_log_error("can't create client session: no memory");
1742 +       pw_resource_error(owner_resource, -ENOMEM,
1743 +                       "can't create client session: no memory");
1744 +       return NULL;
1745 +}
1746 +
1747 +static const struct pw_factory_implementation impl_factory = {
1748 +       PW_VERSION_FACTORY_IMPLEMENTATION,
1749 +       .create_object = create_object,
1750 +};
1751 +
1752 +static void module_destroy(void *data)
1753 +{
1754 +       struct factory_data *d = data;
1755 +
1756 +       spa_hook_remove(&d->module_listener);
1757 +       pw_factory_destroy(d->factory);
1758 +}
1759 +
1760 +static void module_registered(void *data)
1761 +{
1762 +       struct factory_data *d = data;
1763 +       struct pw_module *module = d->module;
1764 +       struct pw_factory *factory = d->factory;
1765 +       struct spa_dict_item items[1];
1766 +       char id[16];
1767 +       int res;
1768 +
1769 +       snprintf(id, sizeof(id), "%d", module->global->id);
1770 +       items[0] = SPA_DICT_ITEM_INIT(PW_KEY_MODULE_ID, id);
1771 +       pw_factory_update_properties(factory, &SPA_DICT_INIT(items, 1));
1772 +
1773 +       if ((res = pw_factory_register(factory, NULL)) < 0) {
1774 +               pw_log_error(NAME" %p: can't register factory: %s", factory, spa_strerror(res));
1775 +       }
1776 +}
1777 +
1778 +static const struct pw_module_events module_events = {
1779 +       PW_VERSION_MODULE_EVENTS,
1780 +       .destroy = module_destroy,
1781 +       .registered = module_registered,
1782 +};
1783 +
1784 +int client_session_factory_init(struct pw_module *module)
1785 +{
1786 +       struct pw_core *core = pw_module_get_core(module);
1787 +       struct pw_factory *factory;
1788 +       struct factory_data *data;
1789 +
1790 +       factory = pw_factory_new(core,
1791 +                                "client-session",
1792 +                                PW_TYPE_INTERFACE_ClientSession,
1793 +                                PW_VERSION_CLIENT_SESSION_PROXY,
1794 +                                NULL,
1795 +                                sizeof(*data));
1796 +       if (factory == NULL)
1797 +               return -ENOMEM;
1798 +
1799 +       data = pw_factory_get_user_data(factory);
1800 +       data->factory = factory;
1801 +       data->module = module;
1802 +
1803 +       pw_factory_set_implementation(factory, &impl_factory, data);
1804 +
1805 +       pw_module_add_listener(module, &data->module_listener, &module_events, data);
1806 +
1807 +       return 0;
1808 +}
1809 diff --git a/src/modules/module-session-manager/client-session.h b/src/modules/module-session-manager/client-session.h
1810 new file mode 100644
1811 index 00000000..c764564d
1812 --- /dev/null
1813 +++ b/src/modules/module-session-manager/client-session.h
1814 @@ -0,0 +1,62 @@
1815 +/* PipeWire
1816 + *
1817 + * Copyright © 2019 Collabora Ltd.
1818 + *   @author George Kiagiadakis <george.kiagiadakis@collabora.com>
1819 + *
1820 + * Permission is hereby granted, free of charge, to any person obtaining a
1821 + * copy of this software and associated documentation files (the "Software"),
1822 + * to deal in the Software without restriction, including without limitation
1823 + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
1824 + * and/or sell copies of the Software, and to permit persons to whom the
1825 + * Software is furnished to do so, subject to the following conditions:
1826 + *
1827 + * The above copyright notice and this permission notice (including the next
1828 + * paragraph) shall be included in all copies or substantial portions of the
1829 + * Software.
1830 + *
1831 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1832 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1833 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1834 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1835 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
1836 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
1837 + * DEALINGS IN THE SOFTWARE.
1838 + */
1839 +
1840 +#ifndef MODULE_SESSION_MANAGER_CLIENT_SESSION_H
1841 +#define MODULE_SESSION_MANAGER_CLIENT_SESSION_H
1842 +
1843 +#include "session.h"
1844 +
1845 +#ifdef __cplusplus
1846 +extern "C" {
1847 +#endif
1848 +
1849 +struct client_session {
1850 +       struct pw_resource *resource;
1851 +       struct spa_hook resource_listener;
1852 +       struct spa_hook object_listener;
1853 +       struct session session;
1854 +       struct spa_list links;
1855 +};
1856 +
1857 +#define pw_client_session_resource(r,m,v,...)  \
1858 +       pw_resource_call_res(r,struct pw_client_session_proxy_events,m,v,__VA_ARGS__)
1859 +#define pw_client_session_resource_set_id(r,...)       \
1860 +       pw_client_session_resource(r,set_id,0,__VA_ARGS__)
1861 +#define pw_client_session_resource_set_param(r,...)    \
1862 +       pw_client_session_resource(r,set_param,0,__VA_ARGS__)
1863 +#define pw_client_session_resource_link_set_param(r,...)       \
1864 +       pw_client_session_resource(r,link_set_param,0,__VA_ARGS__)
1865 +#define pw_client_session_resource_create_link(r,...)  \
1866 +       pw_client_session_resource(r,create_link,0,__VA_ARGS__)
1867 +#define pw_client_session_resource_destroy_link(r,...) \
1868 +       pw_client_session_resource(r,destroy_link,0,__VA_ARGS__)
1869 +#define pw_client_session_resource_link_request_state(r,...)   \
1870 +       pw_client_session_resource(r,link_request_state,0,__VA_ARGS__)
1871 +
1872 +#ifdef __cplusplus
1873 +}  /* extern "C" */
1874 +#endif
1875 +
1876 +#endif /* MODULE_SESSION_MANAGER_CLIENT_SESSION_H */
1877 diff --git a/src/modules/module-session-manager/endpoint-link.c b/src/modules/module-session-manager/endpoint-link.c
1878 new file mode 100644
1879 index 00000000..bce06598
1880 --- /dev/null
1881 +++ b/src/modules/module-session-manager/endpoint-link.c
1882 @@ -0,0 +1,359 @@
1883 +/* PipeWire
1884 + *
1885 + * Copyright © 2019 Collabora Ltd.
1886 + *   @author George Kiagiadakis <george.kiagiadakis@collabora.com>
1887 + *
1888 + * Permission is hereby granted, free of charge, to any person obtaining a
1889 + * copy of this software and associated documentation files (the "Software"),
1890 + * to deal in the Software without restriction, including without limitation
1891 + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
1892 + * and/or sell copies of the Software, and to permit persons to whom the
1893 + * Software is furnished to do so, subject to the following conditions:
1894 + *
1895 + * The above copyright notice and this permission notice (including the next
1896 + * paragraph) shall be included in all copies or substantial portions of the
1897 + * Software.
1898 + *
1899 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1900 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1901 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1902 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1903 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
1904 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
1905 + * DEALINGS IN THE SOFTWARE.
1906 + */
1907 +
1908 +#include <stdbool.h>
1909 +#include <string.h>
1910 +
1911 +#include <pipewire/pipewire.h>
1912 +#include <extensions/session-manager.h>
1913 +
1914 +#include <spa/pod/filter.h>
1915 +
1916 +#include "endpoint-link.h"
1917 +#include "client-session.h"
1918 +
1919 +#include <pipewire/private.h>
1920 +
1921 +#define NAME "endpoint-link"
1922 +
1923 +struct resource_data {
1924 +       struct endpoint_link *link;
1925 +       struct spa_hook resource_listener;
1926 +       struct spa_hook object_listener;
1927 +       uint32_t n_subscribe_ids;
1928 +       uint32_t subscribe_ids[32];
1929 +};
1930 +
1931 +#define pw_endpoint_link_resource(r,m,v,...)   \
1932 +       pw_resource_call(r,struct pw_endpoint_link_proxy_events,m,v,__VA_ARGS__)
1933 +#define pw_endpoint_link_resource_info(r,...)  \
1934 +       pw_endpoint_link_resource(r,info,0,__VA_ARGS__)
1935 +#define pw_endpoint_link_resource_param(r,...) \
1936 +       pw_endpoint_link_resource(r,param,0,__VA_ARGS__)
1937 +
1938 +static int endpoint_link_enum_params (void *object, int seq,
1939 +                               uint32_t id, uint32_t start, uint32_t num,
1940 +                               const struct spa_pod *filter)
1941 +{
1942 +       struct pw_resource *resource = object;
1943 +       struct resource_data *data = pw_resource_get_user_data(resource);
1944 +       struct endpoint_link *this = data->link;
1945 +       struct spa_pod *result;
1946 +       struct spa_pod *param;
1947 +       uint8_t buffer[1024];
1948 +       struct spa_pod_builder b = { 0 };
1949 +       uint32_t index;
1950 +       uint32_t next = start;
1951 +       uint32_t count = 0;
1952 +
1953 +       while (true) {
1954 +               index = next++;
1955 +               if (index >= this->n_params)
1956 +                       break;
1957 +
1958 +               param = this->params[index];
1959 +
1960 +               if (param == NULL || !spa_pod_is_object_id(param, id))
1961 +                       continue;
1962 +
1963 +               spa_pod_builder_init(&b, buffer, sizeof(buffer));
1964 +               if (spa_pod_filter(&b, &result, param, filter) != 0)
1965 +                       continue;
1966 +
1967 +               pw_log_debug(NAME" %p: %d param %u", this, seq, index);
1968 +
1969 +               pw_endpoint_link_resource_param(resource, seq, id, index, next, result);
1970 +
1971 +               if (++count == num)
1972 +                       break;
1973 +       }
1974 +       return 0;
1975 +}
1976 +
1977 +static int endpoint_link_subscribe_params (void *object, uint32_t *ids, uint32_t n_ids)
1978 +{
1979 +       struct pw_resource *resource = object;
1980 +       struct resource_data *data = pw_resource_get_user_data(resource);
1981 +       uint32_t i;
1982 +
1983 +       n_ids = SPA_MIN(n_ids, SPA_N_ELEMENTS(data->subscribe_ids));
1984 +       data->n_subscribe_ids = n_ids;
1985 +
1986 +       for (i = 0; i < n_ids; i++) {
1987 +               data->subscribe_ids[i] = ids[i];
1988 +               pw_log_debug(NAME" %p: resource %d subscribe param %u",
1989 +                       data->link, resource->id, ids[i]);
1990 +               endpoint_link_enum_params(resource, 1, ids[i], 0, UINT32_MAX, NULL);
1991 +       }
1992 +       return 0;
1993 +}
1994 +
1995 +static int endpoint_link_set_param (void *object, uint32_t id, uint32_t flags,
1996 +                               const struct spa_pod *param)
1997 +{
1998 +       struct pw_resource *resource = object;
1999 +       struct resource_data *data = pw_resource_get_user_data(resource);
2000 +       struct endpoint_link *this = data->link;
2001 +
2002 +       pw_client_session_resource_set_param(this->client_sess->resource,
2003 +                                               id, flags, param);
2004 +
2005 +       return 0;
2006 +}
2007 +
2008 +static int endpoint_link_request_state(void *object, enum pw_endpoint_link_state state)
2009 +{
2010 +       struct pw_resource *resource = object;
2011 +       struct resource_data *data = pw_resource_get_user_data(resource);
2012 +       struct endpoint_link *this = data->link;
2013 +
2014 +       pw_client_session_resource_link_request_state(this->client_sess->resource,
2015 +                                                     this->id, state);
2016 +
2017 +       return 0;
2018 +}
2019 +
2020 +static int endpoint_link_destroy(void *object)
2021 +{
2022 +       struct pw_resource *resource = object;
2023 +       struct resource_data *data = pw_resource_get_user_data(resource);
2024 +       struct endpoint_link *this = data->link;
2025 +
2026 +       pw_client_session_resource_destroy_link(this->client_sess->resource,
2027 +                                               this->id);
2028 +
2029 +       return 0;
2030 +}
2031 +
2032 +static const struct pw_endpoint_link_proxy_methods methods = {
2033 +       PW_VERSION_ENDPOINT_LINK_PROXY_METHODS,
2034 +       .subscribe_params = endpoint_link_subscribe_params,
2035 +       .enum_params = endpoint_link_enum_params,
2036 +       .set_param = endpoint_link_set_param,
2037 +       .request_state = endpoint_link_request_state,
2038 +       .destroy = endpoint_link_destroy,
2039 +};
2040 +
2041 +static void endpoint_link_notify_subscribed(struct endpoint_link *this,
2042 +                                       uint32_t index, uint32_t next)
2043 +{
2044 +       struct pw_global *global = this->global;
2045 +       struct pw_resource *resource;
2046 +       struct resource_data *data;
2047 +       struct spa_pod *param = this->params[index];
2048 +       uint32_t id;
2049 +       uint32_t i;
2050 +
2051 +       if (!param || !spa_pod_is_object (param))
2052 +               return;
2053 +
2054 +       id = SPA_POD_OBJECT_ID (param);
2055 +
2056 +       spa_list_for_each(resource, &global->resource_list, link) {
2057 +               data = pw_resource_get_user_data(resource);
2058 +               for (i = 0; i < data->n_subscribe_ids; i++) {
2059 +                       if (data->subscribe_ids[i] == id) {
2060 +                               pw_endpoint_link_resource_param(resource, 1,
2061 +                                       id, index, next, param);
2062 +                       }
2063 +               }
2064 +       }
2065 +}
2066 +
2067 +int endpoint_link_update(struct endpoint_link *this,
2068 +                       uint32_t change_mask,
2069 +                       uint32_t n_params,
2070 +                       const struct spa_pod **params,
2071 +                       const struct pw_endpoint_link_info *info)
2072 +{
2073 +       if (change_mask & PW_CLIENT_SESSION_UPDATE_PARAMS) {
2074 +               uint32_t i;
2075 +               size_t size = n_params * sizeof(struct spa_pod *);
2076 +
2077 +               pw_log_debug(NAME" %p: update %d params", this, n_params);
2078 +
2079 +               for (i = 0; i < this->n_params; i++)
2080 +                       free(this->params[i]);
2081 +               this->params = realloc(this->params, size);
2082 +               if (size > 0 && !this->params) {
2083 +                       this->n_params = 0;
2084 +                       goto no_mem;
2085 +               }
2086 +               this->n_params = n_params;
2087 +
2088 +               for (i = 0; i < this->n_params; i++) {
2089 +                       this->params[i] = params[i] ? spa_pod_copy(params[i]) : NULL;
2090 +                       endpoint_link_notify_subscribed(this, i, i+1);
2091 +               }
2092 +       }
2093 +
2094 +       if (change_mask & PW_CLIENT_SESSION_UPDATE_INFO) {
2095 +               struct pw_resource *resource;
2096 +
2097 +               if (info->change_mask & PW_ENDPOINT_LINK_CHANGE_MASK_STATE) {
2098 +                       this->info.state = info->state;
2099 +                       free(this->info.error);
2100 +                       this->info.error = info->error ? strdup(info->error) : NULL;
2101 +               }
2102 +
2103 +               if (info->change_mask & PW_ENDPOINT_LINK_CHANGE_MASK_PROPS)
2104 +                       pw_properties_update(this->props, info->props);
2105 +
2106 +               if (info->change_mask & PW_ENDPOINT_LINK_CHANGE_MASK_PARAMS) {
2107 +                       size_t size = info->n_params * sizeof(struct spa_param_info);
2108 +
2109 +                       this->info.params = realloc(this->info.params, size);
2110 +                       if (size > 0 && !this->info.params) {
2111 +                               this->info.n_params = 0;
2112 +                               goto no_mem;
2113 +                       }
2114 +                       this->info.n_params = info->n_params;
2115 +
2116 +                       memcpy(this->info.params, info->params, size);
2117 +               }
2118 +
2119 +               if (!this->info.output_endpoint_id) {
2120 +                       this->info.output_endpoint_id = info->output_endpoint_id;
2121 +                       this->info.output_stream_id = info->output_stream_id;
2122 +                       this->info.input_endpoint_id = info->input_endpoint_id;
2123 +                       this->info.input_stream_id = info->input_stream_id;
2124 +               }
2125 +
2126 +               this->info.change_mask = info->change_mask;
2127 +               spa_list_for_each(resource, &this->global->resource_list, link) {
2128 +                       pw_endpoint_link_resource_info(resource, &this->info);
2129 +               }
2130 +               this->info.change_mask = 0;
2131 +       }
2132 +
2133 +       return 0;
2134 +
2135 +      no_mem:
2136 +       pw_log_error(NAME" %p: can't update: no memory", this);
2137 +       pw_resource_error(this->client_sess->resource, -ENOMEM,
2138 +                       NAME" %p: can't update: no memory", this);
2139 +       return -ENOMEM;
2140 +}
2141 +
2142 +static void endpoint_link_unbind(void *data)
2143 +{
2144 +       struct pw_resource *resource = data;
2145 +       spa_list_remove(&resource->link);
2146 +}
2147 +
2148 +static const struct pw_resource_events resource_events = {
2149 +       PW_VERSION_RESOURCE_EVENTS,
2150 +       .destroy = endpoint_link_unbind,
2151 +};
2152 +
2153 +static int endpoint_link_bind(void *_data, struct pw_client *client,
2154 +                       uint32_t permissions, uint32_t version, uint32_t id)
2155 +{
2156 +       struct endpoint_link *this = _data;
2157 +       struct pw_global *global = this->global;
2158 +       struct pw_resource *resource;
2159 +       struct resource_data *data;
2160 +
2161 +       resource = pw_resource_new(client, id, permissions, global->type, version, sizeof(*data));
2162 +       if (resource == NULL)
2163 +               goto no_mem;
2164 +
2165 +       data = pw_resource_get_user_data(resource);
2166 +       data->link = this;
2167 +       pw_resource_add_listener(resource, &data->resource_listener,
2168 +                               &resource_events, resource);
2169 +       pw_resource_add_object_listener(resource, &data->object_listener,
2170 +                                       &methods, resource);
2171 +
2172 +       pw_log_debug(NAME" %p: bound to %d", this, resource->id);
2173 +
2174 +       spa_list_append(&global->resource_list, &resource->link);
2175 +
2176 +       this->info.change_mask = PW_ENDPOINT_LINK_CHANGE_MASK_ALL;
2177 +       pw_endpoint_link_resource_info(resource, &this->info);
2178 +       this->info.change_mask = 0;
2179 +
2180 +       return 0;
2181 +
2182 +      no_mem:
2183 +       pw_log_error(NAME" %p: can't create resource: no memory", this);
2184 +       pw_resource_error(this->client_sess->resource, -ENOMEM,
2185 +                       NAME" %p: can't create resource: no memory", this);
2186 +       return -ENOMEM;
2187 +}
2188 +
2189 +int endpoint_link_init(struct endpoint_link *this,
2190 +               uint32_t id, uint32_t session_id,
2191 +               struct client_session *client_sess,
2192 +               struct pw_core *core,
2193 +               struct pw_properties *properties)
2194 +{
2195 +       pw_log_debug(NAME" %p: new", this);
2196 +
2197 +       this->client_sess = client_sess;
2198 +       this->id = id;
2199 +       this->props = properties;
2200 +
2201 +       properties = pw_properties_copy(properties);
2202 +       if (!properties)
2203 +               goto no_mem;
2204 +
2205 +       this->global = pw_global_new (core,
2206 +                       PW_TYPE_INTERFACE_EndpointLink,
2207 +                       PW_VERSION_ENDPOINT_LINK_PROXY,
2208 +                       properties, endpoint_link_bind, this);
2209 +       if (!this->global)
2210 +               goto no_mem;
2211 +
2212 +       this->info.version = PW_VERSION_ENDPOINT_LINK_INFO;
2213 +       this->info.id = this->global->id;
2214 +       this->info.session_id = session_id;
2215 +       this->info.props = &this->props->dict;
2216 +
2217 +       return pw_global_register(this->global);
2218 +
2219 +      no_mem:
2220 +       pw_log_error(NAME" - can't create - out of memory");
2221 +       return -ENOMEM;
2222 +}
2223 +
2224 +void endpoint_link_clear(struct endpoint_link *this)
2225 +{
2226 +       uint32_t i;
2227 +
2228 +       pw_log_debug(NAME" %p: destroy", this);
2229 +
2230 +       pw_global_destroy(this->global);
2231 +
2232 +       for (i = 0; i < this->n_params; i++)
2233 +               free(this->params[i]);
2234 +       free(this->params);
2235 +
2236 +       free(this->info.error);
2237 +       free(this->info.params);
2238 +
2239 +       if (this->props)
2240 +               pw_properties_free(this->props);
2241 +}
2242 diff --git a/src/modules/module-session-manager/endpoint-link.h b/src/modules/module-session-manager/endpoint-link.h
2243 new file mode 100644
2244 index 00000000..a9c18d32
2245 --- /dev/null
2246 +++ b/src/modules/module-session-manager/endpoint-link.h
2247 @@ -0,0 +1,64 @@
2248 +/* PipeWire
2249 + *
2250 + * Copyright © 2019 Collabora Ltd.
2251 + *   @author George Kiagiadakis <george.kiagiadakis@collabora.com>
2252 + *
2253 + * Permission is hereby granted, free of charge, to any person obtaining a
2254 + * copy of this software and associated documentation files (the "Software"),
2255 + * to deal in the Software without restriction, including without limitation
2256 + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
2257 + * and/or sell copies of the Software, and to permit persons to whom the
2258 + * Software is furnished to do so, subject to the following conditions:
2259 + *
2260 + * The above copyright notice and this permission notice (including the next
2261 + * paragraph) shall be included in all copies or substantial portions of the
2262 + * Software.
2263 + *
2264 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2265 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2266 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
2267 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2268 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
2269 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
2270 + * DEALINGS IN THE SOFTWARE.
2271 + */
2272 +
2273 +#ifndef MODULE_SESSION_MANAGER_ENDPOINT_LINK_H
2274 +#define MODULE_SESSION_MANAGER_ENDPOINT_LINK_H
2275 +
2276 +#ifdef __cplusplus
2277 +extern "C" {
2278 +#endif
2279 +
2280 +struct client_session;
2281 +
2282 +struct endpoint_link {
2283 +       struct spa_list link;
2284 +       struct client_session *client_sess;
2285 +       struct pw_global *global;
2286 +       uint32_t id;                    /* session-local link id */
2287 +       uint32_t n_params;
2288 +       struct spa_pod **params;
2289 +       struct pw_endpoint_link_info info;
2290 +       struct pw_properties *props;    /* wrapper of info.props */
2291 +};
2292 +
2293 +int endpoint_link_init(struct endpoint_link *this,
2294 +               uint32_t id, uint32_t session_id,
2295 +               struct client_session *client_sess,
2296 +               struct pw_core *core,
2297 +               struct pw_properties *properties);
2298 +
2299 +void endpoint_link_clear(struct endpoint_link *this);
2300 +
2301 +int endpoint_link_update(struct endpoint_link *this,
2302 +                       uint32_t change_mask,
2303 +                       uint32_t n_params,
2304 +                       const struct spa_pod **params,
2305 +                       const struct pw_endpoint_link_info *info);
2306 +
2307 +#ifdef __cplusplus
2308 +}  /* extern "C" */
2309 +#endif
2310 +
2311 +#endif /* MODULE_SESSION_MANAGER_ENDPOINT_LINK_H */
2312 diff --git a/src/modules/module-session-manager/endpoint-stream.c b/src/modules/module-session-manager/endpoint-stream.c
2313 new file mode 100644
2314 index 00000000..47d2a4ea
2315 --- /dev/null
2316 +++ b/src/modules/module-session-manager/endpoint-stream.c
2317 @@ -0,0 +1,329 @@
2318 +/* PipeWire
2319 + *
2320 + * Copyright © 2019 Collabora Ltd.
2321 + *   @author George Kiagiadakis <george.kiagiadakis@collabora.com>
2322 + *
2323 + * Permission is hereby granted, free of charge, to any person obtaining a
2324 + * copy of this software and associated documentation files (the "Software"),
2325 + * to deal in the Software without restriction, including without limitation
2326 + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
2327 + * and/or sell copies of the Software, and to permit persons to whom the
2328 + * Software is furnished to do so, subject to the following conditions:
2329 + *
2330 + * The above copyright notice and this permission notice (including the next
2331 + * paragraph) shall be included in all copies or substantial portions of the
2332 + * Software.
2333 + *
2334 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2335 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2336 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
2337 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2338 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
2339 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
2340 + * DEALINGS IN THE SOFTWARE.
2341 + */
2342 +
2343 +#include <stdbool.h>
2344 +#include <string.h>
2345 +
2346 +#include <pipewire/pipewire.h>
2347 +#include <extensions/session-manager.h>
2348 +
2349 +#include <spa/pod/filter.h>
2350 +
2351 +#include "endpoint-stream.h"
2352 +#include "client-endpoint.h"
2353 +
2354 +#include <pipewire/private.h>
2355 +
2356 +#define NAME "endpoint-stream"
2357 +
2358 +struct resource_data {
2359 +       struct endpoint_stream *stream;
2360 +       struct spa_hook resource_listener;
2361 +       struct spa_hook object_listener;
2362 +       uint32_t n_subscribe_ids;
2363 +       uint32_t subscribe_ids[32];
2364 +};
2365 +
2366 +#define pw_endpoint_stream_resource(r,m,v,...) \
2367 +       pw_resource_call(r,struct pw_endpoint_stream_proxy_events,m,v,__VA_ARGS__)
2368 +#define pw_endpoint_stream_resource_info(r,...)        \
2369 +       pw_endpoint_stream_resource(r,info,0,__VA_ARGS__)
2370 +#define pw_endpoint_stream_resource_param(r,...)       \
2371 +       pw_endpoint_stream_resource(r,param,0,__VA_ARGS__)
2372 +
2373 +static int endpoint_stream_enum_params (void *object, int seq,
2374 +                               uint32_t id, uint32_t start, uint32_t num,
2375 +                               const struct spa_pod *filter)
2376 +{
2377 +       struct pw_resource *resource = object;
2378 +       struct resource_data *data = pw_resource_get_user_data(resource);
2379 +       struct endpoint_stream *this = data->stream;
2380 +       struct spa_pod *result;
2381 +       struct spa_pod *param;
2382 +       uint8_t buffer[1024];
2383 +       struct spa_pod_builder b = { 0 };
2384 +       uint32_t index;
2385 +       uint32_t next = start;
2386 +       uint32_t count = 0;
2387 +
2388 +       while (true) {
2389 +               index = next++;
2390 +               if (index >= this->n_params)
2391 +                       break;
2392 +
2393 +               param = this->params[index];
2394 +
2395 +               if (param == NULL || !spa_pod_is_object_id(param, id))
2396 +                       continue;
2397 +
2398 +               spa_pod_builder_init(&b, buffer, sizeof(buffer));
2399 +               if (spa_pod_filter(&b, &result, param, filter) != 0)
2400 +                       continue;
2401 +
2402 +               pw_log_debug(NAME" %p: %d param %u", this, seq, index);
2403 +
2404 +               pw_endpoint_stream_resource_param(resource, seq, id, index, next, result);
2405 +
2406 +               if (++count == num)
2407 +                       break;
2408 +       }
2409 +       return 0;
2410 +}
2411 +
2412 +static int endpoint_stream_subscribe_params (void *object, uint32_t *ids, uint32_t n_ids)
2413 +{
2414 +       struct pw_resource *resource = object;
2415 +       struct resource_data *data = pw_resource_get_user_data(resource);
2416 +       uint32_t i;
2417 +
2418 +       n_ids = SPA_MIN(n_ids, SPA_N_ELEMENTS(data->subscribe_ids));
2419 +       data->n_subscribe_ids = n_ids;
2420 +
2421 +       for (i = 0; i < n_ids; i++) {
2422 +               data->subscribe_ids[i] = ids[i];
2423 +               pw_log_debug(NAME" %p: resource %d subscribe param %u",
2424 +                       data->stream, resource->id, ids[i]);
2425 +               endpoint_stream_enum_params(resource, 1, ids[i], 0, UINT32_MAX, NULL);
2426 +       }
2427 +       return 0;
2428 +}
2429 +
2430 +static int endpoint_stream_set_param (void *object, uint32_t id, uint32_t flags,
2431 +                               const struct spa_pod *param)
2432 +{
2433 +       struct pw_resource *resource = object;
2434 +       struct resource_data *data = pw_resource_get_user_data(resource);
2435 +       struct endpoint_stream *this = data->stream;
2436 +
2437 +       pw_client_endpoint_resource_set_param(this->client_ep->resource,
2438 +                                               id, flags, param);
2439 +
2440 +       return 0;
2441 +}
2442 +
2443 +static const struct pw_endpoint_stream_proxy_methods methods = {
2444 +       PW_VERSION_ENDPOINT_STREAM_PROXY_METHODS,
2445 +       .subscribe_params = endpoint_stream_subscribe_params,
2446 +       .enum_params = endpoint_stream_enum_params,
2447 +       .set_param = endpoint_stream_set_param,
2448 +};
2449 +
2450 +static void endpoint_stream_notify_subscribed(struct endpoint_stream *this,
2451 +                                       uint32_t index, uint32_t next)
2452 +{
2453 +       struct pw_global *global = this->global;
2454 +       struct pw_resource *resource;
2455 +       struct resource_data *data;
2456 +       struct spa_pod *param = this->params[index];
2457 +       uint32_t id;
2458 +       uint32_t i;
2459 +
2460 +       if (!param || !spa_pod_is_object (param))
2461 +               return;
2462 +
2463 +       id = SPA_POD_OBJECT_ID (param);
2464 +
2465 +       spa_list_for_each(resource, &global->resource_list, link) {
2466 +               data = pw_resource_get_user_data(resource);
2467 +               for (i = 0; i < data->n_subscribe_ids; i++) {
2468 +                       if (data->subscribe_ids[i] == id) {
2469 +                               pw_endpoint_stream_resource_param(resource, 1,
2470 +                                       id, index, next, param);
2471 +                       }
2472 +               }
2473 +       }
2474 +}
2475 +
2476 +int endpoint_stream_update(struct endpoint_stream *this,
2477 +                       uint32_t change_mask,
2478 +                       uint32_t n_params,
2479 +                       const struct spa_pod **params,
2480 +                       const struct pw_endpoint_stream_info *info)
2481 +{
2482 +       if (change_mask & PW_CLIENT_ENDPOINT_UPDATE_PARAMS) {
2483 +               uint32_t i;
2484 +               size_t size = n_params * sizeof(struct spa_pod *);
2485 +
2486 +               pw_log_debug(NAME" %p: update %d params", this, n_params);
2487 +
2488 +               for (i = 0; i < this->n_params; i++)
2489 +                       free(this->params[i]);
2490 +               this->params = realloc(this->params, size);
2491 +               if (size > 0 && !this->params) {
2492 +                       this->n_params = 0;
2493 +                       goto no_mem;
2494 +               }
2495 +               this->n_params = n_params;
2496 +
2497 +               for (i = 0; i < this->n_params; i++) {
2498 +                       this->params[i] = params[i] ? spa_pod_copy(params[i]) : NULL;
2499 +                       endpoint_stream_notify_subscribed(this, i, i+1);
2500 +               }
2501 +       }
2502 +
2503 +       if (change_mask & PW_CLIENT_ENDPOINT_UPDATE_INFO) {
2504 +               struct pw_resource *resource;
2505 +
2506 +               if (info->change_mask & PW_ENDPOINT_STREAM_CHANGE_MASK_LINK_PARAMS) {
2507 +                       free(this->info.link_params);
2508 +                       this->info.link_params = spa_pod_copy(info->link_params);
2509 +               }
2510 +
2511 +               if (info->change_mask & PW_ENDPOINT_STREAM_CHANGE_MASK_PROPS)
2512 +                       pw_properties_update(this->props, info->props);
2513 +
2514 +               if (info->change_mask & PW_ENDPOINT_STREAM_CHANGE_MASK_PARAMS) {
2515 +                       size_t size = info->n_params * sizeof(struct spa_param_info);
2516 +
2517 +                       this->info.params = realloc(this->info.params, size);
2518 +                       if (size > 0 && !this->info.params) {
2519 +                               this->info.n_params = 0;
2520 +                               goto no_mem;
2521 +                       }
2522 +                       this->info.n_params = info->n_params;
2523 +
2524 +                       memcpy(this->info.params, info->params, size);
2525 +               }
2526 +
2527 +               if (!this->info.name)
2528 +                       this->info.name = strdup(info->name);
2529 +
2530 +               this->info.change_mask = info->change_mask;
2531 +               spa_list_for_each(resource, &this->global->resource_list, link) {
2532 +                       pw_endpoint_stream_resource_info(resource, &this->info);
2533 +               }
2534 +               this->info.change_mask = 0;
2535 +       }
2536 +
2537 +       return 0;
2538 +
2539 +      no_mem:
2540 +       pw_log_error(NAME" can't update: no memory");
2541 +       pw_resource_error(this->client_ep->resource, -ENOMEM,
2542 +                       NAME" can't update: no memory");
2543 +       return -ENOMEM;
2544 +}
2545 +
2546 +static void endpoint_stream_unbind(void *data)
2547 +{
2548 +       struct pw_resource *resource = data;
2549 +       spa_list_remove(&resource->link);
2550 +}
2551 +
2552 +static const struct pw_resource_events resource_events = {
2553 +       PW_VERSION_RESOURCE_EVENTS,
2554 +       .destroy = endpoint_stream_unbind,
2555 +};
2556 +
2557 +static int endpoint_stream_bind(void *_data, struct pw_client *client,
2558 +                       uint32_t permissions, uint32_t version, uint32_t id)
2559 +{
2560 +       struct endpoint_stream *this = _data;
2561 +       struct pw_global *global = this->global;
2562 +       struct pw_resource *resource;
2563 +       struct resource_data *data;
2564 +
2565 +       resource = pw_resource_new(client, id, permissions, global->type, version, sizeof(*data));
2566 +       if (resource == NULL)
2567 +               goto no_mem;
2568 +
2569 +       data = pw_resource_get_user_data(resource);
2570 +       data->stream = this;
2571 +       pw_resource_add_listener(resource, &data->resource_listener,
2572 +                               &resource_events, resource);
2573 +       pw_resource_add_object_listener(resource, &data->object_listener,
2574 +                                       &methods, resource);
2575 +
2576 +       pw_log_debug(NAME" %p: bound to %d", this, resource->id);
2577 +
2578 +       spa_list_append(&global->resource_list, &resource->link);
2579 +
2580 +       this->info.change_mask = PW_ENDPOINT_STREAM_CHANGE_MASK_ALL;
2581 +       pw_endpoint_stream_resource_info(resource, &this->info);
2582 +       this->info.change_mask = 0;
2583 +
2584 +       return 0;
2585 +
2586 +      no_mem:
2587 +       pw_log_error(NAME" can't create resource: no memory");
2588 +       pw_resource_error(this->client_ep->resource, -ENOMEM,
2589 +                       NAME" can't create resource: no memory");
2590 +       return -ENOMEM;
2591 +}
2592 +
2593 +int endpoint_stream_init(struct endpoint_stream *this,
2594 +               uint32_t id, uint32_t endpoint_id,
2595 +               struct client_endpoint *client_ep,
2596 +               struct pw_core *core,
2597 +               struct pw_properties *properties)
2598 +{
2599 +       pw_log_debug(NAME" %p: new", this);
2600 +
2601 +       this->client_ep = client_ep;
2602 +       this->id = id;
2603 +       this->props = properties;
2604 +
2605 +       properties = pw_properties_copy(properties);
2606 +       if (!properties)
2607 +               goto no_mem;
2608 +
2609 +       this->global = pw_global_new (core,
2610 +                       PW_TYPE_INTERFACE_EndpointStream,
2611 +                       PW_VERSION_ENDPOINT_STREAM_PROXY,
2612 +                       properties, endpoint_stream_bind, this);
2613 +       if (!this->global)
2614 +               goto no_mem;
2615 +
2616 +       this->info.version = PW_VERSION_ENDPOINT_STREAM_INFO;
2617 +       this->info.id = this->global->id;
2618 +       this->info.endpoint_id = endpoint_id;
2619 +       this->info.props = &this->props->dict;
2620 +
2621 +       return pw_global_register(this->global);
2622 +
2623 +      no_mem:
2624 +       pw_log_error(NAME" - can't create - out of memory");
2625 +       return -ENOMEM;
2626 +}
2627 +
2628 +void endpoint_stream_clear(struct endpoint_stream *this)
2629 +{
2630 +       uint32_t i;
2631 +
2632 +       pw_log_debug(NAME" %p: destroy", this);
2633 +
2634 +       pw_global_destroy(this->global);
2635 +
2636 +       for (i = 0; i < this->n_params; i++)
2637 +               free(this->params[i]);
2638 +       free(this->params);
2639 +
2640 +       free(this->info.name);
2641 +       free(this->info.link_params);
2642 +       free(this->info.params);
2643 +
2644 +       if (this->props)
2645 +               pw_properties_free(this->props);
2646 +}
2647 diff --git a/src/modules/module-session-manager/endpoint-stream.h b/src/modules/module-session-manager/endpoint-stream.h
2648 new file mode 100644
2649 index 00000000..99bd4836
2650 --- /dev/null
2651 +++ b/src/modules/module-session-manager/endpoint-stream.h
2652 @@ -0,0 +1,64 @@
2653 +/* PipeWire
2654 + *
2655 + * Copyright © 2019 Collabora Ltd.
2656 + *   @author George Kiagiadakis <george.kiagiadakis@collabora.com>
2657 + *
2658 + * Permission is hereby granted, free of charge, to any person obtaining a
2659 + * copy of this software and associated documentation files (the "Software"),
2660 + * to deal in the Software without restriction, including without limitation
2661 + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
2662 + * and/or sell copies of the Software, and to permit persons to whom the
2663 + * Software is furnished to do so, subject to the following conditions:
2664 + *
2665 + * The above copyright notice and this permission notice (including the next
2666 + * paragraph) shall be included in all copies or substantial portions of the
2667 + * Software.
2668 + *
2669 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2670 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2671 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
2672 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2673 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
2674 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
2675 + * DEALINGS IN THE SOFTWARE.
2676 + */
2677 +
2678 +#ifndef MODULE_SESSION_MANAGER_ENDPOINT_STREAM_H
2679 +#define MODULE_SESSION_MANAGER_ENDPOINT_STREAM_H
2680 +
2681 +#ifdef __cplusplus
2682 +extern "C" {
2683 +#endif
2684 +
2685 +struct client_endpoint;
2686 +
2687 +struct endpoint_stream {
2688 +       struct spa_list link;
2689 +       struct client_endpoint *client_ep;
2690 +       struct pw_global *global;
2691 +       uint32_t id;                    /* endpoint-local stream id */
2692 +       uint32_t n_params;
2693 +       struct spa_pod **params;
2694 +       struct pw_endpoint_stream_info info;
2695 +       struct pw_properties *props;    /* wrapper of info.props */
2696 +};
2697 +
2698 +int endpoint_stream_init(struct endpoint_stream *this,
2699 +               uint32_t id, uint32_t endpoint_id,
2700 +               struct client_endpoint *client_ep,
2701 +               struct pw_core *core,
2702 +               struct pw_properties *properties);
2703 +
2704 +void endpoint_stream_clear(struct endpoint_stream *this);
2705 +
2706 +int endpoint_stream_update(struct endpoint_stream *this,
2707 +                       uint32_t change_mask,
2708 +                       uint32_t n_params,
2709 +                       const struct spa_pod **params,
2710 +                       const struct pw_endpoint_stream_info *info);
2711 +
2712 +#ifdef __cplusplus
2713 +}  /* extern "C" */
2714 +#endif
2715 +
2716 +#endif /* MODULE_SESSION_MANAGER_ENDPOINT_STREAM_H */
2717 diff --git a/src/modules/module-session-manager/endpoint.c b/src/modules/module-session-manager/endpoint.c
2718 new file mode 100644
2719 index 00000000..0866e71d
2720 --- /dev/null
2721 +++ b/src/modules/module-session-manager/endpoint.c
2722 @@ -0,0 +1,343 @@
2723 +/* PipeWire
2724 + *
2725 + * Copyright © 2019 Collabora Ltd.
2726 + *   @author George Kiagiadakis <george.kiagiadakis@collabora.com>
2727 + *
2728 + * Permission is hereby granted, free of charge, to any person obtaining a
2729 + * copy of this software and associated documentation files (the "Software"),
2730 + * to deal in the Software without restriction, including without limitation
2731 + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
2732 + * and/or sell copies of the Software, and to permit persons to whom the
2733 + * Software is furnished to do so, subject to the following conditions:
2734 + *
2735 + * The above copyright notice and this permission notice (including the next
2736 + * paragraph) shall be included in all copies or substantial portions of the
2737 + * Software.
2738 + *
2739 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2740 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2741 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
2742 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2743 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
2744 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
2745 + * DEALINGS IN THE SOFTWARE.
2746 + */
2747 +
2748 +#include <stdbool.h>
2749 +#include <string.h>
2750 +
2751 +#include <pipewire/pipewire.h>
2752 +#include <extensions/session-manager.h>
2753 +
2754 +#include <spa/pod/filter.h>
2755 +
2756 +#include "endpoint.h"
2757 +#include "client-endpoint.h"
2758 +
2759 +#include <pipewire/private.h>
2760 +
2761 +#define NAME "endpoint"
2762 +
2763 +struct resource_data {
2764 +       struct endpoint *endpoint;
2765 +       struct spa_hook resource_listener;
2766 +       struct spa_hook object_listener;
2767 +       uint32_t n_subscribe_ids;
2768 +       uint32_t subscribe_ids[32];
2769 +};
2770 +
2771 +#define pw_endpoint_resource(r,m,v,...)        \
2772 +       pw_resource_call(r,struct pw_endpoint_proxy_events,m,v,__VA_ARGS__)
2773 +#define pw_endpoint_resource_info(r,...)       \
2774 +       pw_endpoint_resource(r,info,0,__VA_ARGS__)
2775 +#define pw_endpoint_resource_param(r,...)      \
2776 +       pw_endpoint_resource(r,param,0,__VA_ARGS__)
2777 +
2778 +static int endpoint_enum_params (void *object, int seq,
2779 +                               uint32_t id, uint32_t start, uint32_t num,
2780 +                               const struct spa_pod *filter)
2781 +{
2782 +       struct pw_resource *resource = object;
2783 +       struct resource_data *data = pw_resource_get_user_data(resource);
2784 +       struct endpoint *this = data->endpoint;
2785 +       struct spa_pod *result;
2786 +       struct spa_pod *param;
2787 +       uint8_t buffer[1024];
2788 +       struct spa_pod_builder b = { 0 };
2789 +       uint32_t index;
2790 +       uint32_t next = start;
2791 +       uint32_t count = 0;
2792 +
2793 +       while (true) {
2794 +               index = next++;
2795 +               if (index >= this->n_params)
2796 +                       break;
2797 +
2798 +               param = this->params[index];
2799 +
2800 +               if (param == NULL || !spa_pod_is_object_id(param, id))
2801 +                       continue;
2802 +
2803 +               spa_pod_builder_init(&b, buffer, sizeof(buffer));
2804 +               if (spa_pod_filter(&b, &result, param, filter) != 0)
2805 +                       continue;
2806 +
2807 +               pw_log_debug(NAME" %p: %d param %u", this, seq, index);
2808 +
2809 +               pw_endpoint_resource_param(resource, seq, id, index, next, result);
2810 +
2811 +               if (++count == num)
2812 +                       break;
2813 +       }
2814 +       return 0;
2815 +}
2816 +
2817 +static int endpoint_subscribe_params (void *object, uint32_t *ids, uint32_t n_ids)
2818 +{
2819 +       struct pw_resource *resource = object;
2820 +       struct resource_data *data = pw_resource_get_user_data(resource);
2821 +       uint32_t i;
2822 +
2823 +       n_ids = SPA_MIN(n_ids, SPA_N_ELEMENTS(data->subscribe_ids));
2824 +       data->n_subscribe_ids = n_ids;
2825 +
2826 +       for (i = 0; i < n_ids; i++) {
2827 +               data->subscribe_ids[i] = ids[i];
2828 +               pw_log_debug(NAME" %p: resource %d subscribe param %u",
2829 +                       data->endpoint, resource->id, ids[i]);
2830 +               endpoint_enum_params(resource, 1, ids[i], 0, UINT32_MAX, NULL);
2831 +       }
2832 +       return 0;
2833 +}
2834 +
2835 +static int endpoint_set_param (void *object, uint32_t id, uint32_t flags,
2836 +                               const struct spa_pod *param)
2837 +{
2838 +       struct pw_resource *resource = object;
2839 +       struct resource_data *data = pw_resource_get_user_data(resource);
2840 +       struct endpoint *this = data->endpoint;
2841 +
2842 +       pw_client_endpoint_resource_set_param(this->client_ep->resource,
2843 +                                               id, flags, param);
2844 +
2845 +       return 0;
2846 +}
2847 +
2848 +static const struct pw_endpoint_proxy_methods methods = {
2849 +       PW_VERSION_ENDPOINT_PROXY_METHODS,
2850 +       .subscribe_params = endpoint_subscribe_params,
2851 +       .enum_params = endpoint_enum_params,
2852 +       .set_param = endpoint_set_param,
2853 +};
2854 +
2855 +static void endpoint_notify_subscribed(struct endpoint *this,
2856 +                                       uint32_t index, uint32_t next)
2857 +{
2858 +       struct pw_global *global = this->global;
2859 +       struct pw_resource *resource;
2860 +       struct resource_data *data;
2861 +       struct spa_pod *param = this->params[index];
2862 +       uint32_t id;
2863 +       uint32_t i;
2864 +
2865 +       if (!param || !spa_pod_is_object (param))
2866 +               return;
2867 +
2868 +       id = SPA_POD_OBJECT_ID (param);
2869 +
2870 +       spa_list_for_each(resource, &global->resource_list, link) {
2871 +               data = pw_resource_get_user_data(resource);
2872 +               for (i = 0; i < data->n_subscribe_ids; i++) {
2873 +                       if (data->subscribe_ids[i] == id) {
2874 +                               pw_endpoint_resource_param(resource, 1, id,
2875 +                                       index, next, param);
2876 +                       }
2877 +               }
2878 +       }
2879 +}
2880 +
2881 +int endpoint_update(struct endpoint *this,
2882 +                       uint32_t change_mask,
2883 +                       uint32_t n_params,
2884 +                       const struct spa_pod **params,
2885 +                       const struct pw_endpoint_info *info)
2886 +{
2887 +       if (change_mask & PW_CLIENT_ENDPOINT_UPDATE_PARAMS) {
2888 +               uint32_t i;
2889 +               size_t size = n_params * sizeof(struct spa_pod *);
2890 +
2891 +               pw_log_debug(NAME" %p: update %d params", this, n_params);
2892 +
2893 +               for (i = 0; i < this->n_params; i++)
2894 +                       free(this->params[i]);
2895 +               this->params = realloc(this->params, size);
2896 +               if (size > 0 && !this->params) {
2897 +                       this->n_params = 0;
2898 +                       goto no_mem;
2899 +               }
2900 +               this->n_params = n_params;
2901 +
2902 +               for (i = 0; i < this->n_params; i++) {
2903 +                       this->params[i] = params[i] ? spa_pod_copy(params[i]) : NULL;
2904 +                       endpoint_notify_subscribed(this, i, i+1);
2905 +               }
2906 +       }
2907 +
2908 +       if (change_mask & PW_CLIENT_ENDPOINT_UPDATE_INFO) {
2909 +               struct pw_resource *resource;
2910 +
2911 +               if (info->change_mask & PW_ENDPOINT_CHANGE_MASK_STREAMS)
2912 +                       this->info.n_streams = info->n_streams;
2913 +
2914 +               if (info->change_mask & PW_ENDPOINT_CHANGE_MASK_SESSION)
2915 +                       this->info.session_id = info->session_id;
2916 +
2917 +               if (info->change_mask & PW_ENDPOINT_CHANGE_MASK_PROPS)
2918 +                       pw_properties_update(this->props, info->props);
2919 +
2920 +               if (info->change_mask & PW_ENDPOINT_CHANGE_MASK_PARAMS) {
2921 +                       size_t size = info->n_params * sizeof(struct spa_param_info);
2922 +
2923 +                       this->info.params = realloc(this->info.params, size);
2924 +                       if (size > 0 && !this->info.params) {
2925 +                               this->info.n_params = 0;
2926 +                               goto no_mem;
2927 +                       }
2928 +                       this->info.n_params = info->n_params;
2929 +
2930 +                       memcpy(this->info.params, info->params, size);
2931 +               }
2932 +
2933 +               if (!this->info.name) {
2934 +                       this->info.name = strdup(info->name);
2935 +                       this->info.media_class = strdup(info->media_class);
2936 +                       this->info.direction = info->direction;
2937 +                       this->info.flags = info->flags;
2938 +               }
2939 +
2940 +               this->info.change_mask = info->change_mask;
2941 +               spa_list_for_each(resource, &this->global->resource_list, link) {
2942 +                       pw_endpoint_resource_info(resource, &this->info);
2943 +               }
2944 +               this->info.change_mask = 0;
2945 +       }
2946 +
2947 +       return 0;
2948 +
2949 +      no_mem:
2950 +       pw_log_error(NAME" can't update: no memory");
2951 +       pw_resource_error(this->client_ep->resource, -ENOMEM,
2952 +                       NAME" can't update: no memory");
2953 +       return -ENOMEM;
2954 +}
2955 +
2956 +static void endpoint_unbind(void *data)
2957 +{
2958 +       struct pw_resource *resource = data;
2959 +       spa_list_remove(&resource->link);
2960 +}
2961 +
2962 +static const struct pw_resource_events resource_events = {
2963 +       PW_VERSION_RESOURCE_EVENTS,
2964 +       .destroy = endpoint_unbind,
2965 +};
2966 +
2967 +static int endpoint_bind(void *_data, struct pw_client *client,
2968 +                       uint32_t permissions, uint32_t version, uint32_t id)
2969 +{
2970 +       struct endpoint *this = _data;
2971 +       struct pw_global *global = this->global;
2972 +       struct pw_resource *resource;
2973 +       struct resource_data *data;
2974 +
2975 +       resource = pw_resource_new(client, id, permissions, global->type, version, sizeof(*data));
2976 +       if (resource == NULL)
2977 +               goto no_mem;
2978 +
2979 +       data = pw_resource_get_user_data(resource);
2980 +       data->endpoint = this;
2981 +       pw_resource_add_listener(resource, &data->resource_listener,
2982 +                               &resource_events, resource);
2983 +       pw_resource_add_object_listener(resource, &data->object_listener,
2984 +                                       &methods, resource);
2985 +
2986 +       pw_log_debug(NAME" %p: bound to %d", this, resource->id);
2987 +
2988 +       spa_list_append(&global->resource_list, &resource->link);
2989 +
2990 +       this->info.change_mask = PW_ENDPOINT_CHANGE_MASK_ALL;
2991 +       pw_endpoint_resource_info(resource, &this->info);
2992 +       this->info.change_mask = 0;
2993 +
2994 +       return 0;
2995 +
2996 +      no_mem:
2997 +       pw_log_error(NAME" can't create resource: no memory");
2998 +       pw_resource_error(this->client_ep->resource, -ENOMEM,
2999 +                       NAME" can't create resource: no memory");
3000 +       return -ENOMEM;
3001 +}
3002 +
3003 +int endpoint_init(struct endpoint *this,
3004 +               struct client_endpoint *client_ep,
3005 +               struct pw_core *core,
3006 +               struct pw_properties *properties)
3007 +{
3008 +       const char *keys[] = {
3009 +               PW_KEY_FACTORY_ID,
3010 +               PW_KEY_CLIENT_ID,
3011 +               NULL
3012 +       };
3013 +
3014 +       pw_log_debug(NAME" %p: new", this);
3015 +
3016 +       this->client_ep = client_ep;
3017 +       this->props = properties;
3018 +
3019 +       properties = pw_properties_new(NULL, NULL);
3020 +       if (!properties)
3021 +               goto no_mem;
3022 +
3023 +       pw_properties_copy_keys(this->props, properties, keys);
3024 +
3025 +       this->global = pw_global_new (core,
3026 +                       PW_TYPE_INTERFACE_Endpoint,
3027 +                       PW_VERSION_ENDPOINT_PROXY,
3028 +                       properties, endpoint_bind, this);
3029 +       if (!this->global)
3030 +               goto no_mem;
3031 +
3032 +       pw_properties_setf(this->props, PW_KEY_ENDPOINT_ID, "%u", this->global->id);
3033 +
3034 +       this->info.version = PW_VERSION_ENDPOINT_INFO;
3035 +       this->info.id = this->global->id;
3036 +       this->info.props = &this->props->dict;
3037 +
3038 +       pw_client_endpoint_resource_set_id(client_ep->resource, this->global->id);
3039 +
3040 +       return pw_global_register(this->global);
3041 +
3042 +      no_mem:
3043 +       pw_log_error(NAME" - can't create - out of memory");
3044 +       return -ENOMEM;
3045 +}
3046 +
3047 +void endpoint_clear(struct endpoint *this)
3048 +{
3049 +       uint32_t i;
3050 +
3051 +       pw_log_debug(NAME" %p: destroy", this);
3052 +
3053 +       pw_global_destroy(this->global);
3054 +
3055 +       for (i = 0; i < this->n_params; i++)
3056 +               free(this->params[i]);
3057 +       free(this->params);
3058 +
3059 +       free(this->info.name);
3060 +       free(this->info.media_class);
3061 +       free(this->info.params);
3062 +
3063 +       if (this->props)
3064 +               pw_properties_free(this->props);
3065 +}
3066 diff --git a/src/modules/module-session-manager/endpoint.h b/src/modules/module-session-manager/endpoint.h
3067 new file mode 100644
3068 index 00000000..89d26028
3069 --- /dev/null
3070 +++ b/src/modules/module-session-manager/endpoint.h
3071 @@ -0,0 +1,61 @@
3072 +/* PipeWire
3073 + *
3074 + * Copyright © 2019 Collabora Ltd.
3075 + *   @author George Kiagiadakis <george.kiagiadakis@collabora.com>
3076 + *
3077 + * Permission is hereby granted, free of charge, to any person obtaining a
3078 + * copy of this software and associated documentation files (the "Software"),
3079 + * to deal in the Software without restriction, including without limitation
3080 + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
3081 + * and/or sell copies of the Software, and to permit persons to whom the
3082 + * Software is furnished to do so, subject to the following conditions:
3083 + *
3084 + * The above copyright notice and this permission notice (including the next
3085 + * paragraph) shall be included in all copies or substantial portions of the
3086 + * Software.
3087 + *
3088 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
3089 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
3090 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
3091 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
3092 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
3093 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
3094 + * DEALINGS IN THE SOFTWARE.
3095 + */
3096 +
3097 +#ifndef MODULE_SESSION_MANAGER_ENDPOINT_H
3098 +#define MODULE_SESSION_MANAGER_ENDPOINT_H
3099 +
3100 +#ifdef __cplusplus
3101 +extern "C" {
3102 +#endif
3103 +
3104 +struct client_endpoint;
3105 +
3106 +struct endpoint {
3107 +       struct client_endpoint *client_ep;
3108 +       struct pw_global *global;
3109 +       uint32_t n_params;
3110 +       struct spa_pod **params;
3111 +       struct pw_endpoint_info info;
3112 +       struct pw_properties *props;    /* wrapper of info.props */
3113 +};
3114 +
3115 +int endpoint_init(struct endpoint *this,
3116 +               struct client_endpoint *client_ep,
3117 +               struct pw_core *core,
3118 +               struct pw_properties *properties);
3119 +
3120 +void endpoint_clear(struct endpoint *this);
3121 +
3122 +int endpoint_update(struct endpoint *this,
3123 +                       uint32_t change_mask,
3124 +                       uint32_t n_params,
3125 +                       const struct spa_pod **params,
3126 +                       const struct pw_endpoint_info *info);
3127 +
3128 +#ifdef __cplusplus
3129 +}  /* extern "C" */
3130 +#endif
3131 +
3132 +#endif /* MODULE_SESSION_MANAGER_ENDPOINT_H */
3133 diff --git a/src/modules/module-session-manager/protocol-native.c b/src/modules/module-session-manager/protocol-native.c
3134 new file mode 100644
3135 index 00000000..2c791ffc
3136 --- /dev/null
3137 +++ b/src/modules/module-session-manager/protocol-native.c
3138 @@ -0,0 +1,2125 @@
3139 +/* PipeWire
3140 + *
3141 + * Copyright © 2019 Collabora Ltd.
3142 + *   @author George Kiagiadakis <george.kiagiadakis@collabora.com>
3143 + *
3144 + * Permission is hereby granted, free of charge, to any person obtaining a
3145 + * copy of this software and associated documentation files (the "Software"),
3146 + * to deal in the Software without restriction, including without limitation
3147 + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
3148 + * and/or sell copies of the Software, and to permit persons to whom the
3149 + * Software is furnished to do so, subject to the following conditions:
3150 + *
3151 + * The above copyright notice and this permission notice (including the next
3152 + * paragraph) shall be included in all copies or substantial portions of the
3153 + * Software.
3154 + *
3155 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
3156 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
3157 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
3158 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
3159 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
3160 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
3161 + * DEALINGS IN THE SOFTWARE.
3162 + */
3163 +
3164 +#include <pipewire/pipewire.h>
3165 +#include <spa/pod/parser.h>
3166 +
3167 +#include <extensions/session-manager.h>
3168 +#include <extensions/protocol-native.h>
3169 +
3170 +static void push_dict(struct spa_pod_builder *b, const struct spa_dict *dict)
3171 +{
3172 +       struct spa_pod_frame f;
3173 +       uint32_t n_items;
3174 +       uint32_t i;
3175 +
3176 +       n_items = dict ? dict->n_items : 0;
3177 +
3178 +       spa_pod_builder_push_struct(b, &f);
3179 +       spa_pod_builder_add(b, SPA_POD_Int(n_items), NULL);
3180 +       for (i = 0; i < n_items; i++) {
3181 +               spa_pod_builder_add(b,
3182 +                       SPA_POD_String(dict->items[i].key),
3183 +                       SPA_POD_String(dict->items[i].value),
3184 +                       NULL);
3185 +       }
3186 +       spa_pod_builder_pop(b, &f);
3187 +}
3188 +
3189 +/* macro because of alloca() */
3190 +#define parse_dict(p, f, dict) \
3191 +do { \
3192 +       uint32_t i; \
3193 +       \
3194 +       if (spa_pod_parser_push_struct(p, f) < 0 || \
3195 +           spa_pod_parser_get(p, SPA_POD_Int(&(dict)->n_items), NULL) < 0) \
3196 +               return -EINVAL; \
3197 +       \
3198 +       if ((dict)->n_items > 0) { \
3199 +               (dict)->items = alloca((dict)->n_items * sizeof(struct spa_dict_item)); \
3200 +               for (i = 0; i < (dict)->n_items; i++) { \
3201 +                       if (spa_pod_parser_get(p, \
3202 +                                       SPA_POD_String(&(dict)->items[i].key), \
3203 +                                       SPA_POD_String(&(dict)->items[i].value), \
3204 +                                       NULL) < 0) \
3205 +                               return -EINVAL; \
3206 +               } \
3207 +       } \
3208 +       spa_pod_parser_pop(p, f); \
3209 +} while(0)
3210 +
3211 +static void push_param_infos(struct spa_pod_builder *b, uint32_t n_params,
3212 +                               const struct spa_param_info *params)
3213 +{
3214 +       struct spa_pod_frame f;
3215 +       uint32_t i;
3216 +
3217 +       spa_pod_builder_push_struct(b, &f);
3218 +       spa_pod_builder_add(b, SPA_POD_Int(n_params), NULL);
3219 +       for (i = 0; i < n_params; i++) {
3220 +               spa_pod_builder_add(b,
3221 +                       SPA_POD_Id(params[i].id),
3222 +                       SPA_POD_Int(params[i].flags),
3223 +                       NULL);
3224 +       }
3225 +       spa_pod_builder_pop(b, &f);
3226 +}
3227 +
3228 +/* macro because of alloca() */
3229 +#define parse_param_infos(p, f, n_params_p, params_p) \
3230 +do { \
3231 +       uint32_t i; \
3232 +       \
3233 +       if (spa_pod_parser_push_struct(p, f) < 0 || \
3234 +           spa_pod_parser_get(p, SPA_POD_Int(n_params_p), NULL) < 0) \
3235 +               return -EINVAL; \
3236 +       \
3237 +       if (*(n_params_p) > 0) { \
3238 +               *(params_p) = alloca(*(n_params_p) * sizeof(struct spa_param_info)); \
3239 +               for (i = 0; i < *(n_params_p); i++) { \
3240 +                       if (spa_pod_parser_get(p, \
3241 +                                       SPA_POD_Id(&(*(params_p))[i].id), \
3242 +                                       SPA_POD_Int(&(*(params_p))[i].flags), \
3243 +                                       NULL) < 0) \
3244 +                               return -EINVAL; \
3245 +               } \
3246 +       } \
3247 +       spa_pod_parser_pop(p, f); \
3248 +} while(0)
3249 +
3250 +/***********************************************
3251 + *             INFO STRUCTURES
3252 + ***********************************************/
3253 +
3254 +static void
3255 +marshal_pw_session_info(struct spa_pod_builder *b,
3256 +                        const struct pw_session_info *info)
3257 +{
3258 +       struct spa_pod_frame f;
3259 +
3260 +       spa_pod_builder_push_struct(b, &f);
3261 +       spa_pod_builder_add(b,
3262 +               SPA_POD_Int(info->version),
3263 +               SPA_POD_Int(info->id),
3264 +               SPA_POD_Int(info->change_mask),
3265 +               NULL);
3266 +       push_dict(b, info->props);
3267 +       push_param_infos(b, info->n_params, info->params);
3268 +       spa_pod_builder_pop(b, &f);
3269 +}
3270 +
3271 +/* macro because of alloca() */
3272 +#define demarshal_pw_session_info(p, f, info) \
3273 +do { \
3274 +       struct spa_pod_frame sub_f; \
3275 +       uint32_t version; \
3276 +       \
3277 +       if (spa_pod_parser_push_struct(p, f) < 0 || \
3278 +           spa_pod_parser_get(p, \
3279 +                       SPA_POD_Int(&version), \
3280 +                       SPA_POD_Int(&(info)->id), \
3281 +                       SPA_POD_Int(&(info)->change_mask), \
3282 +                       SPA_POD_Int(&(info)->n_params), \
3283 +                       SPA_POD_Int(&(info)->props->n_items), \
3284 +                       NULL) < 0) \
3285 +               return -EINVAL; \
3286 +       \
3287 +       (info)->change_mask &= PW_SESSION_CHANGE_MASK_ALL; \
3288 +       \
3289 +       parse_dict(p, &sub_f, (info)->props); \
3290 +       parse_param_infos(p, &sub_f, &(info)->n_params, &(info)->params); \
3291 +       \
3292 +       spa_pod_parser_pop(p, f); \
3293 +} while(0)
3294 +
3295 +static void
3296 +marshal_pw_endpoint_info(struct spa_pod_builder *b,
3297 +                        const struct pw_endpoint_info *info)
3298 +{
3299 +       struct spa_pod_frame f;
3300 +
3301 +       spa_pod_builder_push_struct(b, &f);
3302 +       spa_pod_builder_add(b,
3303 +               SPA_POD_Int(info->version),
3304 +               SPA_POD_Int(info->id),
3305 +               SPA_POD_String(info->name),
3306 +               SPA_POD_String(info->media_class),
3307 +               SPA_POD_Int(info->direction),
3308 +               SPA_POD_Int(info->flags),
3309 +               SPA_POD_Int(info->change_mask),
3310 +               NULL);
3311 +       push_dict(b, info->props);
3312 +       push_param_infos(b, info->n_params, info->params);
3313 +       spa_pod_builder_pop(b, &f);
3314 +}
3315 +
3316 +/* macro because of alloca() */
3317 +#define demarshal_pw_endpoint_info(p, f, info) \
3318 +do { \
3319 +       struct spa_pod_frame sub_f; \
3320 +       uint32_t version; \
3321 +       \
3322 +       if (spa_pod_parser_push_struct(p, f) < 0 || \
3323 +           spa_pod_parser_get(p, \
3324 +                       SPA_POD_Int(&version), \
3325 +                       SPA_POD_Int(&(info)->id), \
3326 +                       SPA_POD_String(&(info)->name), \
3327 +                       SPA_POD_String(&(info)->media_class), \
3328 +                       SPA_POD_Int(&(info)->direction), \
3329 +                       SPA_POD_Int(&(info)->flags), \
3330 +                       SPA_POD_Int(&(info)->change_mask), \
3331 +                       NULL) < 0) \
3332 +               return -EINVAL; \
3333 +       \
3334 +       (info)->change_mask &= PW_ENDPOINT_CHANGE_MASK_ALL; \
3335 +       \
3336 +       parse_dict(p, &sub_f, (info)->props); \
3337 +       parse_param_infos(p, &sub_f, &(info)->n_params, &(info)->params); \
3338 +       \
3339 +       spa_pod_parser_pop(p, f); \
3340 +} while(0)
3341 +
3342 +static void
3343 +marshal_pw_endpoint_stream_info(struct spa_pod_builder *b,
3344 +                        const struct pw_endpoint_stream_info *info)
3345 +{
3346 +       struct spa_pod_frame f;
3347 +
3348 +       spa_pod_builder_push_struct(b, &f);
3349 +       spa_pod_builder_add(b,
3350 +               SPA_POD_Int(info->version),
3351 +               SPA_POD_Int(info->id),
3352 +               SPA_POD_Int(info->endpoint_id),
3353 +               SPA_POD_String(info->name),
3354 +               SPA_POD_Int(info->change_mask),
3355 +               SPA_POD_Pod(info->link_params),
3356 +               NULL);
3357 +       push_dict(b, info->props);
3358 +       push_param_infos(b, info->n_params, info->params);
3359 +       spa_pod_builder_pop(b, &f);
3360 +}
3361 +
3362 +/* macro because of alloca() */
3363 +#define demarshal_pw_endpoint_stream_info(p, f, info) \
3364 +do { \
3365 +       struct spa_pod_frame sub_f; \
3366 +       uint32_t version; \
3367 +       \
3368 +       if (spa_pod_parser_push_struct(p, f) < 0 || \
3369 +           spa_pod_parser_get(p, \
3370 +                       SPA_POD_Int(&version), \
3371 +                       SPA_POD_Int(&(info)->id), \
3372 +                       SPA_POD_Int(&(info)->endpoint_id), \
3373 +                       SPA_POD_String(&(info)->name), \
3374 +                       SPA_POD_Int(&(info)->change_mask), \
3375 +                       SPA_POD_Pod(&(info)->link_params), \
3376 +                       NULL) < 0) \
3377 +               return -EINVAL; \
3378 +       \
3379 +       (info)->change_mask &= PW_ENDPOINT_STREAM_CHANGE_MASK_ALL; \
3380 +       \
3381 +       parse_dict(p, &sub_f, (info)->props); \
3382 +       parse_param_infos(p, &sub_f, &(info)->n_params, &(info)->params); \
3383 +       \
3384 +       spa_pod_parser_pop(p, f); \
3385 +} while(0)
3386 +
3387 +static void
3388 +marshal_pw_endpoint_link_info(struct spa_pod_builder *b,
3389 +                        const struct pw_endpoint_link_info *info)
3390 +{
3391 +       struct spa_pod_frame f;
3392 +
3393 +       spa_pod_builder_push_struct(b, &f);
3394 +       spa_pod_builder_add(b,
3395 +               SPA_POD_Int(info->version),
3396 +               SPA_POD_Int(info->id),
3397 +               SPA_POD_Int(info->session_id),
3398 +               SPA_POD_Int(info->output_endpoint_id),
3399 +               SPA_POD_Int(info->output_stream_id),
3400 +               SPA_POD_Int(info->input_endpoint_id),
3401 +               SPA_POD_Int(info->input_stream_id),
3402 +               SPA_POD_Int(info->change_mask),
3403 +               SPA_POD_Int(info->state),
3404 +               SPA_POD_String(info->error),
3405 +               NULL);
3406 +       push_dict(b, info->props);
3407 +       push_param_infos(b, info->n_params, info->params);
3408 +       spa_pod_builder_pop(b, &f);
3409 +}
3410 +
3411 +/* macro because of alloca() */
3412 +#define demarshal_pw_endpoint_link_info(p, f, info) \
3413 +do { \
3414 +       struct spa_pod_frame sub_f; \
3415 +       uint32_t version; \
3416 +       \
3417 +       if (spa_pod_parser_push_struct(p, f) < 0 || \
3418 +           spa_pod_parser_get(p, \
3419 +                       SPA_POD_Int(&version), \
3420 +                       SPA_POD_Int(&(info)->id), \
3421 +                       SPA_POD_Int(&(info)->session_id), \
3422 +                       SPA_POD_Int(&(info)->output_endpoint_id), \
3423 +                       SPA_POD_Int(&(info)->output_stream_id), \
3424 +                       SPA_POD_Int(&(info)->input_endpoint_id), \
3425 +                       SPA_POD_Int(&(info)->input_stream_id), \
3426 +                       SPA_POD_Int(&(info)->change_mask), \
3427 +                       SPA_POD_Int(&(info)->state), \
3428 +                       SPA_POD_String(&(info)->error), \
3429 +                       NULL) < 0) \
3430 +               return -EINVAL; \
3431 +       \
3432 +       (info)->change_mask &= PW_ENDPOINT_LINK_CHANGE_MASK_ALL; \
3433 +       \
3434 +       parse_dict(p, &sub_f, (info)->props); \
3435 +       parse_param_infos(p, &sub_f, &(info)->n_params, &(info)->params); \
3436 +       \
3437 +       spa_pod_parser_pop(p, f); \
3438 +} while(0)
3439 +
3440 +/***********************************************
3441 + *              CLIENT ENDPOINT
3442 + ***********************************************/
3443 +
3444 +static int client_endpoint_marshal_set_id (void *object, uint32_t id)
3445 +{
3446 +       struct pw_resource *resource = object;
3447 +       struct spa_pod_builder *b;
3448 +
3449 +       b = pw_protocol_native_begin_resource(resource,
3450 +               PW_CLIENT_ENDPOINT_PROXY_EVENT_SET_ID, NULL);
3451 +
3452 +       spa_pod_builder_add (b, SPA_POD_Int(id), NULL);
3453 +
3454 +       return pw_protocol_native_end_resource(resource, b);
3455 +}
3456 +
3457 +static int client_endpoint_marshal_set_session_id (void *object, uint32_t id)
3458 +{
3459 +       struct pw_resource *resource = object;
3460 +       struct spa_pod_builder *b;
3461 +
3462 +       b = pw_protocol_native_begin_resource(resource,
3463 +               PW_CLIENT_ENDPOINT_PROXY_EVENT_SET_SESSION_ID, NULL);
3464 +
3465 +       spa_pod_builder_add (b, SPA_POD_Int(id), NULL);
3466 +
3467 +       return pw_protocol_native_end_resource(resource, b);
3468 +}
3469 +
3470 +static int client_endpoint_marshal_set_param (void *object,
3471 +                                       uint32_t id, uint32_t flags,
3472 +                                       const struct spa_pod *param)
3473 +{
3474 +       struct pw_resource *resource = object;
3475 +       struct spa_pod_builder *b;
3476 +
3477 +       b = pw_protocol_native_begin_resource(resource,
3478 +               PW_CLIENT_ENDPOINT_PROXY_EVENT_SET_PARAM, NULL);
3479 +
3480 +       spa_pod_builder_add_struct(b,
3481 +                               SPA_POD_Id(id),
3482 +                               SPA_POD_Int(flags),
3483 +                               SPA_POD_Pod(param));
3484 +
3485 +       return pw_protocol_native_end_resource(resource, b);
3486 +}
3487 +
3488 +static int client_endpoint_marshal_stream_set_param (void *object,
3489 +                               uint32_t stream_id, uint32_t id,
3490 +                               uint32_t flags, const struct spa_pod *param)
3491 +{
3492 +       struct pw_resource *resource = object;
3493 +       struct spa_pod_builder *b;
3494 +
3495 +       b = pw_protocol_native_begin_resource(resource,
3496 +               PW_CLIENT_ENDPOINT_PROXY_EVENT_STREAM_SET_PARAM, NULL);
3497 +
3498 +       spa_pod_builder_add_struct(b,
3499 +                               SPA_POD_Int(stream_id),
3500 +                               SPA_POD_Id(id),
3501 +                               SPA_POD_Int(flags),
3502 +                               SPA_POD_Pod(param));
3503 +
3504 +       return pw_protocol_native_end_resource(resource, b);
3505 +}
3506 +
3507 +static int client_endpoint_marshal_add_listener(void *object,
3508 +                       struct spa_hook *listener,
3509 +                       const struct pw_client_endpoint_proxy_events *events,
3510 +                       void *data)
3511 +{
3512 +       struct pw_proxy *proxy = object;
3513 +       pw_proxy_add_object_listener(proxy, listener, events, data);
3514 +       return 0;
3515 +}
3516 +
3517 +static int client_endpoint_marshal_update(void *object,
3518 +                                       uint32_t change_mask,
3519 +                                       uint32_t n_params,
3520 +                                       const struct spa_pod **params,
3521 +                                       const struct pw_endpoint_info *info)
3522 +{
3523 +       struct pw_proxy *proxy = object;
3524 +       struct spa_pod_builder *b;
3525 +       struct spa_pod_frame f;
3526 +       uint32_t i;
3527 +
3528 +       b = pw_protocol_native_begin_proxy(proxy,
3529 +               PW_CLIENT_ENDPOINT_PROXY_METHOD_UPDATE, NULL);
3530 +
3531 +       spa_pod_builder_push_struct(b, &f);
3532 +       spa_pod_builder_add(b,
3533 +               SPA_POD_Int(change_mask),
3534 +               SPA_POD_Int(n_params),
3535 +               NULL);
3536 +
3537 +       for (i = 0; i < n_params; i++)
3538 +               spa_pod_builder_add(b, SPA_POD_Pod(params[i]), NULL);
3539 +
3540 +       if (info)
3541 +               marshal_pw_endpoint_info(b, info);
3542 +       else
3543 +               spa_pod_builder_add(b, SPA_POD_Pod(NULL), NULL);
3544 +
3545 +       spa_pod_builder_pop(b, &f);
3546 +
3547 +       return pw_protocol_native_end_proxy(proxy, b);
3548 +}
3549 +
3550 +static int client_endpoint_marshal_stream_update(void *object,
3551 +                                       uint32_t stream_id,
3552 +                                       uint32_t change_mask,
3553 +                                       uint32_t n_params,
3554 +                                       const struct spa_pod **params,
3555 +                                       const struct pw_endpoint_stream_info *info)
3556 +{
3557 +       struct pw_proxy *proxy = object;
3558 +       struct spa_pod_builder *b;
3559 +       struct spa_pod_frame f;
3560 +       uint32_t i;
3561 +
3562 +       b = pw_protocol_native_begin_proxy(proxy,
3563 +               PW_CLIENT_ENDPOINT_PROXY_METHOD_STREAM_UPDATE, NULL);
3564 +
3565 +       spa_pod_builder_push_struct(b, &f);
3566 +       spa_pod_builder_add(b,
3567 +               SPA_POD_Int(stream_id),
3568 +               SPA_POD_Int(change_mask),
3569 +               SPA_POD_Int(n_params),
3570 +               NULL);
3571 +
3572 +       for (i = 0; i < n_params; i++)
3573 +               spa_pod_builder_add(b, SPA_POD_Pod(params[i]), NULL);
3574 +
3575 +       if (info)
3576 +               marshal_pw_endpoint_stream_info(b, info);
3577 +       else
3578 +               spa_pod_builder_add(b, SPA_POD_Pod(NULL), NULL);
3579 +
3580 +       spa_pod_builder_pop(b, &f);
3581 +
3582 +       return pw_protocol_native_end_proxy(proxy, b);
3583 +}
3584 +
3585 +static int client_endpoint_demarshal_set_id(void *object,
3586 +                               const struct pw_protocol_native_message *msg)
3587 +{
3588 +       struct pw_proxy *proxy = object;
3589 +       struct spa_pod_parser prs;
3590 +       uint32_t id;
3591 +
3592 +       spa_pod_parser_init(&prs, msg->data, msg->size);
3593 +       if (spa_pod_parser_get_struct(&prs,
3594 +                       SPA_POD_Int(&id)) < 0)
3595 +               return -EINVAL;
3596 +
3597 +       return pw_proxy_notify(proxy, struct pw_client_endpoint_proxy_events,
3598 +                               set_id, 0, id);
3599 +}
3600 +
3601 +static int client_endpoint_demarshal_set_session_id(void *object,
3602 +                               const struct pw_protocol_native_message *msg)
3603 +{
3604 +       struct pw_proxy *proxy = object;
3605 +       struct spa_pod_parser prs;
3606 +       uint32_t id;
3607 +
3608 +       spa_pod_parser_init(&prs, msg->data, msg->size);
3609 +       if (spa_pod_parser_get_struct(&prs,
3610 +                       SPA_POD_Int(&id)) < 0)
3611 +               return -EINVAL;
3612 +
3613 +       return pw_proxy_notify(proxy, struct pw_client_endpoint_proxy_events,
3614 +                               set_session_id, 0, id);
3615 +}
3616 +
3617 +static int client_endpoint_demarshal_set_param(void *object,
3618 +                               const struct pw_protocol_native_message *msg)
3619 +{
3620 +       struct pw_proxy *proxy = object;
3621 +       struct spa_pod_parser prs;
3622 +       uint32_t id, flags;
3623 +       const struct spa_pod *param = NULL;
3624 +
3625 +       spa_pod_parser_init(&prs, msg->data, msg->size);
3626 +       if (spa_pod_parser_get_struct(&prs,
3627 +                       SPA_POD_Int(&id),
3628 +                       SPA_POD_Int(&flags),
3629 +                       SPA_POD_PodObject(&param)) < 0)
3630 +               return -EINVAL;
3631 +
3632 +       return pw_proxy_notify(proxy, struct pw_client_endpoint_proxy_events,
3633 +                               set_param, 0, id, flags, param);
3634 +}
3635 +
3636 +static int client_endpoint_demarshal_stream_set_param(void *object,
3637 +                               const struct pw_protocol_native_message *msg)
3638 +{
3639 +       struct pw_proxy *proxy = object;
3640 +       struct spa_pod_parser prs;
3641 +       uint32_t stream_id, id, flags;
3642 +       const struct spa_pod *param = NULL;
3643 +
3644 +       spa_pod_parser_init(&prs, msg->data, msg->size);
3645 +       if (spa_pod_parser_get_struct(&prs,
3646 +                       SPA_POD_Int(&stream_id),
3647 +                       SPA_POD_Int(&id),
3648 +                       SPA_POD_Int(&flags),
3649 +                       SPA_POD_PodObject(&param)) < 0)
3650 +               return -EINVAL;
3651 +
3652 +       return pw_proxy_notify(proxy, struct pw_client_endpoint_proxy_events,
3653 +                               stream_set_param, 0, stream_id, id, flags, param);
3654 +}
3655 +
3656 +static int client_endpoint_demarshal_update(void *object,
3657 +                               const struct pw_protocol_native_message *msg)
3658 +{
3659 +       struct pw_resource *resource = object;
3660 +       struct spa_pod_parser prs[2];
3661 +       struct spa_pod_frame f[2];
3662 +       uint32_t change_mask, n_params;
3663 +       const struct spa_pod **params = NULL;
3664 +       struct spa_dict props = SPA_DICT_INIT(NULL, 0);
3665 +       struct pw_endpoint_info info = { .props = &props }, *infop = NULL;
3666 +       struct spa_pod *ipod;
3667 +       uint32_t i;
3668 +
3669 +       spa_pod_parser_init(&prs[0], msg->data, msg->size);
3670 +       if (spa_pod_parser_push_struct(&prs[0], &f[0]) < 0 ||
3671 +           spa_pod_parser_get(&prs[0],
3672 +                       SPA_POD_Int(&change_mask),
3673 +                       SPA_POD_Int(&n_params), NULL) < 0)
3674 +               return -EINVAL;
3675 +
3676 +       if (n_params > 0)
3677 +               params = alloca(n_params * sizeof(struct spa_pod *));
3678 +       for (i = 0; i < n_params; i++)
3679 +               if (spa_pod_parser_get(&prs[0],
3680 +                               SPA_POD_PodObject(&params[i]), NULL) < 0)
3681 +                       return -EINVAL;
3682 +
3683 +       if (spa_pod_parser_get(&prs[0], SPA_POD_PodStruct(&ipod), NULL) < 0)
3684 +               return -EINVAL;
3685 +       if (ipod) {
3686 +               infop = &info;
3687 +               spa_pod_parser_pod(&prs[1], ipod);
3688 +               demarshal_pw_endpoint_info(&prs[1], &f[1], infop);
3689 +       }
3690 +
3691 +       return pw_resource_notify(resource, struct pw_client_endpoint_proxy_methods,
3692 +                       update, 0, change_mask, n_params, params, infop);
3693 +}
3694 +
3695 +static int client_endpoint_demarshal_stream_update(void *object,
3696 +                               const struct pw_protocol_native_message *msg)
3697 +{
3698 +       struct pw_resource *resource = object;
3699 +       struct spa_pod_parser prs[2];
3700 +       struct spa_pod_frame f[2];
3701 +       uint32_t stream_id, change_mask, n_params;
3702 +       const struct spa_pod **params = NULL;
3703 +       struct spa_dict props = SPA_DICT_INIT(NULL, 0);
3704 +       struct pw_endpoint_stream_info info = { .props = &props }, *infop = NULL;
3705 +       struct spa_pod *ipod;
3706 +       uint32_t i;
3707 +
3708 +       spa_pod_parser_init(&prs[0], msg->data, msg->size);
3709 +       if (spa_pod_parser_push_struct(&prs[0], &f[0]) < 0 ||
3710 +           spa_pod_parser_get(&prs[0],
3711 +                       SPA_POD_Int(&stream_id),
3712 +                       SPA_POD_Int(&change_mask),
3713 +                       SPA_POD_Int(&n_params), NULL) < 0)
3714 +               return -EINVAL;
3715 +
3716 +       if (n_params > 0)
3717 +               params = alloca(n_params * sizeof(struct spa_pod *));
3718 +       for (i = 0; i < n_params; i++)
3719 +               if (spa_pod_parser_get(&prs[0],
3720 +                               SPA_POD_PodObject(&params[i]), NULL) < 0)
3721 +                       return -EINVAL;
3722 +
3723 +       if (spa_pod_parser_get(&prs[0], SPA_POD_PodStruct(&ipod), NULL) < 0)
3724 +               return -EINVAL;
3725 +       if (ipod) {
3726 +               infop = &info;
3727 +               spa_pod_parser_pod(&prs[1], ipod);
3728 +               demarshal_pw_endpoint_stream_info(&prs[1], &f[1], infop);
3729 +       }
3730 +
3731 +       return pw_resource_notify(resource, struct pw_client_endpoint_proxy_methods,
3732 +                       stream_update, 0, stream_id, change_mask, n_params, params, infop);
3733 +}
3734 +
3735 +static const struct pw_client_endpoint_proxy_events pw_protocol_native_client_endpoint_event_marshal = {
3736 +       PW_VERSION_CLIENT_ENDPOINT_PROXY_EVENTS,
3737 +       .set_id = client_endpoint_marshal_set_id,
3738 +       .set_session_id = client_endpoint_marshal_set_session_id,
3739 +       .set_param = client_endpoint_marshal_set_param,
3740 +       .stream_set_param = client_endpoint_marshal_stream_set_param,
3741 +};
3742 +
3743 +static const struct pw_protocol_native_demarshal
3744 +pw_protocol_native_client_endpoint_event_demarshal[PW_CLIENT_ENDPOINT_PROXY_EVENT_NUM] =
3745 +{
3746 +       [PW_CLIENT_ENDPOINT_PROXY_EVENT_SET_ID] = { client_endpoint_demarshal_set_id, 0 },
3747 +       [PW_CLIENT_ENDPOINT_PROXY_EVENT_SET_SESSION_ID] = { client_endpoint_demarshal_set_session_id, 0 },
3748 +       [PW_CLIENT_ENDPOINT_PROXY_EVENT_SET_PARAM] = { client_endpoint_demarshal_set_param, 0 },
3749 +       [PW_CLIENT_ENDPOINT_PROXY_EVENT_STREAM_SET_PARAM] = { client_endpoint_demarshal_stream_set_param, 0 },
3750 +};
3751 +
3752 +static const struct pw_client_endpoint_proxy_methods pw_protocol_native_client_endpoint_method_marshal = {
3753 +       PW_VERSION_CLIENT_ENDPOINT_PROXY_METHODS,
3754 +       .add_listener = client_endpoint_marshal_add_listener,
3755 +       .update = client_endpoint_marshal_update,
3756 +       .stream_update = client_endpoint_marshal_stream_update,
3757 +};
3758 +
3759 +static const struct pw_protocol_native_demarshal
3760 +pw_protocol_native_client_endpoint_method_demarshal[PW_CLIENT_ENDPOINT_PROXY_METHOD_NUM] =
3761 +{
3762 +       [PW_CLIENT_ENDPOINT_PROXY_METHOD_ADD_LISTENER] = { NULL, 0 },
3763 +       [PW_CLIENT_ENDPOINT_PROXY_METHOD_UPDATE] = { client_endpoint_demarshal_update, 0 },
3764 +       [PW_CLIENT_ENDPOINT_PROXY_METHOD_STREAM_UPDATE] = { client_endpoint_demarshal_stream_update, 0 },
3765 +};
3766 +
3767 +static const struct pw_protocol_marshal pw_protocol_native_client_endpoint_marshal = {
3768 +       PW_TYPE_INTERFACE_ClientEndpoint,
3769 +       PW_VERSION_CLIENT_ENDPOINT_PROXY,
3770 +       PW_CLIENT_ENDPOINT_PROXY_METHOD_NUM,
3771 +       PW_CLIENT_ENDPOINT_PROXY_EVENT_NUM,
3772 +       &pw_protocol_native_client_endpoint_method_marshal,
3773 +       &pw_protocol_native_client_endpoint_method_demarshal,
3774 +       &pw_protocol_native_client_endpoint_event_marshal,
3775 +       &pw_protocol_native_client_endpoint_event_demarshal,
3776 +};
3777 +
3778 +/***********************************************
3779 + *              CLIENT SESSION
3780 + ***********************************************/
3781 +
3782 +static int client_session_marshal_set_id (void *object, uint32_t id)
3783 +{
3784 +       struct pw_resource *resource = object;
3785 +       struct spa_pod_builder *b;
3786 +
3787 +       b = pw_protocol_native_begin_resource(resource,
3788 +               PW_CLIENT_SESSION_PROXY_EVENT_SET_ID, NULL);
3789 +
3790 +       spa_pod_builder_add (b, SPA_POD_Int(id), NULL);
3791 +
3792 +       return pw_protocol_native_end_resource(resource, b);
3793 +}
3794 +
3795 +static int client_session_marshal_set_param (void *object,
3796 +                                       uint32_t id, uint32_t flags,
3797 +                                       const struct spa_pod *param)
3798 +{
3799 +       struct pw_resource *resource = object;
3800 +       struct spa_pod_builder *b;
3801 +
3802 +       b = pw_protocol_native_begin_resource(resource,
3803 +               PW_CLIENT_SESSION_PROXY_EVENT_SET_PARAM, NULL);
3804 +
3805 +       spa_pod_builder_add_struct(b,
3806 +                               SPA_POD_Int(id),
3807 +                               SPA_POD_Int(flags),
3808 +                               SPA_POD_Pod(param));
3809 +
3810 +       return pw_protocol_native_end_resource(resource, b);
3811 +}
3812 +
3813 +static int client_session_marshal_link_set_param (void *object,
3814 +                               uint32_t link_id, uint32_t id,
3815 +                               uint32_t flags, const struct spa_pod *param)
3816 +{
3817 +       struct pw_resource *resource = object;
3818 +       struct spa_pod_builder *b;
3819 +
3820 +       b = pw_protocol_native_begin_resource(resource,
3821 +               PW_CLIENT_SESSION_PROXY_EVENT_LINK_SET_PARAM, NULL);
3822 +
3823 +       spa_pod_builder_add_struct(b,
3824 +                               SPA_POD_Int(link_id),
3825 +                               SPA_POD_Id(id),
3826 +                               SPA_POD_Int(flags),
3827 +                               SPA_POD_Pod(param));
3828 +
3829 +       return pw_protocol_native_end_resource(resource, b);
3830 +}
3831 +
3832 +static int client_session_marshal_create_link(void *object,
3833 +                                       const struct spa_dict *props)
3834 +{
3835 +       struct pw_resource *resource = object;
3836 +       struct spa_pod_builder *b;
3837 +
3838 +       spa_return_val_if_fail(props, -EINVAL);
3839 +
3840 +       b = pw_protocol_native_begin_resource(resource,
3841 +               PW_CLIENT_SESSION_PROXY_EVENT_CREATE_LINK, NULL);
3842 +
3843 +       push_dict(b, props);
3844 +
3845 +       return pw_protocol_native_end_resource(resource, b);
3846 +}
3847 +
3848 +static int client_session_marshal_destroy_link (void *object, uint32_t link_id)
3849 +{
3850 +       struct pw_resource *resource = object;
3851 +       struct spa_pod_builder *b;
3852 +
3853 +       b = pw_protocol_native_begin_resource(resource,
3854 +               PW_CLIENT_SESSION_PROXY_EVENT_DESTROY_LINK, NULL);
3855 +
3856 +       spa_pod_builder_add(b, SPA_POD_Int(link_id), NULL);
3857 +
3858 +       return pw_protocol_native_end_resource(resource, b);
3859 +}
3860 +
3861 +static int client_session_marshal_link_request_state (void *object,
3862 +                               uint32_t link_id, uint32_t state)
3863 +{
3864 +       struct pw_resource *resource = object;
3865 +       struct spa_pod_builder *b;
3866 +
3867 +       b = pw_protocol_native_begin_resource(resource,
3868 +               PW_CLIENT_SESSION_PROXY_EVENT_LINK_REQUEST_STATE, NULL);
3869 +
3870 +       spa_pod_builder_add_struct(b,
3871 +                               SPA_POD_Int(link_id),
3872 +                               SPA_POD_Int(state));
3873 +
3874 +       return pw_protocol_native_end_resource(resource, b);
3875 +}
3876 +
3877 +static int client_session_marshal_add_listener(void *object,
3878 +                       struct spa_hook *listener,
3879 +                       const struct pw_client_session_proxy_events *events,
3880 +                       void *data)
3881 +{
3882 +       struct pw_proxy *proxy = object;
3883 +       pw_proxy_add_object_listener(proxy, listener, events, data);
3884 +       return 0;
3885 +}
3886 +
3887 +static int client_session_marshal_update(void *object,
3888 +                                       uint32_t change_mask,
3889 +                                       uint32_t n_params,
3890 +                                       const struct spa_pod **params,
3891 +                                       const struct pw_session_info *info)
3892 +{
3893 +       struct pw_proxy *proxy = object;
3894 +       struct spa_pod_builder *b;
3895 +       struct spa_pod_frame f;
3896 +       uint32_t i;
3897 +
3898 +       b = pw_protocol_native_begin_proxy(proxy,
3899 +               PW_CLIENT_SESSION_PROXY_METHOD_UPDATE, NULL);
3900 +
3901 +       spa_pod_builder_push_struct(b, &f);
3902 +       spa_pod_builder_add(b,
3903 +               SPA_POD_Int(change_mask),
3904 +               SPA_POD_Int(n_params),
3905 +               NULL);
3906 +
3907 +       for (i = 0; i < n_params; i++)
3908 +               spa_pod_builder_add(b, SPA_POD_Pod(params[i]), NULL);
3909 +
3910 +       if (info)
3911 +               marshal_pw_session_info(b, info);
3912 +       else
3913 +               spa_pod_builder_add(b, SPA_POD_Pod(NULL), NULL);
3914 +
3915 +       spa_pod_builder_pop(b, &f);
3916 +
3917 +       return pw_protocol_native_end_proxy(proxy, b);
3918 +}
3919 +
3920 +static int client_session_marshal_link_update(void *object,
3921 +                                       uint32_t link_id,
3922 +                                       uint32_t change_mask,
3923 +                                       uint32_t n_params,
3924 +                                       const struct spa_pod **params,
3925 +                                       const struct pw_endpoint_link_info *info)
3926 +{
3927 +       struct pw_proxy *proxy = object;
3928 +       struct spa_pod_builder *b;
3929 +       struct spa_pod_frame f;
3930 +       uint32_t i;
3931 +
3932 +       b = pw_protocol_native_begin_proxy(proxy,
3933 +               PW_CLIENT_SESSION_PROXY_METHOD_LINK_UPDATE, NULL);
3934 +
3935 +       spa_pod_builder_push_struct(b, &f);
3936 +       spa_pod_builder_add(b,
3937 +               SPA_POD_Int(link_id),
3938 +               SPA_POD_Int(change_mask),
3939 +               SPA_POD_Int(n_params),
3940 +               NULL);
3941 +
3942 +       for (i = 0; i < n_params; i++)
3943 +               spa_pod_builder_add(b, SPA_POD_Pod(params[i]), NULL);
3944 +
3945 +       if (info)
3946 +               marshal_pw_endpoint_link_info(b, info);
3947 +       else
3948 +               spa_pod_builder_add(b, SPA_POD_Pod(NULL), NULL);
3949 +
3950 +       spa_pod_builder_pop(b, &f);
3951 +
3952 +       return pw_protocol_native_end_proxy(proxy, b);
3953 +}
3954 +
3955 +static int client_session_demarshal_set_id(void *object,
3956 +                               const struct pw_protocol_native_message *msg)
3957 +{
3958 +       struct pw_proxy *proxy = object;
3959 +       struct spa_pod_parser prs;
3960 +       uint32_t id;
3961 +
3962 +       spa_pod_parser_init(&prs, msg->data, msg->size);
3963 +       if (spa_pod_parser_get_struct(&prs,
3964 +                       SPA_POD_Int(&id)) < 0)
3965 +               return -EINVAL;
3966 +
3967 +       return pw_proxy_notify(proxy, struct pw_client_session_proxy_events,
3968 +                               set_id, 0, id);
3969 +}
3970 +
3971 +static int client_session_demarshal_set_param(void *object,
3972 +                               const struct pw_protocol_native_message *msg)
3973 +{
3974 +       struct pw_proxy *proxy = object;
3975 +       struct spa_pod_parser prs;
3976 +       uint32_t id, flags;
3977 +       const struct spa_pod *param = NULL;
3978 +
3979 +       spa_pod_parser_init(&prs, msg->data, msg->size);
3980 +       if (spa_pod_parser_get_struct(&prs,
3981 +                       SPA_POD_Int(&id),
3982 +                       SPA_POD_Int(&flags),
3983 +                       SPA_POD_PodObject(&param)) < 0)
3984 +               return -EINVAL;
3985 +
3986 +       return pw_proxy_notify(proxy, struct pw_client_session_proxy_events,
3987 +                               set_param, 0, id, flags, param);
3988 +}
3989 +
3990 +static int client_session_demarshal_link_set_param(void *object,
3991 +                               const struct pw_protocol_native_message *msg)
3992 +{
3993 +       struct pw_proxy *proxy = object;
3994 +       struct spa_pod_parser prs;
3995 +       uint32_t link_id, id, flags;
3996 +       const struct spa_pod *param = NULL;
3997 +
3998 +       spa_pod_parser_init(&prs, msg->data, msg->size);
3999 +       if (spa_pod_parser_get_struct(&prs,
4000 +                       SPA_POD_Int(&link_id),
4001 +                       SPA_POD_Int(&id),
4002 +                       SPA_POD_Int(&flags),
4003 +                       SPA_POD_PodObject(&param)) < 0)
4004 +               return -EINVAL;
4005 +
4006 +       return pw_proxy_notify(proxy, struct pw_client_session_proxy_events,
4007 +                               link_set_param, 0, link_id, id, flags, param);
4008 +}
4009 +
4010 +static int client_session_demarshal_create_link(void *object,
4011 +                               const struct pw_protocol_native_message *msg)
4012 +{
4013 +       struct pw_proxy *proxy = object;
4014 +       struct spa_pod_parser prs;
4015 +       struct spa_pod_frame f;
4016 +       struct spa_dict props = SPA_DICT_INIT(NULL, 0);
4017 +
4018 +       spa_pod_parser_init(&prs, msg->data, msg->size);
4019 +       parse_dict(&prs, &f, &props);
4020 +
4021 +       return pw_proxy_notify(proxy, struct pw_client_session_proxy_events,
4022 +                               create_link, 0, &props);
4023 +}
4024 +
4025 +static int client_session_demarshal_destroy_link(void *object,
4026 +                               const struct pw_protocol_native_message *msg)
4027 +{
4028 +       struct pw_proxy *proxy = object;
4029 +       struct spa_pod_parser prs;
4030 +       uint32_t link_id;
4031 +
4032 +       spa_pod_parser_init(&prs, msg->data, msg->size);
4033 +       if (spa_pod_parser_get_struct(&prs,
4034 +                       SPA_POD_Int(&link_id)) < 0)
4035 +               return -EINVAL;
4036 +
4037 +       return pw_proxy_notify(proxy, struct pw_client_session_proxy_events,
4038 +                               destroy_link, 0, link_id);
4039 +}
4040 +
4041 +static int client_session_demarshal_link_request_state(void *object,
4042 +                               const struct pw_protocol_native_message *msg)
4043 +{
4044 +       struct pw_proxy *proxy = object;
4045 +       struct spa_pod_parser prs;
4046 +       uint32_t link_id, state;
4047 +
4048 +       spa_pod_parser_init(&prs, msg->data, msg->size);
4049 +       if (spa_pod_parser_get_struct(&prs,
4050 +                       SPA_POD_Int(&link_id),
4051 +                       SPA_POD_Int(&state)) < 0)
4052 +               return -EINVAL;
4053 +
4054 +       return pw_proxy_notify(proxy, struct pw_client_session_proxy_events,
4055 +                               link_request_state, 0, link_id, state);
4056 +}
4057 +
4058 +static int client_session_demarshal_update(void *object,
4059 +                               const struct pw_protocol_native_message *msg)
4060 +{
4061 +       struct pw_resource *resource = object;
4062 +       struct spa_pod_parser prs[2];
4063 +       struct spa_pod_frame f[2];
4064 +       uint32_t change_mask, n_params;
4065 +       const struct spa_pod **params = NULL;
4066 +       struct spa_dict props = SPA_DICT_INIT(NULL, 0);
4067 +       struct pw_session_info info = { .props = &props }, *infop = NULL;
4068 +       struct spa_pod *ipod;
4069 +       uint32_t i;
4070 +
4071 +       spa_pod_parser_init(&prs[0], msg->data, msg->size);
4072 +       if (spa_pod_parser_push_struct(&prs[0], &f[0]) < 0 ||
4073 +           spa_pod_parser_get(&prs[0],
4074 +                       SPA_POD_Int(&change_mask),
4075 +                       SPA_POD_Int(&n_params), NULL) < 0)
4076 +               return -EINVAL;
4077 +
4078 +       if (n_params > 0)
4079 +               params = alloca(n_params * sizeof(struct spa_pod *));
4080 +       for (i = 0; i < n_params; i++)
4081 +               if (spa_pod_parser_get(&prs[0],
4082 +                               SPA_POD_PodObject(&params[i]), NULL) < 0)
4083 +                       return -EINVAL;
4084 +
4085 +       if (spa_pod_parser_get(&prs[0], SPA_POD_PodStruct(&ipod), NULL) < 0)
4086 +               return -EINVAL;
4087 +       if (ipod) {
4088 +               infop = &info;
4089 +               spa_pod_parser_pod(&prs[1], ipod);
4090 +               demarshal_pw_session_info(&prs[1], &f[1], infop);
4091 +       }
4092 +
4093 +       return pw_resource_notify(resource, struct pw_client_session_proxy_methods,
4094 +                       update, 0, change_mask, n_params, params, infop);
4095 +}
4096 +
4097 +static int client_session_demarshal_link_update(void *object,
4098 +                               const struct pw_protocol_native_message *msg)
4099 +{
4100 +       struct pw_resource *resource = object;
4101 +       struct spa_pod_parser prs[2];
4102 +       struct spa_pod_frame f[2];
4103 +       uint32_t link_id, change_mask, n_params;
4104 +       const struct spa_pod **params = NULL;
4105 +       struct spa_dict props = SPA_DICT_INIT(NULL, 0);
4106 +       struct pw_endpoint_link_info info = { .props = &props }, *infop = NULL;
4107 +       struct spa_pod *ipod;
4108 +       uint32_t i;
4109 +
4110 +       spa_pod_parser_init(&prs[0], msg->data, msg->size);
4111 +       if (spa_pod_parser_push_struct(&prs[0], &f[0]) < 0 ||
4112 +           spa_pod_parser_get(&prs[0],
4113 +                       SPA_POD_Int(&link_id),
4114 +                       SPA_POD_Int(&change_mask),
4115 +                       SPA_POD_Int(&n_params), NULL) < 0)
4116 +               return -EINVAL;
4117 +
4118 +       if (n_params > 0)
4119 +               params = alloca(n_params * sizeof(struct spa_pod *));
4120 +       for (i = 0; i < n_params; i++)
4121 +               if (spa_pod_parser_get(&prs[0],
4122 +                               SPA_POD_PodObject(&params[i]), NULL) < 0)
4123 +                       return -EINVAL;
4124 +
4125 +       if (spa_pod_parser_get(&prs[0], SPA_POD_PodStruct(&ipod), NULL) < 0)
4126 +               return -EINVAL;
4127 +       if (ipod) {
4128 +               infop = &info;
4129 +               spa_pod_parser_pod(&prs[1], ipod);
4130 +               demarshal_pw_endpoint_link_info(&prs[1], &f[1], infop);
4131 +       }
4132 +
4133 +       return pw_resource_notify(resource, struct pw_client_session_proxy_methods,
4134 +                       link_update, 0, link_id, change_mask, n_params, params, infop);
4135 +}
4136 +
4137 +static const struct pw_client_session_proxy_events pw_protocol_native_client_session_event_marshal = {
4138 +       PW_VERSION_CLIENT_SESSION_PROXY_EVENTS,
4139 +       .set_id = client_session_marshal_set_id,
4140 +       .set_param = client_session_marshal_set_param,
4141 +       .link_set_param = client_session_marshal_link_set_param,
4142 +       .create_link = client_session_marshal_create_link,
4143 +       .destroy_link = client_session_marshal_destroy_link,
4144 +       .link_request_state = client_session_marshal_link_request_state,
4145 +};
4146 +
4147 +static const struct pw_protocol_native_demarshal
4148 +pw_protocol_native_client_session_event_demarshal[PW_CLIENT_SESSION_PROXY_EVENT_NUM] =
4149 +{
4150 +       [PW_CLIENT_SESSION_PROXY_EVENT_SET_ID] = { client_session_demarshal_set_id, 0 },
4151 +       [PW_CLIENT_SESSION_PROXY_EVENT_SET_PARAM] = { client_session_demarshal_set_param, 0 },
4152 +       [PW_CLIENT_SESSION_PROXY_EVENT_LINK_SET_PARAM] = { client_session_demarshal_link_set_param, 0 },
4153 +       [PW_CLIENT_SESSION_PROXY_EVENT_CREATE_LINK] = { client_session_demarshal_create_link, 0 },
4154 +       [PW_CLIENT_SESSION_PROXY_EVENT_DESTROY_LINK] = { client_session_demarshal_destroy_link, 0 },
4155 +       [PW_CLIENT_SESSION_PROXY_EVENT_LINK_REQUEST_STATE] = { client_session_demarshal_link_request_state, 0 },
4156 +};
4157 +
4158 +static const struct pw_client_session_proxy_methods pw_protocol_native_client_session_method_marshal = {
4159 +       PW_VERSION_CLIENT_SESSION_PROXY_METHODS,
4160 +       .add_listener = client_session_marshal_add_listener,
4161 +       .update = client_session_marshal_update,
4162 +       .link_update = client_session_marshal_link_update,
4163 +};
4164 +
4165 +static const struct pw_protocol_native_demarshal
4166 +pw_protocol_native_client_session_method_demarshal[PW_CLIENT_SESSION_PROXY_METHOD_NUM] =
4167 +{
4168 +       [PW_CLIENT_SESSION_PROXY_METHOD_ADD_LISTENER] = { NULL, 0 },
4169 +       [PW_CLIENT_SESSION_PROXY_METHOD_UPDATE] = { client_session_demarshal_update, 0 },
4170 +       [PW_CLIENT_SESSION_PROXY_METHOD_LINK_UPDATE] = { client_session_demarshal_link_update, 0 },
4171 +};
4172 +
4173 +static const struct pw_protocol_marshal pw_protocol_native_client_session_marshal = {
4174 +       PW_TYPE_INTERFACE_ClientSession,
4175 +       PW_VERSION_CLIENT_SESSION_PROXY,
4176 +       PW_CLIENT_SESSION_PROXY_METHOD_NUM,
4177 +       PW_CLIENT_SESSION_PROXY_EVENT_NUM,
4178 +       &pw_protocol_native_client_session_method_marshal,
4179 +       &pw_protocol_native_client_session_method_demarshal,
4180 +       &pw_protocol_native_client_session_event_marshal,
4181 +       &pw_protocol_native_client_session_event_demarshal,
4182 +};
4183 +
4184 +/***********************************************
4185 + *               ENDPOINT LINK
4186 + ***********************************************/
4187 +
4188 +static void endpoint_link_marshal_info (void *object,
4189 +                               const struct pw_endpoint_link_info *info)
4190 +{
4191 +       struct pw_resource *resource = object;
4192 +       struct spa_pod_builder *b;
4193 +
4194 +       b = pw_protocol_native_begin_resource(resource,
4195 +               PW_ENDPOINT_LINK_PROXY_EVENT_INFO, NULL);
4196 +
4197 +       marshal_pw_endpoint_link_info(b, info);
4198 +
4199 +       pw_protocol_native_end_resource(resource, b);
4200 +}
4201 +
4202 +static void endpoint_link_marshal_param (void *object, int seq, uint32_t id,
4203 +                                       uint32_t index, uint32_t next,
4204 +                                       const struct spa_pod *param)
4205 +{
4206 +       struct pw_resource *resource = object;
4207 +       struct spa_pod_builder *b;
4208 +
4209 +       b = pw_protocol_native_begin_resource(resource,
4210 +               PW_ENDPOINT_LINK_PROXY_EVENT_PARAM, NULL);
4211 +
4212 +       spa_pod_builder_add_struct(b,
4213 +                               SPA_POD_Int(seq),
4214 +                               SPA_POD_Id(id),
4215 +                               SPA_POD_Int(index),
4216 +                               SPA_POD_Int(next),
4217 +                               SPA_POD_Pod(param));
4218 +
4219 +       pw_protocol_native_end_resource(resource, b);
4220 +}
4221 +
4222 +static int endpoint_link_marshal_add_listener(void *object,
4223 +                       struct spa_hook *listener,
4224 +                       const struct pw_endpoint_link_proxy_events *events,
4225 +                       void *data)
4226 +{
4227 +       struct pw_proxy *proxy = object;
4228 +       pw_proxy_add_object_listener(proxy, listener, events, data);
4229 +       return 0;
4230 +}
4231 +
4232 +static int endpoint_link_marshal_subscribe_params(void *object,
4233 +                                               uint32_t *ids, uint32_t n_ids)
4234 +{
4235 +       struct pw_proxy *proxy = object;
4236 +       struct spa_pod_builder *b;
4237 +
4238 +       b = pw_protocol_native_begin_proxy(proxy,
4239 +               PW_ENDPOINT_LINK_PROXY_METHOD_SUBSCRIBE_PARAMS, NULL);
4240 +
4241 +       spa_pod_builder_add_struct(b,
4242 +                       SPA_POD_Array(sizeof(uint32_t), SPA_TYPE_Id, n_ids, ids));
4243 +
4244 +       return pw_protocol_native_end_proxy(proxy, b);
4245 +}
4246 +
4247 +static int endpoint_link_marshal_enum_params(void *object,
4248 +                                       int seq, uint32_t id,
4249 +                                       uint32_t start, uint32_t num,
4250 +                                       const struct spa_pod *filter)
4251 +{
4252 +       struct pw_protocol_native_message *msg;
4253 +       struct pw_proxy *proxy = object;
4254 +       struct spa_pod_builder *b;
4255 +
4256 +       b = pw_protocol_native_begin_proxy(proxy,
4257 +               PW_ENDPOINT_LINK_PROXY_METHOD_ENUM_PARAMS, &msg);
4258 +
4259 +       spa_pod_builder_add_struct(b,
4260 +                       SPA_POD_Int(SPA_RESULT_RETURN_ASYNC(msg->seq)),
4261 +                       SPA_POD_Id(id),
4262 +                       SPA_POD_Int(index),
4263 +                       SPA_POD_Int(num),
4264 +                       SPA_POD_Pod(filter));
4265 +
4266 +       return pw_protocol_native_end_proxy(proxy, b);
4267 +}
4268 +
4269 +static int endpoint_link_marshal_set_param(void *object,
4270 +                                       uint32_t id, uint32_t flags,
4271 +                                       const struct spa_pod *param)
4272 +{
4273 +       struct pw_proxy *proxy = object;
4274 +       struct spa_pod_builder *b;
4275 +
4276 +       b = pw_protocol_native_begin_proxy(proxy,
4277 +               PW_ENDPOINT_LINK_PROXY_METHOD_SET_PARAM, NULL);
4278 +
4279 +       spa_pod_builder_add_struct(b,
4280 +                       SPA_POD_Id(id),
4281 +                       SPA_POD_Int(flags),
4282 +                       SPA_POD_Pod(param));
4283 +
4284 +       return pw_protocol_native_end_proxy(proxy, b);
4285 +}
4286 +
4287 +static int endpoint_link_marshal_request_state(void *object,
4288 +                                       enum pw_endpoint_link_state state)
4289 +{
4290 +       struct pw_proxy *proxy = object;
4291 +       struct spa_pod_builder *b;
4292 +
4293 +       b = pw_protocol_native_begin_proxy(proxy,
4294 +               PW_ENDPOINT_LINK_PROXY_METHOD_REQUEST_STATE, NULL);
4295 +
4296 +       spa_pod_builder_add_struct(b, SPA_POD_Int(state));
4297 +
4298 +       return pw_protocol_native_end_proxy(proxy, b);
4299 +}
4300 +
4301 +static int endpoint_link_marshal_destroy(void *object)
4302 +{
4303 +       struct pw_proxy *proxy = object;
4304 +       struct spa_pod_builder *b;
4305 +
4306 +       b = pw_protocol_native_begin_proxy(proxy,
4307 +               PW_ENDPOINT_LINK_PROXY_METHOD_DESTROY, NULL);
4308 +
4309 +       return pw_protocol_native_end_proxy(proxy, b);
4310 +}
4311 +
4312 +static int endpoint_link_demarshal_info(void *object,
4313 +                               const struct pw_protocol_native_message *msg)
4314 +{
4315 +       struct pw_proxy *proxy = object;
4316 +       struct spa_pod_parser prs;
4317 +       struct spa_pod_frame f;
4318 +       struct spa_dict props = SPA_DICT_INIT(NULL, 0);
4319 +       struct pw_endpoint_link_info info = { .props = &props };
4320 +
4321 +       spa_pod_parser_init(&prs, msg->data, msg->size);
4322 +
4323 +       demarshal_pw_endpoint_link_info(&prs, &f, &info);
4324 +
4325 +       return pw_proxy_notify(proxy, struct pw_endpoint_link_proxy_events,
4326 +                               info, 0, &info);
4327 +}
4328 +
4329 +static int endpoint_link_demarshal_param(void *object,
4330 +                               const struct pw_protocol_native_message *msg)
4331 +{
4332 +       struct pw_proxy *proxy = object;
4333 +       struct spa_pod_parser prs;
4334 +       uint32_t id, index, next;
4335 +       int seq;
4336 +       struct spa_pod *param;
4337 +
4338 +       spa_pod_parser_init(&prs, msg->data, msg->size);
4339 +       if (spa_pod_parser_get_struct(&prs,
4340 +                               SPA_POD_Int(&seq),
4341 +                               SPA_POD_Id(&id),
4342 +                               SPA_POD_Int(&index),
4343 +                               SPA_POD_Int(&next),
4344 +                               SPA_POD_Pod(&param)) < 0)
4345 +               return -EINVAL;
4346 +
4347 +       return pw_proxy_notify(proxy, struct pw_endpoint_link_proxy_events,
4348 +                               param, 0, seq, id, index, next, param);
4349 +}
4350 +
4351 +static int endpoint_link_demarshal_subscribe_params(void *object,
4352 +                               const struct pw_protocol_native_message *msg)
4353 +{
4354 +       struct pw_resource *resource = object;
4355 +       struct spa_pod_parser prs;
4356 +       uint32_t csize, ctype, n_ids;
4357 +       uint32_t *ids;
4358 +
4359 +       spa_pod_parser_init(&prs, msg->data, msg->size);
4360 +       if (spa_pod_parser_get_struct(&prs,
4361 +                               SPA_POD_Array(&csize, &ctype, &n_ids, &ids)) < 0)
4362 +               return -EINVAL;
4363 +
4364 +       if (ctype != SPA_TYPE_Id)
4365 +               return -EINVAL;
4366 +
4367 +       return pw_resource_notify(resource, struct pw_endpoint_link_proxy_methods,
4368 +                               subscribe_params, 0, ids, n_ids);
4369 +}
4370 +
4371 +static int endpoint_link_demarshal_enum_params(void *object,
4372 +                               const struct pw_protocol_native_message *msg)
4373 +{
4374 +       struct pw_resource *resource = object;
4375 +       struct spa_pod_parser prs;
4376 +       uint32_t id, index, num;
4377 +       int seq;
4378 +       struct spa_pod *filter;
4379 +
4380 +       spa_pod_parser_init(&prs, msg->data, msg->size);
4381 +       if (spa_pod_parser_get_struct(&prs,
4382 +                               SPA_POD_Int(&seq),
4383 +                               SPA_POD_Id(&id),
4384 +                               SPA_POD_Int(&index),
4385 +                               SPA_POD_Int(&num),
4386 +                               SPA_POD_Pod(&filter)) < 0)
4387 +               return -EINVAL;
4388 +
4389 +       return pw_resource_notify(resource, struct pw_endpoint_link_proxy_methods,
4390 +                               enum_params, 0, seq, id, index, num, filter);
4391 +}
4392 +
4393 +static int endpoint_link_demarshal_set_param(void *object,
4394 +                               const struct pw_protocol_native_message *msg)
4395 +{
4396 +       struct pw_resource *resource = object;
4397 +       struct spa_pod_parser prs;
4398 +       uint32_t id, flags;
4399 +       struct spa_pod *param;
4400 +
4401 +       spa_pod_parser_init(&prs, msg->data, msg->size);
4402 +       if (spa_pod_parser_get_struct(&prs,
4403 +                               SPA_POD_Id(&id),
4404 +                               SPA_POD_Int(&flags),
4405 +                               SPA_POD_Pod(&param)) < 0)
4406 +               return -EINVAL;
4407 +
4408 +       return pw_resource_notify(resource, struct pw_endpoint_link_proxy_methods,
4409 +                               set_param, 0, id, flags, param);
4410 +}
4411 +
4412 +static int endpoint_link_demarshal_request_state(void *object,
4413 +                               const struct pw_protocol_native_message *msg)
4414 +{
4415 +       struct pw_resource *resource = object;
4416 +       struct spa_pod_parser prs;
4417 +       enum pw_endpoint_link_state state;
4418 +
4419 +       spa_pod_parser_init(&prs, msg->data, msg->size);
4420 +       if (spa_pod_parser_get_struct(&prs,
4421 +                               SPA_POD_Int(&state)) < 0)
4422 +               return -EINVAL;
4423 +
4424 +       return pw_resource_notify(resource, struct pw_endpoint_link_proxy_methods,
4425 +                               request_state, 0, state);
4426 +}
4427 +
4428 +static int endpoint_link_demarshal_destroy(void *object,
4429 +                               const struct pw_protocol_native_message *msg)
4430 +{
4431 +       struct pw_resource *resource = object;
4432 +
4433 +       return pw_resource_notify(resource, struct pw_endpoint_link_proxy_methods,
4434 +                               destroy, 0);
4435 +}
4436 +
4437 +static const struct pw_endpoint_link_proxy_events pw_protocol_native_endpoint_link_event_marshal = {
4438 +       PW_VERSION_ENDPOINT_LINK_PROXY_EVENTS,
4439 +       .info = endpoint_link_marshal_info,
4440 +       .param = endpoint_link_marshal_param,
4441 +};
4442 +
4443 +static const struct pw_protocol_native_demarshal
4444 +pw_protocol_native_endpoint_link_event_demarshal[PW_ENDPOINT_LINK_PROXY_EVENT_NUM] =
4445 +{
4446 +       [PW_ENDPOINT_LINK_PROXY_EVENT_INFO] = { endpoint_link_demarshal_info, 0 },
4447 +       [PW_ENDPOINT_LINK_PROXY_EVENT_PARAM] = { endpoint_link_demarshal_param, 0 },
4448 +};
4449 +
4450 +static const struct pw_endpoint_link_proxy_methods pw_protocol_native_endpoint_link_method_marshal = {
4451 +       PW_VERSION_ENDPOINT_LINK_PROXY_METHODS,
4452 +       .add_listener = endpoint_link_marshal_add_listener,
4453 +       .subscribe_params = endpoint_link_marshal_subscribe_params,
4454 +       .enum_params = endpoint_link_marshal_enum_params,
4455 +       .set_param = endpoint_link_marshal_set_param,
4456 +       .request_state = endpoint_link_marshal_request_state,
4457 +       .destroy = endpoint_link_marshal_destroy,
4458 +};
4459 +
4460 +static const struct pw_protocol_native_demarshal
4461 +pw_protocol_native_endpoint_link_method_demarshal[PW_ENDPOINT_LINK_PROXY_METHOD_NUM] =
4462 +{
4463 +       [PW_ENDPOINT_LINK_PROXY_METHOD_ADD_LISTENER] = { NULL, 0 },
4464 +       [PW_ENDPOINT_LINK_PROXY_METHOD_SUBSCRIBE_PARAMS] = { endpoint_link_demarshal_subscribe_params, 0 },
4465 +       [PW_ENDPOINT_LINK_PROXY_METHOD_ENUM_PARAMS] = { endpoint_link_demarshal_enum_params, 0 },
4466 +       [PW_ENDPOINT_LINK_PROXY_METHOD_SET_PARAM] = { endpoint_link_demarshal_set_param, PW_PERM_W },
4467 +       [PW_ENDPOINT_LINK_PROXY_METHOD_REQUEST_STATE] = { endpoint_link_demarshal_request_state, PW_PERM_W },
4468 +       [PW_ENDPOINT_LINK_PROXY_METHOD_DESTROY] = { endpoint_link_demarshal_destroy, PW_PERM_W },
4469 +};
4470 +
4471 +static const struct pw_protocol_marshal pw_protocol_native_endpoint_link_marshal = {
4472 +       PW_TYPE_INTERFACE_EndpointLink,
4473 +       PW_VERSION_ENDPOINT_LINK_PROXY,
4474 +       PW_ENDPOINT_LINK_PROXY_METHOD_NUM,
4475 +       PW_ENDPOINT_LINK_PROXY_EVENT_NUM,
4476 +       &pw_protocol_native_endpoint_link_method_marshal,
4477 +       &pw_protocol_native_endpoint_link_method_demarshal,
4478 +       &pw_protocol_native_endpoint_link_event_marshal,
4479 +       &pw_protocol_native_endpoint_link_event_demarshal,
4480 +};
4481 +
4482 +/***********************************************
4483 + *               ENDPOINT STREAM
4484 + ***********************************************/
4485 +
4486 +static void endpoint_stream_marshal_info (void *object,
4487 +                               const struct pw_endpoint_stream_info *info)
4488 +{
4489 +       struct pw_resource *resource = object;
4490 +       struct spa_pod_builder *b;
4491 +
4492 +       b = pw_protocol_native_begin_resource(resource,
4493 +               PW_ENDPOINT_STREAM_PROXY_EVENT_INFO, NULL);
4494 +
4495 +       marshal_pw_endpoint_stream_info(b, info);
4496 +
4497 +       pw_protocol_native_end_resource(resource, b);
4498 +}
4499 +
4500 +static void endpoint_stream_marshal_param (void *object, int seq, uint32_t id,
4501 +                                       uint32_t index, uint32_t next,
4502 +                                       const struct spa_pod *param)
4503 +{
4504 +       struct pw_resource *resource = object;
4505 +       struct spa_pod_builder *b;
4506 +
4507 +       b = pw_protocol_native_begin_resource(resource,
4508 +               PW_ENDPOINT_STREAM_PROXY_EVENT_PARAM, NULL);
4509 +
4510 +       spa_pod_builder_add_struct(b,
4511 +                               SPA_POD_Int(seq),
4512 +                               SPA_POD_Id(id),
4513 +                               SPA_POD_Int(index),
4514 +                               SPA_POD_Int(next),
4515 +                               SPA_POD_Pod(param));
4516 +
4517 +       pw_protocol_native_end_resource(resource, b);
4518 +}
4519 +
4520 +static int endpoint_stream_marshal_add_listener(void *object,
4521 +                       struct spa_hook *listener,
4522 +                       const struct pw_endpoint_stream_proxy_events *events,
4523 +                       void *data)
4524 +{
4525 +       struct pw_proxy *proxy = object;
4526 +       pw_proxy_add_object_listener(proxy, listener, events, data);
4527 +       return 0;
4528 +}
4529 +
4530 +static int endpoint_stream_marshal_subscribe_params(void *object,
4531 +                                               uint32_t *ids, uint32_t n_ids)
4532 +{
4533 +       struct pw_proxy *proxy = object;
4534 +       struct spa_pod_builder *b;
4535 +
4536 +       b = pw_protocol_native_begin_proxy(proxy,
4537 +               PW_ENDPOINT_STREAM_PROXY_METHOD_SUBSCRIBE_PARAMS, NULL);
4538 +
4539 +       spa_pod_builder_add_struct(b,
4540 +                       SPA_POD_Array(sizeof(uint32_t), SPA_TYPE_Id, n_ids, ids));
4541 +
4542 +       return pw_protocol_native_end_proxy(proxy, b);
4543 +}
4544 +
4545 +static int endpoint_stream_marshal_enum_params(void *object,
4546 +                                       int seq, uint32_t id,
4547 +                                       uint32_t start, uint32_t num,
4548 +                                       const struct spa_pod *filter)
4549 +{
4550 +       struct pw_protocol_native_message *msg;
4551 +       struct pw_proxy *proxy = object;
4552 +       struct spa_pod_builder *b;
4553 +
4554 +       b = pw_protocol_native_begin_proxy(proxy,
4555 +               PW_ENDPOINT_STREAM_PROXY_METHOD_ENUM_PARAMS, &msg);
4556 +
4557 +       spa_pod_builder_add_struct(b,
4558 +                       SPA_POD_Int(SPA_RESULT_RETURN_ASYNC(msg->seq)),
4559 +                       SPA_POD_Id(id),
4560 +                       SPA_POD_Int(index),
4561 +                       SPA_POD_Int(num),
4562 +                       SPA_POD_Pod(filter));
4563 +
4564 +       return pw_protocol_native_end_proxy(proxy, b);
4565 +}
4566 +
4567 +static int endpoint_stream_marshal_set_param(void *object,
4568 +                                       uint32_t id, uint32_t flags,
4569 +                                       const struct spa_pod *param)
4570 +{
4571 +       struct pw_proxy *proxy = object;
4572 +       struct spa_pod_builder *b;
4573 +
4574 +       b = pw_protocol_native_begin_proxy(proxy,
4575 +               PW_ENDPOINT_STREAM_PROXY_METHOD_SET_PARAM, NULL);
4576 +
4577 +       spa_pod_builder_add_struct(b,
4578 +                       SPA_POD_Id(id),
4579 +                       SPA_POD_Int(flags),
4580 +                       SPA_POD_Pod(param));
4581 +
4582 +       return pw_protocol_native_end_proxy(proxy, b);
4583 +}
4584 +
4585 +static int endpoint_stream_demarshal_info(void *object,
4586 +                               const struct pw_protocol_native_message *msg)
4587 +{
4588 +       struct pw_proxy *proxy = object;
4589 +       struct spa_pod_parser prs;
4590 +       struct spa_pod_frame f;
4591 +       struct spa_dict props = SPA_DICT_INIT(NULL, 0);
4592 +       struct pw_endpoint_stream_info info = { .props = &props };
4593 +
4594 +       spa_pod_parser_init(&prs, msg->data, msg->size);
4595 +
4596 +       demarshal_pw_endpoint_stream_info(&prs, &f, &info);
4597 +
4598 +       return pw_proxy_notify(proxy, struct pw_endpoint_stream_proxy_events,
4599 +                               info, 0, &info);
4600 +}
4601 +
4602 +static int endpoint_stream_demarshal_param(void *object,
4603 +                               const struct pw_protocol_native_message *msg)
4604 +{
4605 +       struct pw_proxy *proxy = object;
4606 +       struct spa_pod_parser prs;
4607 +       uint32_t id, index, next;
4608 +       int seq;
4609 +       struct spa_pod *param;
4610 +
4611 +       spa_pod_parser_init(&prs, msg->data, msg->size);
4612 +       if (spa_pod_parser_get_struct(&prs,
4613 +                               SPA_POD_Int(&seq),
4614 +                               SPA_POD_Id(&id),
4615 +                               SPA_POD_Int(&index),
4616 +                               SPA_POD_Int(&next),
4617 +                               SPA_POD_Pod(&param)) < 0)
4618 +               return -EINVAL;
4619 +
4620 +       return pw_proxy_notify(proxy, struct pw_endpoint_stream_proxy_events,
4621 +                               param, 0, seq, id, index, next, param);
4622 +}
4623 +
4624 +static int endpoint_stream_demarshal_subscribe_params(void *object,
4625 +                               const struct pw_protocol_native_message *msg)
4626 +{
4627 +       struct pw_resource *resource = object;
4628 +       struct spa_pod_parser prs;
4629 +       uint32_t csize, ctype, n_ids;
4630 +       uint32_t *ids;
4631 +
4632 +       spa_pod_parser_init(&prs, msg->data, msg->size);
4633 +       if (spa_pod_parser_get_struct(&prs,
4634 +                               SPA_POD_Array(&csize, &ctype, &n_ids, &ids)) < 0)
4635 +               return -EINVAL;
4636 +
4637 +       if (ctype != SPA_TYPE_Id)
4638 +               return -EINVAL;
4639 +
4640 +       return pw_resource_notify(resource, struct pw_endpoint_stream_proxy_methods,
4641 +                               subscribe_params, 0, ids, n_ids);
4642 +}
4643 +
4644 +static int endpoint_stream_demarshal_enum_params(void *object,
4645 +                               const struct pw_protocol_native_message *msg)
4646 +{
4647 +       struct pw_resource *resource = object;
4648 +       struct spa_pod_parser prs;
4649 +       uint32_t id, index, num;
4650 +       int seq;
4651 +       struct spa_pod *filter;
4652 +
4653 +       spa_pod_parser_init(&prs, msg->data, msg->size);
4654 +       if (spa_pod_parser_get_struct(&prs,
4655 +                               SPA_POD_Int(&seq),
4656 +                               SPA_POD_Id(&id),
4657 +                               SPA_POD_Int(&index),
4658 +                               SPA_POD_Int(&num),
4659 +                               SPA_POD_Pod(&filter)) < 0)
4660 +               return -EINVAL;
4661 +
4662 +       return pw_resource_notify(resource, struct pw_endpoint_stream_proxy_methods,
4663 +                               enum_params, 0, seq, id, index, num, filter);
4664 +}
4665 +
4666 +static int endpoint_stream_demarshal_set_param(void *object,
4667 +                               const struct pw_protocol_native_message *msg)
4668 +{
4669 +       struct pw_resource *resource = object;
4670 +       struct spa_pod_parser prs;
4671 +       uint32_t id, flags;
4672 +       struct spa_pod *param;
4673 +
4674 +       spa_pod_parser_init(&prs, msg->data, msg->size);
4675 +       if (spa_pod_parser_get_struct(&prs,
4676 +                               SPA_POD_Id(&id),
4677 +                               SPA_POD_Int(&flags),
4678 +                               SPA_POD_Pod(&param)) < 0)
4679 +               return -EINVAL;
4680 +
4681 +       return pw_resource_notify(resource, struct pw_endpoint_stream_proxy_methods,
4682 +                               set_param, 0, id, flags, param);
4683 +}
4684 +
4685 +static const struct pw_endpoint_stream_proxy_events pw_protocol_native_endpoint_stream_event_marshal = {
4686 +       PW_VERSION_ENDPOINT_STREAM_PROXY_EVENTS,
4687 +       .info = endpoint_stream_marshal_info,
4688 +       .param = endpoint_stream_marshal_param,
4689 +};
4690 +
4691 +static const struct pw_protocol_native_demarshal
4692 +pw_protocol_native_endpoint_stream_event_demarshal[PW_ENDPOINT_STREAM_PROXY_EVENT_NUM] =
4693 +{
4694 +       [PW_ENDPOINT_STREAM_PROXY_EVENT_INFO] = { endpoint_stream_demarshal_info, 0 },
4695 +       [PW_ENDPOINT_STREAM_PROXY_EVENT_PARAM] = { endpoint_stream_demarshal_param, 0 },
4696 +};
4697 +
4698 +static const struct pw_endpoint_stream_proxy_methods pw_protocol_native_endpoint_stream_method_marshal = {
4699 +       PW_VERSION_ENDPOINT_STREAM_PROXY_METHODS,
4700 +       .add_listener = endpoint_stream_marshal_add_listener,
4701 +       .subscribe_params = endpoint_stream_marshal_subscribe_params,
4702 +       .enum_params = endpoint_stream_marshal_enum_params,
4703 +       .set_param = endpoint_stream_marshal_set_param,
4704 +};
4705 +
4706 +static const struct pw_protocol_native_demarshal
4707 +pw_protocol_native_endpoint_stream_method_demarshal[PW_ENDPOINT_STREAM_PROXY_METHOD_NUM] =
4708 +{
4709 +       [PW_ENDPOINT_STREAM_PROXY_METHOD_ADD_LISTENER] = { NULL, 0 },
4710 +       [PW_ENDPOINT_STREAM_PROXY_METHOD_SUBSCRIBE_PARAMS] = { endpoint_stream_demarshal_subscribe_params, 0 },
4711 +       [PW_ENDPOINT_STREAM_PROXY_METHOD_ENUM_PARAMS] = { endpoint_stream_demarshal_enum_params, 0 },
4712 +       [PW_ENDPOINT_STREAM_PROXY_METHOD_SET_PARAM] = { endpoint_stream_demarshal_set_param, PW_PERM_W },
4713 +};
4714 +
4715 +static const struct pw_protocol_marshal pw_protocol_native_endpoint_stream_marshal = {
4716 +       PW_TYPE_INTERFACE_EndpointStream,
4717 +       PW_VERSION_ENDPOINT_STREAM_PROXY,
4718 +       PW_ENDPOINT_STREAM_PROXY_METHOD_NUM,
4719 +       PW_ENDPOINT_STREAM_PROXY_EVENT_NUM,
4720 +       &pw_protocol_native_endpoint_stream_method_marshal,
4721 +       &pw_protocol_native_endpoint_stream_method_demarshal,
4722 +       &pw_protocol_native_endpoint_stream_event_marshal,
4723 +       &pw_protocol_native_endpoint_stream_event_demarshal,
4724 +};
4725 +
4726 +/***********************************************
4727 + *                  ENDPOINT
4728 + ***********************************************/
4729 +
4730 +static void endpoint_marshal_info (void *object,
4731 +                               const struct pw_endpoint_info *info)
4732 +{
4733 +       struct pw_resource *resource = object;
4734 +       struct spa_pod_builder *b;
4735 +
4736 +       b = pw_protocol_native_begin_resource(resource,
4737 +               PW_ENDPOINT_PROXY_EVENT_INFO, NULL);
4738 +
4739 +       marshal_pw_endpoint_info(b, info);
4740 +
4741 +       pw_protocol_native_end_resource(resource, b);
4742 +}
4743 +
4744 +static void endpoint_marshal_param (void *object, int seq, uint32_t id,
4745 +                                       uint32_t index, uint32_t next,
4746 +                                       const struct spa_pod *param)
4747 +{
4748 +       struct pw_resource *resource = object;
4749 +       struct spa_pod_builder *b;
4750 +
4751 +       b = pw_protocol_native_begin_resource(resource,
4752 +               PW_ENDPOINT_PROXY_EVENT_PARAM, NULL);
4753 +
4754 +       spa_pod_builder_add_struct(b,
4755 +                               SPA_POD_Int(seq),
4756 +                               SPA_POD_Id(id),
4757 +                               SPA_POD_Int(index),
4758 +                               SPA_POD_Int(next),
4759 +                               SPA_POD_Pod(param));
4760 +
4761 +       pw_protocol_native_end_resource(resource, b);
4762 +}
4763 +
4764 +static int endpoint_marshal_add_listener(void *object,
4765 +                       struct spa_hook *listener,
4766 +                       const struct pw_endpoint_proxy_events *events,
4767 +                       void *data)
4768 +{
4769 +       struct pw_proxy *proxy = object;
4770 +       pw_proxy_add_object_listener(proxy, listener, events, data);
4771 +       return 0;
4772 +}
4773 +
4774 +static int endpoint_marshal_subscribe_params(void *object,
4775 +                                               uint32_t *ids, uint32_t n_ids)
4776 +{
4777 +       struct pw_proxy *proxy = object;
4778 +       struct spa_pod_builder *b;
4779 +
4780 +       b = pw_protocol_native_begin_proxy(proxy,
4781 +               PW_ENDPOINT_PROXY_METHOD_SUBSCRIBE_PARAMS, NULL);
4782 +
4783 +       spa_pod_builder_add_struct(b,
4784 +                       SPA_POD_Array(sizeof(uint32_t), SPA_TYPE_Id, n_ids, ids));
4785 +
4786 +       return pw_protocol_native_end_proxy(proxy, b);
4787 +}
4788 +
4789 +static int endpoint_marshal_enum_params(void *object,
4790 +                                       int seq, uint32_t id,
4791 +                                       uint32_t start, uint32_t num,
4792 +                                       const struct spa_pod *filter)
4793 +{
4794 +       struct pw_protocol_native_message *msg;
4795 +       struct pw_proxy *proxy = object;
4796 +       struct spa_pod_builder *b;
4797 +
4798 +       b = pw_protocol_native_begin_proxy(proxy,
4799 +               PW_ENDPOINT_PROXY_METHOD_ENUM_PARAMS, &msg);
4800 +
4801 +       spa_pod_builder_add_struct(b,
4802 +                       SPA_POD_Int(SPA_RESULT_RETURN_ASYNC(msg->seq)),
4803 +                       SPA_POD_Id(id),
4804 +                       SPA_POD_Int(index),
4805 +                       SPA_POD_Int(num),
4806 +                       SPA_POD_Pod(filter));
4807 +
4808 +       return pw_protocol_native_end_proxy(proxy, b);
4809 +}
4810 +
4811 +static int endpoint_marshal_set_param(void *object,
4812 +                                       uint32_t id, uint32_t flags,
4813 +                                       const struct spa_pod *param)
4814 +{
4815 +       struct pw_proxy *proxy = object;
4816 +       struct spa_pod_builder *b;
4817 +
4818 +       b = pw_protocol_native_begin_proxy(proxy,
4819 +               PW_ENDPOINT_PROXY_METHOD_SET_PARAM, NULL);
4820 +
4821 +       spa_pod_builder_add_struct(b,
4822 +                       SPA_POD_Id(id),
4823 +                       SPA_POD_Int(flags),
4824 +                       SPA_POD_Pod(param));
4825 +
4826 +       return pw_protocol_native_end_proxy(proxy, b);
4827 +}
4828 +
4829 +static int endpoint_demarshal_info(void *object,
4830 +                               const struct pw_protocol_native_message *msg)
4831 +{
4832 +       struct pw_proxy *proxy = object;
4833 +       struct spa_pod_parser prs;
4834 +       struct spa_pod_frame f;
4835 +       struct spa_dict props = SPA_DICT_INIT(NULL, 0);
4836 +       struct pw_endpoint_info info = { .props = &props };
4837 +
4838 +       spa_pod_parser_init(&prs, msg->data, msg->size);
4839 +
4840 +       demarshal_pw_endpoint_info(&prs, &f, &info);
4841 +
4842 +       return pw_proxy_notify(proxy, struct pw_endpoint_proxy_events,
4843 +                               info, 0, &info);
4844 +}
4845 +
4846 +static int endpoint_demarshal_param(void *object,
4847 +                               const struct pw_protocol_native_message *msg)
4848 +{
4849 +       struct pw_proxy *proxy = object;
4850 +       struct spa_pod_parser prs;
4851 +       uint32_t id, index, next;
4852 +       int seq;
4853 +       struct spa_pod *param;
4854 +
4855 +       spa_pod_parser_init(&prs, msg->data, msg->size);
4856 +       if (spa_pod_parser_get_struct(&prs,
4857 +                               SPA_POD_Int(&seq),
4858 +                               SPA_POD_Id(&id),
4859 +                               SPA_POD_Int(&index),
4860 +                               SPA_POD_Int(&next),
4861 +                               SPA_POD_Pod(&param)) < 0)
4862 +               return -EINVAL;
4863 +
4864 +       return pw_proxy_notify(proxy, struct pw_endpoint_proxy_events,
4865 +                               param, 0, seq, id, index, next, param);
4866 +}
4867 +
4868 +static int endpoint_demarshal_subscribe_params(void *object,
4869 +                               const struct pw_protocol_native_message *msg)
4870 +{
4871 +       struct pw_resource *resource = object;
4872 +       struct spa_pod_parser prs;
4873 +       uint32_t csize, ctype, n_ids;
4874 +       uint32_t *ids;
4875 +
4876 +       spa_pod_parser_init(&prs, msg->data, msg->size);
4877 +       if (spa_pod_parser_get_struct(&prs,
4878 +                               SPA_POD_Array(&csize, &ctype, &n_ids, &ids)) < 0)
4879 +               return -EINVAL;
4880 +
4881 +       if (ctype != SPA_TYPE_Id)
4882 +               return -EINVAL;
4883 +
4884 +       return pw_resource_notify(resource, struct pw_endpoint_proxy_methods,
4885 +                               subscribe_params, 0, ids, n_ids);
4886 +}
4887 +
4888 +static int endpoint_demarshal_enum_params(void *object,
4889 +                               const struct pw_protocol_native_message *msg)
4890 +{
4891 +       struct pw_resource *resource = object;
4892 +       struct spa_pod_parser prs;
4893 +       uint32_t id, index, num;
4894 +       int seq;
4895 +       struct spa_pod *filter;
4896 +
4897 +       spa_pod_parser_init(&prs, msg->data, msg->size);
4898 +       if (spa_pod_parser_get_struct(&prs,
4899 +                               SPA_POD_Int(&seq),
4900 +                               SPA_POD_Id(&id),
4901 +                               SPA_POD_Int(&index),
4902 +                               SPA_POD_Int(&num),
4903 +                               SPA_POD_Pod(&filter)) < 0)
4904 +               return -EINVAL;
4905 +
4906 +       return pw_resource_notify(resource, struct pw_endpoint_proxy_methods,
4907 +                               enum_params, 0, seq, id, index, num, filter);
4908 +}
4909 +
4910 +static int endpoint_demarshal_set_param(void *object,
4911 +                               const struct pw_protocol_native_message *msg)
4912 +{
4913 +       struct pw_resource *resource = object;
4914 +       struct spa_pod_parser prs;
4915 +       uint32_t id, flags;
4916 +       struct spa_pod *param;
4917 +
4918 +       spa_pod_parser_init(&prs, msg->data, msg->size);
4919 +       if (spa_pod_parser_get_struct(&prs,
4920 +                               SPA_POD_Id(&id),
4921 +                               SPA_POD_Int(&flags),
4922 +                               SPA_POD_Pod(&param)) < 0)
4923 +               return -EINVAL;
4924 +
4925 +       return pw_resource_notify(resource, struct pw_endpoint_proxy_methods,
4926 +                               set_param, 0, id, flags, param);
4927 +}
4928 +
4929 +static const struct pw_endpoint_proxy_events pw_protocol_native_endpoint_event_marshal = {
4930 +       PW_VERSION_ENDPOINT_PROXY_EVENTS,
4931 +       .info = endpoint_marshal_info,
4932 +       .param = endpoint_marshal_param,
4933 +};
4934 +
4935 +static const struct pw_protocol_native_demarshal
4936 +pw_protocol_native_endpoint_event_demarshal[PW_ENDPOINT_PROXY_EVENT_NUM] =
4937 +{
4938 +       [PW_ENDPOINT_PROXY_EVENT_INFO] = { endpoint_demarshal_info, 0 },
4939 +       [PW_ENDPOINT_PROXY_EVENT_PARAM] = { endpoint_demarshal_param, 0 },
4940 +};
4941 +
4942 +static const struct pw_endpoint_proxy_methods pw_protocol_native_endpoint_method_marshal = {
4943 +       PW_VERSION_ENDPOINT_PROXY_METHODS,
4944 +       .add_listener = endpoint_marshal_add_listener,
4945 +       .subscribe_params = endpoint_marshal_subscribe_params,
4946 +       .enum_params = endpoint_marshal_enum_params,
4947 +       .set_param = endpoint_marshal_set_param,
4948 +};
4949 +
4950 +static const struct pw_protocol_native_demarshal
4951 +pw_protocol_native_endpoint_method_demarshal[PW_ENDPOINT_PROXY_METHOD_NUM] =
4952 +{
4953 +       [PW_ENDPOINT_PROXY_METHOD_ADD_LISTENER] = { NULL, 0 },
4954 +       [PW_ENDPOINT_PROXY_METHOD_SUBSCRIBE_PARAMS] = { endpoint_demarshal_subscribe_params, 0 },
4955 +       [PW_ENDPOINT_PROXY_METHOD_ENUM_PARAMS] = { endpoint_demarshal_enum_params, 0 },
4956 +       [PW_ENDPOINT_PROXY_METHOD_SET_PARAM] = { endpoint_demarshal_set_param, PW_PERM_W },
4957 +};
4958 +
4959 +static const struct pw_protocol_marshal pw_protocol_native_endpoint_marshal = {
4960 +       PW_TYPE_INTERFACE_Endpoint,
4961 +       PW_VERSION_ENDPOINT_PROXY,
4962 +       PW_ENDPOINT_PROXY_METHOD_NUM,
4963 +       PW_ENDPOINT_PROXY_EVENT_NUM,
4964 +       &pw_protocol_native_endpoint_method_marshal,
4965 +       &pw_protocol_native_endpoint_method_demarshal,
4966 +       &pw_protocol_native_endpoint_event_marshal,
4967 +       &pw_protocol_native_endpoint_event_demarshal,
4968 +};
4969 +
4970 +/***********************************************
4971 + *                 SESSION
4972 + ***********************************************/
4973 +
4974 +static void session_marshal_info (void *object,
4975 +                               const struct pw_session_info *info)
4976 +{
4977 +       struct pw_resource *resource = object;
4978 +       struct spa_pod_builder *b;
4979 +
4980 +       b = pw_protocol_native_begin_resource(resource,
4981 +               PW_SESSION_PROXY_EVENT_INFO, NULL);
4982 +
4983 +       marshal_pw_session_info(b, info);
4984 +
4985 +       pw_protocol_native_end_resource(resource, b);
4986 +}
4987 +
4988 +static void session_marshal_param (void *object, int seq, uint32_t id,
4989 +                                       uint32_t index, uint32_t next,
4990 +                                       const struct spa_pod *param)
4991 +{
4992 +       struct pw_resource *resource = object;
4993 +       struct spa_pod_builder *b;
4994 +
4995 +       b = pw_protocol_native_begin_resource(resource,
4996 +               PW_SESSION_PROXY_EVENT_PARAM, NULL);
4997 +
4998 +       spa_pod_builder_add_struct(b,
4999 +                               SPA_POD_Int(seq),
5000 +                               SPA_POD_Id(id),
5001 +                               SPA_POD_Int(index),
5002 +                               SPA_POD_Int(next),
5003 +                               SPA_POD_Pod(param));
5004 +
5005 +       pw_protocol_native_end_resource(resource, b);
5006 +}
5007 +
5008 +static int session_marshal_add_listener(void *object,
5009 +                       struct spa_hook *listener,
5010 +                       const struct pw_session_proxy_events *events,
5011 +                       void *data)
5012 +{
5013 +       struct pw_proxy *proxy = object;
5014 +       pw_proxy_add_object_listener(proxy, listener, events, data);
5015 +       return 0;
5016 +}
5017 +
5018 +static int session_marshal_subscribe_params(void *object,
5019 +                                               uint32_t *ids, uint32_t n_ids)
5020 +{
5021 +       struct pw_proxy *proxy = object;
5022 +       struct spa_pod_builder *b;
5023 +
5024 +       b = pw_protocol_native_begin_proxy(proxy,
5025 +               PW_SESSION_PROXY_METHOD_SUBSCRIBE_PARAMS, NULL);
5026 +
5027 +       spa_pod_builder_add_struct(b,
5028 +                       SPA_POD_Array(sizeof(uint32_t), SPA_TYPE_Id, n_ids, ids));
5029 +
5030 +       return pw_protocol_native_end_proxy(proxy, b);
5031 +}
5032 +
5033 +static int session_marshal_enum_params(void *object,
5034 +                                       int seq, uint32_t id,
5035 +                                       uint32_t start, uint32_t num,
5036 +                                       const struct spa_pod *filter)
5037 +{
5038 +       struct pw_protocol_native_message *msg;
5039 +       struct pw_proxy *proxy = object;
5040 +       struct spa_pod_builder *b;
5041 +
5042 +       b = pw_protocol_native_begin_proxy(proxy,
5043 +               PW_SESSION_PROXY_METHOD_ENUM_PARAMS, &msg);
5044 +
5045 +       spa_pod_builder_add_struct(b,
5046 +                       SPA_POD_Int(SPA_RESULT_RETURN_ASYNC(msg->seq)),
5047 +                       SPA_POD_Id(id),
5048 +                       SPA_POD_Int(index),
5049 +                       SPA_POD_Int(num),
5050 +                       SPA_POD_Pod(filter));
5051 +
5052 +       return pw_protocol_native_end_proxy(proxy, b);
5053 +}
5054 +
5055 +static int session_marshal_set_param(void *object,
5056 +                                       uint32_t id, uint32_t flags,
5057 +                                       const struct spa_pod *param)
5058 +{
5059 +       struct pw_proxy *proxy = object;
5060 +       struct spa_pod_builder *b;
5061 +
5062 +       b = pw_protocol_native_begin_proxy(proxy,
5063 +               PW_SESSION_PROXY_METHOD_SET_PARAM, NULL);
5064 +
5065 +       spa_pod_builder_add_struct(b,
5066 +                       SPA_POD_Id(id),
5067 +                       SPA_POD_Int(flags),
5068 +                       SPA_POD_Pod(param));
5069 +
5070 +       return pw_protocol_native_end_proxy(proxy, b);
5071 +}
5072 +
5073 +static int session_marshal_create_link(void *object,
5074 +                                       const struct spa_dict *props)
5075 +{
5076 +       struct pw_proxy *proxy = object;
5077 +       struct spa_pod_builder *b;
5078 +
5079 +       b = pw_protocol_native_begin_proxy(proxy,
5080 +               PW_SESSION_PROXY_METHOD_CREATE_LINK, NULL);
5081 +
5082 +       push_dict(b, props);
5083 +
5084 +       return pw_protocol_native_end_proxy(proxy, b);
5085 +}
5086 +
5087 +static int session_demarshal_info(void *object,
5088 +                               const struct pw_protocol_native_message *msg)
5089 +{
5090 +       struct pw_proxy *proxy = object;
5091 +       struct spa_pod_parser prs;
5092 +       struct spa_pod_frame f;
5093 +       struct spa_dict props = SPA_DICT_INIT(NULL, 0);
5094 +       struct pw_session_info info = { .props = &props };
5095 +
5096 +       spa_pod_parser_init(&prs, msg->data, msg->size);
5097 +
5098 +       demarshal_pw_session_info(&prs, &f, &info);
5099 +
5100 +       return pw_proxy_notify(proxy, struct pw_session_proxy_events,
5101 +                               info, 0, &info);
5102 +}
5103 +
5104 +static int session_demarshal_param(void *object,
5105 +                               const struct pw_protocol_native_message *msg)
5106 +{
5107 +       struct pw_proxy *proxy = object;
5108 +       struct spa_pod_parser prs;
5109 +       uint32_t id, index, next;
5110 +       int seq;
5111 +       struct spa_pod *param;
5112 +
5113 +       spa_pod_parser_init(&prs, msg->data, msg->size);
5114 +       if (spa_pod_parser_get_struct(&prs,
5115 +                               SPA_POD_Int(&seq),
5116 +                               SPA_POD_Id(&id),
5117 +                               SPA_POD_Int(&index),
5118 +                               SPA_POD_Int(&next),
5119 +                               SPA_POD_Pod(&param)) < 0)
5120 +               return -EINVAL;
5121 +
5122 +       return pw_proxy_notify(proxy, struct pw_session_proxy_events,
5123 +                               param, 0, seq, id, index, next, param);
5124 +}
5125 +
5126 +static int session_demarshal_subscribe_params(void *object,
5127 +                               const struct pw_protocol_native_message *msg)
5128 +{
5129 +       struct pw_resource *resource = object;
5130 +       struct spa_pod_parser prs;
5131 +       uint32_t csize, ctype, n_ids;
5132 +       uint32_t *ids;
5133 +
5134 +       spa_pod_parser_init(&prs, msg->data, msg->size);
5135 +       if (spa_pod_parser_get_struct(&prs,
5136 +                               SPA_POD_Array(&csize, &ctype, &n_ids, &ids)) < 0)
5137 +               return -EINVAL;
5138 +
5139 +       if (ctype != SPA_TYPE_Id)
5140 +               return -EINVAL;
5141 +
5142 +       return pw_resource_notify(resource, struct pw_session_proxy_methods,
5143 +                               subscribe_params, 0, ids, n_ids);
5144 +}
5145 +
5146 +static int session_demarshal_enum_params(void *object,
5147 +                               const struct pw_protocol_native_message *msg)
5148 +{
5149 +       struct pw_resource *resource = object;
5150 +       struct spa_pod_parser prs;
5151 +       uint32_t id, index, num;
5152 +       int seq;
5153 +       struct spa_pod *filter;
5154 +
5155 +       spa_pod_parser_init(&prs, msg->data, msg->size);
5156 +       if (spa_pod_parser_get_struct(&prs,
5157 +                               SPA_POD_Int(&seq),
5158 +                               SPA_POD_Id(&id),
5159 +                               SPA_POD_Int(&index),
5160 +                               SPA_POD_Int(&num),
5161 +                               SPA_POD_Pod(&filter)) < 0)
5162 +               return -EINVAL;
5163 +
5164 +       return pw_resource_notify(resource, struct pw_session_proxy_methods,
5165 +                               enum_params, 0, seq, id, index, num, filter);
5166 +}
5167 +
5168 +static int session_demarshal_set_param(void *object,
5169 +                               const struct pw_protocol_native_message *msg)
5170 +{
5171 +       struct pw_resource *resource = object;
5172 +       struct spa_pod_parser prs;
5173 +       uint32_t id, flags;
5174 +       struct spa_pod *param;
5175 +
5176 +       spa_pod_parser_init(&prs, msg->data, msg->size);
5177 +       if (spa_pod_parser_get_struct(&prs,
5178 +                               SPA_POD_Id(&id),
5179 +                               SPA_POD_Int(&flags),
5180 +                               SPA_POD_Pod(&param)) < 0)
5181 +               return -EINVAL;
5182 +
5183 +       return pw_resource_notify(resource, struct pw_session_proxy_methods,
5184 +                               set_param, 0, id, flags, param);
5185 +}
5186 +
5187 +static int session_demarshal_create_link(void *object,
5188 +                               const struct pw_protocol_native_message *msg)
5189 +{
5190 +       struct pw_resource *resource = object;
5191 +       struct spa_pod_parser prs;
5192 +       struct spa_pod_frame f;
5193 +       struct spa_dict props = SPA_DICT_INIT(NULL, 0);
5194 +
5195 +       spa_pod_parser_init(&prs, msg->data, msg->size);
5196 +
5197 +       parse_dict(&prs, &f, &props);
5198 +
5199 +       return pw_resource_notify(resource, struct pw_session_proxy_methods,
5200 +                               create_link, 0, &props);
5201 +}
5202 +
5203 +static const struct pw_session_proxy_events pw_protocol_native_session_event_marshal = {
5204 +       PW_VERSION_SESSION_PROXY_EVENTS,
5205 +       .info = session_marshal_info,
5206 +       .param = session_marshal_param,
5207 +};
5208 +
5209 +static const struct pw_protocol_native_demarshal
5210 +pw_protocol_native_session_event_demarshal[PW_SESSION_PROXY_EVENT_NUM] =
5211 +{
5212 +       [PW_SESSION_PROXY_EVENT_INFO] = { session_demarshal_info, 0 },
5213 +       [PW_SESSION_PROXY_EVENT_PARAM] = { session_demarshal_param, 0 },
5214 +};
5215 +
5216 +static const struct pw_session_proxy_methods pw_protocol_native_session_method_marshal = {
5217 +       PW_VERSION_SESSION_PROXY_METHODS,
5218 +       .add_listener = session_marshal_add_listener,
5219 +       .subscribe_params = session_marshal_subscribe_params,
5220 +       .enum_params = session_marshal_enum_params,
5221 +       .set_param = session_marshal_set_param,
5222 +       .create_link = session_marshal_create_link,
5223 +};
5224 +
5225 +static const struct pw_protocol_native_demarshal
5226 +pw_protocol_native_session_method_demarshal[PW_SESSION_PROXY_METHOD_NUM] =
5227 +{
5228 +       [PW_SESSION_PROXY_METHOD_ADD_LISTENER] = { NULL, 0 },
5229 +       [PW_SESSION_PROXY_METHOD_SUBSCRIBE_PARAMS] = { session_demarshal_subscribe_params, 0 },
5230 +       [PW_SESSION_PROXY_METHOD_ENUM_PARAMS] = { session_demarshal_enum_params, 0 },
5231 +       [PW_SESSION_PROXY_METHOD_SET_PARAM] = { session_demarshal_set_param, PW_PERM_W },
5232 +       [PW_SESSION_PROXY_METHOD_CREATE_LINK] = { session_demarshal_create_link, PW_PERM_W },
5233 +};
5234 +
5235 +static const struct pw_protocol_marshal pw_protocol_native_session_marshal = {
5236 +       PW_TYPE_INTERFACE_Session,
5237 +       PW_VERSION_SESSION_PROXY,
5238 +       PW_SESSION_PROXY_METHOD_NUM,
5239 +       PW_SESSION_PROXY_EVENT_NUM,
5240 +       &pw_protocol_native_session_method_marshal,
5241 +       &pw_protocol_native_session_method_demarshal,
5242 +       &pw_protocol_native_session_event_marshal,
5243 +       &pw_protocol_native_session_event_demarshal,
5244 +};
5245 +
5246 +struct pw_protocol *pw_protocol_native_ext_session_manager_init(struct pw_core *core)
5247 +{
5248 +       struct pw_protocol *protocol;
5249 +
5250 +       protocol = pw_core_find_protocol(core, PW_TYPE_INFO_PROTOCOL_Native);
5251 +
5252 +       if (protocol == NULL)
5253 +               return NULL;
5254 +
5255 +       pw_protocol_add_marshal(protocol, &pw_protocol_native_client_endpoint_marshal);
5256 +       pw_protocol_add_marshal(protocol, &pw_protocol_native_client_session_marshal);
5257 +       pw_protocol_add_marshal(protocol, &pw_protocol_native_endpoint_link_marshal);
5258 +       pw_protocol_add_marshal(protocol, &pw_protocol_native_endpoint_stream_marshal);
5259 +       pw_protocol_add_marshal(protocol, &pw_protocol_native_endpoint_marshal);
5260 +       pw_protocol_add_marshal(protocol, &pw_protocol_native_session_marshal);
5261 +
5262 +       return protocol;
5263 +}
5264 diff --git a/src/modules/module-session-manager/session.c b/src/modules/module-session-manager/session.c
5265 new file mode 100644
5266 index 00000000..226eba4e
5267 --- /dev/null
5268 +++ b/src/modules/module-session-manager/session.c
5269 @@ -0,0 +1,341 @@
5270 +/* PipeWire
5271 + *
5272 + * Copyright © 2019 Collabora Ltd.
5273 + *   @author George Kiagiadakis <george.kiagiadakis@collabora.com>
5274 + *
5275 + * Permission is hereby granted, free of charge, to any person obtaining a
5276 + * copy of this software and associated documentation files (the "Software"),
5277 + * to deal in the Software without restriction, including without limitation
5278 + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
5279 + * and/or sell copies of the Software, and to permit persons to whom the
5280 + * Software is furnished to do so, subject to the following conditions:
5281 + *
5282 + * The above copyright notice and this permission notice (including the next
5283 + * paragraph) shall be included in all copies or substantial portions of the
5284 + * Software.
5285 + *
5286 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
5287 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
5288 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
5289 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
5290 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
5291 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
5292 + * DEALINGS IN THE SOFTWARE.
5293 + */
5294 +
5295 +#include <stdbool.h>
5296 +#include <string.h>
5297 +
5298 +#include <pipewire/pipewire.h>
5299 +#include <extensions/session-manager.h>
5300 +
5301 +#include <spa/pod/filter.h>
5302 +
5303 +#include "session.h"
5304 +#include "client-session.h"
5305 +
5306 +#include <pipewire/private.h>
5307 +
5308 +#define NAME "session"
5309 +
5310 +struct resource_data {
5311 +       struct session *session;
5312 +       struct spa_hook resource_listener;
5313 +       struct spa_hook object_listener;
5314 +       uint32_t n_subscribe_ids;
5315 +       uint32_t subscribe_ids[32];
5316 +};
5317 +
5318 +#define pw_session_resource(r,m,v,...) \
5319 +       pw_resource_call(r,struct pw_session_proxy_events,m,v,__VA_ARGS__)
5320 +#define pw_session_resource_info(r,...)        \
5321 +       pw_session_resource(r,info,0,__VA_ARGS__)
5322 +#define pw_session_resource_param(r,...)       \
5323 +       pw_session_resource(r,param,0,__VA_ARGS__)
5324 +
5325 +static int session_enum_params (void *object, int seq,
5326 +                               uint32_t id, uint32_t start, uint32_t num,
5327 +                               const struct spa_pod *filter)
5328 +{
5329 +       struct pw_resource *resource = object;
5330 +       struct resource_data *data = pw_resource_get_user_data(resource);
5331 +       struct session *this = data->session;
5332 +       struct spa_pod *result;
5333 +       struct spa_pod *param;
5334 +       uint8_t buffer[1024];
5335 +       struct spa_pod_builder b = { 0 };
5336 +       uint32_t index;
5337 +       uint32_t next = start;
5338 +       uint32_t count = 0;
5339 +
5340 +       while (true) {
5341 +               index = next++;
5342 +               if (index >= this->n_params)
5343 +                       break;
5344 +
5345 +               param = this->params[index];
5346 +
5347 +               if (param == NULL || !spa_pod_is_object_id(param, id))
5348 +                       continue;
5349 +
5350 +               spa_pod_builder_init(&b, buffer, sizeof(buffer));
5351 +               if (spa_pod_filter(&b, &result, param, filter) != 0)
5352 +                       continue;
5353 +
5354 +               pw_log_debug(NAME" %p: %d param %u", this, seq, index);
5355 +
5356 +               pw_session_resource_param(resource, seq, id, index, next, result);
5357 +
5358 +               if (++count == num)
5359 +                       break;
5360 +       }
5361 +       return 0;
5362 +}
5363 +
5364 +static int session_subscribe_params (void *object, uint32_t *ids, uint32_t n_ids)
5365 +{
5366 +       struct pw_resource *resource = object;
5367 +       struct resource_data *data = pw_resource_get_user_data(resource);
5368 +       uint32_t i;
5369 +
5370 +       n_ids = SPA_MIN(n_ids, SPA_N_ELEMENTS(data->subscribe_ids));
5371 +       data->n_subscribe_ids = n_ids;
5372 +
5373 +       for (i = 0; i < n_ids; i++) {
5374 +               data->subscribe_ids[i] = ids[i];
5375 +               pw_log_debug(NAME" %p: resource %d subscribe param %u",
5376 +                       data->session, resource->id, ids[i]);
5377 +               session_enum_params(resource, 1, ids[i], 0, UINT32_MAX, NULL);
5378 +       }
5379 +       return 0;
5380 +}
5381 +
5382 +static int session_set_param (void *object, uint32_t id, uint32_t flags,
5383 +                               const struct spa_pod *param)
5384 +{
5385 +       struct pw_resource *resource = object;
5386 +       struct resource_data *data = pw_resource_get_user_data(resource);
5387 +       struct session *this = data->session;
5388 +
5389 +       pw_client_session_resource_set_param(this->client_sess->resource,
5390 +                                               id, flags, param);
5391 +
5392 +       return 0;
5393 +}
5394 +
5395 +static int session_create_link(void *object, const struct spa_dict *props)
5396 +{
5397 +       struct pw_resource *resource = object;
5398 +       struct resource_data *data = pw_resource_get_user_data(resource);
5399 +       struct session *this = data->session;
5400 +
5401 +       pw_client_session_resource_create_link(this->client_sess->resource,
5402 +                                               props);
5403 +
5404 +       return 0;
5405 +}
5406 +
5407 +static const struct pw_session_proxy_methods methods = {
5408 +       PW_VERSION_SESSION_PROXY_METHODS,
5409 +       .subscribe_params = session_subscribe_params,
5410 +       .enum_params = session_enum_params,
5411 +       .set_param = session_set_param,
5412 +       .create_link = session_create_link,
5413 +};
5414 +
5415 +static void session_notify_subscribed(struct session *this,
5416 +                                       uint32_t index, uint32_t next)
5417 +{
5418 +       struct pw_global *global = this->global;
5419 +       struct pw_resource *resource;
5420 +       struct resource_data *data;
5421 +       struct spa_pod *param = this->params[index];
5422 +       uint32_t id;
5423 +       uint32_t i;
5424 +
5425 +       if (!param || !spa_pod_is_object (param))
5426 +               return;
5427 +
5428 +       id = SPA_POD_OBJECT_ID (param);
5429 +
5430 +       spa_list_for_each(resource, &global->resource_list, link) {
5431 +               data = pw_resource_get_user_data(resource);
5432 +               for (i = 0; i < data->n_subscribe_ids; i++) {
5433 +                       if (data->subscribe_ids[i] == id) {
5434 +                               pw_session_resource_param(resource, 1, id,
5435 +                                       index, next, param);
5436 +                       }
5437 +               }
5438 +       }
5439 +}
5440 +
5441 +int session_update(struct session *this,
5442 +                       uint32_t change_mask,
5443 +                       uint32_t n_params,
5444 +                       const struct spa_pod **params,
5445 +                       const struct pw_session_info *info)
5446 +{
5447 +       if (change_mask & PW_CLIENT_SESSION_UPDATE_PARAMS) {
5448 +               uint32_t i;
5449 +               size_t size = n_params * sizeof(struct spa_pod *);
5450 +
5451 +               pw_log_debug(NAME" %p: update %d params", this, n_params);
5452 +
5453 +               for (i = 0; i < this->n_params; i++)
5454 +                       free(this->params[i]);
5455 +               this->params = realloc(this->params, size);
5456 +               if (size > 0 && !this->params) {
5457 +                       this->n_params = 0;
5458 +                       goto no_mem;
5459 +               }
5460 +               this->n_params = n_params;
5461 +
5462 +               for (i = 0; i < this->n_params; i++) {
5463 +                       this->params[i] = params[i] ? spa_pod_copy(params[i]) : NULL;
5464 +                       session_notify_subscribed(this, i, i+1);
5465 +               }
5466 +       }
5467 +
5468 +       if (change_mask & PW_CLIENT_SESSION_UPDATE_INFO) {
5469 +               struct pw_resource *resource;
5470 +
5471 +               if (info->change_mask & PW_SESSION_CHANGE_MASK_PROPS)
5472 +                       pw_properties_update(this->props, info->props);
5473 +
5474 +               if (info->change_mask & PW_SESSION_CHANGE_MASK_PARAMS) {
5475 +                       size_t size = info->n_params * sizeof(struct spa_param_info);
5476 +
5477 +                       this->info.params = realloc(this->info.params, size);
5478 +                       if (size > 0 && !this->info.params) {
5479 +                               this->info.n_params = 0;
5480 +                               goto no_mem;
5481 +                       }
5482 +                       this->info.n_params = info->n_params;
5483 +
5484 +                       memcpy(this->info.params, info->params, size);
5485 +               }
5486 +
5487 +               this->info.change_mask = info->change_mask;
5488 +               spa_list_for_each(resource, &this->global->resource_list, link) {
5489 +                       pw_session_resource_info(resource, &this->info);
5490 +               }
5491 +               this->info.change_mask = 0;
5492 +       }
5493 +
5494 +       return 0;
5495 +
5496 +      no_mem:
5497 +       pw_log_error(NAME" can't update: no memory");
5498 +       pw_resource_error(this->client_sess->resource, -ENOMEM,
5499 +                       NAME" can't update: no memory");
5500 +       return -ENOMEM;
5501 +}
5502 +
5503 +static void session_unbind(void *data)
5504 +{
5505 +       struct pw_resource *resource = data;
5506 +       spa_list_remove(&resource->link);
5507 +}
5508 +
5509 +static const struct pw_resource_events resource_events = {
5510 +       PW_VERSION_RESOURCE_EVENTS,
5511 +       .destroy = session_unbind,
5512 +};
5513 +
5514 +static int session_bind(void *_data, struct pw_client *client,
5515 +                       uint32_t permissions, uint32_t version, uint32_t id)
5516 +{
5517 +       struct session *this = _data;
5518 +       struct pw_global *global = this->global;
5519 +       struct pw_resource *resource;
5520 +       struct resource_data *data;
5521 +
5522 +       resource = pw_resource_new(client, id, permissions, global->type, version, sizeof(*data));
5523 +       if (resource == NULL)
5524 +               goto no_mem;
5525 +
5526 +       data = pw_resource_get_user_data(resource);
5527 +       data->session = this;
5528 +       pw_resource_add_listener(resource, &data->resource_listener,
5529 +                               &resource_events, resource);
5530 +       pw_resource_add_object_listener(resource, &data->object_listener,
5531 +                                       &methods, resource);
5532 +
5533 +       pw_log_debug(NAME" %p: bound to %d", this, resource->id);
5534 +
5535 +       spa_list_append(&global->resource_list, &resource->link);
5536 +
5537 +       this->info.change_mask = PW_SESSION_CHANGE_MASK_ALL;
5538 +       pw_session_resource_info(resource, &this->info);
5539 +       this->info.change_mask = 0;
5540 +
5541 +       return 0;
5542 +
5543 +      no_mem:
5544 +       pw_log_error(NAME" can't create resource: no memory");
5545 +       pw_resource_error(this->client_sess->resource, -ENOMEM,
5546 +                       NAME" can't create resource: no memory");
5547 +       return -ENOMEM;
5548 +}
5549 +
5550 +int session_init(struct session *this,
5551 +               struct client_session *client_sess,
5552 +               struct pw_core *core,
5553 +               struct pw_properties *properties)
5554 +{
5555 +       const char *keys[] = {
5556 +               PW_KEY_FACTORY_ID,
5557 +               PW_KEY_CLIENT_ID,
5558 +               NULL
5559 +       };
5560 +
5561 +       pw_log_debug(NAME" %p: new", this);
5562 +
5563 +       this->client_sess = client_sess;
5564 +       this->props = properties;
5565 +
5566 +       properties = pw_properties_new(NULL, NULL);
5567 +       if (!properties)
5568 +               goto no_mem;
5569 +
5570 +       pw_properties_copy_keys(this->props, properties, keys);
5571 +
5572 +       this->global = pw_global_new (core,
5573 +                       PW_TYPE_INTERFACE_Session,
5574 +                       PW_VERSION_SESSION_PROXY,
5575 +                       properties, session_bind, this);
5576 +       if (!this->global)
5577 +               goto no_mem;
5578 +
5579 +       pw_properties_setf(this->props, PW_KEY_SESSION_ID, "%u", this->global->id);
5580 +
5581 +       this->info.version = PW_VERSION_SESSION_INFO;
5582 +       this->info.id = this->global->id;
5583 +       this->info.props = &this->props->dict;
5584 +
5585 +       pw_client_session_resource_set_id(client_sess->resource, this->global->id);
5586 +
5587 +       return pw_global_register(this->global);
5588 +
5589 +      no_mem:
5590 +       pw_log_error(NAME" - can't create - out of memory");
5591 +       return -ENOMEM;
5592 +}
5593 +
5594 +void session_clear(struct session *this)
5595 +{
5596 +       uint32_t i;
5597 +
5598 +       pw_log_debug(NAME" %p: destroy", this);
5599 +
5600 +       pw_global_destroy(this->global);
5601 +
5602 +       for (i = 0; i < this->n_params; i++)
5603 +               free(this->params[i]);
5604 +       free(this->params);
5605 +
5606 +       free(this->info.params);
5607 +
5608 +       if (this->props)
5609 +               pw_properties_free(this->props);
5610 +}
5611 diff --git a/src/modules/module-session-manager/session.h b/src/modules/module-session-manager/session.h
5612 new file mode 100644
5613 index 00000000..ad0b9b1b
5614 --- /dev/null
5615 +++ b/src/modules/module-session-manager/session.h
5616 @@ -0,0 +1,61 @@
5617 +/* PipeWire
5618 + *
5619 + * Copyright © 2019 Collabora Ltd.
5620 + *   @author George Kiagiadakis <george.kiagiadakis@collabora.com>
5621 + *
5622 + * Permission is hereby granted, free of charge, to any person obtaining a
5623 + * copy of this software and associated documentation files (the "Software"),
5624 + * to deal in the Software without restriction, including without limitation
5625 + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
5626 + * and/or sell copies of the Software, and to permit persons to whom the
5627 + * Software is furnished to do so, subject to the following conditions:
5628 + *
5629 + * The above copyright notice and this permission notice (including the next
5630 + * paragraph) shall be included in all copies or substantial portions of the
5631 + * Software.
5632 + *
5633 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
5634 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
5635 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
5636 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
5637 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
5638 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
5639 + * DEALINGS IN THE SOFTWARE.
5640 + */
5641 +
5642 +#ifndef MODULE_SESSION_MANAGER_SESSION_H
5643 +#define MODULE_SESSION_MANAGER_SESSION_H
5644 +
5645 +#ifdef __cplusplus
5646 +extern "C" {
5647 +#endif
5648 +
5649 +struct client_session;
5650 +
5651 +struct session {
5652 +       struct client_session *client_sess;
5653 +       struct pw_global *global;
5654 +       uint32_t n_params;
5655 +       struct spa_pod **params;
5656 +       struct pw_session_info info;
5657 +       struct pw_properties *props;    /* wrapper of info.props */
5658 +};
5659 +
5660 +int session_init(struct session *this,
5661 +               struct client_session *client_sess,
5662 +               struct pw_core *core,
5663 +               struct pw_properties *properties);
5664 +
5665 +void session_clear(struct session *this);
5666 +
5667 +int session_update(struct session *this,
5668 +                       uint32_t change_mask,
5669 +                       uint32_t n_params,
5670 +                       const struct spa_pod **params,
5671 +                       const struct pw_session_info *info);
5672 +
5673 +#ifdef __cplusplus
5674 +}  /* extern "C" */
5675 +#endif
5676 +
5677 +#endif /* MODULE_SESSION_MANAGER_SESSION_H */
5678 diff --git a/src/pipewire/pipewire.c b/src/pipewire/pipewire.c
5679 index c556a1db..06ccccc3 100644
5680 --- a/src/pipewire/pipewire.c
5681 +++ b/src/pipewire/pipewire.c
5682 @@ -577,6 +577,12 @@ static const struct spa_type_info type_info[] = {
5683         { PW_TYPE_INTERFACE_Module, SPA_TYPE_Pointer, PW_TYPE_INFO_INTERFACE_BASE "Module", NULL },
5684         { PW_TYPE_INTERFACE_ClientNode, SPA_TYPE_Pointer, PW_TYPE_INFO_INTERFACE_BASE "ClientNode", NULL },
5685         { PW_TYPE_INTERFACE_Device, SPA_TYPE_Pointer, PW_TYPE_INFO_INTERFACE_BASE "Device", NULL },
5686 +       { PW_TYPE_INTERFACE_ClientEndpoint, SPA_TYPE_Pointer, PW_TYPE_INFO_INTERFACE_BASE "ClientEndpoint", NULL},
5687 +       { PW_TYPE_INTERFACE_Endpoint, SPA_TYPE_Pointer, PW_TYPE_INFO_INTERFACE_BASE "Endpoint", NULL},
5688 +       { PW_TYPE_INTERFACE_EndpointStream, SPA_TYPE_Pointer, PW_TYPE_INFO_INTERFACE_BASE "EndpointStream", NULL},
5689 +       { PW_TYPE_INTERFACE_ClientSession, SPA_TYPE_Pointer, PW_TYPE_INFO_INTERFACE_BASE "ClientSession", NULL},
5690 +       { PW_TYPE_INTERFACE_Session, SPA_TYPE_Pointer, PW_TYPE_INFO_INTERFACE_BASE "Session", NULL},
5691 +       { PW_TYPE_INTERFACE_EndpointLink, SPA_TYPE_Pointer, PW_TYPE_INFO_INTERFACE_BASE "EndpointLink", NULL},
5692         { SPA_ID_INVALID, SPA_ID_INVALID, "spa_types", spa_types },
5693         { 0, 0, NULL, NULL },
5694  };
5695 diff --git a/src/pipewire/type.h b/src/pipewire/type.h
5696 index a1b205f7..6b1b8b50 100644
5697 --- a/src/pipewire/type.h
5698 +++ b/src/pipewire/type.h
5699 @@ -48,7 +48,12 @@ enum {
5700         /* extensions */
5701         PW_TYPE_INTERFACE_EXTENSIONS = PW_TYPE_INTERFACE_START + 0x1000,
5702         PW_TYPE_INTERFACE_ClientNode,
5703 -
5704 +       PW_TYPE_INTERFACE_ClientEndpoint,
5705 +       PW_TYPE_INTERFACE_Endpoint,
5706 +       PW_TYPE_INTERFACE_EndpointStream,
5707 +       PW_TYPE_INTERFACE_ClientSession,
5708 +       PW_TYPE_INTERFACE_Session,
5709 +       PW_TYPE_INTERFACE_EndpointLink,
5710  };
5711  
5712  #define PW_TYPE_INFO_BASE              "PipeWire:"
5713 -- 
5714 2.23.0
5715