8bf945479a604737a9ccf7e3b521fcdacc0cbb4c
[AGL/meta-agl.git] / meta-pipewire / recipes-multimedia / pipewire / pipewire / 0010-Revert-spa-improve-the-AEC-interface.patch
1 From 3ac842085c60a0c745bd3f8f0d8419e98220675b Mon Sep 17 00:00:00 2001
2 From: Ashok Sidipotu <ashok.sidipotu@collabora.com>
3 Date: Thu, 24 Feb 2022 18:02:29 +0530
4 Subject: [PATCH 10/12] Revert "spa: improve the AEC interface"
5
6 This reverts commit c5c9ecdd87225ecd4978e9f6176a8a6d1fdd4252.
7 Upstream-Status: Inappropriate[meson version dependent]
8
9 This patch had to be reverted as it is dependent on
10 9386c70b3a2cc2df6aabfd7b6a6bc1d7ec873bd1 which needs
11 higher meson version.
12
13 ---
14  spa/include/spa/interfaces/audio/aec.h       | 71 +++-----------------
15  spa/plugins/aec/aec-null.c                   | 62 +++++++++--------
16  spa/plugins/aec/aec-webrtc.cpp               | 56 ++++++++-------
17  src/modules/module-echo-cancel.c             | 39 +++++------
18  src/modules/module-echo-cancel/echo-cancel.h | 34 ++++++++++
19  5 files changed, 130 insertions(+), 132 deletions(-)
20  create mode 100644 src/modules/module-echo-cancel/echo-cancel.h
21
22 diff --git a/spa/include/spa/interfaces/audio/aec.h b/spa/include/spa/interfaces/audio/aec.h
23 index 17e4e4e46..e1fcda563 100644
24 --- a/spa/include/spa/interfaces/audio/aec.h
25 +++ b/spa/include/spa/interfaces/audio/aec.h
26 @@ -25,71 +25,20 @@
27  
28  #include <spa/utils/dict.h>
29  #include <spa/utils/hook.h>
30 +#include <spa/pod/pod.h>
31  #include <spa/param/audio/raw.h>
32 +#include <spa/support/plugin.h>
33  
34 -#ifndef SPA_AUDIO_AEC_H
35 -#define SPA_AUDIO_AEC_H
36 +#define SPA_TYPE_INTERFACE_AEC SPA_TYPE_INFO_INTERFACE_BASE "AEC"
37 +#define SPA_VERSION_AUDIO_AEC   1
38  
39 -#ifdef __cplusplus
40 -extern "C" {
41 -#endif
42 -
43 -#define SPA_TYPE_INTERFACE_AUDIO_AEC SPA_TYPE_INFO_INTERFACE_BASE "Audio:AEC"
44 -
45 -#define SPA_VERSION_AUDIO_AEC   0
46 -struct spa_audio_aec {
47 +struct echo_cancel_info {
48         struct spa_interface iface;
49         const char *name;
50 -       const struct spa_dict *info;
51 +       const struct spa_dict info;
52         const char *latency;
53 +       int (*create) (struct spa_handle *handle, const struct spa_dict *args, const struct spa_audio_info_raw *info);
54 +       int (*run) (struct spa_handle *handle, const float *rec[], const float *play[], float *out[], uint32_t n_samples);
55 +       struct spa_dict *(*get_properties) (struct spa_handle *handle);
56 +       int (*set_properties) (struct spa_handle *handle, const struct spa_dict *args);
57  };
58 -
59 -struct spa_audio_aec_info {
60 -#define SPA_AUDIO_AEC_CHANGE_MASK_PROPS        (1u<<0)
61 -        uint64_t change_mask;
62 -
63 -       const struct spa_dict *props;
64 -};
65 -
66 -struct spa_audio_aec_events {
67 -#define SPA_VERSION_AUDIO_AEC_EVENTS   0
68 -        uint32_t version;       /**< version of this structure */
69 -
70 -       /** Emitted when info changes */
71 -       void (*info) (void *data, const struct spa_audio_aec_info *info);
72 -};
73 -
74 -struct spa_audio_aec_methods {
75 -#define SPA_VERSION_AUDIO_AEC_METHODS  0
76 -        uint32_t version;
77 -
78 -       int (*add_listener) (void *object,
79 -                       struct spa_hook *listener,
80 -                       const struct spa_audio_aec_events *events,
81 -                       void *data);
82 -
83 -       int (*init) (void *data, const struct spa_dict *args, const struct spa_audio_info_raw *info);
84 -       int (*run) (void *data, const float *rec[], const float *play[], float *out[], uint32_t n_samples);
85 -       int (*set_props) (void *data, const struct spa_dict *args);
86 -};
87 -
88 -#define spa_audio_aec_method(o,method,version,...)                     \
89 -({                                                                     \
90 -       int _res = -ENOTSUP;                                            \
91 -       struct spa_audio_aec *_o = o;                                   \
92 -       spa_interface_call_res(&_o->iface,                              \
93 -                       struct spa_audio_aec_methods, _res,             \
94 -                       method, version, ##__VA_ARGS__);                \
95 -       _res;                                                           \
96 -})
97 -
98 -#define spa_audio_aec_add_listener(o,...)      spa_audio_aec_method(o, add_listener, 0, __VA_ARGS__)
99 -#define spa_audio_aec_init(o,...)              spa_audio_aec_method(o, init, 0, __VA_ARGS__)
100 -#define spa_audio_aec_run(o,...)               spa_audio_aec_method(o, run, 0, __VA_ARGS__)
101 -#define spa_audio_aec_set_props(o,...)         spa_audio_aec_method(o, set_props, 0, __VA_ARGS__)
102 -
103 -#ifdef __cplusplus
104 -}  /* extern "C" */
105 -#endif
106 -
107 -#endif /* SPA_AUDIO_AEC_H */
108 diff --git a/spa/plugins/aec/aec-null.c b/spa/plugins/aec/aec-null.c
109 index 2909eb213..3168a6b36 100644
110 --- a/spa/plugins/aec/aec-null.c
111 +++ b/spa/plugins/aec/aec-null.c
112 @@ -30,11 +30,7 @@
113  
114  struct impl {
115         struct spa_handle handle;
116 -       struct spa_audio_aec aec;
117         struct spa_log *log;
118 -
119 -       struct spa_hook_list hooks_list;
120 -
121         uint32_t channels;
122  };
123  
124 @@ -42,38 +38,54 @@ static struct spa_log_topic log_topic = SPA_LOG_TOPIC(0, "spa.aec.null");
125  #undef SPA_LOG_TOPIC_DEFAULT
126  #define SPA_LOG_TOPIC_DEFAULT &log_topic
127  
128 -static int null_init(void *data, const struct spa_dict *args, const struct spa_audio_info_raw *info)
129 +static int null_create(struct spa_handle *handle, const struct spa_dict *args, const struct spa_audio_info_raw *info)
130  {
131 -       struct impl *impl = data;
132 +       struct impl *impl;
133 +       impl = (struct impl *) handle;
134         impl->channels = info->channels;
135 +
136         return 0;
137  }
138  
139 -static int null_run(void *data, const float *rec[], const float *play[], float *out[], uint32_t n_samples)
140 +static int null_run(struct spa_handle *handle, const float *rec[], const float *play[], float *out[], uint32_t n_samples)
141  {
142 -       struct impl *impl = data;
143 +       struct impl *impl = (struct impl *) handle;
144         uint32_t i;
145         for (i = 0; i < impl->channels; i++)
146                 memcpy(out[i], rec[i], n_samples * sizeof(float));
147         return 0;
148  }
149  
150 -static struct spa_audio_aec_methods impl_aec = {
151 -       .init = null_init,
152 +struct spa_dict *null_get_properties(SPA_UNUSED struct spa_handle *handle)
153 +{
154 +       /* Not supported */
155 +       return NULL;
156 +}
157 +
158 +int null_set_properties(SPA_UNUSED struct spa_handle *handle, SPA_UNUSED const struct spa_dict *args)
159 +{
160 +       /* Not supported */
161 +       return -1;
162 +}
163 +
164 +static struct echo_cancel_info echo_cancel_null_impl = {
165 +       .name = "null",
166 +       .info = SPA_DICT_INIT(NULL, 0),
167 +       .latency = NULL,
168 +       .create = null_create,
169         .run = null_run,
170 +       .get_properties = null_get_properties,
171 +       .set_properties = null_set_properties,
172  };
173  
174  static int impl_get_interface(struct spa_handle *handle, const char *type, void **interface)
175  {
176 -       struct impl *impl;
177  
178         spa_return_val_if_fail(handle != NULL, -EINVAL);
179         spa_return_val_if_fail(interface != NULL, -EINVAL);
180  
181 -       impl = (struct impl *) handle;
182 -
183 -       if (spa_streq(type, SPA_TYPE_INTERFACE_AUDIO_AEC))
184 -               *interface = &impl->aec;
185 +       if (spa_streq(type, SPA_TYPE_INTERFACE_AEC))
186 +               *interface = &echo_cancel_null_impl;
187         else
188                 return -ENOENT;
189  
190 @@ -106,29 +118,23 @@ impl_init(const struct spa_handle_factory *factory,
191         spa_return_val_if_fail(factory != NULL, -EINVAL);
192         spa_return_val_if_fail(handle != NULL, -EINVAL);
193  
194 +       echo_cancel_null_impl.iface = SPA_INTERFACE_INIT(
195 +               SPA_TYPE_INTERFACE_AEC,
196 +               SPA_VERSION_AUDIO_AEC,
197 +               NULL,
198 +               NULL);
199 +
200         handle->get_interface = impl_get_interface;
201         handle->clear = impl_clear;
202 -
203         impl = (struct impl *) handle;
204 -
205 -       impl->aec.iface = SPA_INTERFACE_INIT(
206 -               SPA_TYPE_INTERFACE_AUDIO_AEC,
207 -               SPA_VERSION_AUDIO_AEC,
208 -               &impl_aec, impl);
209 -       impl->aec.name = "null";
210 -       impl->aec.info = NULL;
211 -       impl->aec.latency = NULL;
212 -
213         impl->log = (struct spa_log*)spa_support_find(support, n_support, SPA_TYPE_INTERFACE_Log);
214         spa_log_topic_init(impl->log, &log_topic);
215  
216 -       spa_hook_list_init(&impl->hooks_list);
217 -
218         return 0;
219  }
220  
221  static const struct spa_interface_info impl_interfaces[] = {
222 -       {SPA_TYPE_INTERFACE_AUDIO_AEC,},
223 +       {SPA_TYPE_INTERFACE_AEC,},
224  };
225  
226  static int
227 diff --git a/spa/plugins/aec/aec-webrtc.cpp b/spa/plugins/aec/aec-webrtc.cpp
228 index f519189c7..d44fa6e30 100644
229 --- a/spa/plugins/aec/aec-webrtc.cpp
230 +++ b/spa/plugins/aec/aec-webrtc.cpp
231 @@ -38,8 +38,6 @@
232  
233  struct impl_data {
234         struct spa_handle handle;
235 -       struct spa_audio_aec aec;
236 -
237         struct spa_log *log;
238         std::unique_ptr<webrtc::AudioProcessing> apm;
239         spa_audio_info_raw info;
240 @@ -60,9 +58,9 @@ static bool webrtc_get_spa_bool(const struct spa_dict *args, const char *key, bo
241         return value;
242  }
243  
244 -static int webrtc_init(void *data, const struct spa_dict *args, const struct spa_audio_info_raw *info)
245 +static int webrtc_create(struct spa_handle *handle, const struct spa_dict *args, const struct spa_audio_info_raw *info)
246  {
247 -       auto impl = reinterpret_cast<struct impl_data*>(data);
248 +       auto impl = reinterpret_cast<struct impl_data*>(handle);
249  
250         bool extended_filter = webrtc_get_spa_bool(args, "webrtc.extended_filter", true);
251         bool delay_agnostic = webrtc_get_spa_bool(args, "webrtc.delay_agnostic", true);
252 @@ -122,9 +120,9 @@ static int webrtc_init(void *data, const struct spa_dict *args, const struct spa
253         return 0;
254  }
255  
256 -static int webrtc_run(void *data, const float *rec[], const float *play[], float *out[], uint32_t n_samples)
257 +static int webrtc_run(struct spa_handle *handle, const float *rec[], const float *play[], float *out[], uint32_t n_samples)
258  {
259 -       auto impl = reinterpret_cast<struct impl_data*>(data);
260 +       auto impl = reinterpret_cast<struct impl_data*>(handle);
261         webrtc::StreamConfig config =
262                 webrtc::StreamConfig(impl->info.rate, impl->info.channels, false);
263         unsigned int num_blocks = n_samples * 1000 / impl->info.rate / 10;
264 @@ -160,22 +158,36 @@ static int webrtc_run(void *data, const float *rec[], const float *play[], float
265         return 0;
266  }
267  
268 -static struct spa_audio_aec_methods impl_aec = {
269 -       SPA_VERSION_AUDIO_AEC_METHODS,
270 -       .add_listener = NULL,
271 -       .init = webrtc_init,
272 +struct spa_dict *webrtc_get_properties(SPA_UNUSED struct spa_handle *handle)
273 +{
274 +       /* Not supported */
275 +       return NULL;
276 +}
277 +
278 +int webrtc_set_properties(SPA_UNUSED struct spa_handle *handle, SPA_UNUSED const struct spa_dict *args)
279 +{
280 +       /* Not supported */
281 +       return -1;
282 +}
283 +
284 +static struct echo_cancel_info echo_cancel_webrtc_impl = {
285 +       .name = "webrtc",
286 +       .info = SPA_DICT_INIT(NULL, 0),
287 +       .latency = "480/48000",
288 +       .create = webrtc_create,
289         .run = webrtc_run,
290 +       .get_properties = webrtc_get_properties,
291 +       .set_properties = webrtc_set_properties,
292  };
293  
294  static int impl_get_interface(struct spa_handle *handle, const char *type, void **interface)
295  {
296 -       auto impl = reinterpret_cast<struct impl_data*>(handle);
297  
298         spa_return_val_if_fail(handle != NULL, -EINVAL);
299         spa_return_val_if_fail(interface != NULL, -EINVAL);
300  
301 -       if (spa_streq(type, SPA_TYPE_INTERFACE_AUDIO_AEC))
302 -               *interface = &impl->aec;
303 +       if (spa_streq(type, SPA_TYPE_INTERFACE_AEC))
304 +               *interface = &echo_cancel_webrtc_impl;
305         else
306                 return -ENOENT;
307  
308 @@ -207,19 +219,15 @@ impl_init(const struct spa_handle_factory *factory,
309         spa_return_val_if_fail(factory != NULL, -EINVAL);
310         spa_return_val_if_fail(handle != NULL, -EINVAL);
311  
312 -       auto impl = new (handle) impl_data();
313 +       echo_cancel_webrtc_impl.iface = SPA_INTERFACE_INIT(
314 +               SPA_TYPE_INTERFACE_AEC,
315 +               SPA_VERSION_AUDIO_AEC,
316 +               NULL,
317 +               NULL);
318  
319 +       auto impl = new (handle) impl_data();
320         impl->handle.get_interface = impl_get_interface;
321         impl->handle.clear = impl_clear;
322 -
323 -       impl->aec.iface = SPA_INTERFACE_INIT(
324 -               SPA_TYPE_INTERFACE_AUDIO_AEC,
325 -               SPA_VERSION_AUDIO_AEC,
326 -               &impl_aec, impl);
327 -       impl->aec.name = "webrtc",
328 -       impl->aec.info = NULL;
329 -       impl->aec.latency = "480/48000",
330 -
331         impl->log = (struct spa_log*)spa_support_find(support, n_support, SPA_TYPE_INTERFACE_Log);
332         spa_log_topic_init(impl->log, &log_topic);
333  
334 @@ -227,7 +235,7 @@ impl_init(const struct spa_handle_factory *factory,
335  }
336  
337  static const struct spa_interface_info impl_interfaces[] = {
338 -       {SPA_TYPE_INTERFACE_AUDIO_AEC,},
339 +       {SPA_TYPE_INTERFACE_AEC,},
340  };
341  
342  static int
343 diff --git a/src/modules/module-echo-cancel.c b/src/modules/module-echo-cancel.c
344 index c933a9376..728325938 100644
345 --- a/src/modules/module-echo-cancel.c
346 +++ b/src/modules/module-echo-cancel.c
347 @@ -24,6 +24,7 @@
348   */
349  
350  #include "config.h"
351 +#include "module-echo-cancel/echo-cancel.h"
352  
353  #include <errno.h>
354  #include <fcntl.h>
355 @@ -187,7 +188,7 @@ struct impl {
356         uint32_t out_ringsize;
357         struct spa_ringbuffer out_ring;
358  
359 -       struct spa_audio_aec *aec;
360 +       const struct echo_cancel_info *aec_info;
361         uint32_t aec_blocksize;
362  
363         unsigned int capture_ready:1;
364 @@ -287,7 +288,7 @@ static void process(struct impl *impl)
365         pw_stream_queue_buffer(impl->playback, pout);
366  
367         /* Now run the canceller */
368 -       spa_audio_aec_run(impl->aec, rec, play_delayed, out, size / sizeof(float));
369 +       echo_cancel_run(impl->aec_info, impl->spa_handle, rec,  play_delayed, out, size / sizeof(float));
370  
371         /* Next, copy over the output to the output ringbuffer */
372         avail = spa_ringbuffer_get_write_index(&impl->out_ring, &oindex);
373 @@ -651,8 +652,8 @@ static int setup_streams(struct impl *impl)
374                 pw_properties_set(props, PW_KEY_NODE_LINK_GROUP, str);
375         if ((str = pw_properties_get(impl->source_props, PW_KEY_NODE_LATENCY)) != NULL)
376                 pw_properties_set(props, PW_KEY_NODE_LATENCY, str);
377 -       else if (impl->aec->latency)
378 -               pw_properties_set(props, PW_KEY_NODE_LATENCY, impl->aec->latency);
379 +       else if (impl->aec_info->latency)
380 +               pw_properties_set(props, PW_KEY_NODE_LATENCY, impl->aec_info->latency);
381  
382         impl->capture = pw_stream_new(impl->core,
383                         "Echo-Cancel Capture", props);
384 @@ -684,8 +685,8 @@ static int setup_streams(struct impl *impl)
385                 pw_properties_set(props, PW_KEY_NODE_LINK_GROUP, str);
386         if ((str = pw_properties_get(impl->sink_props, PW_KEY_NODE_LATENCY)) != NULL)
387                 pw_properties_set(props, PW_KEY_NODE_LATENCY, str);
388 -       else if (impl->aec->latency)
389 -               pw_properties_set(props, PW_KEY_NODE_LATENCY, impl->aec->latency);
390 +       else if (impl->aec_info->latency)
391 +               pw_properties_set(props, PW_KEY_NODE_LATENCY, impl->aec_info->latency);
392  
393         impl->playback = pw_stream_new(impl->core,
394                         "Echo-Cancel Playback", props);
395 @@ -998,42 +999,42 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args)
396                 return -ENOENT;
397         }
398  
399 -       if ((res = spa_handle_get_interface(handle, SPA_TYPE_INTERFACE_AUDIO_AEC, &iface)) < 0) {
400 -               pw_log_error("can't get %s interface %d", SPA_TYPE_INTERFACE_AUDIO_AEC, res);
401 +       if ((res = spa_handle_get_interface(handle, SPA_TYPE_INTERFACE_AEC, &iface)) < 0) {
402 +               pw_log_error("can't get %s interface %d", SPA_TYPE_INTERFACE_AEC, res);
403                 return res;
404         }
405 -       impl->aec = iface;
406 +       impl->aec_info = iface;
407         impl->spa_handle = handle;
408 -       if (impl->aec->iface.version != SPA_VERSION_AUDIO_AEC) {
409 +       if (impl->aec_info->iface.version != SPA_VERSION_AUDIO_AEC) {
410                 pw_log_error("codec plugin %s has incompatible ABI version (%d != %d)",
411 -                       SPA_NAME_AEC, impl->aec->iface.version, SPA_VERSION_AUDIO_AEC);
412 +                       SPA_NAME_AEC, impl->aec_info->iface.version, SPA_VERSION_AUDIO_AEC);
413                 res = -ENOENT;
414                 goto error;
415         }
416  
417 -       (void)SPA_SUPPORT_INIT(SPA_TYPE_INTERFACE_AUDIO_AEC, (struct spa_audio_aec *)impl->aec);
418 +       (void)SPA_SUPPORT_INIT(SPA_TYPE_INTERFACE_AEC, (struct echo_cancel_info *)impl->aec_info);
419  
420 -       pw_log_info("Using plugin AEC %s", impl->aec->name);
421 +       pw_log_info("Using plugin AEC %s", impl->aec_info->name);
422  
423         if ((str = pw_properties_get(props, "aec.args")) != NULL)
424                 aec_props = pw_properties_new_string(str);
425         else
426                 aec_props = pw_properties_new(NULL, NULL);
427  
428 -       if (spa_audio_aec_init(impl->aec, &aec_props->dict, &impl->info)) {
429 -               pw_log_error("codec plugin %s create failed", impl->aec->name);
430 +       if (echo_cancel_create(impl->aec_info, impl->spa_handle, &aec_props->dict, &impl->info)) {
431 +               pw_log_error("codec plugin %s create failed", impl->aec_info->name);
432                 res = -ENOENT;
433                 goto error;
434         }
435  
436         pw_properties_free(aec_props);
437  
438 -       if (impl->aec->latency) {
439 +       if (impl->aec_info->latency) {
440                 unsigned int num, denom, req_num, req_denom;
441                 unsigned int factor = 0;
442                 unsigned int new_num = 0;
443  
444 -               spa_assert_se(sscanf(impl->aec->latency, "%u/%u", &num, &denom) == 2);
445 +               spa_assert_se(sscanf(impl->aec_info->latency, "%u/%u", &num, &denom) == 2);
446  
447                 if ((str = pw_properties_get(props, PW_KEY_NODE_LATENCY)) != NULL) {
448                         sscanf(str, "%u/%u", &req_num, &req_denom);
449 @@ -1042,8 +1043,8 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args)
450                 }
451  
452                 if (factor == 0 || new_num == 0) {
453 -                       pw_log_info("Setting node latency to %s", impl->aec->latency);
454 -                       pw_properties_set(props, PW_KEY_NODE_LATENCY, impl->aec->latency);
455 +                       pw_log_info("Setting node latency to %s", impl->aec_info->latency);
456 +                       pw_properties_set(props, PW_KEY_NODE_LATENCY, impl->aec_info->latency);
457                         impl->aec_blocksize = sizeof(float) * impl->info.rate * num / denom;
458                 } else {
459                         pw_log_info("Setting node latency to %u/%u", new_num, req_denom);
460 diff --git a/src/modules/module-echo-cancel/echo-cancel.h b/src/modules/module-echo-cancel/echo-cancel.h
461 new file mode 100644
462 index 000000000..ac83f70e4
463 --- /dev/null
464 +++ b/src/modules/module-echo-cancel/echo-cancel.h
465 @@ -0,0 +1,34 @@
466 +/* PipeWire
467 + *
468 + * Copyright © 2021 Wim Taymans <wim.taymans@gmail.com>
469 + *
470 + * Permission is hereby granted, free of charge, to any person obtaining a
471 + * copy of this software and associated documentation files (the "Software"),
472 + * to deal in the Software without restriction, including without limitation
473 + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
474 + * and/or sell copies of the Software, and to permit persons to whom the
475 + * Software is furnished to do so, subject to the following conditions:
476 + *
477 + * The above copyright notice and this permission notice (including the next
478 + * paragraph) shall be included in all copies or substantial portions of the
479 + * Software.
480 + *
481 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
482 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
483 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
484 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
485 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
486 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
487 + * DEALINGS IN THE SOFTWARE.
488 + */
489 +
490 +
491 +#include <spa/utils/dict.h>
492 +#include <spa/utils/hook.h>
493 +#include <spa/param/audio/raw.h>
494 +#include <spa/support/plugin.h>
495 +
496 +#include <pipewire/properties.h>
497 +
498 +#define echo_cancel_create(i,...)      (i)->create(__VA_ARGS__)
499 +#define echo_cancel_run(i,...)         (i)->run(__VA_ARGS__)
500 -- 
501 2.35.1
502