Changes of Revision 2

pipewire-aptx.changes Changed
x
 
1
@@ -1,4 +1,9 @@
2
 -------------------------------------------------------------------
3
+Sun Jan 30 16:36:30 UTC 2022 - Bjørn Lie <zaitor@opensuse.org>
4
+
5
+- Update to version 0.3.44
6
+
7
+-------------------------------------------------------------------
8
 Wed Jan  5 16:20:56 UTC 2022 - Bjørn Lie <zaitor@opensuse.org>
9
 
10
 - Update to version 0.3.43
11
pipewire-aptx.spec Changed
10
 
1
@@ -7,7 +7,7 @@
2
 %define soversion 0_2
3
 
4
 Name:           pipewire-aptx
5
-Version:        0.3.43
6
+Version:        0.3.44
7
 Release:        0
8
 Summary:        PipeWire Bluetooth aptX codec plugin
9
 License:        MIT
10
pipewire-0.3.43.tar.gz/doc/pipewire-tools.dox Deleted
6
 
1
@@ -1,4 +0,0 @@
2
-/** \page page_tools PipeWire Tools
3
-
4
-*/
5
-
6
pipewire-0.3.43.tar.gz/spa/plugins/alsa/mixer/profile-sets/behringer-umc22.conf Deleted
70
 
1
@@ -1,68 +0,0 @@
2
-# This file is part of PulseAudio.
3
-#
4
-# PulseAudio is free software; you can redistribute it and/or modify
5
-# it under the terms of the GNU Lesser General Public License as
6
-# published by the Free Software Foundation; either version 2.1 of the
7
-# License, or (at your option) any later version.
8
-#
9
-# PulseAudio is distributed in the hope that it will be useful, but
10
-# WITHOUT ANY WARRANTY; without even the implied warranty of
11
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
-# General Public License for more details.
13
-#
14
-# You should have received a copy of the GNU Lesser General Public License
15
-# along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
16
-
17
-; Behringer U-Phoria UMC22
18
-;
19
-; Default mapping only allows to use stereo input and sound card has two
20
-; physical input channels.
21
-;
22
-; However in case of only using a single input channel (like condenser
23
-; microphone) only one channel will have any sound, which is often
24
-; inconvenient for casual use.
25
-;
26
-; This config includes mono input options which makes it much more
27
-; friendly in single input configuration.
28
-;
29
-; This config also removes default digital input/output mappings that do
30
-; not physically exist on this card.
31
-;
32
-; Added by Nazar Mokrynskyi <nazar@mokrynskyi.com>
33
-
34
-[General]
35
-auto-profiles = yes
36
-
37
-[Mapping analog-stereo-input]
38
-device-strings = hw:%f
39
-channel-map = left,right
40
-paths-input = analog-input-mic
41
-direction = input
42
-priority = 4
43
-
44
-[Mapping analog-mono]
45
-device-strings = hw:%f
46
-channel-map = mono,mono
47
-paths-input = analog-input-mic
48
-direction = input
49
-priority = 3
50
-
51
-[Mapping analog-mono-left]
52
-device-strings = hw:%f
53
-channel-map = mono,aux1
54
-paths-input = analog-input-mic
55
-direction = input
56
-priority = 2
57
-
58
-[Mapping analog-mono-right]
59
-device-strings = hw:%f
60
-channel-map = aux1,mono
61
-paths-input = analog-input-mic
62
-direction = input
63
-priority = 1
64
-
65
-[Mapping analog-stereo-output]
66
-device-strings = front:%f
67
-channel-map = left,right
68
-paths-output = analog-output
69
-direction = output
70
pipewire-0.3.43.tar.gz/src/modules/module-rtkit.c Deleted
732
 
1
@@ -1,730 +0,0 @@
2
-/* PipeWire
3
- *
4
- * Copyright © 2018 Wim Taymans
5
- *
6
- * Permission is hereby granted, free of charge, to any person obtaining a
7
- * copy of this software and associated documentation files (the "Software"),
8
- * to deal in the Software without restriction, including without limitation
9
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
- * and/or sell copies of the Software, and to permit persons to whom the
11
- * Software is furnished to do so, subject to the following conditions:
12
- *
13
- * The above copyright notice and this permission notice (including the next
14
- * paragraph) shall be included in all copies or substantial portions of the
15
- * Software.
16
- *
17
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23
- * DEALINGS IN THE SOFTWARE.
24
- */
25
-
26
-#include <stdlib.h>
27
-#include <stdbool.h>
28
-#include <string.h>
29
-#include <stdio.h>
30
-#include <errno.h>
31
-#include <sys/stat.h>
32
-#ifdef __FreeBSD__
33
-#include <sys/thr.h>
34
-#endif
35
-#include <fcntl.h>
36
-#include <unistd.h>
37
-#include <pthread.h>
38
-#include <sys/resource.h>
39
-
40
-#include "config.h"
41
-
42
-#include <spa/support/dbus.h>
43
-#include <spa/utils/result.h>
44
-#include <spa/utils/string.h>
45
-
46
-#include <pipewire/impl.h>
47
-#include <pipewire/thread.h>
48
-
49
-/** \page page_module_rtkit PipeWire Module: RTKit
50
- */
51
-
52
-#define NAME "rtkit"
53
-
54
-PW_LOG_TOPIC_STATIC(mod_topic, "mod." NAME);
55
-#define PW_LOG_TOPIC_DEFAULT mod_topic
56
-
57
-#define DEFAULT_NICE_LEVEL -11
58
-#define DEFAULT_RT_PRIO        88
59
-#define DEFAULT_RT_TIME_SOFT   2000000
60
-#define DEFAULT_RT_TIME_HARD   2000000
61
-
62
-#define MODULE_USAGE   "[nice.level=<priority: default "SPA_STRINGIFY(DEFAULT_NICE_LEVEL) ">] "    \
63
-           "[rt.prio=<priority: default "SPA_STRINGIFY(DEFAULT_RT_PRIO) ">] "      \
64
-           "[rt.time.soft=<in usec: default "SPA_STRINGIFY(DEFAULT_RT_TIME_SOFT)"] "   \
65
-           "[rt.time.hard=<in usec: default "SPA_STRINGIFY(DEFAULT_RT_TIME_HARD)"] "
66
-
67
-static const struct spa_dict_item module_props[] = {
68
-   { PW_KEY_MODULE_AUTHOR, "Wim Taymans <wim.taymans@gmail.com>" },
69
-   { PW_KEY_MODULE_DESCRIPTION, "Use RTKit to raise thread priorities" },
70
-   { PW_KEY_MODULE_USAGE, MODULE_USAGE },
71
-   { PW_KEY_MODULE_VERSION, PACKAGE_VERSION },
72
-};
73
-
74
-struct pw_rtkit_bus;
75
-
76
-struct thread {
77
-   struct impl *impl;
78
-   struct spa_list link;
79
-   pthread_t thread;
80
-   pid_t pid;
81
-   void *(*start)(void*);
82
-   void *arg;
83
-};
84
-
85
-struct impl {
86
-   struct pw_context *context;
87
-
88
-   struct pw_properties *props;
89
-
90
-   struct pw_rtkit_bus *system_bus;
91
-
92
-   pthread_mutex_t lock;
93
-   pthread_cond_t cond;
94
-
95
-   struct spa_list threads_list;
96
-   struct spa_thread_utils thread_utils;
97
-
98
-   int nice_level;
99
-   int rt_prio;
100
-   rlim_t rt_time_soft;
101
-   rlim_t rt_time_hard;
102
-
103
-   struct spa_hook module_listener;
104
-};
105
-
106
-/***
107
-  Copyright 2009 Lennart Poettering
108
-  Copyright 2010 David Henningsson <diwic@ubuntu.com>
109
-
110
-  Permission is hereby granted, free of charge, to any person
111
-  obtaining a copy of this software and associated documentation files
112
-  (the "Software"), to deal in the Software without restriction,
113
-  including without limitation the rights to use, copy, modify, merge,
114
-  publish, distribute, sublicense, and/or sell copies of the Software,
115
-  and to permit persons to whom the Software is furnished to do so,
116
-  subject to the following conditions:
117
-
118
-  The above copyright notice and this permission notice shall be
119
-  included in all copies or substantial portions of the Software.
120
-
121
-  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
122
-  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
123
-  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
124
-  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
125
-  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
126
-  ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
127
-  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
128
-  SOFTWARE.
129
-***/
130
-
131
-#include <dbus/dbus.h>
132
-
133
-#include "config.h"
134
-
135
-#include <sys/syscall.h>
136
-
137
-#define RTKIT_SERVICE_NAME "org.freedesktop.RealtimeKit1"
138
-#define RTKIT_OBJECT_PATH "/org/freedesktop/RealtimeKit1"
139
-
140
-#ifndef RLIMIT_RTTIME
141
-#define RLIMIT_RTTIME 15
142
-#endif
143
-
144
-/** \cond */
145
-struct pw_rtkit_bus {
146
-   DBusConnection *bus;
147
-};
148
-/** \endcond */
149
-
150
-struct pw_rtkit_bus *pw_rtkit_bus_get_system(void)
151
-{
152
-   struct pw_rtkit_bus *bus;
153
-   DBusError error;
154
-
155
-   if (getenv("DISABLE_RTKIT")) {
156
-       errno = ENOTSUP;
157
-       return NULL;
158
-   }
159
-
160
-   dbus_error_init(&error);
161
-
162
-   bus = calloc(1, sizeof(struct pw_rtkit_bus));
163
-   if (bus == NULL)
164
-       return NULL;
165
-
166
-   bus->bus = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error);
167
-   if (bus->bus == NULL)
168
-       goto error;
169
-
170
-   dbus_connection_set_exit_on_disconnect(bus->bus, false);
171
-
172
-   return bus;
173
-
174
-error:
175
-   free(bus);
176
-   pw_log_error("Failed to connect to system bus: %s", error.message);
177
-   dbus_error_free(&error);
178
-   errno = ECONNREFUSED;
179
-   return NULL;
180
-}
181
-
182
-void pw_rtkit_bus_free(struct pw_rtkit_bus *system_bus)
183
-{
184
-   dbus_connection_close(system_bus->bus);
185
-   dbus_connection_unref(system_bus->bus);
186
-   free(system_bus);
187
-}
188
-
189
-static pid_t _gettid(void)
190
-{
191
-#if defined(HAVE_GETTID)
192
-   return (pid_t) gettid();
193
-#elif defined(__linux__)
194
-   return syscall(SYS_gettid);
195
-#elif defined(__FreeBSD__)
196
-   long pid;
197
-   thr_self(&pid);
198
-   return (pid_t)pid;
199
-#else
200
-#error "No gettid impl"
201
-#endif
202
-}
203
-
204
-static int translate_error(const char *name)
205
-{
206
-   pw_log_warn("RTKit error: %s", name);
207
-
208
-   if (spa_streq(name, DBUS_ERROR_NO_MEMORY))
209
-       return -ENOMEM;
210
-   if (spa_streq(name, DBUS_ERROR_SERVICE_UNKNOWN) ||
211
-       spa_streq(name, DBUS_ERROR_NAME_HAS_NO_OWNER))
212
-       return -ENOENT;
213
-   if (spa_streq(name, DBUS_ERROR_ACCESS_DENIED) ||
214
-       spa_streq(name, DBUS_ERROR_AUTH_FAILED))
215
-       return -EACCES;
216
-
217
-   return -EIO;
218
-}
219
-
220
-static long long rtkit_get_int_property(struct pw_rtkit_bus *connection, const char *propname,
221
-                   long long *propval)
222
-{
223
-   DBusMessage *m = NULL, *r = NULL;
224
-   DBusMessageIter iter, subiter;
225
-   dbus_int64_t i64;
226
-   dbus_int32_t i32;
227
-   DBusError error;
228
-   int current_type;
229
-   long long ret;
230
-   const char *interfacestr = "org.freedesktop.RealtimeKit1";
231
-
232
-   dbus_error_init(&error);
233
-
234
-   if (!(m = dbus_message_new_method_call(RTKIT_SERVICE_NAME,
235
-                          RTKIT_OBJECT_PATH,
236
-                          "org.freedesktop.DBus.Properties", "Get"))) {
237
-       ret = -ENOMEM;
238
-       goto finish;
239
-   }
240
-
241
-   if (!dbus_message_append_args(m,
242
-                     DBUS_TYPE_STRING, &interfacestr,
243
-                     DBUS_TYPE_STRING, &propname, DBUS_TYPE_INVALID)) {
244
-       ret = -ENOMEM;
245
-       goto finish;
246
-   }
247
-
248
-   if (!(r = dbus_connection_send_with_reply_and_block(connection->bus, m, -1, &error))) {
249
-       ret = translate_error(error.name);
250
-       goto finish;
251
-   }
252
-
253
-   if (dbus_set_error_from_message(&error, r)) {
254
-       ret = translate_error(error.name);
255
-       goto finish;
256
-   }
257
-
258
-   ret = -EBADMSG;
259
-   dbus_message_iter_init(r, &iter);
260
-   while ((current_type = dbus_message_iter_get_arg_type(&iter)) != DBUS_TYPE_INVALID) {
261
-
262
-       if (current_type == DBUS_TYPE_VARIANT) {
263
-           dbus_message_iter_recurse(&iter, &subiter);
264
-
265
-           while ((current_type =
266
-               dbus_message_iter_get_arg_type(&subiter)) != DBUS_TYPE_INVALID) {
267
-
268
-               if (current_type == DBUS_TYPE_INT32) {
269
-                   dbus_message_iter_get_basic(&subiter, &i32);
270
-                   *propval = i32;
271
-                   ret = 0;
272
-               }
273
-
274
-               if (current_type == DBUS_TYPE_INT64) {
275
-                   dbus_message_iter_get_basic(&subiter, &i64);
276
-                   *propval = i64;
277
-                   ret = 0;
278
-               }
279
-
280
-               dbus_message_iter_next(&subiter);
281
-           }
282
-       }
283
-       dbus_message_iter_next(&iter);
284
-   }
285
-
286
-finish:
287
-
288
-   if (m)
289
-       dbus_message_unref(m);
290
-
291
-   if (r)
292
-       dbus_message_unref(r);
293
-
294
-   dbus_error_free(&error);
295
-
296
-   return ret;
297
-}
298
-
299
-int pw_rtkit_get_max_realtime_priority(struct pw_rtkit_bus *connection)
300
-{
301
-   long long retval;
302
-   int err;
303
-
304
-   err = rtkit_get_int_property(connection, "MaxRealtimePriority", &retval);
305
-   return err < 0 ? err : retval;
306
-}
307
-
308
-int pw_rtkit_get_min_nice_level(struct pw_rtkit_bus *connection, int *min_nice_level)
309
-{
310
-   long long retval;
311
-   int err;
312
-
313
-   err = rtkit_get_int_property(connection, "MinNiceLevel", &retval);
314
-   if (err >= 0)
315
-       *min_nice_level = retval;
316
-   return err;
317
-}
318
-
319
-long long pw_rtkit_get_rttime_usec_max(struct pw_rtkit_bus *connection)
320
-{
321
-   long long retval;
322
-   int err;
323
-
324
-   err = rtkit_get_int_property(connection, "RTTimeUSecMax", &retval);
325
-   return err < 0 ? err : retval;
326
-}
327
-
328
-int pw_rtkit_make_realtime(struct pw_rtkit_bus *connection, pid_t thread, int priority)
329
-{
330
-   DBusMessage *m = NULL, *r = NULL;
331
-   dbus_uint64_t u64;
332
-   dbus_uint32_t u32;
333
-   DBusError error;
334
-   int ret;
335
-
336
-   dbus_error_init(&error);
337
-
338
-   if (thread == 0)
339
-       thread = _gettid();
340
-
341
-   if (!(m = dbus_message_new_method_call(RTKIT_SERVICE_NAME,
342
-                          RTKIT_OBJECT_PATH,
343
-                          "org.freedesktop.RealtimeKit1",
344
-                          "MakeThreadRealtime"))) {
345
-       ret = -ENOMEM;
346
-       goto finish;
347
-   }
348
-
349
-   u64 = (dbus_uint64_t) thread;
350
-   u32 = (dbus_uint32_t) priority;
351
-
352
-   if (!dbus_message_append_args(m,
353
-                     DBUS_TYPE_UINT64, &u64,
354
-                     DBUS_TYPE_UINT32, &u32, DBUS_TYPE_INVALID)) {
355
-       ret = -ENOMEM;
356
-       goto finish;
357
-   }
358
-
359
-   if (!(r = dbus_connection_send_with_reply_and_block(connection->bus, m, -1, &error))) {
360
-       ret = translate_error(error.name);
361
-       goto finish;
362
-   }
363
-
364
-
365
-   if (dbus_set_error_from_message(&error, r)) {
366
-       ret = translate_error(error.name);
367
-       goto finish;
368
-   }
369
-
370
-   ret = 0;
371
-
372
-finish:
373
-
374
-   if (m)
375
-       dbus_message_unref(m);
376
-
377
-   if (r)
378
-       dbus_message_unref(r);
379
-
380
-   dbus_error_free(&error);
381
-
382
-   return ret;
383
-}
384
-
385
-int pw_rtkit_make_high_priority(struct pw_rtkit_bus *connection, pid_t thread, int nice_level)
386
-{
387
-   DBusMessage *m = NULL, *r = NULL;
388
-   dbus_uint64_t u64;
389
-   dbus_int32_t s32;
390
-   DBusError error;
391
-   int ret;
392
-
393
-   dbus_error_init(&error);
394
-
395
-   if (thread == 0)
396
-       thread = _gettid();
397
-
398
-   if (!(m = dbus_message_new_method_call(RTKIT_SERVICE_NAME,
399
-                          RTKIT_OBJECT_PATH,
400
-                          "org.freedesktop.RealtimeKit1",
401
-                          "MakeThreadHighPriority"))) {
402
-       ret = -ENOMEM;
403
-       goto finish;
404
-   }
405
-
406
-   u64 = (dbus_uint64_t) thread;
407
-   s32 = (dbus_int32_t) nice_level;
408
-
409
-   if (!dbus_message_append_args(m,
410
-                     DBUS_TYPE_UINT64, &u64,
411
-                     DBUS_TYPE_INT32, &s32, DBUS_TYPE_INVALID)) {
412
-       ret = -ENOMEM;
413
-       goto finish;
414
-   }
415
-
416
-
417
-
418
-   if (!(r = dbus_connection_send_with_reply_and_block(connection->bus, m, -1, &error))) {
419
-       ret = translate_error(error.name);
420
-       goto finish;
421
-   }
422
-
423
-
424
-   if (dbus_set_error_from_message(&error, r)) {
425
-       ret = translate_error(error.name);
426
-       goto finish;
427
-   }
428
-
429
-   ret = 0;
430
-
431
-finish:
432
-
433
-   if (m)
434
-       dbus_message_unref(m);
435
-
436
-   if (r)
437
-       dbus_message_unref(r);
438
-
439
-   dbus_error_free(&error);
440
-
441
-   return ret;
442
-}
443
-
444
-static void module_destroy(void *data)
445
-{
446
-   struct impl *impl = data;
447
-
448
-   pw_thread_utils_set(NULL);
449
-   spa_hook_remove(&impl->module_listener);
450
-
451
-   pw_properties_free(impl->props);
452
-   if (impl->system_bus)
453
-       pw_rtkit_bus_free(impl->system_bus);
454
-   free(impl);
455
-}
456
-
457
-static const struct pw_impl_module_events module_events = {
458
-   PW_VERSION_IMPL_MODULE_EVENTS,
459
-   .destroy = module_destroy,
460
-};
461
-
462
-static int set_nice(struct impl *impl, int nice_level)
463
-{
464
-   int res;
465
-   if ((res = pw_rtkit_make_high_priority(impl->system_bus, 0, nice_level)) < 0) {
466
-       pw_log_warn("could not set nice-level to %d: %s",
467
-               nice_level, spa_strerror(res));
468
-   } else {
469
-       pw_log_info("main thread nice level set to %d", nice_level);
470
-   }
471
-   return 0;
472
-}
473
-
474
-static int set_rlimit(struct impl *impl)
475
-{
476
-   struct rlimit rl;
477
-   long long rttime;
478
-   int res = 0;
479
-
480
-   rl.rlim_cur = impl->rt_time_soft;
481
-   rl.rlim_max = impl->rt_time_hard;
482
-
483
-   rttime = pw_rtkit_get_rttime_usec_max(impl->system_bus);
484
-   if (rttime >= 0) {
485
-       rl.rlim_cur = SPA_MIN(rl.rlim_cur, (rlim_t)rttime);
486
-       rl.rlim_max = SPA_MIN(rl.rlim_max, (rlim_t)rttime);
487
-   }
488
-
489
-   if (setrlimit(RLIMIT_RTTIME, &rl) < 0)
490
-       res = -errno;
491
-
492
-   if (res < 0)
493
-       pw_log_debug("setrlimit() failed: %s", spa_strerror(res));
494
-   else
495
-       pw_log_debug("rt.time.soft:%"PRIi64" rt.time.hard:%"PRIi64,
496
-               (int64_t)rl.rlim_cur, (int64_t)rl.rlim_max);
497
-
498
-   return res;
499
-}
500
-
501
-static struct thread *find_thread_by_pt(struct impl *impl, pthread_t pt)
502
-{
503
-   struct thread *t;
504
-
505
-   spa_list_for_each(t, &impl->threads_list, link) {
506
-       if (pthread_equal(t->thread, pt))
507
-           return t;
508
-   }
509
-   return NULL;
510
-}
511
-
512
-static void *custom_start(void *data)
513
-{
514
-   struct thread *this = data;
515
-   struct impl *impl = this->impl;
516
-
517
-   pthread_mutex_lock(&impl->lock);
518
-   this->pid = _gettid();
519
-   pthread_cond_broadcast(&impl->cond);
520
-   pthread_mutex_unlock(&impl->lock);
521
-
522
-   return this->start(this->arg);
523
-}
524
-
525
-static struct spa_thread *impl_create(void *data, const struct spa_dict *props,
526
-       void *(*start_routine)(void*), void *arg)
527
-{
528
-   struct impl *impl = data;
529
-   struct thread *this;
530
-   int err;
531
-
532
-   this = calloc(1, sizeof(*this));
533
-   this->impl = impl;
534
-   this->start = start_routine;
535
-   this->arg = arg;
536
-
537
-   pthread_mutex_lock(&impl->lock);
538
-   err = pthread_create(&this->thread, NULL, custom_start, this);
539
-   if (err != 0)
540
-       goto exit;
541
-
542
-   pthread_cond_wait(&impl->cond, &impl->lock);
543
-
544
-   spa_list_append(&impl->threads_list, &this->link);
545
-exit:
546
-   pthread_mutex_unlock(&impl->lock);
547
-
548
-   if (err != 0) {
549
-       errno = err;
550
-       free(this);
551
-       return NULL;
552
-   }
553
-   return (struct spa_thread*)this->thread;
554
-}
555
-
556
-static int impl_join(void *data, struct spa_thread *thread, void **retval)
557
-{
558
-   struct impl *impl = data;
559
-   pthread_t pt = (pthread_t)thread;
560
-   struct thread *thr;
561
-
562
-   pthread_mutex_lock(&impl->lock);
563
-   if ((thr = find_thread_by_pt(impl, pt)) != NULL) {
564
-       spa_list_remove(&thr->link);
565
-       free(thr);
566
-   }
567
-   pthread_mutex_unlock(&impl->lock);
568
-
569
-   return pthread_join(pt, retval);
570
-}
571
-
572
-static int impl_get_rt_range(void *data, const struct spa_dict *props,
573
-       int *min, int *max)
574
-{
575
-   struct impl *impl = data;
576
-   if (min)
577
-       *min = 1;
578
-   if (max)
579
-       *max = pw_rtkit_get_max_realtime_priority(impl->system_bus);
580
-   return 0;
581
-}
582
-
583
-static pid_t impl_gettid(struct impl *impl, pthread_t pt)
584
-{
585
-   struct thread *thr;
586
-   pid_t pid;
587
-
588
-   pthread_mutex_lock(&impl->lock);
589
-   if ((thr = find_thread_by_pt(impl, pt)) != NULL)
590
-       pid = thr->pid;
591
-   else
592
-       pid = _gettid();
593
-   pthread_mutex_unlock(&impl->lock);
594
-
595
-   return pid;
596
-}
597
-
598
-static int impl_acquire_rt(void *data, struct spa_thread *thread, int priority)
599
-{
600
-   struct impl *impl = data;
601
-   struct sched_param sp;
602
-   int r, rtprio;
603
-   pthread_t pt = (pthread_t)thread;
604
-   pid_t pid;
605
-
606
-   priority = impl->rt_prio;
607
-
608
-   rtprio = pw_rtkit_get_max_realtime_priority(impl->system_bus);
609
-   if (rtprio >= 0)
610
-       rtprio = SPA_MIN(rtprio, priority);
611
-   else
612
-       rtprio = priority;
613
-
614
-   spa_zero(sp);
615
-   sp.sched_priority = rtprio;
616
-
617
-#ifndef __FreeBSD__
618
-   if (pthread_setschedparam(pt, SCHED_OTHER | SCHED_RESET_ON_FORK, &sp) == 0) {
619
-       pw_log_debug("SCHED_OTHER|SCHED_RESET_ON_FORK worked.");
620
-   }
621
-#endif
622
-
623
-   pid = impl_gettid(impl, pt);
624
-
625
-   if ((r = pw_rtkit_make_realtime(impl->system_bus, pid, rtprio)) < 0) {
626
-       pw_log_warn("could not make thread realtime: %s", spa_strerror(r));
627
-   } else {
628
-       pw_log_info("acquired realtime prio:%d", rtprio);
629
-   }
630
-   return 0;
631
-}
632
-
633
-static int impl_drop_rt(void *data, struct spa_thread *thread)
634
-{
635
-   struct sched_param sp;
636
-   pthread_t pt = (pthread_t)thread;
637
-   int err;
638
-
639
-   spa_zero(sp);
640
-#ifndef __FreeBSD__
641
-   if ((err = pthread_setschedparam(pt,
642
-               SCHED_OTHER | SCHED_RESET_ON_FORK, &sp)) != 0) {
643
-       pw_log_debug("thread %p: SCHED_OTHER|SCHED_RESET_ON_FORK failed: %s",
644
-               thread, strerror(err));
645
-       return -err;
646
-   }
647
-#endif
648
-   pw_log_info("thread %p dropped realtime priority", thread);
649
-   return 0;
650
-}
651
-
652
-static const struct spa_thread_utils_methods impl_thread_utils = {
653
-   SPA_VERSION_THREAD_UTILS_METHODS,
654
-   .create = impl_create,
655
-   .join = impl_join,
656
-   .get_rt_range = impl_get_rt_range,
657
-   .acquire_rt = impl_acquire_rt,
658
-   .drop_rt = impl_drop_rt,
659
-};
660
-
661
-
662
-SPA_EXPORT
663
-int pipewire__module_init(struct pw_impl_module *module, const char *args)
664
-{
665
-   struct pw_context *context = pw_impl_module_get_context(module);
666
-   struct impl *impl;
667
-   const struct pw_properties *props;
668
-   const char *str;
669
-   int res;
670
-
671
-   PW_LOG_TOPIC_INIT(mod_topic);
672
-
673
-   if ((props = pw_context_get_properties(context)) != NULL &&
674
-       (str = pw_properties_get(props, "support.dbus")) != NULL &&
675
-       !pw_properties_parse_bool(str))
676
-       return -ENOTSUP;
677
-
678
-   impl = calloc(1, sizeof(struct impl));
679
-   if (impl == NULL)
680
-       return -ENOMEM;
681
-
682
-   spa_list_init(&impl->threads_list);
683
-   pthread_mutex_init(&impl->lock, NULL);
684
-   pthread_cond_init(&impl->cond, NULL);
685
-
686
-   pw_log_debug("module %p: new", impl);
687
-
688
-   impl->context = context;
689
-   impl->props = args ? pw_properties_new_string(args) : pw_properties_new(NULL, NULL);
690
-   if (impl->props == NULL) {
691
-       res = -errno;
692
-       goto error;
693
-   }
694
-
695
-   impl->system_bus = pw_rtkit_bus_get_system();
696
-   if (impl->system_bus == NULL) {
697
-       res = -errno;
698
-       pw_log_warn("could not get system bus: %m");
699
-       goto error;
700
-   }
701
-   impl->nice_level = pw_properties_get_int32(impl->props, "nice.level", DEFAULT_NICE_LEVEL);
702
-
703
-   set_nice(impl, impl->nice_level);
704
-
705
-   impl->rt_prio = pw_properties_get_int32(impl->props, "rt.prio", DEFAULT_RT_PRIO);
706
-   impl->rt_time_soft = pw_properties_get_int32(impl->props, "rt.time.soft", DEFAULT_RT_TIME_SOFT);
707
-   impl->rt_time_hard = pw_properties_get_int32(impl->props, "rt.time.hard", DEFAULT_RT_TIME_HARD);
708
-
709
-   set_rlimit(impl);
710
-
711
-   impl->thread_utils.iface = SPA_INTERFACE_INIT(
712
-           SPA_TYPE_INTERFACE_ThreadUtils,
713
-           SPA_VERSION_THREAD_UTILS,
714
-           &impl_thread_utils, impl);
715
-
716
-   pw_thread_utils_set(&impl->thread_utils);
717
-
718
-   pw_impl_module_add_listener(module, &impl->module_listener, &module_events, impl);
719
-
720
-   pw_impl_module_update_properties(module, &SPA_DICT_INIT_ARRAY(module_props));
721
-   pw_impl_module_update_properties(module, &impl->props->dict);
722
-
723
-   return 0;
724
-
725
-error:
726
-   pw_properties_free(impl->props);
727
-   if (impl->system_bus)
728
-       pw_rtkit_bus_free(impl->system_bus);
729
-   free(impl);
730
-   return res;
731
-}
732
pipewire-0.3.43.tar.gz/.cirrus.yml -> pipewire-0.3.44.tar.gz/.cirrus.yml Changed
10
 
1
@@ -17,7 +17,7 @@
2
   build_script:
3
     - mkdir build
4
     - cd build
5
-    - meson setup -Dalsa=enabled -Draop=enabled -Dv4l2=enabled -Dpipewire-alsa=enabled -Dbluez5=disabled -Djack=disabled -Dpipewire-jack=disabled -Dpw-cat=enabled -Dpipewire-v4l2=disabled -Dsdl2=enabled -Dsystemd=disabled -Dsession-managers=media-session ..
6
+    - meson setup -Dalsa=enabled -Draop=enabled -Dv4l2=enabled -Dpipewire-alsa=enabled -Dbluez5=disabled -Djack=disabled -Dpipewire-jack=enabled -Dpw-cat=enabled -Dpipewire-v4l2=disabled -Dsdl2=enabled -Dsystemd=disabled -Dsession-managers=media-session ..
7
     - ninja
8
   test_script:
9
     - cd build
10
pipewire-0.3.43.tar.gz/.gitlab-ci.yml -> pipewire-0.3.44.tar.gz/.gitlab-ci.yml Changed
32
 
1
@@ -8,8 +8,8 @@
2
 variables:
3
   FDO_UPSTREAM_REPO: 'pipewire/pipewire'
4
 
5
-# ci-templates as of March 19th 2021
6
-.templates_sha: &templates_sha 290b79e0e78eab67a83766f4e9691be554fc4afd
7
+# ci-templates as of Jan 27th 2022
8
+.templates_sha: &templates_sha 0c312d9c7255f46e741d43bcd1930f09cd12efe7
9
 
10
 include:
11
   - project: 'freedesktop/ci-templates'
12
@@ -22,8 +22,8 @@
13
 .fedora:
14
   variables:
15
     # Update this tag when you want to trigger a rebuild
16
-    FDO_DISTRIBUTION_TAG: '2021-10-12.1'
17
-    FDO_DISTRIBUTION_VERSION: '34'
18
+    FDO_DISTRIBUTION_TAG: '2022-01-27.1'
19
+    FDO_DISTRIBUTION_VERSION: '35'
20
     FDO_DISTRIBUTION_PACKAGES: >-
21
       alsa-lib-devel
22
       bluez-libs-devel
23
@@ -62,7 +62,7 @@
24
 .ubuntu:
25
   variables:
26
     # Update this tag when you want to trigger a rebuild
27
-    FDO_DISTRIBUTION_TAG: '2021-10-15.0'
28
+    FDO_DISTRIBUTION_TAG: '2022-01-27.0'
29
     FDO_DISTRIBUTION_VERSION: '20.04'
30
     FDO_DISTRIBUTION_PACKAGES: >-
31
       debhelper-compat
32
pipewire-0.3.43.tar.gz/NEWS -> pipewire-0.3.44.tar.gz/NEWS Changed
156
 
1
@@ -1,4 +1,142 @@
2
-# PipeWire 0.3.43 (2021-01-05)
3
+# PipeWire 0.3.44 (2022-01-27)
4
+
5
+This is a bugfix release that is API and ABI compatible with previous
6
+0.3.x releases.
7
+
8
+## Highlights
9
+  - It is now possible to run a minimal PipeWire server without a session
10
+    manager, enough to run JACK clients.
11
+  - The maximum buffer size is now configurable and can be larger than
12
+    the previously hardcoded limit of 8192 samples. When using high sample
13
+    rates, the larger buffer size can avoid xruns.
14
+  - The default maximum latency was reduced from 170ms to 42ms. This should
15
+    improve overall latency for application that ask for a large latency,
16
+    such as notifications.
17
+  - Better JACK compatibility. Patchbays should now get less confused about
18
+    ports appearing and disappearing.
19
+  - Fix some bluetooth crashes.
20
+  - Fix some races in ALSA device detection.
21
+  - Many bug fixes and improvements all over the place.
22
+
23
+## PipeWire
24
+  - Bump the meson requirement to 0.59.0.
25
+  - pw-top now reports correct times for filter-chain and loopback.
26
+  - max-quantum is now also scaled with the rate. A new quantum-limit
27
+    property was added as a hard limit for the quantum. This makes it
28
+    possible to configure for larger than 8192 buffer sizes. Note
29
+    than many JACK applications have a hardcoded 8192 limit. (#1931)
30
+  - The max-quantum was reduced to 2048, This gives a 42ms default
31
+    latency. (#1908)
32
+  - pw-filter can now return a NULL buffer from _get_dsp_buffer().
33
+  - Add a PIPEWIRE_RATE and PIPEWIRE_QUANTUM env variable to set the
34
+    graph rate and the graph quantum and rate respectively.
35
+  - Fix a potential file descriptor leak in the connection.
36
+  - A new minimal.conf file was added to demonstrate a static setup
37
+    of a daemon that doesn't require a session manager and is able to
38
+    run JACK applicaions.
39
+  - Nice levels are now only changed on the servers, not the clients.
40
+  - Add an option to suspend nodes when idle.
41
+  - Make it possible to avoid quantum and rate changes with
42
+    pw-metadata. This is essential in a locked down system.
43
+  - Handle mixer port errors better and fail to create the link instead
44
+    of silently not working.
45
+  - Nodes that are moved to a driver now have all the linked nodes moved
46
+    as well. This makes it possible to run some graphs without a
47
+    driver, such as paplay -> zita-j2n.
48
+  - pw-cli and pw-dump can now also list objects by name, serial and
49
+    object.path using glob style pattern matching.
50
+
51
+
52
+## modules
53
+  - filter-chain can now also configure parameters by index.
54
+  - Fix the client name of module-protocol-simple. (#2017)
55
+  - module-rtkit was merged into module-rt. This makes it easier to
56
+    ship a default config that works on more systems by default.
57
+  - module-adapter can now configure the adapter node from the config.
58
+    Previously, this was a task only performed by the session manager.
59
+  - module-metadata can now also create metadata object from the
60
+    config file.
61
+  - The ROC module should now work again. (#2045)
62
+  - An X11-bell module was added to handle X11 bell events. (#1668)
63
+  - filter-chain and loopback modules now have better unique default
64
+    names for the streams, which makes it possible to save and restore
65
+    their volumes independently. (#1983)
66
+  - module-echo-cancel now has properties to control the delay and
67
+    buffer size.
68
+
69
+## ALSA
70
+  - The monitor names are now correctly parsed.
71
+  - The default period size for batch devices is limited now to avoid
72
+    large latency.
73
+  - The unused min/max-latency properties were removed.
74
+  - Internal latency is now also configurable with params at runtime.
75
+  - The udev rule for TI2902 was removed because it causes problems.
76
+  - Fix a race where some devices would sometimes be missing. (#2046)
77
+  - Add some more timeouts to work around a race in udev device
78
+    permission changes when switching VTs.
79
+
80
+## SPA
81
+  - Fix potential infinite loop in audioconvert.
82
+  - The spa-resample tools can now also use optimized implementations.
83
+  - Fix a potential crash in resampler. (#1994)
84
+  - audioconvert can now also handle F64 formats. (#1990)
85
+  - The channelmixer now does normalization by default to avoid clipping
86
+    when downmixing is active.
87
+  - The channelmixer will now generate LFE channels when the lfe_cutoff
88
+    frequency is set, even when upmix is disabled.
89
+  - The channelmixer will now always generate FC when the target has it.
90
+  - Adapter now reports latency correctly, even after linking the monitor
91
+    ports.
92
+  - Reduce memory usage and preallocated memory in some of the
93
+    audioconvert nodes.
94
+  - Many properties are now exposed in adapter, such as the resample
95
+    quality.
96
+  - The resampler and channelmixer can now be disabled.
97
+
98
+## V4L2
99
+  - pw-v4l2 now also works for ffplay. (#2029)
100
+  - Take product names from udev now that the kernel returns a generic
101
+    name.
102
+
103
+## JACK
104
+  - The jack pkgconfig file now has the `jack_implementation=pipewire`
105
+    variable to be able to distinguish jack implementations. (#1666)
106
+  - jconvolver now starts correctly again. (#1989)
107
+  - The object.serial is now used for the port_id. This makes it easier
108
+    to track old objects in the cache.
109
+  - Add a dummy jacknet implementation. (#2043)
110
+  - A bug in the port allocation was fixed that would make it impossible
111
+    to allocate ports at some point. (#1714)
112
+
113
+## Bluetooth
114
+  - Bluetooth profiles are now saved properly by the session manager.
115
+  - Improved profile detections, increased timeouts for slow devices.
116
+  - Implement HFP call indicator for improved compatibility.
117
+  - Handle the case where bluez does not set the adapter or address
118
+    properties on the device instead of crashing.
119
+  - Improved support for setting the profile from the session manager.
120
+
121
+## pulse-server
122
+  - Monitor sources now have the device.class=monitor for better
123
+    compatibility.
124
+  - Behaviour after seeking is improved. The algorithm for requesting
125
+    bytes from the client was simplified and improved. (#1981)
126
+  - module-ladspa-sink implements the control argument now. (#1987)
127
+  - A potential memory leak in the message queue was fixed. (#1840)
128
+  - Use the object.serial for the pulseaudio object index. The index is
129
+    not supposed to be reused and this would cause problems with some
130
+    clients.
131
+  - Servers should now again be able to listen in IPv4. (#2047)
132
+  - module-x11-bell was added. (#1668)
133
+  - There is now support for per-application quirks and properties in
134
+    the pipewire-pulse.conf file. Per-application latency and buffering
135
+    properties can also be configured.
136
+  - Fix a regression in telegram sounds not playing.
137
+
138
+
139
+Older versions:
140
+
141
+# PipeWire 0.3.43 (2022-01-05)
142
 
143
 This is a bugfix release that is API and ABI compatible with previous
144
 0.3.x releases.
145
@@ -81,10 +219,6 @@
146
   - Add command access control. This avoids execution of commands without
147
     proper authentication.
148
 
149
-
150
-Older versions:
151
-
152
-
153
 # PipeWire 0.3.42 (2021-12-16)
154
 
155
 This is a bugfix release that is API and ABI compatible with previous
156
pipewire-0.3.43.tar.gz/README.md -> pipewire-0.3.44.tar.gz/README.md Changed
15
 
1
@@ -48,6 +48,13 @@
2
                   expressed as a fraction of the samplerate,
3
                   like 256/48000, which uses 256 samples at a
4
                   samplerate of 48KHz for a latency of 5.33ms.
5
+                  This function does not attempt to configure
6
+                  the samplerate.
7
+* `PIPEWIRE_RATE=<num/denom>`      to configure a rate for the graph.
8
+* `PIPEWIRE_QUANTUM=<num/denom>`   to configure latency as a fraction and a
9
+                  samplerate. This function will attempt to change
10
+                  the graph samplerate to `denom` and use the
11
+                  specified `num` as the buffer size.
12
 * `PIPEWIRE_NODE=<id>`             to request a link to the specified node
13
 
14
 ### Using tools
15
pipewire-0.3.44.tar.gz/doc/manpage.dox.in Added
7
 
1
@@ -0,0 +1,5 @@
2
+/** \page @pagename@ @title@
3
+
4
+\verbinclude @filename@
5
+
6
+*/
7
pipewire-0.3.43.tar.gz/doc/meson.build -> pipewire-0.3.44.tar.gz/doc/meson.build Changed
49
 
1
@@ -26,7 +26,6 @@
2
   'pipewire-daemon.dox',
3
   'pipewire-library.dox',
4
   'pipewire-modules.dox',
5
-  'pipewire-tools.dox',
6
   'pipewire-session-manager.dox',
7
   'pipewire-objects-design.dox',
8
   'pipewire-audio.dox',
9
@@ -115,6 +114,30 @@
10
 
11
 input_dirs += [ 'doc/examples.dox' ]
12
 
13
+man_doxygen = []
14
+man_subpages = []
15
+foreach m : manpages
16
+  manconf = configuration_data()
17
+  pagename = 'page_man_' + m.split('.rst.in').get(0).replace('.', '_').replace('-', '_')
18
+  filename = m.split('.rst.in').get(0) + '.dox'
19
+  manconf.set('pagename', pagename)
20
+  manconf.set('title', m.split('.rst.in').get(0).replace('.1','').replace('.5',''))
21
+  manconf.set('filename', meson.project_source_root() / 'man' / m)
22
+  manfile = configure_file(input: 'manpage.dox.in',
23
+                           output: filename,
24
+                           configuration: manconf)
25
+  man_doxygen += [manfile]
26
+  man_subpages += ['- \subpage ' + pagename]
27
+  input_dirs += [ 'doc/' + filename ]
28
+endforeach
29
+
30
+pw_tools_dox_conf = configuration_data()
31
+pw_tools_dox_conf.set('man_subpages', '\n'.join(man_subpages))
32
+pw_tools_dox = configure_file(input: 'pipewire-tools.dox.in',
33
+                          output: 'pipewire-tools.dox',
34
+                          configuration: pw_tools_dox_conf)
35
+input_dirs += [ 'doc/pipewire-tools.dox' ]
36
+
37
 doxyfile_conf.set('inputs', ' '.join(inputs + input_dirs))
38
 doxyfile_conf.set('cssfiles', ' '.join(cssfiles))
39
 doxyfile_conf.set('path_prefixes', ' '.join(path_prefixes))
40
@@ -131,7 +154,7 @@
41
 endif
42
 
43
 html_target = custom_target('pipewire-docs',
44
-                            input: [ doxyfile, examples_dox ] + inputs + cssfiles,
45
+                            input: [ doxyfile, examples_dox, pw_tools_dox ] + inputs + cssfiles + man_doxygen,
46
                             output: [ 'html' ],
47
                             command: [ doxygen, doxyfile ],
48
                             install: true,
49
pipewire-0.3.43.tar.gz/doc/pipewire-modules.dox -> pipewire-0.3.44.tar.gz/doc/pipewire-modules.dox Changed
11
 
1
@@ -74,8 +74,8 @@
2
 - \subpage page_module_roc_sink
3
 - \subpage page_module_roc_source
4
 - \subpage page_module_rt
5
-- \subpage page_module_rtkit
6
 - \subpage page_module_session_manager
7
+- \subpage page_module_x11_bell
8
 - \subpage page_module_zeroconf_discover
9
 
10
 
11
pipewire-0.3.44.tar.gz/doc/pipewire-tools.dox.in Added
9
 
1
@@ -0,0 +1,7 @@
2
+/** \page page_tools PipeWire Tools
3
+
4
+Manual pages:
5
+
6
+@man_subpages@
7
+
8
+*/
9
pipewire-0.3.43.tar.gz/man/meson.build -> pipewire-0.3.44.tar.gz/man/meson.build Changed
12
 
1
@@ -23,6 +23,10 @@
2
   manpages += 'pw-jack.1.rst.in'
3
 endif
4
 
5
+if not generate_manpages
6
+  subdir_done()
7
+endif
8
+
9
 foreach m : manpages
10
   file = m.split('.rst.in').get(0)
11
   rst = configure_file(input : m,
12
pipewire-0.3.43.tar.gz/man/pipewire-pulse.1.rst.in -> pipewire-0.3.44.tar.gz/man/pipewire-pulse.1.rst.in Changed
7
 
1
@@ -1,5 +1,3 @@
2
-.. This file is part of PipeWire.
3
-
4
 pipewire-pulse
5
 ##############
6
 
7
pipewire-0.3.43.tar.gz/man/pipewire.1.rst.in -> pipewire-0.3.44.tar.gz/man/pipewire.1.rst.in Changed
7
 
1
@@ -1,5 +1,3 @@
2
-.. This file is part of PipeWire.
3
-
4
 pipewire
5
 ########
6
 
7
pipewire-0.3.43.tar.gz/man/pipewire.conf.5.rst.in -> pipewire-0.3.44.tar.gz/man/pipewire.conf.5.rst.in Changed
7
 
1
@@ -1,5 +1,3 @@
2
-.. This file is part of PipeWire.
3
-
4
 pipewire.conf
5
 #############
6
 
7
pipewire-0.3.43.tar.gz/man/pw-cat.1.rst.in -> pipewire-0.3.44.tar.gz/man/pw-cat.1.rst.in Changed
27
 
1
@@ -1,5 +1,3 @@
2
-.. This file is part of PipeWire.
3
-
4
 pw-cat
5
 ######
6
 
7
@@ -44,13 +42,16 @@
8
   a connection is made to the default PipeWire instance.
9
 
10
 -p | --playback
11
-  Playback mode. Read data from the specified file, and play it back. If the tool is called under the name **pw-play** or **pw-midiplay** this is the default.
12
+  Playback mode. Read data from the specified file, and play it back. If the tool
13
+  is called under the name **pw-play** or **pw-midiplay** this is the default.
14
 
15
 -r | --record
16
-  Recording mode. Capture data and write it to the specified file. If the tool is called under the name **pw-record** or **pw-midirecord** this is the default.
17
+  Recording mode. Capture data and write it to the specified file. If the tool is
18
+  called under the name **pw-record** or **pw-midirecord** this is the default.
19
 
20
 -m | --midi
21
-  MIDI mode. *FILE* is a MIDI file. If the tool is called under the name **pw-midiplay** or **pw-midirecord** this is the default.
22
+  MIDI mode. *FILE* is a MIDI file. If the tool is called under the name
23
+  **pw-midiplay** or **pw-midirecord** this is the default.
24
 
25
 --media-type=VALUE
26
   Set the media type property (default Audio/Midi depending on mode).
27
pipewire-0.3.43.tar.gz/man/pw-cli.1.rst.in -> pipewire-0.3.44.tar.gz/man/pw-cli.1.rst.in Changed
17
 
1
@@ -1,5 +1,3 @@
2
-.. This file is part of PipeWire.
3
-
4
 pw-cli
5
 ######
6
 
7
@@ -45,7 +43,8 @@
8
 MODULE MANAGEMENT
9
 =================
10
 
11
-| Modules are loaded and unloaded in the local instance and can add functionality or objects to the local instance.
12
+| Modules are loaded and unloaded in the local instance and can add
13
+| functionality or objects to the local instance.
14
 
15
 load-module *name* [*arguments...*]
16
   Load a module specified by its name and arguments. For most
17
pipewire-0.3.43.tar.gz/man/pw-dot.1.rst.in -> pipewire-0.3.44.tar.gz/man/pw-dot.1.rst.in Changed
7
 
1
@@ -1,5 +1,3 @@
2
-.. This file is part of PipeWire.
3
-
4
 pw-dot
5
 ######
6
 
7
pipewire-0.3.43.tar.gz/man/pw-jack.1.rst.in -> pipewire-0.3.44.tar.gz/man/pw-jack.1.rst.in Changed
7
 
1
@@ -1,5 +1,3 @@
2
-.. This file is part of PipeWire.
3
-
4
 pw-jack
5
 #######
6
 
7
pipewire-0.3.43.tar.gz/man/pw-metadata.1.rst.in -> pipewire-0.3.44.tar.gz/man/pw-metadata.1.rst.in Changed
7
 
1
@@ -1,5 +1,3 @@
2
-.. This file is part of PipeWire.
3
-
4
 pw-metadata
5
 ###########
6
 
7
pipewire-0.3.43.tar.gz/man/pw-mididump.1.rst.in -> pipewire-0.3.44.tar.gz/man/pw-mididump.1.rst.in Changed
7
 
1
@@ -1,5 +1,3 @@
2
-.. This file is part of PipeWire.
3
-
4
 pw-mididump
5
 ###########
6
 
7
pipewire-0.3.43.tar.gz/man/pw-mon.1.rst.in -> pipewire-0.3.44.tar.gz/man/pw-mon.1.rst.in Changed
7
 
1
@@ -1,5 +1,3 @@
2
-.. This file is part of PipeWire.
3
-
4
 pw-mon
5
 ######
6
 
7
pipewire-0.3.43.tar.gz/man/pw-profiler.1.rst.in -> pipewire-0.3.44.tar.gz/man/pw-profiler.1.rst.in Changed
7
 
1
@@ -1,5 +1,3 @@
2
-.. This file is part of PipeWire.
3
-
4
 pw-profiler
5
 ###########
6
 
7
pipewire-0.3.43.tar.gz/meson.build -> pipewire-0.3.44.tar.gz/meson.build Changed
116
 
1
@@ -1,7 +1,7 @@
2
 project('pipewire', ['c' ],
3
-  version : '0.3.43',
4
+  version : '0.3.44',
5
   license : [ 'MIT', 'LGPL-2.1-or-later', 'GPL-2.0-only' ],
6
-  meson_version : '>= 0.56.0',
7
+  meson_version : '>= 0.59.0',
8
   default_options : [ 'warning_level=3',
9
                       'c_std=gnu99',
10
                       'cpp_std=c++17',
11
@@ -323,12 +323,12 @@
12
 dl_lib = cc.find_library('dl', required : false)
13
 pthread_lib = dependency('threads')
14
 dbus_dep = dependency('dbus-1', required : get_option('dbus'))
15
-summary({'dbus (Bluetooth, rtkit, portal, pw-reserve)': dbus_dep.found()}, bool_yn: true, section: 'Misc dependencies')
16
+summary({'dbus (Bluetooth, rt, portal, pw-reserve)': dbus_dep.found()}, bool_yn: true, section: 'Misc dependencies')
17
 if dbus_dep.found()
18
   cdata.set('HAVE_DBUS', 1)
19
 endif
20
 sdl_dep = dependency('sdl2', required : get_option('sdl2'))
21
-summary({'SDL 2': sdl_dep.found()}, bool_yn: true, section: 'Misc dependencies')
22
+summary({'SDL2 (video examples)': sdl_dep.found()}, bool_yn: true, section: 'Misc dependencies')
23
 drm_dep = dependency('libdrm', required : false)
24
 readline_dep = dependency('readline', required : false)
25
 
26
@@ -349,6 +349,14 @@
27
 summary({'Avahi DNS-SD (Zeroconf)': avahi_dep.found()}, bool_yn: true,
28
   section: 'Streaming between daemons')
29
 
30
+x11_dep = dependency('x11-xcb', required : get_option('x11'))
31
+summary({'X11 (x11-bell)': x11_dep.found()}, bool_yn: true,
32
+  section: 'Misc dependencies')
33
+
34
+canberra_dep = dependency('libcanberra', required : get_option('libcanberra'))
35
+summary({'libcanberra (x11-bell)': canberra_dep.found()}, bool_yn: true,
36
+  section: 'Misc dependencies')
37
+
38
 libusb_dep = dependency('libusb-1.0', required : get_option('libusb'))
39
 summary({'libusb (Bluetooth quirks)': libusb_dep.found()}, bool_yn: true, section: 'Backend')
40
 if libusb_dep.found()
41
@@ -479,22 +487,25 @@
42
   subdir('pipewire-alsa/tests')
43
 endif
44
 
45
-doxygen = find_program('doxygen', required : get_option('docs'))
46
-if doxygen.found()
47
-  subdir('doc')
48
-endif
49
-
50
+generate_manpages = false
51
 if not get_option('man').disabled()
52
   rst2man = find_program('rst2man', required: false)
53
   if not rst2man.found()
54
     rst2man = find_program('rst2man.py', required: get_option('man'))
55
   endif
56
-  summary({'Manpage generation': rst2man.found()}, bool_yn: true)
57
   if rst2man.found()
58
-    subdir('man')
59
+    generate_manpages = true
60
   endif
61
 endif
62
 
63
+summary({'Manpage generation': generate_manpages}, bool_yn: true)
64
+subdir('man')
65
+
66
+doxygen = find_program('doxygen', required : get_option('docs'))
67
+if doxygen.found()
68
+  subdir('doc')
69
+endif
70
+
71
 setenv = find_program('pw-uninstalled.sh')
72
 run_target('pw-uninstalled',
73
   command : [setenv,
74
@@ -502,27 +513,25 @@
75
              '-v@0@'.format(pipewire_version)]
76
 )
77
 
78
-if meson.version().version_compare('>=0.58.0')
79
-  devenv = environment()
80
+devenv = environment()
81
 
82
-  builddir = meson.project_build_root()
83
-  srcdir = meson.project_source_root()
84
+builddir = meson.project_build_root()
85
+srcdir = meson.project_source_root()
86
 
87
-  devenv.set('PIPEWIRE_CONFIG_DIR', pipewire_dep.get_variable(internal: 'confdatadir'))
88
-  devenv.set('PIPEWIRE_MODULE_DIR', pipewire_dep.get_variable(internal: 'moduledir'))
89
+devenv.set('PIPEWIRE_CONFIG_DIR', pipewire_dep.get_variable('confdatadir'))
90
+devenv.set('PIPEWIRE_MODULE_DIR', pipewire_dep.get_variable('moduledir'))
91
 
92
-  devenv.set('SPA_PLUGIN_DIR', spa_dep.get_variable(internal: 'plugindir'))
93
-  devenv.set('SPA_DATA_DIR', spa_dep.get_variable(internal: 'datadir'))
94
+devenv.set('SPA_PLUGIN_DIR', spa_dep.get_variable('plugindir'))
95
+devenv.set('SPA_DATA_DIR', spa_dep.get_variable('datadir'))
96
 
97
-  devenv.set('GST_PLUGIN_PATH', builddir / 'src'/ 'gst')
98
+devenv.set('GST_PLUGIN_PATH', builddir / 'src'/ 'gst')
99
 
100
-  devenv.set('ALSA_PLUGIN_DIR', builddir / 'pipewire-alsa' / 'alsa-plugins')
101
-  devenv.set('ACP_PATHS_DIR', srcdir / 'spa' / 'plugins' / 'alsa' / 'mixer' / 'paths')
102
-  devenv.set('ACP_PROFILES_DIR', srcdir / 'spa' / 'plugins' / 'alsa' / 'mixer' / 'profile-sets')
103
+devenv.set('ALSA_PLUGIN_DIR', builddir / 'pipewire-alsa' / 'alsa-plugins')
104
+devenv.set('ACP_PATHS_DIR', srcdir / 'spa' / 'plugins' / 'alsa' / 'mixer' / 'paths')
105
+devenv.set('ACP_PROFILES_DIR', srcdir / 'spa' / 'plugins' / 'alsa' / 'mixer' / 'profile-sets')
106
 
107
-  devenv.set('LD_LIBRARY_PATH', builddir / 'pipewire-jack' / 'src')
108
+devenv.set('LD_LIBRARY_PATH', builddir / 'pipewire-jack' / 'src')
109
 
110
-  devenv.set('PW_UNINSTALLED', '1')
111
+devenv.set('PW_UNINSTALLED', '1')
112
 
113
-  meson.add_devenv(devenv)
114
-endif
115
+meson.add_devenv(devenv)
116
pipewire-0.3.43.tar.gz/meson_options.txt -> pipewire-0.3.44.tar.gz/meson_options.txt Changed
23
 
1
@@ -179,6 +179,9 @@
2
 option('udevrulesdir',
3
        type : 'string',
4
        description : 'Directory for udev rules (defaults to /lib/udev/rules.d)')
5
+option('systemd-system-unit-dir',
6
+       type : 'string',
7
+       description : 'Directory for system systemd units (defaults to /usr/lib/systemd/system)')
8
 option('systemd-user-unit-dir',
9
        type : 'string',
10
        description : 'Directory for user systemd units (defaults to /usr/lib/systemd/user)')
11
@@ -222,3 +225,11 @@
12
        description: 'Enable loading of LV2 plugins',
13
        type: 'feature',
14
        value: 'auto')
15
+option('x11',
16
+       description: 'Enable code that depends on X11',
17
+       type: 'feature',
18
+       value: 'auto')
19
+option('libcanberra',
20
+       description: 'Enable code that depends on libcanberra',
21
+       type: 'feature',
22
+       value: 'auto')
23
pipewire-0.3.43.tar.gz/pipewire-jack/src/meson.build -> pipewire-0.3.44.tar.gz/pipewire-jack/src/meson.build Changed
34
 
1
@@ -11,10 +11,9 @@
2
   'control.c',
3
 ]
4
 
5
-pipewire_dummy_sources = [
6
-  'dummy.c',
7
+pipewire_net_sources = [
8
+  'net.c',
9
 ]
10
-
11
 pipewire_jack_c_args = [
12
   '-DPIC',
13
 ]
14
@@ -57,8 +56,8 @@
15
     install_dir : libjack_path,
16
 )
17
 
18
-pipewire_jackserver = shared_library('jacknet',
19
-    pipewire_dummy_sources,
20
+pipewire_jacknet = shared_library('jacknet',
21
+    pipewire_net_sources,
22
     soversion : soversion,
23
     version : libversion,
24
     c_args : pipewire_jack_c_args,
25
@@ -85,7 +84,7 @@
26
   description : 'PipeWire JACK API',
27
   version : '1.9.17',
28
   extra_cflags : '-D_REENTRANT',
29
-  unescaped_variables: ['server_libs=-L${libdir} -ljackserver'])
30
+  unescaped_variables: ['server_libs=-L${libdir} -ljackserver', 'jack_implementation=pipewire'])
31
 endif
32
 
33
 if sdl_dep.found()
34
pipewire-0.3.43.tar.gz/pipewire-jack/src/metadata.c -> pipewire-0.3.44.tar.gz/pipewire-jack/src/metadata.c Changed
31
 
1
@@ -213,7 +213,8 @@
2
              const char* type)
3
 {
4
    struct client *c = (struct client *) client;
5
-   uint32_t id;
6
+   struct object *o;
7
+   uint32_t serial;
8
    int res = -1;
9
 
10
    spa_return_val_if_fail(c != NULL, -EINVAL);
11
@@ -227,14 +228,16 @@
12
    if (subject & (1<<30))
13
        goto done;
14
 
15
-   id = jack_uuid_to_index(subject);
16
+   serial = jack_uuid_to_index(subject);
17
+   if ((o = find_by_serial(c, serial)) == NULL)
18
+       goto done;
19
 
20
    if (type == NULL)
21
        type = "";
22
 
23
-   pw_log_info("set id:%u (%"PRIu64") '%s' to '%s@%s'", id, subject, key, value, type);
24
+   pw_log_info("set id:%u (%"PRIu64") '%s' to '%s@%s'", o->id, subject, key, value, type);
25
    if (update_property(c, subject, key, type, value))
26
-       pw_metadata_set_property(c->metadata->proxy, id, key, type, value);
27
+       pw_metadata_set_property(c->metadata->proxy, o->id, key, type, value);
28
    res = 0;
29
 done:
30
    pw_thread_loop_unlock(c->context.loop);
31
pipewire-0.3.44.tar.gz/pipewire-jack/src/net.c Added
171
 
1
@@ -0,0 +1,169 @@
2
+/* PipeWire
3
+ *
4
+ * Copyright © 2022 Wim Taymans
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a
7
+ * copy of this software and associated documentation files (the "Software"),
8
+ * to deal in the Software without restriction, including without limitation
9
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
+ * and/or sell copies of the Software, and to permit persons to whom the
11
+ * Software is furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice (including the next
14
+ * paragraph) shall be included in all copies or substantial portions of the
15
+ * Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23
+ * DEALINGS IN THE SOFTWARE.
24
+ */
25
+
26
+#include "config.h"
27
+
28
+#include <stdio.h>
29
+#include <unistd.h>
30
+#include <errno.h>
31
+
32
+#include <jack/net.h>
33
+
34
+#include <pipewire/pipewire.h>
35
+
36
+SPA_EXPORT
37
+jack_net_slave_t* jack_net_slave_open(const char* ip, int port, const char* name,
38
+       jack_slave_t* request, jack_master_t* result)
39
+{
40
+   return NULL;
41
+}
42
+
43
+SPA_EXPORT
44
+int jack_net_slave_close(jack_net_slave_t* net)
45
+{
46
+   return ENOTSUP;
47
+}
48
+
49
+SPA_EXPORT
50
+int jack_set_net_slave_process_callback(jack_net_slave_t * net, JackNetSlaveProcessCallback net_callback, void *arg)
51
+{
52
+   return ENOTSUP;
53
+}
54
+
55
+SPA_EXPORT
56
+int jack_net_slave_activate(jack_net_slave_t* net)
57
+{
58
+   return ENOTSUP;
59
+}
60
+
61
+SPA_EXPORT
62
+int jack_net_slave_deactivate(jack_net_slave_t* net)
63
+{
64
+   return ENOTSUP;
65
+}
66
+
67
+SPA_EXPORT
68
+int jack_net_slave_is_active(jack_net_slave_t* net)
69
+{
70
+   return false;
71
+}
72
+
73
+SPA_EXPORT
74
+int jack_set_net_slave_buffer_size_callback(jack_net_slave_t *net, JackNetSlaveBufferSizeCallback bufsize_callback, void *arg)
75
+{
76
+   return ENOTSUP;
77
+}
78
+
79
+SPA_EXPORT
80
+int jack_set_net_slave_sample_rate_callback(jack_net_slave_t *net, JackNetSlaveSampleRateCallback samplerate_callback, void *arg)
81
+{
82
+   return ENOTSUP;
83
+}
84
+
85
+SPA_EXPORT
86
+int jack_set_net_slave_shutdown_callback(jack_net_slave_t *net, JackNetSlaveShutdownCallback shutdown_callback, void *arg)
87
+{
88
+   return ENOTSUP;
89
+}
90
+
91
+SPA_EXPORT
92
+int jack_set_net_slave_restart_callback(jack_net_slave_t *net, JackNetSlaveRestartCallback restart_callback, void *arg)
93
+{
94
+   return ENOTSUP;
95
+}
96
+
97
+SPA_EXPORT
98
+int jack_set_net_slave_error_callback(jack_net_slave_t *net, JackNetSlaveErrorCallback error_callback, void *arg)
99
+{
100
+   return ENOTSUP;
101
+}
102
+
103
+SPA_EXPORT
104
+jack_net_master_t* jack_net_master_open(const char* ip, int port, jack_master_t* request, jack_slave_t* result)
105
+{
106
+   return NULL;
107
+}
108
+
109
+SPA_EXPORT
110
+int jack_net_master_close(jack_net_master_t* net)
111
+{
112
+   return ENOTSUP;
113
+}
114
+
115
+SPA_EXPORT
116
+int jack_net_master_recv(jack_net_master_t* net, int audio_input, float** audio_input_buffer, int midi_input, void** midi_input_buffer)
117
+{
118
+   return ENOTSUP;
119
+}
120
+
121
+SPA_EXPORT
122
+int jack_net_master_recv_slice(jack_net_master_t* net, int audio_input, float** audio_input_buffer, int midi_input, void** midi_input_buffer, int frames)
123
+{
124
+   return ENOTSUP;
125
+}
126
+
127
+SPA_EXPORT
128
+int jack_net_master_send(jack_net_master_t* net, int audio_output, float** audio_output_buffer, int midi_output, void** midi_output_buffer)
129
+{
130
+   return ENOTSUP;
131
+}
132
+
133
+SPA_EXPORT
134
+int jack_net_master_send_slice(jack_net_master_t* net, int audio_output, float** audio_output_buffer, int midi_output, void** midi_output_buffer, int frames)
135
+{
136
+   return ENOTSUP;
137
+}
138
+
139
+SPA_EXPORT
140
+jack_adapter_t* jack_create_adapter(int input, int output,
141
+                                    jack_nframes_t host_buffer_size,
142
+                                    jack_nframes_t host_sample_rate,
143
+                                    jack_nframes_t adapted_buffer_size,
144
+                                    jack_nframes_t adapted_sample_rate)
145
+{
146
+   return NULL;
147
+}
148
+
149
+SPA_EXPORT
150
+int jack_destroy_adapter(jack_adapter_t* adapter)
151
+{
152
+   return ENOTSUP;
153
+}
154
+
155
+SPA_EXPORT
156
+void jack_flush_adapter(jack_adapter_t* adapter)
157
+{
158
+}
159
+
160
+SPA_EXPORT
161
+int jack_adapter_push_and_pull(jack_adapter_t* adapter, float** input, float** output, unsigned int frames)
162
+{
163
+   return ENOTSUP;
164
+}
165
+
166
+SPA_EXPORT
167
+int jack_adapter_pull_and_push(jack_adapter_t* adapter, float** input, float** output, unsigned int frames)
168
+{
169
+   return ENOTSUP;
170
+}
171
pipewire-0.3.43.tar.gz/pipewire-jack/src/pipewire-jack.c -> pipewire-0.3.44.tar.gz/pipewire-jack/src/pipewire-jack.c Changed
1238
 
1
@@ -99,14 +99,14 @@
2
    jack_thread_creator_t creator;
3
    pthread_mutex_t lock;
4
    struct pw_array descriptions;
5
-   struct spa_list free_objects[3];
6
-   struct pw_map cache;
7
+   struct spa_list free_objects;
8
 };
9
 
10
 static struct globals globals;
11
 static bool mlock_warned = false;
12
 
13
-#define OBJECT_CHUNK   8
14
+#define OBJECT_CHUNK       8
15
+#define RECYCLE_THRESHOLD  128
16
 
17
 typedef void (*mix2_func) (float *dst, float *src1, float *src2, int n_samples);
18
 
19
@@ -122,7 +122,7 @@
20
 #define INTERFACE_Link     2
21
    uint32_t type;
22
    uint32_t id;
23
-   uint32_t idx;
24
+   uint32_t serial;
25
 
26
    union {
27
        struct {
28
@@ -134,11 +134,11 @@
29
        struct {
30
            uint32_t src;
31
            uint32_t dst;
32
+           uint32_t src_serial;
33
+           uint32_t dst_serial;
34
            bool src_ours;
35
            bool dst_ours;
36
            bool is_complete;
37
-           uint32_t src_idx;
38
-           uint32_t dst_idx;
39
            struct port *our_input;
40
            struct port *our_output;
41
        } port_link;
42
@@ -151,7 +151,6 @@
43
            uint32_t system_id;
44
            uint32_t type_id;
45
            uint32_t node_id;
46
-           uint32_t port_id;
47
            uint32_t monitor_requests;
48
            int32_t priority;
49
            struct port *port;
50
@@ -164,6 +163,7 @@
51
    struct spa_hook proxy_listener;
52
    struct spa_hook object_listener;
53
    unsigned int removing:1;
54
+   unsigned int removed:1;
55
 };
56
 
57
 struct midi_buffer {
58
@@ -223,7 +223,7 @@
59
    struct client *client;
60
 
61
    enum spa_direction direction;
62
-   uint32_t id;
63
+   uint32_t port_id;
64
    struct object *object;
65
    struct pw_properties *props;
66
    struct spa_port_info info;
67
@@ -264,15 +264,13 @@
68
    struct pw_context *context;
69
 
70
    pthread_mutex_t lock;       /* protects map and lists below, in addition to thread_lock */
71
-   struct pw_map globals;
72
-   struct spa_list ports;
73
-   struct spa_list nodes;
74
-   struct spa_list links;
75
+   struct spa_list objects;
76
+   uint32_t free_count;
77
 };
78
 
79
 #define GET_DIRECTION(f)   ((f) & JackPortIsInput ? SPA_DIRECTION_INPUT : SPA_DIRECTION_OUTPUT)
80
 
81
-#define GET_PORT(c,d,p)        ((d >= 0 && d <=1 && p < c->n_port_pool[d]) ? c->port_pool[d][p] : NULL)
82
+#define GET_PORT(c,d,p)        (pw_map_lookup(&c->ports[d], p))
83
 
84
 struct metadata {
85
    struct pw_metadata *proxy;
86
@@ -315,6 +313,7 @@
87
    struct metadata *metadata;
88
 
89
    uint32_t node_id;
90
+   uint32_t serial;
91
    struct spa_source *socket_source;
92
 
93
    JackThreadCallback thread_callback;
94
@@ -362,10 +361,8 @@
95
    struct spa_list mix;
96
    struct spa_list free_mix;
97
 
98
-   uint32_t n_port_pool[2];
99
-   struct port *port_pool[2][MAX_PORTS];
100
-   struct spa_list ports[2];
101
-   struct spa_list free_ports[2];
102
+   struct spa_list free_ports;
103
+   struct pw_map ports[2];
104
 
105
    struct spa_list links;
106
    uint32_t driver_id;
107
@@ -406,6 +403,7 @@
108
 };
109
 
110
 static int do_sync(struct client *client);
111
+static struct object *find_by_serial(struct client *c, uint32_t serial);
112
 
113
 #include "metadata.c"
114
 
115
@@ -413,64 +411,66 @@
116
        int (*matched) (void *data, const char *action, const char *val, int len),
117
        void *data);
118
 
119
-static void init_port_pool(struct client *c, enum spa_direction direction)
120
-{
121
-   spa_list_init(&c->ports[direction]);
122
-   spa_list_init(&c->free_ports[direction]);
123
-   c->n_port_pool[direction] = 0;
124
-}
125
-
126
-static struct object * find_cache(uint32_t type, uint32_t idx)
127
-{
128
-   struct object *o;
129
-   pthread_mutex_lock(&globals.lock);
130
-   o = pw_map_lookup(&globals.cache, idx);
131
-   if (o != NULL && o->type != type)
132
-       o = NULL;
133
-   pthread_mutex_unlock(&globals.lock);
134
-   return o;
135
-}
136
-
137
 static struct object * alloc_object(struct client *c, int type)
138
 {
139
    struct object *o;
140
    int i;
141
 
142
    pthread_mutex_lock(&globals.lock);
143
-   if (spa_list_is_empty(&globals.free_objects[type])) {
144
+   if (spa_list_is_empty(&globals.free_objects)) {
145
        o = calloc(OBJECT_CHUNK, sizeof(struct object));
146
        if (o == NULL) {
147
            pthread_mutex_unlock(&globals.lock);
148
            return NULL;
149
        }
150
-       for (i = 0; i < OBJECT_CHUNK; i++) {
151
-           o[i].idx = pw_map_insert_new(&globals.cache, &o[i]);
152
-           spa_list_append(&globals.free_objects[type], &o[i].link);
153
-       }
154
+       for (i = 0; i < OBJECT_CHUNK; i++)
155
+           spa_list_append(&globals.free_objects, &o[i].link);
156
    }
157
-   o = spa_list_first(&globals.free_objects[type], struct object, link);
158
+   o = spa_list_first(&globals.free_objects, struct object, link);
159
    spa_list_remove(&o->link);
160
    pthread_mutex_unlock(&globals.lock);
161
 
162
    o->client = c;
163
+   o->removed = false;
164
    o->type = type;
165
    pw_log_debug("%p: object:%p type:%d", c, o, type);
166
 
167
    return o;
168
 }
169
 
170
+static void recycle_objects(struct client *c, uint32_t remain)
171
+{
172
+   struct object *o, *t;
173
+   pthread_mutex_lock(&globals.lock);
174
+   spa_list_for_each_safe(o, t, &c->context.objects, link) {
175
+       if (o->removed) {
176
+           pw_log_info("%p: recycle object:%p type:%d id:%u/%u",
177
+                   c, o, o->type, o->id, o->serial);
178
+           spa_list_remove(&o->link);
179
+           memset(o, 0, sizeof(struct object));
180
+           spa_list_append(&globals.free_objects, &o->link);
181
+           if (--c->context.free_count == remain)
182
+               break;
183
+       }
184
+   }
185
+   pthread_mutex_unlock(&globals.lock);
186
+}
187
+
188
+/* JACK clients expect the objects to hang around after
189
+ * they are unregistered and freed. We mark the object removed and
190
+ * move it to the end of the queue. */
191
 static void free_object(struct client *c, struct object *o)
192
 {
193
+   pw_log_debug("%p: object:%p type:%d", c, o, o->type);
194
    pthread_mutex_lock(&c->context.lock);
195
    spa_list_remove(&o->link);
196
+   o->removed = true;
197
+   o->id = SPA_ID_INVALID;
198
+   spa_list_append(&c->context.objects, &o->link);
199
+   if (++c->context.free_count > RECYCLE_THRESHOLD)
200
+       recycle_objects(c, RECYCLE_THRESHOLD / 2);
201
    pthread_mutex_unlock(&c->context.lock);
202
 
203
-   pw_log_debug("%p: object:%p type:%d", c, o, o->type);
204
-
205
-   pthread_mutex_lock(&globals.lock);
206
-   spa_list_append(&globals.free_objects[o->type], &o->link);
207
-   o->client = NULL;
208
-   pthread_mutex_unlock(&globals.lock);
209
 }
210
 
211
 static void init_mix(struct mix *mix, uint32_t mix_id, struct port *port)
212
@@ -565,30 +565,21 @@
213
 {
214
    struct port *p;
215
    struct object *o;
216
-   uint32_t i, n;
217
+   uint32_t i;
218
 
219
-   if (spa_list_is_empty(&c->free_ports[direction])) {
220
+   if (spa_list_is_empty(&c->free_ports)) {
221
        p = calloc(OBJECT_CHUNK, sizeof(struct port));
222
        if (p == NULL)
223
            return NULL;
224
-       n = c->n_port_pool[direction];
225
-       for (i = 0; i < OBJECT_CHUNK; i++, n++) {
226
-           p[i].direction = direction;
227
-           p[i].id = n;
228
-           p[i].emptyptr = SPA_PTR_ALIGN(p[i].empty, MAX_ALIGN, float);
229
-           c->port_pool[direction][n] = &p[i];
230
-           spa_list_append(&c->free_ports[direction], &p[i].link);
231
-       }
232
-       c->n_port_pool[direction] = n;
233
-
234
+       for (i = 0; i < OBJECT_CHUNK; i++)
235
+           spa_list_append(&c->free_ports, &p[i].link);
236
    }
237
-   p = spa_list_first(&c->free_ports[direction], struct port, link);
238
+   p = spa_list_first(&c->free_ports, struct port, link);
239
    spa_list_remove(&p->link);
240
 
241
    o = alloc_object(c, INTERFACE_Port);
242
    o->id = SPA_ID_INVALID;
243
    o->port.node_id = c->node_id;
244
-   o->port.port_id = p->id;
245
    o->port.port = p;
246
    o->port.latency[SPA_DIRECTION_INPUT] = SPA_LATENCY_INFO(SPA_DIRECTION_INPUT);
247
    o->port.latency[SPA_DIRECTION_OUTPUT] = SPA_LATENCY_INFO(SPA_DIRECTION_OUTPUT);
248
@@ -600,10 +591,12 @@
249
    spa_list_init(&p->mix);
250
    p->props = pw_properties_new(NULL, NULL);
251
 
252
-   spa_list_append(&c->ports[direction], &p->link);
253
+   p->direction = direction;
254
+   p->emptyptr = SPA_PTR_ALIGN(p->empty, MAX_ALIGN, float);
255
+   p->port_id = pw_map_insert_new(&c->ports[direction], p);
256
 
257
    pthread_mutex_lock(&c->context.lock);
258
-   spa_list_append(&c->context.ports, &o->link);
259
+   spa_list_append(&c->context.objects, &o->link);
260
    pthread_mutex_unlock(&c->context.lock);
261
 
262
    return p;
263
@@ -619,19 +612,21 @@
264
    spa_list_consume(m, &p->mix, port_link)
265
        free_mix(c, m);
266
 
267
-   spa_list_remove(&p->link);
268
    p->valid = false;
269
+   pw_map_remove(&c->ports[p->direction], p->port_id);
270
    free_object(c, p->object);
271
    pw_properties_free(p->props);
272
-   spa_list_append(&c->free_ports[p->direction], &p->link);
273
+   spa_list_append(&c->free_ports, &p->link);
274
 }
275
 
276
 static struct object *find_node(struct client *c, const char *name)
277
 {
278
    struct object *o;
279
 
280
-   spa_list_for_each(o, &c->context.nodes, link) {
281
-       if (!o->removing && spa_streq(o->node.name, name))
282
+   spa_list_for_each(o, &c->context.objects, link) {
283
+       if (o->removing || o->removed || o->type != INTERFACE_Node)
284
+           continue;
285
+       if (spa_streq(o->node.name, name))
286
            return o;
287
    }
288
    return NULL;
289
@@ -652,11 +647,13 @@
290
    return false;
291
 }
292
 
293
-static struct object *find_port(struct client *c, const char *name)
294
+static struct object *find_port_by_name(struct client *c, const char *name)
295
 {
296
    struct object *o;
297
 
298
-   spa_list_for_each(o, &c->context.ports, link) {
299
+   spa_list_for_each(o, &c->context.objects, link) {
300
+       if (o->type != INTERFACE_Port || o->removed)
301
+           continue;
302
        if (spa_streq(o->port.name, name) ||
303
            spa_streq(o->port.alias1, name) ||
304
            spa_streq(o->port.alias2, name))
305
@@ -667,9 +664,29 @@
306
    return NULL;
307
 }
308
 
309
+static struct object *find_by_id(struct client *c, uint32_t id)
310
+{
311
+   struct object *o;
312
+   spa_list_for_each(o, &c->context.objects, link) {
313
+       if (o->id == id)
314
+           return o;
315
+   }
316
+   return NULL;
317
+}
318
+
319
+static struct object *find_by_serial(struct client *c, uint32_t serial)
320
+{
321
+   struct object *o;
322
+   spa_list_for_each(o, &c->context.objects, link) {
323
+       if (o->serial == serial)
324
+           return o;
325
+   }
326
+   return NULL;
327
+}
328
+
329
 static struct object *find_id(struct client *c, uint32_t id, bool valid)
330
 {
331
-   struct object *o = pw_map_lookup(&c->context.globals, id);
332
+   struct object *o = find_by_id(c, id);
333
    if (o != NULL && (!valid || o->client == c))
334
        return o;
335
    return NULL;
336
@@ -687,7 +704,9 @@
337
 {
338
    struct object *l;
339
 
340
-   spa_list_for_each(l, &c->context.links, link) {
341
+   spa_list_for_each(l, &c->context.objects, link) {
342
+       if (l->type != INTERFACE_Link || l->removed)
343
+           continue;
344
        if (l->port_link.src == src &&
345
            l->port_link.dst == dst) {
346
            return l;
347
@@ -1002,7 +1021,7 @@
348
        return NULL;
349
 
350
    pw_log_trace_fp("%p: port %s %d get buffer %d n_buffers:%d",
351
-           c, p->object->port.name, p->id, frames, mix->n_buffers);
352
+           c, p->object->port.name, p->port_id, frames, mix->n_buffers);
353
 
354
    if (SPA_UNLIKELY(mix->n_buffers == 0))
355
        return NULL;
356
@@ -1077,14 +1096,21 @@
357
 {
358
    struct port *p;
359
    struct mix *mix;
360
+   union pw_map_item *item;
361
 
362
-   spa_list_for_each(p, &c->ports[SPA_DIRECTION_INPUT], link) {
363
+   pw_array_for_each(item, &c->ports[SPA_DIRECTION_INPUT].items) {
364
+                if (pw_map_item_is_free(item))
365
+           continue;
366
+       p = item->data;
367
        spa_list_for_each(mix, &p->mix, port_link) {
368
            if (SPA_LIKELY(mix->io != NULL))
369
                mix->io->status = SPA_STATUS_NEED_DATA;
370
        }
371
-   }
372
-   spa_list_for_each(p, &c->ports[SPA_DIRECTION_OUTPUT], link) {
373
+        }
374
+   pw_array_for_each(item, &c->ports[SPA_DIRECTION_OUTPUT].items) {
375
+                if (pw_map_item_is_free(item))
376
+           continue;
377
+       p = item->data;
378
        prepare_output(p, frames);
379
        p->io.status = SPA_STATUS_NEED_DATA;
380
    }
381
@@ -1227,7 +1253,8 @@
382
 {
383
    uint32_t buffer_frames = *((uint32_t*)data);
384
    struct client *c = user_data;
385
-   do_callback_expr(c, c->buffer_frames = buffer_frames, bufsize_callback, buffer_frames, c->bufsize_arg);
386
+   if (c->buffer_frames != buffer_frames)
387
+       do_callback_expr(c, c->buffer_frames = buffer_frames, bufsize_callback, buffer_frames, c->bufsize_arg);
388
    recompute_latencies(c);
389
    return 0;
390
 }
391
@@ -1771,7 +1798,7 @@
392
            SPA_PARAM_BUFFERS_size,    SPA_POD_CHOICE_STEP_Int(
393
                                MAX_BUFFER_FRAMES * sizeof(float),
394
                                sizeof(float),
395
-                               MAX_BUFFER_FRAMES * sizeof(float),
396
+                               INT32_MAX,
397
                                sizeof(float)),
398
            SPA_PARAM_BUFFERS_stride,  SPA_POD_Int(p->object->port.type_id == TYPE_ID_AUDIO ?
399
                                    sizeof(float) : 1));
400
@@ -1889,7 +1916,7 @@
401
 
402
    pw_client_node_port_update(c->node,
403
                     p->direction,
404
-                    p->id,
405
+                    p->port_id,
406
                     PW_CLIENT_NODE_PORT_UPDATE_PARAMS |
407
                     PW_CLIENT_NODE_PORT_UPDATE_INFO,
408
                     SPA_N_ELEMENTS(params),
409
@@ -1921,7 +1948,7 @@
410
 
411
    pw_client_node_port_update(c->node,
412
                     p->direction,
413
-                    p->id,
414
+                    p->port_id,
415
                     PW_CLIENT_NODE_PORT_UPDATE_PARAMS |
416
                     PW_CLIENT_NODE_PORT_UPDATE_INFO,
417
                     SPA_N_ELEMENTS(params),
418
@@ -1935,14 +1962,19 @@
419
        struct spa_latency_info *latency)
420
 {
421
    enum spa_direction other;
422
+   union pw_map_item *item;
423
    struct port *p;
424
 
425
    other = SPA_DIRECTION_REVERSE(direction);
426
 
427
    spa_latency_info_combine_start(latency, direction);
428
 
429
-   spa_list_for_each(p, &c->ports[other], link)
430
+   pw_array_for_each(item, &c->ports[other].items) {
431
+                if (pw_map_item_is_free(item))
432
+           continue;
433
+       p = item->data;
434
        spa_latency_info_combine(latency, &p->object->port.latency[direction]);
435
+   }
436
 
437
    spa_latency_info_combine_finish(latency);
438
 }
439
@@ -1952,6 +1984,7 @@
440
 {
441
    struct spa_latency_info latency, *current;
442
    enum spa_direction direction;
443
+   union pw_map_item *item;
444
    struct port *p;
445
 
446
    if (mode == JackPlaybackLatency)
447
@@ -1967,7 +2000,10 @@
448
            latency.min_rate, latency.max_rate,
449
            latency.min_ns, latency.max_ns);
450
 
451
-   spa_list_for_each(p, &c->ports[direction], link) {
452
+   pw_array_for_each(item, &c->ports[direction].items) {
453
+                if (pw_map_item_is_free(item))
454
+           continue;
455
+       p = item->data;
456
        current = &p->object->port.latency[direction];
457
        if (spa_latency_info_compare(current, &latency) == 0)
458
            continue;
459
@@ -2407,11 +2443,11 @@
460
 
461
        if (!l->port_link.is_complete) {
462
            l->port_link.is_complete = true;
463
-           pw_log_info("%p: our link %d/%u -> %d/%u completed", c,
464
-                   l->port_link.src, l->port_link.src_idx,
465
-                   l->port_link.dst, l->port_link.dst_idx);
466
+           pw_log_info("%p: our link %u/%u -> %u/%u completed", c,
467
+                   l->port_link.src, l->port_link.src_serial,
468
+                   l->port_link.dst, l->port_link.dst_serial);
469
            do_callback(c, connect_callback,
470
-                   l->port_link.src_idx, l->port_link.dst_idx, 1, c->connect_arg);
471
+                   l->port_link.src_serial, l->port_link.dst_serial, 1, c->connect_arg);
472
            recompute_latencies(c);
473
            do_callback(c, graph_callback, c->graph_arg);
474
        }
475
@@ -2538,10 +2574,10 @@
476
 
477
        switch (o->type) {
478
        case INTERFACE_Node:
479
-           uuid = client_make_uuid(id, false);
480
+           uuid = client_make_uuid(o->serial, false);
481
            break;
482
        case INTERFACE_Port:
483
-           uuid = jack_port_uuid_generate(id);
484
+           uuid = jack_port_uuid_generate(o->serial);
485
            break;
486
        default:
487
            return -EINVAL;
488
@@ -2621,12 +2657,18 @@
489
    struct client *c = (struct client *) data;
490
    struct object *o, *ot, *op;
491
    const char *str;
492
-   size_t size;
493
    bool is_first = false, graph_changed = false;
494
+   uint32_t serial;
495
 
496
    if (props == NULL)
497
        return;
498
 
499
+   str = spa_dict_lookup(props, PW_KEY_OBJECT_SERIAL);
500
+   if (!spa_atou32(str, &serial, 0))
501
+       serial = SPA_ID_INVALID;
502
+
503
+   pw_log_debug("new %s id:%u serial:%u", type, id, serial);
504
+
505
    if (spa_streq(type, PW_TYPE_INTERFACE_Node)) {
506
        const char *app, *node_name;
507
        char tmp[JACK_CLIENT_NAME_SIZE+1];
508
@@ -2642,6 +2684,7 @@
509
            pw_log_debug("%p: add our node %d", c, id);
510
            if (node_name != NULL)
511
                snprintf(c->name, sizeof(c->name), "%s", node_name);
512
+           c->serial = serial;
513
        }
514
        snprintf(o->node.node_name, sizeof(o->node.node_name),
515
                "%s", node_name);
516
@@ -2685,7 +2728,7 @@
517
        pw_log_debug("%p: add node %d", c, id);
518
 
519
        pthread_mutex_lock(&c->context.lock);
520
-       spa_list_append(&c->context.nodes, &o->link);
521
+       spa_list_append(&c->context.objects, &o->link);
522
        pthread_mutex_unlock(&c->context.lock);
523
    }
524
    else if (spa_streq(type, PW_TYPE_INTERFACE_Port)) {
525
@@ -2742,34 +2785,19 @@
526
        o = NULL;
527
        if (node_id == c->node_id) {
528
            snprintf(tmp, sizeof(tmp), "%s:%s", c->name, str);
529
-           o = find_port(c, tmp);
530
+           o = find_port_by_name(c, tmp);
531
            if (o != NULL)
532
-               pw_log_debug("%p: %s found our port %p", c, tmp, o);
533
+               pw_log_info("%p: %s found our port %p", c, tmp, o);
534
        }
535
        if (o == NULL) {
536
+           if ((ot = find_type(c, node_id, INTERFACE_Node, true)) == NULL)
537
+               goto exit;
538
+
539
            o = alloc_object(c, INTERFACE_Port);
540
            if (o == NULL)
541
                goto exit;
542
 
543
-           pthread_mutex_lock(&c->context.lock);
544
-           spa_list_append(&c->context.ports, &o->link);
545
-           pthread_mutex_unlock(&c->context.lock);
546
-
547
-           if ((ot = find_type(c, node_id, INTERFACE_Node, true)) == NULL)
548
-               goto exit_free;
549
-
550
-           if (is_monitor && !c->merge_monitor)
551
-               snprintf(tmp, sizeof(tmp), "%.*s%s:%s",
552
-                   (int)(JACK_CLIENT_NAME_SIZE-(sizeof(MONITOR_EXT)-1)),
553
-                   ot->node.name, MONITOR_EXT, str);
554
-           else
555
-               snprintf(tmp, sizeof(tmp), "%s:%s", ot->node.name, str);
556
-
557
-           if (c->filter_name)
558
-               filter_name(tmp, FILTER_PORT);
559
-
560
            o->port.system_id = 0;
561
-           o->port.port_id = SPA_ID_INVALID;
562
            o->port.priority = ot->node.priority;
563
            o->port.node = ot;
564
            o->port.latency[SPA_DIRECTION_INPUT] = SPA_LATENCY_INFO(SPA_DIRECTION_INPUT);
565
@@ -2788,6 +2816,26 @@
566
                pw_port_subscribe_params((struct pw_port*)o->proxy,
567
                        ids, 1);
568
            }
569
+           pthread_mutex_lock(&c->context.lock);
570
+           spa_list_append(&c->context.objects, &o->link);
571
+           pthread_mutex_unlock(&c->context.lock);
572
+
573
+           if (is_monitor && !c->merge_monitor)
574
+               snprintf(tmp, sizeof(tmp), "%.*s%s:%s",
575
+                   (int)(JACK_CLIENT_NAME_SIZE-(sizeof(MONITOR_EXT)-1)),
576
+                   ot->node.name, MONITOR_EXT, str);
577
+           else
578
+               snprintf(tmp, sizeof(tmp), "%s:%s", ot->node.name, str);
579
+
580
+           if (c->filter_name)
581
+               filter_name(tmp, FILTER_PORT);
582
+
583
+           op = find_port_by_name(c, tmp);
584
+           if (op != NULL)
585
+               snprintf(o->port.name, sizeof(o->port.name), "%.*s-%u",
586
+                       (int)(sizeof(tmp)-11), tmp, serial);
587
+           else
588
+               snprintf(o->port.name, sizeof(o->port.name), "%s", tmp);
589
        }
590
 
591
        if ((str = spa_dict_lookup(props, PW_KEY_OBJECT_PATH)) != NULL)
592
@@ -2809,14 +2857,7 @@
593
        o->port.node_id = node_id;
594
        o->port.is_monitor = is_monitor;
595
 
596
-       op = find_port(c, tmp);
597
-       if (op != NULL && op != o)
598
-           snprintf(o->port.name, sizeof(o->port.name), "%.*s-%d",
599
-                   (int)(sizeof(tmp)-11), tmp, id);
600
-       else
601
-           snprintf(o->port.name, sizeof(o->port.name), "%s", tmp);
602
-
603
-       pw_log_debug("%p: add port %d name:%s %d", c, id,
604
+       pw_log_debug("%p: %p add port %d name:%s %d", c, o, id,
605
                o->port.name, type_id);
606
    }
607
    else if (spa_streq(type, PW_TYPE_INTERFACE_Link)) {
608
@@ -2825,7 +2866,7 @@
609
        o = alloc_object(c, INTERFACE_Link);
610
 
611
        pthread_mutex_lock(&c->context.lock);
612
-       spa_list_append(&c->context.links, &o->link);
613
+       spa_list_append(&c->context.objects, &o->link);
614
        pthread_mutex_unlock(&c->context.lock);
615
 
616
        if ((str = spa_dict_lookup(props, PW_KEY_LINK_OUTPUT_PORT)) == NULL)
617
@@ -2834,7 +2875,7 @@
618
 
619
        if ((p = find_type(c, o->port_link.src, INTERFACE_Port, true)) == NULL)
620
            goto exit_free;
621
-       o->port_link.src_idx = p->idx;
622
+       o->port_link.src_serial = p->serial;
623
 
624
        o->port_link.src_ours = p->port.port != NULL &&
625
            p->port.port->client == c;
626
@@ -2847,16 +2888,17 @@
627
 
628
        if ((p = find_type(c, o->port_link.dst, INTERFACE_Port, true)) == NULL)
629
            goto exit_free;
630
+       o->port_link.dst_serial = p->serial;
631
 
632
-       o->port_link.dst_idx = p->idx;
633
        o->port_link.dst_ours = p->port.port != NULL &&
634
            p->port.port->client == c;
635
        if (o->port_link.dst_ours)
636
            o->port_link.our_input = p->port.port;
637
 
638
        o->port_link.is_complete = !o->port_link.src_ours && !o->port_link.dst_ours;
639
-       pw_log_debug("%p: add link %d %d->%d", c, id,
640
-               o->port_link.src, o->port_link.dst);
641
+       pw_log_debug("%p: add link %d %u/%u->%u/%u", c, id,
642
+               o->port_link.src, o->port_link.src_serial,
643
+               o->port_link.dst, o->port_link.dst_serial);
644
    }
645
    else if (spa_streq(type, PW_TYPE_INTERFACE_Metadata)) {
646
        struct pw_proxy *proxy;
647
@@ -2885,13 +2927,7 @@
648
    }
649
 
650
    o->id = id;
651
-
652
-   pthread_mutex_lock(&c->context.lock);
653
-        size = pw_map_get_size(&c->context.globals);
654
-        while (id > size)
655
-       pw_map_insert_at(&c->context.globals, size++, NULL);
656
-   pw_map_insert_at(&c->context.globals, id, o);
657
-   pthread_mutex_unlock(&c->context.lock);
658
+   o->serial = serial;
659
 
660
    switch (o->type) {
661
    case INTERFACE_Node:
662
@@ -2904,20 +2940,21 @@
663
        break;
664
 
665
    case INTERFACE_Port:
666
-       pw_log_info("%p: port added %d/%d \"%s\"", c, o->id, o->idx, o->port.name);
667
+       pw_log_info("%p: port added %u/%u \"%s\"", c, o->id, o->serial, o->port.name);
668
        do_callback(c, portregistration_callback,
669
-               o->idx, 1, c->portregistration_arg);
670
+               o->serial, 1, c->portregistration_arg);
671
        graph_changed = true;
672
        break;
673
 
674
    case INTERFACE_Link:
675
-       pw_log_info("%p: link %u/%u %d/%d -> %d/%d added complete:%d", c, o->id, o->idx,
676
-               o->port_link.src, o->port_link.src_idx,
677
-               o->port_link.dst, o->port_link.dst_idx,
678
+       pw_log_info("%p: link %u %u/%u -> %u/%u added complete:%d", c,
679
+               o->id, o->port_link.src, o->port_link.src_serial,
680
+               o->port_link.dst, o->port_link.dst_serial,
681
                o->port_link.is_complete);
682
        if (o->port_link.is_complete) {
683
            do_callback(c, connect_callback,
684
-                   o->port_link.src_idx, o->port_link.dst_idx, 1, c->connect_arg);
685
+                   o->port_link.src_serial,
686
+                   o->port_link.dst_serial, 1, c->connect_arg);
687
            graph_changed = true;
688
        }
689
        break;
690
@@ -2967,21 +3004,21 @@
691
        }
692
        break;
693
    case INTERFACE_Port:
694
-       pw_log_info("%p: port %u/%u removed \"%s\"", c, o->id, o->idx, o->port.name);
695
+       pw_log_info("%p: port %u/%u removed \"%s\"", c, o->id, o->serial, o->port.name);
696
        do_callback(c, portregistration_callback,
697
-               o->idx, 0, c->portregistration_arg);
698
+               o->serial, 0, c->portregistration_arg);
699
        graph_changed = true;
700
        break;
701
    case INTERFACE_Link:
702
        if (o->port_link.is_complete &&
703
            find_type(c, o->port_link.src, INTERFACE_Port, true) != NULL &&
704
            find_type(c, o->port_link.dst, INTERFACE_Port, true) != NULL) {
705
-           pw_log_info("%p: link %u/%u %d/%u -> %d/%u removed", c, o->id, o->idx,
706
-                   o->port_link.src, o->port_link.src_idx,
707
-                   o->port_link.dst, o->port_link.dst_idx);
708
+           pw_log_info("%p: link %u %u/%u -> %u/%u removed", c, o->id,
709
+                   o->port_link.src, o->port_link.src_serial,
710
+                   o->port_link.dst, o->port_link.dst_serial);
711
            o->port_link.is_complete = false;
712
            do_callback(c, connect_callback,
713
-                   o->port_link.src_idx, o->port_link.dst_idx, 0, c->connect_arg);
714
+                   o->port_link.src_serial, o->port_link.dst_serial, 0, c->connect_arg);
715
            graph_changed = true;
716
        } else
717
            pw_log_warn("unlink between unknown ports %d and %d",
718
@@ -2993,16 +3030,8 @@
719
        do_callback(c, graph_callback, c->graph_arg);
720
    }
721
 
722
-   /* JACK clients expect the objects to hang around after
723
-    * they are unregistered. We keep the memory around for that
724
-    * reason but reuse it when we can. */
725
    o->removing = false;
726
    free_object(c, o);
727
-   /* we keep the object available with the id because jack clients
728
-    * tend to access the objects with it later.
729
-    *
730
-    * pw_map_insert_at(&c->context.globals, id, NULL);
731
-    */
732
 
733
    return;
734
 }
735
@@ -3135,9 +3164,7 @@
736
 
737
    pthread_mutex_init(&client->context.lock, NULL);
738
    pthread_mutex_init(&client->rt_lock, NULL);
739
-   spa_list_init(&client->context.nodes);
740
-   spa_list_init(&client->context.ports);
741
-   spa_list_init(&client->context.links);
742
+   spa_list_init(&client->context.objects);
743
 
744
    support = pw_context_get_support(client->context.context, &n_support);
745
 
746
@@ -3162,10 +3189,9 @@
747
         spa_list_init(&client->mix);
748
         spa_list_init(&client->free_mix);
749
 
750
-   init_port_pool(client, SPA_DIRECTION_INPUT);
751
-   init_port_pool(client, SPA_DIRECTION_OUTPUT);
752
-
753
-   pw_map_init(&client->context.globals, 64, 64);
754
+   pw_map_init(&client->ports[SPA_DIRECTION_INPUT], MAX_PORTS, 32);
755
+   pw_map_init(&client->ports[SPA_DIRECTION_OUTPUT], MAX_PORTS, 32);
756
+   spa_list_init(&client->free_ports);
757
 
758
    pw_thread_loop_start(client->context.loop);
759
 
760
@@ -3189,6 +3215,19 @@
761
 
762
    if ((str = getenv("PIPEWIRE_LATENCY")) != NULL)
763
        pw_properties_set(client->props, PW_KEY_NODE_LATENCY, str);
764
+   if ((str = getenv("PIPEWIRE_RATE")) != NULL)
765
+       pw_properties_set(client->props, PW_KEY_NODE_RATE, str);
766
+   if ((str = getenv("PIPEWIRE_QUANTUM")) != NULL) {
767
+       struct spa_fraction q;
768
+       if (sscanf(str, "%u/%u", &q.num, &q.denom) == 2 && q.denom != 0) {
769
+           pw_properties_setf(client->props, PW_KEY_NODE_RATE,
770
+                   "1/%u", q.denom);
771
+           pw_properties_setf(client->props, PW_KEY_NODE_LATENCY,
772
+                   "%u/%u", q.num, q.denom);
773
+       } else {
774
+           pw_log_warn("invalid PIPEWIRE_QUANTUM: %s", str);
775
+       }
776
+   }
777
    if ((str = pw_properties_get(client->props, PW_KEY_NODE_LATENCY)) != NULL) {
778
        uint32_t num, denom;
779
        if (sscanf(str, "%u/%u", &num, &denom) == 2 && denom != 0) {
780
@@ -3207,7 +3246,7 @@
781
        pw_properties_set(client->props, PW_KEY_MEDIA_ROLE, "DSP");
782
    if (pw_properties_get(client->props, PW_KEY_NODE_ALWAYS_PROCESS) == NULL)
783
        pw_properties_set(client->props, PW_KEY_NODE_ALWAYS_PROCESS, "true");
784
-   pw_properties_set(client->props, "node.transport.sync", "true");
785
+   pw_properties_set(client->props, PW_KEY_NODE_TRANSPORT_SYNC, "true");
786
 
787
    client->node = pw_core_create_object(client->core,
788
                "client-node",
789
@@ -3324,14 +3363,13 @@
790
 
791
    pw_log_debug("%p: free", client);
792
 
793
-   spa_list_consume(o, &c->context.nodes, link)
794
-       free_object(c, o);
795
-   spa_list_consume(o, &c->context.ports, link)
796
-       free_object(c, o);
797
-   spa_list_consume(o, &c->context.links, link)
798
+   spa_list_consume(o, &c->context.objects, link)
799
        free_object(c, o);
800
+   recycle_objects(c, 0);
801
+
802
+   pw_map_clear(&c->ports[SPA_DIRECTION_INPUT]);
803
+   pw_map_clear(&c->ports[SPA_DIRECTION_OUTPUT]);
804
 
805
-   pw_map_clear(&c->context.globals);
806
    pthread_mutex_destroy(&c->context.lock);
807
    pthread_mutex_destroy(&c->rt_lock);
808
    pw_properties_free(c->props);
809
@@ -3412,11 +3450,13 @@
810
 
811
    pthread_mutex_lock(&c->context.lock);
812
 
813
-   spa_list_for_each(o, &c->context.nodes, link) {
814
+   spa_list_for_each(o, &c->context.objects, link) {
815
+       if (o->type != INTERFACE_Node)
816
+           continue;
817
        if (spa_streq(o->node.name, client_name) ||
818
            (monitor && spa_strneq(o->node.name, client_name,
819
                strlen(client_name) - strlen(MONITOR_EXT)))) {
820
-           uuid = spa_aprintf( "%" PRIu64, client_make_uuid(o->id, monitor));
821
+           uuid = spa_aprintf( "%" PRIu64, client_make_uuid(o->serial, monitor));
822
            break;
823
        }
824
    }
825
@@ -3444,8 +3484,10 @@
826
    monitor = uuid & (1 << 30);
827
 
828
    pthread_mutex_lock(&c->context.lock);
829
-   spa_list_for_each(o, &c->context.nodes, link) {
830
-       if (client_make_uuid(o->id, monitor) == uuid) {
831
+   spa_list_for_each(o, &c->context.objects, link) {
832
+       if (o->type != INTERFACE_Node)
833
+           continue;
834
+       if (client_make_uuid(o->serial, monitor) == uuid) {
835
            pw_log_debug("%p: uuid %s (%"PRIu64")-> %s",
836
                    client, client_uuid, uuid, o->node.name);
837
            name = spa_aprintf("%s%s", o->node.name, monitor ? MONITOR_EXT : "");
838
@@ -3533,10 +3575,11 @@
839
    c->activation->pending_new_pos = false;
840
    c->activation->pending_sync = false;
841
 
842
-   spa_list_for_each(l, &c->context.links, link) {
843
-       if (l->port_link.src_ours || l->port_link.dst_ours) {
844
+   spa_list_for_each(l, &c->context.objects, link) {
845
+       if (l->type != INTERFACE_Link || l->removed)
846
+           continue;
847
+       if (l->port_link.src_ours || l->port_link.dst_ours)
848
            pw_registry_destroy(c->registry, l->id);
849
-       }
850
    }
851
 
852
    res = do_sync(c);
853
@@ -3985,6 +4028,7 @@
854
                res = c->position->clock.duration;
855
        }
856
    }
857
+   c->buffer_frames = res;
858
    pw_log_debug("buffer_frames: %u", res);
859
    return res;
860
 }
861
@@ -4042,21 +4086,27 @@
862
    spa_return_val_if_fail(port_name != NULL, NULL);
863
    spa_return_val_if_fail(port_type != NULL, NULL);
864
 
865
-   pw_log_info("%p: port register \"%s\" \"%s\" %08lx %ld",
866
-           c, port_name, port_type, flags, buffer_frames);
867
+   pw_log_info("%p: port register \"%s:%s\" \"%s\" %08lx %ld",
868
+           c, c->name, port_name, port_type, flags, buffer_frames);
869
 
870
    if (flags & JackPortIsInput)
871
        direction = PW_DIRECTION_INPUT;
872
    else if (flags & JackPortIsOutput)
873
        direction = PW_DIRECTION_OUTPUT;
874
-   else
875
+   else {
876
+       pw_log_warn("invalid port flags %lu for %s", flags, port_name);
877
        return NULL;
878
+   }
879
 
880
-   if ((type_id = string_to_type(port_type)) == SPA_ID_INVALID)
881
+   if ((type_id = string_to_type(port_type)) == SPA_ID_INVALID) {
882
+       pw_log_warn("unknown port type %s", port_type);
883
        return NULL;
884
+   }
885
 
886
-   if ((p = alloc_port(c, direction)) == NULL)
887
+   if ((p = alloc_port(c, direction)) == NULL) {
888
+       pw_log_warn("can't allocate port %s: %m", port_name);
889
        return NULL;
890
+   }
891
 
892
    o = p->object;
893
    o->port.flags = flags;
894
@@ -4132,7 +4182,7 @@
895
 
896
    pw_client_node_port_update(c->node,
897
                     direction,
898
-                    p->id,
899
+                    p->port_id,
900
                     PW_CLIENT_NODE_PORT_UPDATE_PARAMS |
901
                     PW_CLIENT_NODE_PORT_UPDATE_INFO,
902
                     n_params,
903
@@ -4145,8 +4195,11 @@
904
 
905
    pw_thread_loop_unlock(c->context.loop);
906
 
907
-   if (res < 0)
908
+   if (res < 0) {
909
+       pw_log_warn("can't create port %s: %s", port_name,
910
+               spa_strerror(res));
911
        return NULL;
912
+   }
913
 
914
    return (jack_port_t *) o;
915
 }
916
@@ -4162,30 +4215,28 @@
917
    spa_return_val_if_fail(c != NULL, -EINVAL);
918
    spa_return_val_if_fail(o != NULL, -EINVAL);
919
 
920
-   if (o->type != INTERFACE_Port || o->port.port_id == SPA_ID_INVALID ||
921
-       o->client != c) {
922
-       pw_log_error("%p: invalid port %p", client, port);
923
-       return -EINVAL;
924
-   }
925
-   pw_log_info("%p: port %p unregister \"%s\"", client, port, o->port.name);
926
-
927
    pw_thread_loop_lock(c->context.loop);
928
 
929
-   p = GET_PORT(c, GET_DIRECTION(o->port.flags), o->port.port_id);
930
-   if (p == NULL || !p->valid) {
931
+   p = o->port.port;
932
+   if (o->type != INTERFACE_Port || p == NULL || !p->valid ||
933
+       o->client != c) {
934
+       pw_log_error("%p: invalid port %p", client, port);
935
        res = -EINVAL;
936
        goto done;
937
    }
938
+   pw_log_info("%p: port %p unregister \"%s\"", client, port, o->port.name);
939
 
940
    pw_client_node_port_update(c->node,
941
                     p->direction,
942
-                    p->id,
943
+                    p->port_id,
944
                     0, 0, NULL, NULL);
945
 
946
    res = do_sync(c);
947
-
948
+   if (res < 0) {
949
+       pw_log_warn("can't unregister port %s: %s", o->port.name,
950
+               spa_strerror(res));
951
+   }
952
    free_port(c, p);
953
-
954
 done:
955
    pw_thread_loop_unlock(c->context.loop);
956
 
957
@@ -4221,7 +4272,7 @@
958
        void *np;
959
 
960
        pw_log_trace_fp("%p: port %s mix %d.%d get buffer %d",
961
-               p->client, p->object->port.name, p->id, mix->id, frames);
962
+               p->client, p->object->port.name, p->port_id, mix->id, frames);
963
 
964
        if ((b = get_mix_buffer(mix, frames)) == NULL)
965
            continue;
966
@@ -4261,7 +4312,7 @@
967
        void *pod;
968
 
969
        pw_log_trace_fp("%p: port %p mix %d.%d get buffer %d",
970
-               p->client, p, p->id, mix->id, frames);
971
+               p->client, p, p->port_id, mix->id, frames);
972
 
973
        if ((b = get_mix_buffer(mix, frames)) == NULL)
974
            continue;
975
@@ -4352,7 +4403,7 @@
976
 {
977
    struct object *o = (struct object *) port;
978
    spa_return_val_if_fail(o != NULL, 0);
979
-   return jack_port_uuid_generate(o->id);
980
+   return jack_port_uuid_generate(o->serial);
981
 }
982
 
983
 SPA_EXPORT
984
@@ -4420,16 +4471,18 @@
985
    c = o->client;
986
 
987
    pthread_mutex_lock(&c->context.lock);
988
-   spa_list_for_each(l, &c->context.links, link) {
989
+   spa_list_for_each(l, &c->context.objects, link) {
990
+       if (l->type != INTERFACE_Link || l->removed)
991
+           continue;
992
        if (!l->port_link.is_complete)
993
            continue;
994
-       if (l->port_link.src == o->id ||
995
-           l->port_link.dst == o->id)
996
+       if (l->port_link.src_serial == o->serial ||
997
+           l->port_link.dst_serial == o->serial)
998
            res++;
999
    }
1000
    pthread_mutex_unlock(&c->context.lock);
1001
 
1002
-   pw_log_debug("%p: id:%d res:%d", port, o->id, res);
1003
+   pw_log_debug("%p: id:%u/%u res:%d", port, o->id, o->serial, res);
1004
 
1005
    return res;
1006
 }
1007
@@ -4452,7 +4505,7 @@
1008
 
1009
    pthread_mutex_lock(&c->context.lock);
1010
 
1011
-   p = find_port(c, port_name);
1012
+   p = find_port_by_name(c, port_name);
1013
    if (p == NULL)
1014
        goto exit;
1015
 
1016
@@ -4470,7 +4523,8 @@
1017
 
1018
      exit:
1019
    pthread_mutex_unlock(&c->context.lock);
1020
-   pw_log_debug("%p: id:%d name:%s res:%d", port, o->id, port_name, res);
1021
+   pw_log_debug("%p: id:%u/%u name:%s res:%d", port, o->id,
1022
+           o->serial, port_name, res);
1023
 
1024
    return res;
1025
 }
1026
@@ -4503,10 +4557,12 @@
1027
    res = malloc(sizeof(char*) * (CONNECTION_NUM_FOR_PORT + 1));
1028
 
1029
    pthread_mutex_lock(&c->context.lock);
1030
-   spa_list_for_each(l, &c->context.links, link) {
1031
-       if (l->port_link.src == o->id)
1032
+   spa_list_for_each(l, &c->context.objects, link) {
1033
+       if (l->type != INTERFACE_Link || l->removed)
1034
+           continue;
1035
+       if (l->port_link.src_serial == o->serial)
1036
            p = find_type(c, l->port_link.dst, INTERFACE_Port, true);
1037
-       else if (l->port_link.dst == o->id)
1038
+       else if (l->port_link.dst_serial == o->serial)
1039
            p = find_type(c, l->port_link.src, INTERFACE_Port, true);
1040
        else
1041
            continue;
1042
@@ -4567,13 +4623,12 @@
1043
    pw_log_info("%p: port rename %p %s -> %s:%s",
1044
            client, port, o->port.name, c->name, port_name);
1045
 
1046
-   p = GET_PORT(c, GET_DIRECTION(o->port.flags), o->port.port_id);
1047
+   p = o->port.port;
1048
    if (p == NULL || !p->valid) {
1049
        res = -EINVAL;
1050
        goto done;
1051
    }
1052
 
1053
-
1054
    pw_properties_set(p->props, PW_KEY_PORT_NAME, port_name);
1055
    snprintf(o->port.name, sizeof(o->port.name), "%s:%s", c->name, port_name);
1056
 
1057
@@ -4582,7 +4637,7 @@
1058
 
1059
    pw_client_node_port_update(c->node,
1060
                     p->direction,
1061
-                    p->id,
1062
+                    p->port_id,
1063
                     PW_CLIENT_NODE_PORT_UPDATE_INFO,
1064
                     0, NULL,
1065
                     &p->info);
1066
@@ -4605,14 +4660,14 @@
1067
 
1068
    spa_return_val_if_fail(o != NULL, -EINVAL);
1069
    spa_return_val_if_fail(alias != NULL, -EINVAL);
1070
-   if (o->type != INTERFACE_Port || o->client == NULL)
1071
-       return -EINVAL;
1072
 
1073
    c = o->client;
1074
+   if (o->type != INTERFACE_Port || c == NULL)
1075
+       return -EINVAL;
1076
 
1077
    pw_thread_loop_lock(c->context.loop);
1078
 
1079
-   p = GET_PORT(c, GET_DIRECTION(o->port.flags), o->port.port_id);
1080
+   p = o->port.port;
1081
    if (p == NULL || !p->valid) {
1082
        res = -EINVAL;
1083
        goto done;
1084
@@ -4638,7 +4693,7 @@
1085
 
1086
    pw_client_node_port_update(c->node,
1087
                     p->direction,
1088
-                    p->id,
1089
+                    p->port_id,
1090
                     PW_CLIENT_NODE_PORT_UPDATE_INFO,
1091
                     0, NULL,
1092
                     &p->info);
1093
@@ -4661,14 +4716,13 @@
1094
 
1095
    spa_return_val_if_fail(o != NULL, -EINVAL);
1096
    spa_return_val_if_fail(alias != NULL, -EINVAL);
1097
-   if (o->type != INTERFACE_Port || o->client == NULL)
1098
-       return -EINVAL;
1099
 
1100
    c = o->client;
1101
+   if (o->type != INTERFACE_Port || c == NULL)
1102
+       return -EINVAL;
1103
 
1104
    pw_thread_loop_lock(c->context.loop);
1105
-
1106
-   p = GET_PORT(c, GET_DIRECTION(o->port.flags), o->port.port_id);
1107
+   p = o->port.port;
1108
    if (p == NULL || !p->valid) {
1109
        res = -EINVAL;
1110
        goto done;
1111
@@ -4690,7 +4744,7 @@
1112
 
1113
    pw_client_node_port_update(c->node,
1114
                     p->direction,
1115
-                    p->id,
1116
+                    p->port_id,
1117
                     PW_CLIENT_NODE_PORT_UPDATE_INFO,
1118
                     0, NULL,
1119
                     &p->info);
1120
@@ -4750,7 +4804,7 @@
1121
    spa_return_val_if_fail(port_name != NULL, -EINVAL);
1122
 
1123
    pthread_mutex_lock(&c->context.lock);
1124
-   p = find_port(c, port_name);
1125
+   p = find_port_by_name(c, port_name);
1126
    pthread_mutex_unlock(&c->context.lock);
1127
 
1128
    if (p == NULL) {
1129
@@ -4849,8 +4903,8 @@
1130
 
1131
    pw_thread_loop_lock(c->context.loop);
1132
 
1133
-   src = find_port(c, source_port);
1134
-   dst = find_port(c, destination_port);
1135
+   src = find_port_by_name(c, source_port);
1136
+   dst = find_port_by_name(c, destination_port);
1137
 
1138
    if (src == NULL || dst == NULL ||
1139
        !(src->port.flags & JackPortIsOutput) ||
1140
@@ -4923,8 +4977,8 @@
1141
 
1142
    pw_thread_loop_lock(c->context.loop);
1143
 
1144
-   src = find_port(c, source_port);
1145
-   dst = find_port(c, destination_port);
1146
+   src = find_port_by_name(c, source_port);
1147
+   dst = find_port_by_name(c, destination_port);
1148
 
1149
    pw_log_debug("%p: %d %d", client, src->id, dst->id);
1150
 
1151
@@ -4968,9 +5022,11 @@
1152
 
1153
    pw_thread_loop_lock(c->context.loop);
1154
 
1155
-   spa_list_for_each(l, &c->context.links, link) {
1156
-       if (l->port_link.src == o->id ||
1157
-           l->port_link.dst == o->id) {
1158
+   spa_list_for_each(l, &c->context.objects, link) {
1159
+       if (l->type != INTERFACE_Link || l->removed)
1160
+           continue;
1161
+       if (l->port_link.src_serial == o->serial ||
1162
+           l->port_link.dst_serial == o->serial) {
1163
            pw_registry_destroy(c->registry, l->id);
1164
        }
1165
    }
1166
@@ -5229,7 +5285,7 @@
1167
        if (res == 0)
1168
            res = (*o1)->port.system_id - (*o2)->port.system_id;
1169
        if (res == 0)
1170
-           res = (*o1)->id - (*o2)->id;
1171
+           res = (*o1)->serial - (*o2)->serial;
1172
    }
1173
 
1174
 
1175
@@ -5238,7 +5294,7 @@
1176
            (*o1)->port.type_id, (*o2)->port.type_id,
1177
            is_def1, is_def2,
1178
            (*o1)->port.priority, (*o2)->port.priority,
1179
-           (*o1)->id, (*o2)->id, res);
1180
+           (*o1)->serial, (*o2)->serial, res);
1181
    return res;
1182
 }
1183
 
1184
@@ -5282,7 +5338,9 @@
1185
 
1186
    pthread_mutex_lock(&c->context.lock);
1187
    count = 0;
1188
-   spa_list_for_each(o, &c->context.ports, link) {
1189
+   spa_list_for_each(o, &c->context.objects, link) {
1190
+       if (o->type != INTERFACE_Port || o->removed)
1191
+           continue;
1192
        pw_log_debug("%p: check port type:%d flags:%08lx name:\"%s\"", c,
1193
                o->port.type_id, o->port.flags, o->port.name);
1194
        if (count == JACK_PORT_MAX)
1195
@@ -5342,7 +5400,7 @@
1196
    spa_return_val_if_fail(c != NULL, NULL);
1197
 
1198
    pthread_mutex_lock(&c->context.lock);
1199
-   res = find_port(c, port_name);
1200
+   res = find_port_by_name(c, port_name);
1201
    pthread_mutex_unlock(&c->context.lock);
1202
 
1203
    if (res == NULL)
1204
@@ -5360,9 +5418,12 @@
1205
 
1206
    spa_return_val_if_fail(c != NULL, NULL);
1207
 
1208
-   res = find_cache(INTERFACE_Port, port_id);
1209
-
1210
+   pthread_mutex_lock(&c->context.lock);
1211
+   res = find_by_serial(c, port_id);
1212
+   if (res && res->type != INTERFACE_Port)
1213
+       res = NULL;
1214
    pw_log_debug("%p: port %d -> %p", c, port_id, res);
1215
+   pthread_mutex_unlock(&c->context.lock);
1216
 
1217
    if (res == NULL)
1218
        pw_log_info("%p: port %d not found", c, port_id);
1219
@@ -5790,7 +5851,7 @@
1220
 
1221
    spa_return_val_if_fail(c != NULL, NULL);
1222
 
1223
-   return spa_aprintf("%"PRIu64, client_make_uuid(c->node_id, false));
1224
+   return spa_aprintf("%"PRIu64, client_make_uuid(c->serial, false));
1225
 }
1226
 
1227
 SPA_EXPORT
1228
@@ -6167,8 +6228,5 @@
1229
    PW_LOG_TOPIC_INIT(jack_log_topic);
1230
    pthread_mutex_init(&globals.lock, NULL);
1231
    pw_array_init(&globals.descriptions, 16);
1232
-   spa_list_init(&globals.free_objects[INTERFACE_Port]);
1233
-   spa_list_init(&globals.free_objects[INTERFACE_Node]);
1234
-   spa_list_init(&globals.free_objects[INTERFACE_Link]);
1235
-   pw_map_init(&globals.cache, 64, 64);
1236
+   spa_list_init(&globals.free_objects);
1237
 }
1238
pipewire-0.3.43.tar.gz/pipewire-jack/src/pw-jack.in -> pipewire-0.3.44.tar.gz/pipewire-jack/src/pw-jack.in Changed
34
 
1
@@ -24,7 +24,7 @@
2
 # DEALINGS IN THE SOFTWARE.
3
 #
4
 
5
-SAMPLERATE=48000
6
+DEFAULT_SAMPLERATE=48000
7
 
8
 while getopts 'hr:vs:p:' param ; do
9
    case $param in
10
@@ -55,7 +55,7 @@
11
            echo "  -h                  show brief help"
12
            echo "  -r <remote>         remote daemon name"
13
            echo "  -v                  verbose debug info"
14
-           echo "  -s                  samplerate (default \"$SAMPLERATE\")"
15
+           echo "  -s                  samplerate (default \"$DEFAULT_SAMPLERATE\")"
16
            echo "  -p                  period in samples"
17
            exit 0
18
            ;;
19
@@ -65,8 +65,12 @@
20
 shift $(( OPTIND - 1 ))
21
 
22
 if [ -n "$PERIOD" ]; then
23
-   PIPEWIRE_LATENCY="$PERIOD/$SAMPLERATE"
24
-   export PIPEWIRE_LATENCY
25
+   if [ -n "$SAMPLERATE" ]; then
26
+       PIPEWIRE_QUANTUM="$PERIOD/$SAMPLERATE"
27
+   else
28
+       PIPEWIRE_QUANTUM="$PERIOD/$DEFAULT_SAMPLERATE"
29
+   fi
30
+   export PIPEWIRE_QUANTUM
31
 fi
32
 LD_LIBRARY_PATH='@LIBJACK_PATH@'"${LD_LIBRARY_PATH+":$LD_LIBRARY_PATH"}"
33
 export LD_LIBRARY_PATH
34
pipewire-0.3.43.tar.gz/pipewire-v4l2/src/pipewire-v4l2.c -> pipewire-0.3.44.tar.gz/pipewire-v4l2/src/pipewire-v4l2.c Changed
17
 
1
@@ -1119,12 +1119,13 @@
2
 
3
    file->v4l2_format = fmt;
4
 
5
-   buffers = file->reqbufs;
6
+   buffers = SPA_CLAMP(file->reqbufs, 2u, MAX_BUFFERS);
7
    size = 0;
8
 
9
    params[n_params++] = spa_pod_builder_add_object(&b,
10
            SPA_TYPE_OBJECT_ParamBuffers, SPA_PARAM_Buffers,
11
-           SPA_PARAM_BUFFERS_buffers, SPA_POD_Int(buffers),
12
+           SPA_PARAM_BUFFERS_buffers, SPA_POD_CHOICE_RANGE_Int(buffers,
13
+                           2, MAX_BUFFERS),
14
            SPA_PARAM_BUFFERS_blocks,  SPA_POD_Int(1),
15
            SPA_PARAM_BUFFERS_size,    SPA_POD_CHOICE_RANGE_Int(size, 0, INT_MAX),
16
            SPA_PARAM_BUFFERS_stride,  SPA_POD_CHOICE_RANGE_Int(0, 0, INT_MAX),
17
pipewire-0.3.43.tar.gz/spa/include/spa/buffer/meta.h -> pipewire-0.3.44.tar.gz/spa/include/spa/buffer/meta.h Changed
10
 
1
@@ -81,7 +81,7 @@
2
 #define SPA_META_HEADER_FLAG_DELTA_UNIT    (1 << 5)    /**< cannot be decoded independently */
3
    uint32_t flags;             /**< flags */
4
    uint32_t offset;            /**< offset in current cycle */
5
-   int64_t pts;                /**< presentation timestamp */
6
+   int64_t pts;                /**< presentation timestamp in nanoseconds */
7
    int64_t dts_offset;         /**< decoding timestamp as a difference with pts */
8
    uint64_t seq;               /**< sequence number, increments with a
9
                          *  media specific frequency */
10
pipewire-0.3.43.tar.gz/spa/include/spa/debug/types.h -> pipewire-0.3.44.tar.gz/spa/include/spa/debug/types.h Changed
28
 
1
@@ -96,6 +96,26 @@
2
    return SPA_ID_INVALID;
3
 }
4
 
5
+static inline const struct spa_type_info *spa_debug_type_find_short(const struct spa_type_info *info, const char *name)
6
+{
7
+   while (info && info->name) {
8
+       if (strcmp(spa_debug_type_short_name(info->name), name) == 0)
9
+           return info;
10
+       if (strcmp(info->name, name) == 0)
11
+           return info;
12
+       if (info->type != 0 && info->type == (uint32_t)atoi(name))
13
+           return info;
14
+       info++;
15
+   }
16
+   return NULL;
17
+}
18
+
19
+static inline uint32_t spa_debug_type_find_type_short(const struct spa_type_info *info, const char *name)
20
+{
21
+   if ((info = spa_debug_type_find_short(info, name)) == NULL)
22
+       return SPA_ID_INVALID;
23
+   return info->type;
24
+}
25
 /**
26
  * \}
27
  */
28
pipewire-0.3.43.tar.gz/spa/include/spa/support/thread.h -> pipewire-0.3.44.tar.gz/spa/include/spa/support/thread.h Changed
12
 
1
@@ -68,7 +68,9 @@
2
 
3
    /** get realtime priority range for threads created with \a props */
4
    int (*get_rt_range) (void *data, const struct spa_dict *props, int *min, int *max);
5
-   /** acquire realtime priority */
6
+   /** acquire realtime priority, a priority of -1 refers to the priority
7
+    * configured in the realtime module
8
+    */
9
    int (*acquire_rt) (void *data, struct spa_thread *thread, int priority);
10
    /** drop realtime priority */
11
    int (*drop_rt) (void *data, struct spa_thread *thread);
12
pipewire-0.3.43.tar.gz/spa/include/spa/utils/dict.h -> pipewire-0.3.44.tar.gz/spa/include/spa/utils/dict.h Changed
23
 
1
@@ -74,8 +74,9 @@
2
 
3
 static inline void spa_dict_qsort(struct spa_dict *dict)
4
 {
5
-   qsort((void*)dict->items, dict->n_items, sizeof(struct spa_dict_item),
6
-           spa_dict_item_compare);
7
+   if (dict->n_items > 0)
8
+       qsort((void*)dict->items, dict->n_items, sizeof(struct spa_dict_item),
9
+               spa_dict_item_compare);
10
    SPA_FLAG_SET(dict->flags, SPA_DICT_FLAG_SORTED);
11
 }
12
 
13
@@ -84,7 +85,8 @@
14
 {
15
    const struct spa_dict_item *item;
16
 
17
-   if (SPA_FLAG_IS_SET(dict->flags, SPA_DICT_FLAG_SORTED)) {
18
+   if (SPA_FLAG_IS_SET(dict->flags, SPA_DICT_FLAG_SORTED) &&
19
+           dict->n_items > 0) {
20
        struct spa_dict_item k = SPA_DICT_ITEM_INIT(key, NULL);
21
        item = (const struct spa_dict_item *)bsearch(&k,
22
                (const void *) dict->items, dict->n_items,
23
pipewire-0.3.44.tar.gz/spa/include/spa/utils/json-pod.h Added
179
 
1
@@ -0,0 +1,177 @@
2
+/* Simple Plugin API
3
+ *
4
+ * Copyright © 2022 Wim Taymans
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a
7
+ * copy of this software and associated documentation files (the "Software"),
8
+ * to deal in the Software without restriction, including without limitation
9
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
+ * and/or sell copies of the Software, and to permit persons to whom the
11
+ * Software is furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice (including the next
14
+ * paragraph) shall be included in all copies or substantial portions of the
15
+ * Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23
+ * DEALINGS IN THE SOFTWARE.
24
+ */
25
+
26
+#ifndef SPA_UTILS_JSON_POD_H
27
+#define SPA_UTILS_JSON_POD_H
28
+
29
+#ifdef __cplusplus
30
+extern "C" {
31
+#endif
32
+
33
+#include <spa/utils/string.h>
34
+#include <spa/utils/json.h>
35
+#include <spa/pod/pod.h>
36
+#include <spa/pod/builder.h>
37
+#include <spa/debug/types.h>
38
+
39
+/** \defgroup spa_json_pod JSON to POD
40
+ * JSON to POD conversion
41
+ */
42
+
43
+/**
44
+ * \addtogroup spa_json_pod
45
+ * \{
46
+ */
47
+
48
+static inline int spa_json_to_pod_part(struct spa_pod_builder *b, uint32_t flags, uint32_t id,
49
+       const struct spa_type_info *info, struct spa_json *iter, const char *value, int len)
50
+{
51
+   const struct spa_type_info *ti;
52
+   char key[256];
53
+   struct spa_pod_frame f[1];
54
+   struct spa_json it[1];
55
+   int l, res;
56
+   const char *v;
57
+   uint32_t type;
58
+
59
+   if (spa_json_is_object(value, len) && info != NULL) {
60
+       if ((ti = spa_debug_type_find(NULL, info->parent)) == NULL)
61
+           return -EINVAL;
62
+
63
+       spa_pod_builder_push_object(b, &f[0], info->parent, id);
64
+
65
+       spa_json_enter(iter, &it[0]);
66
+       while (spa_json_get_string(&it[0], key, sizeof(key)) > 0) {
67
+           const struct spa_type_info *pi;
68
+           if ((l = spa_json_next(&it[0], &v)) <= 0)
69
+               break;
70
+           if ((pi = spa_debug_type_find_short(ti->values, key)) != NULL)
71
+               type = pi->type;
72
+           else if (!spa_atou32(key, &type, 0))
73
+               continue;
74
+           spa_pod_builder_prop(b, type, 0);
75
+           if ((res = spa_json_to_pod_part(b, flags, id, pi, &it[0], v, l)) < 0)
76
+               return res;
77
+       }
78
+       spa_pod_builder_pop(b, &f[0]);
79
+   }
80
+   else if (spa_json_is_array(value, len)) {
81
+       if (info == NULL || info->parent == SPA_TYPE_Struct) {
82
+           spa_pod_builder_push_struct(b, &f[0]);
83
+       } else {
84
+           spa_pod_builder_push_array(b, &f[0]);
85
+           info = info->values;
86
+       }
87
+       spa_json_enter(iter, &it[0]);
88
+       while ((l = spa_json_next(&it[0], &v)) > 0)
89
+           if ((res = spa_json_to_pod_part(b, flags, id, info, &it[0], v, l)) < 0)
90
+               return res;
91
+       spa_pod_builder_pop(b, &f[0]);
92
+   }
93
+   else if (spa_json_is_float(value, len)) {
94
+       float val = 0.0f;
95
+       spa_json_parse_float(value, len, &val);
96
+       switch (info ? info->parent : (uint32_t)SPA_TYPE_Struct) {
97
+       case SPA_TYPE_Bool:
98
+           spa_pod_builder_bool(b, val >= 0.5f);
99
+           break;
100
+       case SPA_TYPE_Id:
101
+           spa_pod_builder_id(b, val);
102
+           break;
103
+       case SPA_TYPE_Int:
104
+           spa_pod_builder_int(b, val);
105
+           break;
106
+       case SPA_TYPE_Long:
107
+           spa_pod_builder_long(b, val);
108
+           break;
109
+       case SPA_TYPE_Struct:
110
+           if (spa_json_is_int(value, len))
111
+               spa_pod_builder_int(b, val);
112
+           else
113
+               spa_pod_builder_float(b, val);
114
+           break;
115
+       case SPA_TYPE_Float:
116
+           spa_pod_builder_float(b, val);
117
+           break;
118
+       case SPA_TYPE_Double:
119
+           spa_pod_builder_double(b, val);
120
+           break;
121
+       default:
122
+           spa_pod_builder_none(b);
123
+           break;
124
+       }
125
+   }
126
+   else if (spa_json_is_bool(value, len)) {
127
+       bool val = false;
128
+       spa_json_parse_bool(value, len, &val);
129
+       spa_pod_builder_bool(b, val);
130
+   }
131
+   else if (spa_json_is_null(value, len)) {
132
+       spa_pod_builder_none(b);
133
+   }
134
+   else {
135
+       char *val = (char*)alloca(len+1);
136
+       spa_json_parse_stringn(value, len, val, len+1);
137
+       switch (info ? info->parent : (uint32_t)SPA_TYPE_Struct) {
138
+       case SPA_TYPE_Id:
139
+           if ((ti = spa_debug_type_find_short(info->values, val)) != NULL)
140
+               type = ti->type;
141
+           else if (!spa_atou32(val, &type, 0))
142
+               return -EINVAL;
143
+           spa_pod_builder_id(b, type);
144
+           break;
145
+       case SPA_TYPE_Struct:
146
+       case SPA_TYPE_String:
147
+           spa_pod_builder_string(b, val);
148
+           break;
149
+       default:
150
+           spa_pod_builder_none(b);
151
+           break;
152
+       }
153
+   }
154
+   return 0;
155
+}
156
+
157
+static inline int spa_json_to_pod(struct spa_pod_builder *b, uint32_t flags,
158
+       const struct spa_type_info *info, const char *value, int len)
159
+{
160
+   struct spa_json iter;
161
+   const char *val;
162
+
163
+   spa_json_init(&iter, value, len);
164
+   if ((len = spa_json_next(&iter, &val)) <= 0)
165
+       return -EINVAL;
166
+
167
+   return spa_json_to_pod_part(b, flags, info->type, info, &iter, val, len);
168
+}
169
+
170
+/**
171
+ * \}
172
+ */
173
+
174
+#ifdef __cplusplus
175
+} /* extern "C" */
176
+#endif
177
+
178
+#endif /* SPA_UTILS_JSON_POD_H */
179
pipewire-0.3.43.tar.gz/spa/meson.build -> pipewire-0.3.44.tar.gz/spa/meson.build Changed
9
 
1
@@ -9,6 +9,7 @@
2
   include_directories : [
3
     include_directories('include'),
4
   ],
5
+  dependencies : [atomic_dep],
6
   version : spaversion,
7
   variables : {
8
     'plugindir' : meson.current_build_dir() / 'plugins',
9
pipewire-0.3.43.tar.gz/spa/plugins/alsa/90-pipewire-alsa.rules -> pipewire-0.3.44.tar.gz/spa/plugins/alsa/90-pipewire-alsa.rules Changed
11
 
1
@@ -113,8 +113,7 @@
2
 ATTRS{idVendor}=="041e", ATTRS{idProduct}=="322c", ENV{ACP_PROFILE_SET}="sb-omni-surround-5.1.conf"
3
 ATTRS{idVendor}=="0bda", ATTRS{idProduct}=="4014", ENV{ACP_PROFILE_SET}="dell-dock-tb16-usb-audio.conf"
4
 ATTRS{idVendor}=="0bda", ATTRS{idProduct}=="402e", ENV{ACP_PROFILE_SET}="dell-dock-tb16-usb-audio.conf"
5
-ATTRS{idVendor}=="1397", ATTRS{idProduct}=="0507", ENV{ACP_PROFILE_SET}="behringer-umc22.conf"
6
-ATTRS{idVendor}=="08bb", ATTRS{idProduct}=="2902", ENV{ACP_PROFILE_SET}="texas-instruments-pcm2902.conf"
7
+#ATTRS{idVendor}=="08bb", ATTRS{idProduct}=="2902", ENV{ACP_PROFILE_SET}="texas-instruments-pcm2902.conf"
8
 ATTRS{idVendor}=="03f0", ATTRS{idProduct}=="0269", ENV{ACP_PROFILE_SET}="hp-tbt-dock-120w-g2.conf"
9
 ATTRS{idVendor}=="03f0", ATTRS{idProduct}=="0567", ENV{ACP_PROFILE_SET}="hp-tbt-dock-audio-module.conf"
10
 
11
pipewire-0.3.43.tar.gz/spa/plugins/alsa/acp/compat.h -> pipewire-0.3.44.tar.gz/spa/plugins/alsa/acp/compat.h Changed
57
 
1
@@ -34,6 +34,9 @@
2
 #include <inttypes.h>
3
 #include <stdlib.h>
4
 #include <unistd.h>
5
+#include <math.h>
6
+
7
+#include <spa/utils/string.h>
8
 
9
 typedef struct pa_core pa_core;
10
 
11
@@ -545,25 +548,35 @@
12
 
13
 static inline int pa_atod(const char *s, double *ret_d)
14
 {
15
-   char *x;
16
-   *ret_d = strtod(s, &x);
17
-   return 0;
18
+   if (spa_atod(s, ret_d) && !isnan(*ret_d))
19
+       return 0;
20
+   errno = EINVAL;
21
+   return -1;
22
 }
23
 static inline int pa_atoi(const char *s, int32_t *ret_i)
24
 {
25
-   *ret_i = (int32_t) atoi(s);
26
-   return 0;
27
+   if (spa_atoi32(s, ret_i, 0))
28
+       return 0;
29
+   errno = EINVAL;
30
+   return -1;
31
 }
32
 static inline int pa_atou(const char *s, uint32_t *ret_u)
33
 {
34
-   *ret_u = (uint32_t) atoi(s);
35
-   return 0;
36
+   if (spa_atou32(s, ret_u, 0))
37
+       return 0;
38
+   errno = EINVAL;
39
+   return -1;
40
 }
41
 static inline int pa_atol(const char *s, long *ret_l)
42
 {
43
-   char *x;
44
-   *ret_l = strtol(s, &x, 0);
45
-   return 0;
46
+   int64_t res;
47
+   if (spa_atoi64(s, &res, 0)) {
48
+       *ret_l = res;
49
+       if (*ret_l == res)
50
+           return 0;
51
+   }
52
+   errno = EINVAL;
53
+   return -1;
54
 }
55
 
56
 static inline int pa_parse_boolean(const char *v)
57
pipewire-0.3.43.tar.gz/spa/plugins/alsa/alsa-pcm-sink.c -> pipewire-0.3.44.tar.gz/spa/plugins/alsa/alsa-pcm-sink.c Changed
100
 
1
@@ -42,14 +42,10 @@
2
 #define CHECK_PORT(this,d,p)    ((d) == SPA_DIRECTION_INPUT && (p) == 0)
3
 
4
 static const char default_device[] = "hw:0";
5
-static const uint32_t default_min_latency = MIN_LATENCY;
6
-static const uint32_t default_max_latency = MAX_LATENCY;
7
 
8
 static void reset_props(struct props *props)
9
 {
10
    strncpy(props->device, default_device, 64);
11
-   props->min_latency = default_min_latency;
12
-   props->max_latency = default_max_latency;
13
    props->use_chmap = DEFAULT_USE_CHMAP;
14
 }
15
 
16
@@ -68,7 +64,7 @@
17
        items[n_items++] = SPA_DICT_ITEM_INIT(SPA_KEY_MEDIA_CLASS, "Audio/Sink");
18
        items[n_items++] = SPA_DICT_ITEM_INIT(SPA_KEY_NODE_DRIVER, "true");
19
        if (this->have_format) {
20
-           snprintf(latency, sizeof(latency), "%lu/%d", this->buffer_frames / 4, this->rate);
21
+           snprintf(latency, sizeof(latency), "%lu/%d", this->buffer_frames / 2, this->rate);
22
            items[n_items++] = SPA_DICT_ITEM_INIT(SPA_KEY_NODE_MAX_LATENCY, latency);
23
        }
24
        this->info.props = &SPA_DICT_INIT(items, n_items);
25
@@ -162,25 +158,11 @@
26
        case 3:
27
            param = spa_pod_builder_add_object(&b,
28
                SPA_TYPE_OBJECT_PropInfo, id,
29
-               SPA_PROP_INFO_id,   SPA_POD_Id(SPA_PROP_minLatency),
30
-               SPA_PROP_INFO_description, SPA_POD_String("The minimum latency"),
31
-               SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Int(p->min_latency, 1, INT32_MAX));
32
-           break;
33
-       case 4:
34
-           param = spa_pod_builder_add_object(&b,
35
-               SPA_TYPE_OBJECT_PropInfo, id,
36
-               SPA_PROP_INFO_id,   SPA_POD_Id(SPA_PROP_maxLatency),
37
-               SPA_PROP_INFO_description, SPA_POD_String("The maximum latency"),
38
-               SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Int(p->max_latency, 1, INT32_MAX));
39
-           break;
40
-       case 5:
41
-           param = spa_pod_builder_add_object(&b,
42
-               SPA_TYPE_OBJECT_PropInfo, id,
43
                SPA_PROP_INFO_id,   SPA_POD_Id(SPA_PROP_latencyOffsetNsec),
44
                SPA_PROP_INFO_description, SPA_POD_String("Latency offset (ns)"),
45
                SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Long(0LL, 0LL, INT64_MAX));
46
            break;
47
-       case 6:
48
+       case 4:
49
            if (!this->is_iec958 && !this->is_hdmi)
50
                goto next;
51
            param = spa_pod_builder_add_object(&b,
52
@@ -193,7 +175,7 @@
53
                                 SPA_PROP_INFO_container, SPA_POD_Id(SPA_TYPE_Array));
54
            break;
55
        default:
56
-           param = spa_alsa_enum_propinfo(this, result.index - 7, &b);
57
+           param = spa_alsa_enum_propinfo(this, result.index - 5, &b);
58
            if (param == NULL)
59
                return 0;
60
        }
61
@@ -213,8 +195,6 @@
62
                SPA_PROP_device,       SPA_POD_Stringn(p->device, sizeof(p->device)),
63
                SPA_PROP_deviceName,   SPA_POD_Stringn(p->device_name, sizeof(p->device_name)),
64
                SPA_PROP_cardName,     SPA_POD_Stringn(p->card_name, sizeof(p->card_name)),
65
-               SPA_PROP_minLatency,   SPA_POD_Int(p->min_latency),
66
-               SPA_PROP_maxLatency,   SPA_POD_Int(p->max_latency),
67
                SPA_PROP_latencyOffsetNsec,   SPA_POD_Long(this->process_latency.ns),
68
                0);
69
 
70
@@ -343,8 +323,6 @@
71
        spa_pod_parse_object(param,
72
            SPA_TYPE_OBJECT_Props, NULL,
73
            SPA_PROP_device,       SPA_POD_OPT_Stringn(p->device, sizeof(p->device)),
74
-           SPA_PROP_minLatency,   SPA_POD_OPT_Int(&p->min_latency),
75
-           SPA_PROP_maxLatency,   SPA_POD_OPT_Int(&p->max_latency),
76
            SPA_PROP_latencyOffsetNsec,   SPA_POD_OPT_Long(&info.ns),
77
            SPA_PROP_iec958Codecs, SPA_POD_OPT_Pod(&iec958_codecs),
78
            SPA_PROP_params,       SPA_POD_OPT_Pod(&params));
79
@@ -363,8 +341,8 @@
80
            this->port_info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS;
81
            this->port_params[PORT_EnumFormat].user++;
82
        }
83
-       handle_process_latency(this, &info);
84
        spa_alsa_parse_prop_params(this, params);
85
+       handle_process_latency(this, &info);
86
 
87
        emit_node_info(this, false);
88
        emit_port_info(this, false);
89
@@ -551,8 +529,8 @@
90
            SPA_PARAM_BUFFERS_buffers, SPA_POD_CHOICE_RANGE_Int(2, 1, MAX_BUFFERS),
91
            SPA_PARAM_BUFFERS_blocks,  SPA_POD_Int(this->blocks),
92
            SPA_PARAM_BUFFERS_size,    SPA_POD_CHOICE_RANGE_Int(
93
-                           this->props.max_latency * this->frame_size,
94
-                           this->props.min_latency * this->frame_size,
95
+                           this->quantum_limit * this->frame_size,
96
+                           16 * this->frame_size,
97
                            INT32_MAX),
98
            SPA_PARAM_BUFFERS_stride,  SPA_POD_Int(this->frame_size));
99
        break;
100
pipewire-0.3.43.tar.gz/spa/plugins/alsa/alsa-pcm-source.c -> pipewire-0.3.44.tar.gz/spa/plugins/alsa/alsa-pcm-source.c Changed
88
 
1
@@ -44,14 +44,10 @@
2
 #define CHECK_PORT(this,d,p)    ((d) == SPA_DIRECTION_OUTPUT && (p) == 0)
3
 
4
 static const char default_device[] = "hw:0";
5
-static const uint32_t default_min_latency = MIN_LATENCY;
6
-static const uint32_t default_max_latency = MAX_LATENCY;
7
 
8
 static void reset_props(struct props *props)
9
 {
10
    strncpy(props->device, default_device, 64);
11
-   props->min_latency = default_min_latency;
12
-   props->max_latency = default_max_latency;
13
    props->use_chmap = DEFAULT_USE_CHMAP;
14
 }
15
 
16
@@ -69,7 +65,7 @@
17
        items[n_items++] = SPA_DICT_ITEM_INIT(SPA_KEY_MEDIA_CLASS, "Audio/Source");
18
        items[n_items++] = SPA_DICT_ITEM_INIT(SPA_KEY_NODE_DRIVER, "true");
19
        if (this->have_format) {
20
-           snprintf(latency, sizeof(latency), "%lu/%d", this->buffer_frames / 4, this->rate);
21
+           snprintf(latency, sizeof(latency), "%lu/%d", this->buffer_frames / 2, this->rate);
22
            items[n_items++] = SPA_DICT_ITEM_INIT(SPA_KEY_NODE_MAX_LATENCY, latency);
23
        }
24
        this->info.props = &SPA_DICT_INIT(items, n_items);
25
@@ -162,26 +158,12 @@
26
        case 3:
27
            param = spa_pod_builder_add_object(&b,
28
                SPA_TYPE_OBJECT_PropInfo, id,
29
-               SPA_PROP_INFO_id,   SPA_POD_Id(SPA_PROP_minLatency),
30
-               SPA_PROP_INFO_description, SPA_POD_String("The minimum latency"),
31
-               SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Int(p->min_latency, 1, INT32_MAX));
32
-           break;
33
-       case 4:
34
-           param = spa_pod_builder_add_object(&b,
35
-               SPA_TYPE_OBJECT_PropInfo, id,
36
-               SPA_PROP_INFO_id,   SPA_POD_Id(SPA_PROP_maxLatency),
37
-               SPA_PROP_INFO_description, SPA_POD_String("The maximum latency"),
38
-               SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Int(p->max_latency, 1, INT32_MAX));
39
-           break;
40
-       case 5:
41
-           param = spa_pod_builder_add_object(&b,
42
-               SPA_TYPE_OBJECT_PropInfo, id,
43
                SPA_PROP_INFO_id,   SPA_POD_Id(SPA_PROP_latencyOffsetNsec),
44
                SPA_PROP_INFO_description, SPA_POD_String("Latency offset (ns)"),
45
                SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Long(0LL, 0LL, INT64_MAX));
46
            break;
47
        default:
48
-           param = spa_alsa_enum_propinfo(this, result.index - 6, &b);
49
+           param = spa_alsa_enum_propinfo(this, result.index - 4, &b);
50
            if (param == NULL)
51
                return 0;
52
        }
53
@@ -199,8 +181,6 @@
54
                SPA_PROP_device,       SPA_POD_Stringn(p->device, sizeof(p->device)),
55
                SPA_PROP_deviceName,   SPA_POD_Stringn(p->device_name, sizeof(p->device_name)),
56
                SPA_PROP_cardName,     SPA_POD_Stringn(p->card_name, sizeof(p->card_name)),
57
-               SPA_PROP_minLatency,   SPA_POD_Int(p->min_latency),
58
-               SPA_PROP_maxLatency,   SPA_POD_Int(p->max_latency),
59
                SPA_PROP_latencyOffsetNsec,   SPA_POD_Long(this->process_latency.ns),
60
                0);
61
            spa_alsa_add_prop_params(this, &b);
62
@@ -323,13 +303,11 @@
63
        spa_pod_parse_object(param,
64
            SPA_TYPE_OBJECT_Props, NULL,
65
            SPA_PROP_device,       SPA_POD_OPT_Stringn(p->device, sizeof(p->device)),
66
-           SPA_PROP_minLatency,   SPA_POD_OPT_Int(&p->min_latency),
67
-           SPA_PROP_maxLatency,   SPA_POD_OPT_Int(&p->max_latency),
68
            SPA_PROP_latencyOffsetNsec,   SPA_POD_OPT_Long(&info.ns),
69
            SPA_PROP_params,       SPA_POD_OPT_Pod(&params));
70
 
71
-       handle_process_latency(this, &info);
72
        spa_alsa_parse_prop_params(this, params);
73
+       handle_process_latency(this, &info);
74
 
75
        emit_node_info(this, false);
76
        emit_port_info(this, false);
77
@@ -500,8 +478,8 @@
78
            SPA_PARAM_BUFFERS_buffers, SPA_POD_CHOICE_RANGE_Int(2, 1, MAX_BUFFERS),
79
            SPA_PARAM_BUFFERS_blocks,  SPA_POD_Int(this->blocks),
80
            SPA_PARAM_BUFFERS_size,    SPA_POD_CHOICE_RANGE_Int(
81
-                           this->props.max_latency * this->frame_size,
82
-                           this->props.min_latency * this->frame_size,
83
+                           this->quantum_limit * this->frame_size,
84
+                           16 * this->frame_size,
85
                            INT32_MAX),
86
            SPA_PARAM_BUFFERS_stride,  SPA_POD_Int(this->frame_size));
87
        break;
88
pipewire-0.3.43.tar.gz/spa/plugins/alsa/alsa-pcm.c -> pipewire-0.3.44.tar.gz/spa/plugins/alsa/alsa-pcm.c Changed
154
 
1
@@ -125,6 +125,10 @@
2
        state->props.use_chmap = spa_atob(s);
3
    } else if (spa_streq(k, "api.alsa.multi-rate")) {
4
        state->multi_rate = spa_atob(s);
5
+   } else if (spa_streq(k, "latency.internal.rate")) {
6
+       state->process_latency.rate = atoi(s);
7
+   } else if (spa_streq(k, "latency.internal.ns")) {
8
+       state->process_latency.ns = atoi(s);
9
    } else if (spa_streq(k, "clock.name")) {
10
        spa_scnprintf(state->clock_name,
11
                sizeof(state->clock_name), "%s", s);
12
@@ -295,6 +299,22 @@
13
    case 13:
14
        param = spa_pod_builder_add_object(b,
15
            SPA_TYPE_OBJECT_PropInfo, SPA_PARAM_PropInfo,
16
+           SPA_PROP_INFO_name, SPA_POD_String("latency.internal.rate"),
17
+           SPA_PROP_INFO_description, SPA_POD_String("Internal latency in samples"),
18
+           SPA_PROP_INFO_type, SPA_POD_Int(state->process_latency.rate),
19
+           SPA_PROP_INFO_params, SPA_POD_Bool(true));
20
+       break;
21
+   case 14:
22
+       param = spa_pod_builder_add_object(b,
23
+           SPA_TYPE_OBJECT_PropInfo, SPA_PARAM_PropInfo,
24
+           SPA_PROP_INFO_name, SPA_POD_String("latency.internal.ns"),
25
+           SPA_PROP_INFO_description, SPA_POD_String("Internal latency in nanoseconds"),
26
+           SPA_PROP_INFO_type, SPA_POD_Long(state->process_latency.ns),
27
+           SPA_PROP_INFO_params, SPA_POD_Bool(true));
28
+       break;
29
+   case 15:
30
+       param = spa_pod_builder_add_object(b,
31
+           SPA_TYPE_OBJECT_PropInfo, SPA_PARAM_PropInfo,
32
            SPA_PROP_INFO_name, SPA_POD_String("clock.name"),
33
            SPA_PROP_INFO_description, SPA_POD_String("The name of the clock"),
34
            SPA_PROP_INFO_type, SPA_POD_String(state->clock_name),
35
@@ -358,6 +378,12 @@
36
    spa_pod_builder_string(b, "api.alsa.multi-rate");
37
    spa_pod_builder_bool(b, state->multi_rate);
38
 
39
+   spa_pod_builder_string(b, "latency.internal.rate");
40
+   spa_pod_builder_int(b, state->process_latency.rate);
41
+
42
+   spa_pod_builder_string(b, "latency.internal.ns");
43
+   spa_pod_builder_long(b, state->process_latency.ns);
44
+
45
    spa_pod_builder_string(b, "clock.name");
46
    spa_pod_builder_string(b, state->clock_name);
47
 
48
@@ -391,8 +417,11 @@
49
        if (spa_pod_is_string(pod)) {
50
            spa_pod_copy_string(pod, sizeof(value), value);
51
        } else if (spa_pod_is_int(pod)) {
52
-           snprintf(value, sizeof(value), "%u",
53
+           snprintf(value, sizeof(value), "%d",
54
                    SPA_POD_VALUE(struct spa_pod_int, pod));
55
+       } else if (spa_pod_is_long(pod)) {
56
+           snprintf(value, sizeof(value), "%"PRIi64,
57
+                   SPA_POD_VALUE(struct spa_pod_long, pod));
58
        } else if (spa_pod_is_bool(pod)) {
59
            snprintf(value, sizeof(value), "%s",
60
                    SPA_POD_VALUE(struct spa_pod_bool, pod) ?
61
@@ -427,10 +456,8 @@
62
            state->card_index = atoi(s);
63
        } else if (spa_streq(k, SPA_KEY_API_ALSA_OPEN_UCM)) {
64
            state->open_ucm = spa_atob(s);
65
-       } else if (spa_streq(k, "latency.internal.rate")) {
66
-           state->process_latency.rate = atoi(s);
67
-       } else if (spa_streq(k, "latency.internal.ns")) {
68
-           state->process_latency.ns = atoi(s);
69
+       } else if (spa_streq(k, "clock.quantum-limit")) {
70
+           spa_atou32(s, &state->quantum_limit, 0);
71
        } else {
72
            alsa_set_param(state, k, s);
73
        }
74
@@ -732,31 +759,32 @@
75
    CHECK(snd_pcm_hw_params_get_rate_min(params, &min, &dir), "get_rate_min");
76
    CHECK(snd_pcm_hw_params_get_rate_max(params, &max, &dir), "get_rate_max");
77
 
78
-   rate = state->default_rate;
79
    if (!state->multi_rate && state->card->format_ref > 0)
80
        rate = state->card->rate;
81
+   else
82
+       rate = state->default_rate;
83
 
84
-   if (rate != 0 && !all) {
85
-       if (min < rate)
86
-           min = rate;
87
-       if (max > rate)
88
-           max = rate;
89
-   }
90
+   if (rate < min || rate > max)
91
+       rate = 0;
92
+
93
+   if (rate != 0 && !all)
94
+       min = max = rate;
95
+
96
+   if (rate == 0)
97
+       rate = state->position ? state->position->clock.rate.denom : DEFAULT_RATE;
98
+
99
+   rate = SPA_CLAMP(rate, min, max);
100
 
101
    spa_pod_builder_prop(b, SPA_FORMAT_AUDIO_rate, 0);
102
 
103
    spa_pod_builder_push_choice(b, &f[0], SPA_CHOICE_None, 0);
104
    choice = (struct spa_pod_choice*)spa_pod_builder_frame(b, &f[0]);
105
 
106
-   if (rate == 0)
107
-       rate = state->position ? state->position->clock.rate.denom : DEFAULT_RATE;
108
-
109
    if (state->n_allowed_rates > 0) {
110
        uint32_t i, v, last = 0, count = 0;
111
 
112
-       v = SPA_CLAMP(rate, min, max);
113
-       if (uint32_array_contains(state->allowed_rates, state->n_allowed_rates, v)) {
114
-           spa_pod_builder_int(b, v * scale);
115
+       if (uint32_array_contains(state->allowed_rates, state->n_allowed_rates, rate)) {
116
+           spa_pod_builder_int(b, rate * scale);
117
            count++;
118
        }
119
        for (i = 0; i < state->n_allowed_rates; i++) {
120
@@ -773,7 +801,7 @@
121
        if (count > 1)
122
            choice->body.type = SPA_CHOICE_Enum;
123
    } else {
124
-       spa_pod_builder_int(b, SPA_CLAMP(rate, min, max) * scale);
125
+       spa_pod_builder_int(b, rate * scale);
126
 
127
        if (min != max) {
128
            spa_pod_builder_int(b, min * scale);
129
@@ -1419,9 +1447,13 @@
130
    if (is_batch) {
131
        if (period_size == 0)
132
            period_size = state->position ? state->position->clock.duration : DEFAULT_PERIOD;
133
+       if (period_size == 0)
134
+           period_size = DEFAULT_PERIOD;
135
        /* batch devices get their hw pointers updated every period. Make
136
-        * the period smaller and add one period of headroom */
137
-       period_size /= 2;
138
+        * the period smaller and add one period of headroom. Limit the
139
+        * period size to our default so that we don't create too much
140
+        * headroom. */
141
+       period_size = SPA_MIN(period_size, DEFAULT_PERIOD) / 2;
142
        spa_log_info(state->log, "%s: batch mode, period_size:%ld",
143
            state->props.device, period_size);
144
    } else {
145
@@ -2306,7 +2338,7 @@
146
    else {
147
        spa_log_warn(state->log, "%s: no position set, using defaults",
148
                state->props.device);
149
-       state->duration = state->props.min_latency;
150
+       state->duration = 1024;
151
        state->rate_denom = state->rate;
152
    }
153
 
154
pipewire-0.3.43.tar.gz/spa/plugins/alsa/alsa-pcm.h -> pipewire-0.3.44.tar.gz/spa/plugins/alsa/alsa-pcm.h Changed
28
 
1
@@ -52,9 +52,6 @@
2
 
3
 #include "dll.h"
4
 
5
-#define MIN_LATENCY    16
6
-#define MAX_LATENCY    8192
7
-
8
 #define MAX_RATES  16
9
 
10
 #define DEFAULT_PERIOD     1024u
11
@@ -66,8 +63,6 @@
12
    char device[64];
13
    char device_name[128];
14
    char card_name[128];
15
-   uint32_t min_latency;
16
-   uint32_t max_latency;
17
    bool use_chmap;
18
 };
19
 
20
@@ -148,6 +143,7 @@
21
    unsigned int disable_mmap;
22
    unsigned int disable_batch;
23
    char clock_name[64];
24
+   uint32_t quantum_limit;
25
 
26
    snd_pcm_uframes_t buffer_frames;
27
    snd_pcm_uframes_t period_frames;
28
pipewire-0.3.43.tar.gz/spa/plugins/alsa/alsa-udev.c -> pipewire-0.3.44.tar.gz/spa/plugins/alsa/alsa-udev.c Changed
270
 
1
@@ -47,6 +47,9 @@
2
 
3
 #define MAX_DEVICES    64
4
 
5
+#define RETRY_COUNT    1
6
+#define RETRY_MSEC 2000
7
+
8
 #define ACTION_ADD 0
9
 #define ACTION_REMOVE  1
10
 #define ACTION_DISABLE 2
11
@@ -54,6 +57,7 @@
12
 struct device {
13
    uint32_t id;
14
    struct udev_device *dev;
15
+   uint8_t retry;
16
    unsigned int accessible:1;
17
    unsigned int ignored:1;
18
    unsigned int emitted:1;
19
@@ -65,6 +69,7 @@
20
 
21
    struct spa_log *log;
22
    struct spa_loop *main_loop;
23
+   struct spa_system *main_system;
24
 
25
    struct spa_hook_list hooks;
26
 
27
@@ -79,6 +84,7 @@
28
 
29
    struct spa_source source;
30
    struct spa_source notify;
31
+   struct spa_source retry_timer;
32
    unsigned int use_acp:1;
33
 };
34
 
35
@@ -243,6 +249,39 @@
36
    *d = 0;
37
 }
38
 
39
+static int check_device_busy(struct impl *this, struct device *device, snd_ctl_t *ctl_hndl)
40
+{
41
+   int dev;
42
+
43
+   /* Check if some pcm devices of the card cannot be opened because they are busy */
44
+
45
+   for (dev = -1; snd_ctl_pcm_next_device(ctl_hndl, &dev) >= 0 && dev >= 0;) {
46
+       char devpath[64];
47
+       int i;
48
+
49
+       snprintf(devpath, sizeof(devpath), "hw:%u,%u", device->id, dev);
50
+
51
+       for (i = 0; i < 2; ++i) {
52
+           snd_pcm_t *handle;
53
+           int res;
54
+
55
+           res = snd_pcm_open(&handle, devpath,
56
+                   (i == 0) ? SND_PCM_STREAM_PLAYBACK : SND_PCM_STREAM_CAPTURE,
57
+                   SND_PCM_NONBLOCK | SND_PCM_NO_AUTO_RESAMPLE |
58
+                   SND_PCM_NO_AUTO_CHANNELS | SND_PCM_NO_AUTO_FORMAT);
59
+           if (res == -EBUSY) {
60
+               spa_log_debug(this->log, "pcm device %s busy", devpath);
61
+               return -EBUSY;
62
+           } else if (res >= 0) {
63
+               snd_pcm_close(handle);
64
+           }
65
+       }
66
+       spa_log_debug(this->log, "pcm device %s free", devpath);
67
+   }
68
+
69
+   return 0;
70
+}
71
+
72
 static int emit_object_info(struct impl *this, struct device *device)
73
 {
74
    struct spa_device_object_info info;
75
@@ -267,20 +306,24 @@
76
    pcm = -1;
77
    res = snd_ctl_pcm_next_device(ctl_hndl, &pcm);
78
 
79
-   spa_log_debug(this->log, "close card %s", path);
80
-   snd_ctl_close(ctl_hndl);
81
-
82
    if (res < 0) {
83
        spa_log_error(this->log, "error iterating devices: %s", snd_strerror(res));
84
        device->ignored = true;
85
-       return res;
86
-   }
87
-   if (pcm < 0) {
88
+   } else if (pcm < 0) {
89
        spa_log_debug(this->log, "no pcm devices for %s", path);
90
        device->ignored = true;
91
-       return 0;
92
+       res = 0;
93
+   } else if (device->retry > 0) {
94
+       /* Check if we can open all PCM devices (retry later if not) */
95
+       res = check_device_busy(this, device, ctl_hndl);
96
    }
97
 
98
+   spa_log_debug(this->log, "close card %s", path);
99
+   snd_ctl_close(ctl_hndl);
100
+
101
+   if (res < 0 || device->ignored)
102
+       return res;
103
+
104
    info = SPA_DEVICE_OBJECT_INFO_INIT();
105
 
106
    info.type = SPA_TYPE_INTERFACE_Device;
107
@@ -393,6 +436,82 @@
108
    return 1;
109
 }
110
 
111
+static void start_retry(struct impl *this);
112
+
113
+static void stop_retry(struct impl *this);
114
+
115
+static void retry_timer_event(struct spa_source *source)
116
+{
117
+   struct impl *this = source->data;
118
+   bool have_retry = false;
119
+   size_t i;
120
+
121
+   stop_retry(this);
122
+
123
+   for (i = 0; i < this->n_devices; ++i) {
124
+       struct device *device = &this->devices[i];
125
+       if (device->ignored)
126
+           device->retry = 0;
127
+       if (device->retry > 0) {
128
+           --device->retry;
129
+
130
+           spa_log_debug(this->log, "retrying device %u", device->id);
131
+
132
+           if (emit_object_info(this, device) == -EBUSY) {
133
+               spa_log_debug(this->log, "device %u busy (remaining retries %u)",
134
+                       device->id, device->retry);
135
+           } else {
136
+               device->retry = 0;
137
+           }
138
+       }
139
+       if (device->retry > 0)
140
+           have_retry = true;
141
+   }
142
+
143
+   if (have_retry)
144
+       start_retry(this);
145
+}
146
+
147
+static void start_retry(struct impl *this)
148
+{
149
+   struct itimerspec ts;
150
+
151
+   spa_log_debug(this->log, "start retry");
152
+
153
+   if (this->retry_timer.data == NULL) {
154
+       this->retry_timer.data = this;
155
+       this->retry_timer.func = retry_timer_event;
156
+       this->retry_timer.mask = SPA_IO_IN;
157
+       this->retry_timer.rmask = 0;
158
+       spa_loop_add_source(this->main_loop, &this->retry_timer);
159
+   }
160
+
161
+   ts.it_value.tv_sec = ((uint64_t)RETRY_MSEC * SPA_NSEC_PER_MSEC) / SPA_NSEC_PER_SEC;
162
+   ts.it_value.tv_nsec = ((uint64_t)RETRY_MSEC * SPA_NSEC_PER_MSEC) % SPA_NSEC_PER_SEC;
163
+   ts.it_interval.tv_sec = 0;
164
+   ts.it_interval.tv_nsec = 0;
165
+   spa_system_timerfd_settime(this->main_system, this->retry_timer.fd, 0, &ts, NULL);
166
+}
167
+
168
+static void stop_retry(struct impl *this)
169
+{
170
+   struct itimerspec ts;
171
+
172
+   if (this->retry_timer.data == NULL)
173
+       return;
174
+
175
+   spa_log_debug(this->log, "stop retry");
176
+
177
+   spa_loop_remove_source(this->main_loop, &this->retry_timer);
178
+   this->retry_timer.data = NULL;
179
+
180
+   ts.it_value.tv_sec = 0;
181
+   ts.it_value.tv_nsec = 0;
182
+   ts.it_interval.tv_sec = 0;
183
+   ts.it_interval.tv_nsec = 0;
184
+   spa_system_timerfd_settime(this->main_system, this->retry_timer.fd, 0, &ts, NULL);
185
+}
186
+
187
 static bool check_access(struct impl *this, struct device *device)
188
 {
189
    char path[128];
190
@@ -425,7 +544,14 @@
191
            return;
192
        if (!check_access(this, device))
193
            return;
194
-       emit_object_info(this, device);
195
+       device->retry = RETRY_COUNT;
196
+       if (emit_object_info(this, device) == -EBUSY) {
197
+           spa_log_debug(this->log, "device %u busy (remaining retries %u)",
198
+                   device->id, device->retry);
199
+           start_retry(this);
200
+       } else {
201
+           device->retry = 0;
202
+       }
203
        break;
204
 
205
    case ACTION_REMOVE:
206
@@ -440,6 +566,7 @@
207
    case ACTION_DISABLE:
208
        if (device == NULL)
209
            return;
210
+       device->retry = 0;
211
        if (device->emitted) {
212
            device->emitted = false;
213
            spa_device_emit_object_info(&this->hooks, id, NULL);
214
@@ -687,10 +814,10 @@
215
 
216
    emit_device_info(this, true);
217
 
218
-   if ((res = enum_devices(this)) < 0)
219
+   if ((res = start_monitor(this)) < 0)
220
        return res;
221
 
222
-   if ((res = start_monitor(this)) < 0)
223
+   if ((res = enum_devices(this)) < 0)
224
        return res;
225
 
226
         spa_hook_list_join(&this->hooks, &save);
227
@@ -728,6 +855,10 @@
228
    struct impl *this = (struct impl *) handle;
229
    stop_monitor(this);
230
    impl_udev_close(this);
231
+   stop_retry(this);
232
+   if (this->retry_timer.fd >= 0)
233
+       spa_system_close(this->main_system, this->retry_timer.fd);
234
+   this->retry_timer.fd = -1;
235
    return 0;
236
 }
237
 
238
@@ -756,15 +887,21 @@
239
 
240
    this = (struct impl *) handle;
241
    this->notify.fd = -1;
242
+   this->retry_timer.fd = -1;
243
 
244
    this->log = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_Log);
245
    alsa_log_topic_init(this->log);
246
    this->main_loop = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_Loop);
247
+   this->main_system = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_System);
248
 
249
    if (this->main_loop == NULL) {
250
        spa_log_error(this->log, "a main-loop is needed");
251
        return -EINVAL;
252
    }
253
+   if (this->main_system == NULL) {
254
+       spa_log_error(this->log, "a main-system is needed");
255
+       return -EINVAL;
256
+   }
257
    spa_hook_list_init(&this->hooks);
258
 
259
    this->device.iface = SPA_INTERFACE_INIT(
260
@@ -782,6 +919,9 @@
261
            this->use_acp = spa_atob(str);
262
    }
263
 
264
+   this->retry_timer.fd = spa_system_timerfd_create(this->main_system,
265
+           CLOCK_MONOTONIC, SPA_FD_CLOEXEC | SPA_FD_NONBLOCK);
266
+
267
    return 0;
268
 }
269
 
270
pipewire-0.3.43.tar.gz/spa/plugins/audioconvert/audioadapter.c -> pipewire-0.3.44.tar.gz/spa/plugins/audioconvert/audioadapter.c Changed
27
 
1
@@ -118,19 +118,20 @@
2
                 struct spa_pod_builder *builder)
3
 {
4
    int res;
5
-   if (result->next < 0x10000) {
6
+   if (result->next < 0x100000) {
7
        if ((res = spa_node_enum_params_sync(this->convert,
8
                id, &result->next, filter, &result->param, builder)) == 1)
9
            return res;
10
-       result->next = 0x10000;
11
+       result->next = 0x100000;
12
    }
13
-   if (result->next >= 0x10000 && this->follower_params_flags[idx] & SPA_PARAM_INFO_READ) {
14
-       result->next &= 0xffff;
15
+   if (result->next < 0x200000 && this->follower_params_flags[idx] & SPA_PARAM_INFO_READ) {
16
+       result->next &= 0xfffff;
17
        if ((res = spa_node_enum_params_sync(this->follower,
18
                id, &result->next, filter, &result->param, builder)) == 1) {
19
-           result->next |= 0x10000;
20
+           result->next |= 0x100000;
21
            return res;
22
        }
23
+       result->next = 0x200000;
24
    }
25
    return 0;
26
 }
27
pipewire-0.3.43.tar.gz/spa/plugins/audioconvert/audioconvert.c -> pipewire-0.3.44.tar.gz/spa/plugins/audioconvert/audioconvert.c Changed
51
 
1
@@ -472,13 +472,22 @@
2
        }
3
        result->next = 0x1000;
4
    }
5
-   if (result->next >= 0x1000) {
6
+   if (result->next < 0x2000) {
7
        result->next &= 0xfff;
8
        if ((res = spa_node_enum_params_sync(this->channelmix,
9
                id, &result->next, filter, &result->param, builder)) == 1) {
10
            result->next |= 0x1000;
11
            return res;
12
        }
13
+       result->next = 0x2000;
14
+   }
15
+   if (result->next >= 0x2000) {
16
+       result->next &= 0xfff;
17
+       if ((res = spa_node_enum_params_sync(this->resample,
18
+               id, &result->next, filter, &result->param, builder)) == 1) {
19
+           result->next |= 0x2000;
20
+           return res;
21
+       }
22
    }
23
    return 0;
24
 }
25
@@ -881,6 +890,7 @@
26
        if (this->fmt[SPA_DIRECTION_INPUT] == this->merger)
27
            res = spa_node_set_param(this->merger, id, flags, param);
28
        res = spa_node_set_param(this->channelmix, id, flags, param);
29
+       res = spa_node_set_param(this->resample, id, flags, param);
30
        break;
31
    }
32
    default:
33
@@ -1112,11 +1122,12 @@
34
 
35
    switch (id) {
36
    case SPA_PARAM_Latency:
37
-       target = this->fmt[SPA_DIRECTION_REVERSE(direction)];
38
-       port_id = 0;
39
-       if ((res = spa_node_port_set_param(target,
40
-                   direction, port_id, id, flags, param)) < 0)
41
-           return res;
42
+       if (port_id == 0) {
43
+           target = this->fmt[SPA_DIRECTION_REVERSE(direction)];
44
+           if ((res = spa_node_port_set_param(target,
45
+                       direction, port_id, id, flags, param)) < 0)
46
+               return res;
47
+       }
48
        break;
49
    }
50
 
51
pipewire-0.3.43.tar.gz/spa/plugins/audioconvert/channelmix-ops.c -> pipewire-0.3.44.tar.gz/spa/plugins/audioconvert/channelmix-ops.c Changed
87
 
1
@@ -149,17 +149,16 @@
2
    float matrix[SPA_AUDIO_MAX_CHANNELS][SPA_AUDIO_MAX_CHANNELS] = {{ 0.0f }};
3
    uint64_t src_mask = mix->src_mask;
4
    uint64_t dst_mask = mix->dst_mask;
5
-   uint64_t unassigned;
6
+   uint64_t unassigned, keep;
7
    uint32_t i, j, ic, jc, matrix_encoding = MATRIX_NORMAL;
8
    float clev = SQRT1_2;
9
    float slev = SQRT1_2;
10
    float llev = 0.5f;
11
    float maxsum = 0.0f;
12
-   bool do_upmix = SPA_FLAG_IS_SET(mix->options, CHANNELMIX_OPTION_UPMIX);
13
 #define _MATRIX(s,d)   matrix[_CH(s)][_CH(d)]
14
 
15
-   spa_log_debug(mix->log, "src-mask:%08"PRIx64" dst-mask:%08"PRIx64,
16
-           src_mask, dst_mask);
17
+   spa_log_debug(mix->log, "src-mask:%08"PRIx64" dst-mask:%08"PRIx64
18
+           " options:%08x", src_mask, dst_mask, mix->options);
19
 
20
    /* move the MONO mask to FRONT so that the lower bits can be shifted
21
     * away. */
22
@@ -207,6 +206,14 @@
23
    }
24
 
25
    unassigned = src_mask & ~dst_mask;
26
+   keep = dst_mask & ~src_mask;
27
+
28
+   if (!SPA_FLAG_IS_SET(mix->options, CHANNELMIX_OPTION_UPMIX))
29
+       keep = 0;
30
+
31
+   keep |= FRONT;
32
+   if (mix->lfe_cutoff > 0.0f)
33
+       keep |= _MASK(LFE);
34
 
35
    spa_log_debug(mix->log, "unassigned downmix %08" PRIx64, unassigned);
36
 
37
@@ -232,6 +239,7 @@
38
            _MATRIX(FC,FR) += SQRT1_2;
39
            if (src_mask & FRONT)
40
                _MATRIX(FC,FC) = clev * SQRT2;
41
+           keep &= ~FRONT;
42
        } else {
43
            spa_log_warn(mix->log, "can't assign STEREO");
44
        }
45
@@ -374,12 +382,10 @@
46
        }
47
    }
48
 
49
-   if (!do_upmix)
50
-       goto done;
51
-
52
-   unassigned = dst_mask & ~src_mask;
53
+   unassigned = dst_mask & ~src_mask & keep;
54
 
55
-   spa_log_debug(mix->log, "unassigned upmix %08" PRIx64, unassigned);
56
+   spa_log_debug(mix->log, "unassigned upmix %08"PRIx64" lfe:%f",
57
+           unassigned, mix->lfe_cutoff);
58
 
59
    if (unassigned & FRONT) {
60
        if ((src_mask & STEREO) == STEREO) {
61
@@ -390,7 +396,7 @@
62
            spa_log_warn(mix->log, "can't produce FC");
63
        }
64
    }
65
-   if (unassigned & _MASK(LFE) && mix->lfe_cutoff > 0.0f) {
66
+   if (unassigned & _MASK(LFE)) {
67
        if ((src_mask & STEREO) == STEREO) {
68
            spa_log_debug(mix->log, "produce LFE from STEREO");
69
            _MATRIX(LFE,FL) += llev;
70
@@ -445,7 +451,7 @@
71
            sum += fabs(matrix[i][j]);
72
        }
73
        maxsum = SPA_MAX(maxsum, sum);
74
-       if (i == _CH(LFE) && do_upmix && mix->lfe_cutoff > 0.0f) {
75
+       if (i == _CH(LFE) && mix->lfe_cutoff > 0.0f) {
76
            spa_log_debug(mix->log, "channel %d is LFE", ic);
77
            lr4_set(&mix->lr4[ic], BQ_LOWPASS, mix->lfe_cutoff / mix->freq);
78
            mix->lr4_info[ic] = 1;
79
@@ -456,6 +462,7 @@
80
    }
81
    if (SPA_FLAG_IS_SET(mix->options, CHANNELMIX_OPTION_NORMALIZE) &&
82
        maxsum > 1.0f) {
83
+       spa_log_debug(mix->log, "normalize %f", maxsum);
84
        for (i = 0; i < ic; i++)
85
            for (j = 0; j < jc; j++)
86
                        mix->matrix_orig[i][j] /= maxsum;
87
pipewire-0.3.43.tar.gz/spa/plugins/audioconvert/channelmix.c -> pipewire-0.3.44.tar.gz/spa/plugins/audioconvert/channelmix.c Changed
147
 
1
@@ -48,7 +48,6 @@
2
 #define DEFAULT_RATE       48000
3
 #define DEFAULT_CHANNELS   2
4
 
5
-#define DEFAULT_SAMPLES    8192
6
 #define MAX_BUFFERS    32
7
 #define MAX_DATAS  SPA_AUDIO_MAX_CHANNELS
8
 
9
@@ -82,6 +81,7 @@
10
    struct volumes soft;
11
    struct volumes monitor;
12
    unsigned int have_soft_volume:1;
13
+   unsigned int disabled:1;
14
 };
15
 
16
 static void props_reset(struct props *props)
17
@@ -142,6 +142,7 @@
18
 
19
    struct spa_log *log;
20
    struct spa_cpu *cpu;
21
+   uint32_t quantum_limit;
22
 
23
    struct spa_io_position *io_position;
24
 
25
@@ -363,6 +364,8 @@
26
    emit_props_changed(this);
27
 
28
    this->is_passthrough = SPA_FLAG_IS_SET(this->mix.flags, CHANNELMIX_FLAG_IDENTITY);
29
+   if (!this->is_passthrough && this->props.disabled)
30
+       return -EINVAL;
31
 
32
    spa_log_debug(this->log, "%p: got channelmix features %08x:%08x flags:%08x passthrough:%d",
33
            this, this->cpu_flags, this->mix.cpu_flags,
34
@@ -495,6 +498,14 @@
35
                    this->mix.lfe_cutoff, 0.0, 1000.0),
36
                SPA_PROP_INFO_params, SPA_POD_Bool(true));
37
            break;
38
+       case 12:
39
+           param = spa_pod_builder_add_object(&b,
40
+               SPA_TYPE_OBJECT_PropInfo, id,
41
+               SPA_PROP_INFO_name, SPA_POD_String("channelmix.disable"),
42
+               SPA_PROP_INFO_description, SPA_POD_String("Disable Channel mixing"),
43
+               SPA_PROP_INFO_type, SPA_POD_CHOICE_Bool(p->disabled),
44
+               SPA_PROP_INFO_params, SPA_POD_Bool(true));
45
+           break;
46
        default:
47
            return 0;
48
        }
49
@@ -544,6 +555,8 @@
50
                        CHANNELMIX_OPTION_UPMIX));
51
            spa_pod_builder_string(&b, "channelmix.lfe-cutoff");
52
            spa_pod_builder_float(&b, this->mix.lfe_cutoff);
53
+           spa_pod_builder_string(&b, "channelmix.disable");
54
+           spa_pod_builder_bool(&b, this->props.disabled);
55
            spa_pod_builder_pop(&b, &f[1]);
56
            param = spa_pod_builder_pop(&b, &f[0]);
57
            break;
58
@@ -577,6 +590,8 @@
59
        SPA_FLAG_UPDATE(this->mix.options, CHANNELMIX_OPTION_UPMIX, spa_atob(s));
60
    else if (spa_streq(k, "channelmix.lfe-cutoff"))
61
        this->mix.lfe_cutoff = atoi(s);
62
+   else if (spa_streq(k, "channelmix.disable"))
63
+       this->props.disabled = spa_atob(s);
64
    return 0;
65
 }
66
 
67
@@ -634,6 +649,9 @@
68
    if (param == NULL)
69
        return 0;
70
 
71
+   if (this->props.disabled)
72
+       return 0;
73
+
74
    SPA_POD_OBJECT_FOREACH(obj, prop) {
75
        switch (prop->key) {
76
        case SPA_PROP_volume:
77
@@ -716,6 +734,9 @@
78
    if (size < 3)
79
        return -EINVAL;
80
 
81
+   if (this->props.disabled)
82
+       return 0;
83
+
84
    if ((val[0] & 0xf0) != 0xb0 || val[1] != 7)
85
        return 0;
86
 
87
@@ -863,6 +884,7 @@
88
        } else {
89
            struct spa_pod_frame f;
90
            struct port *other;
91
+           int32_t channels, min = 1, max = INT32_MAX;
92
 
93
            other = GET_PORT(this, SPA_DIRECTION_REVERSE(direction), 0);
94
 
95
@@ -875,19 +897,24 @@
96
                0);
97
 
98
            if (other->have_format) {
99
+               channels = other->format.info.raw.channels;
100
+               if (this->props.disabled)
101
+                   min = max = channels;
102
+
103
                spa_pod_builder_add(builder,
104
                    SPA_FORMAT_AUDIO_rate, SPA_POD_Int(other->format.info.raw.rate),
105
                    SPA_FORMAT_AUDIO_channels, SPA_POD_CHOICE_RANGE_Int(
106
-                       other->format.info.raw.channels, 1, INT32_MAX),
107
+                       channels, min, max),
108
                    0);
109
            } else {
110
                uint32_t rate = this->io_position ?
111
                    this->io_position->clock.rate.denom : DEFAULT_RATE;
112
+               channels = DEFAULT_CHANNELS;
113
 
114
                spa_pod_builder_add(builder,
115
                    SPA_FORMAT_AUDIO_rate, SPA_POD_CHOICE_RANGE_Int(rate, 0, INT32_MAX),
116
                    SPA_FORMAT_AUDIO_channels, SPA_POD_CHOICE_RANGE_Int(
117
-                       DEFAULT_CHANNELS, 1, INT32_MAX),
118
+                       channels, min, max),
119
                    0);
120
            }
121
            *param = spa_pod_builder_pop(builder, &f);
122
@@ -978,7 +1005,7 @@
123
                size = other->size / other->stride;
124
            } else {
125
                buffers = 1;
126
-               size = DEFAULT_SAMPLES;
127
+               size = this->quantum_limit;
128
            }
129
 
130
            param = spa_pod_builder_add_object(&b,
131
@@ -1539,11 +1566,15 @@
132
 
133
    props_reset(&this->props);
134
 
135
+   this->mix.options = CHANNELMIX_OPTION_NORMALIZE;
136
+
137
    for (i = 0; info && i < info->n_items; i++) {
138
        const char *k = info->items[i].key;
139
        const char *s = info->items[i].value;
140
        if (spa_streq(k, SPA_KEY_AUDIO_POSITION))
141
            this->props.n_channels = parse_position(this->props.channel_map, s, strlen(s));
142
+       else if (spa_streq(k, "clock.quantum-limit"))
143
+           spa_atou32(s, &this->quantum_limit, 0);
144
        else
145
            channelmix_set_param(this, k, s);
146
 
147
pipewire-0.3.43.tar.gz/spa/plugins/audioconvert/fmt-ops-c.c -> pipewire-0.3.44.tar.gz/spa/plugins/audioconvert/fmt-ops-c.c Changed
219
 
1
@@ -99,6 +99,22 @@
2
 }
3
 
4
 void
5
+conv_copy64d_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
6
+       uint32_t n_samples)
7
+{
8
+   uint32_t i, n_channels = conv->n_channels;
9
+   for (i = 0; i < n_channels; i++)
10
+       spa_memcpy(dst[i], src[i], n_samples * sizeof(int64_t));
11
+}
12
+
13
+void
14
+conv_copy64_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
15
+       uint32_t n_samples)
16
+{
17
+   spa_memcpy(dst[0], src[0], n_samples * sizeof(int64_t) * conv->n_channels);
18
+}
19
+
20
+void
21
 conv_u8d_to_f32d_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
22
        uint32_t n_samples)
23
 {
24
@@ -650,6 +666,77 @@
25
 }
26
 
27
 void
28
+conv_f64d_to_f32d_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
29
+       uint32_t n_samples)
30
+{
31
+   uint32_t i, j, n_channels = conv->n_channels;
32
+
33
+   for (i = 0; i < n_channels; i++) {
34
+       const double *s = src[i];
35
+       float *d = dst[i];
36
+
37
+       for (j = 0; j < n_samples; j++)
38
+           d[j] = s[j];
39
+   }
40
+}
41
+
42
+void
43
+conv_f64_to_f32_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
44
+       uint32_t n_samples)
45
+{
46
+   uint32_t i, n_channels = conv->n_channels;
47
+   const double *s = src[0];
48
+   float *d = dst[0];
49
+
50
+   n_samples *= n_channels;
51
+
52
+   for (i = 0; i < n_samples; i++)
53
+       d[i] = s[i];
54
+}
55
+
56
+void
57
+conv_f64_to_f32d_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
58
+       uint32_t n_samples)
59
+{
60
+   const double *s = src[0];
61
+   float **d = (float **) dst;
62
+   uint32_t i, j, n_channels = conv->n_channels;
63
+
64
+   for (j = 0; j < n_samples; j++) {
65
+       for (i = 0; i < n_channels; i++)
66
+           d[i][j] = *s++;
67
+   }
68
+}
69
+
70
+void
71
+conv_f64s_to_f32d_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
72
+       uint32_t n_samples)
73
+{
74
+   const double *s = src[0];
75
+   float **d = (float **) dst;
76
+   uint32_t i, j, n_channels = conv->n_channels;
77
+
78
+   for (j = 0; j < n_samples; j++) {
79
+       for (i = 0; i < n_channels; i++)
80
+           d[i][j] = bswap_64(*s++);
81
+   }
82
+}
83
+
84
+void
85
+conv_f64d_to_f32_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
86
+       uint32_t n_samples)
87
+{
88
+   const double **s = (const double **) src;
89
+   float *d = dst[0];
90
+   uint32_t i, j, n_channels = conv->n_channels;
91
+
92
+   for (j = 0; j < n_samples; j++) {
93
+       for (i = 0; i < n_channels; i++)
94
+           *d++ = s[i][j];
95
+   }
96
+}
97
+
98
+void
99
 conv_f32d_to_u8d_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
100
        uint32_t n_samples)
101
 {
102
@@ -989,6 +1076,77 @@
103
 }
104
 
105
 void
106
+conv_f32d_to_f64d_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
107
+       uint32_t n_samples)
108
+{
109
+   uint32_t i, j, n_channels = conv->n_channels;
110
+
111
+   for (i = 0; i < n_channels; i++) {
112
+       const float *s = src[i];
113
+       double *d = dst[i];
114
+
115
+       for (j = 0; j < n_samples; j++)
116
+           d[j] = s[j];
117
+   }
118
+}
119
+
120
+void
121
+conv_f32_to_f64_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
122
+       uint32_t n_samples)
123
+{
124
+   uint32_t i, n_channels = conv->n_channels;
125
+   const float *s = src[0];
126
+   double *d = dst[0];
127
+
128
+   n_samples *= n_channels;
129
+
130
+   for (i = 0; i < n_samples; i++)
131
+       d[i] = s[i];
132
+}
133
+
134
+void
135
+conv_f32_to_f64d_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
136
+       uint32_t n_samples)
137
+{
138
+   const float *s = src[0];
139
+   double **d = (double **) dst;
140
+   uint32_t i, j, n_channels = conv->n_channels;
141
+
142
+   for (j = 0; j < n_samples; j++) {
143
+       for (i = 0; i < n_channels; i++)
144
+           d[i][j] = *s++;
145
+   }
146
+}
147
+
148
+void
149
+conv_f32d_to_f64_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
150
+       uint32_t n_samples)
151
+{
152
+   const float **s = (const float **) src;
153
+   double *d = dst[0];
154
+   uint32_t i, j, n_channels = conv->n_channels;
155
+
156
+   for (j = 0; j < n_samples; j++) {
157
+       for (i = 0; i < n_channels; i++)
158
+           *d++ = s[i][j];
159
+   }
160
+}
161
+
162
+void
163
+conv_f32d_to_f64s_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
164
+       uint32_t n_samples)
165
+{
166
+   const float **s = (const float **) src;
167
+   double *d = dst[0];
168
+   uint32_t i, j, n_channels = conv->n_channels;
169
+
170
+   for (j = 0; j < n_samples; j++) {
171
+       for (i = 0; i < n_channels; i++)
172
+           *d++ = bswap_32(s[i][j]);
173
+   }
174
+}
175
+
176
+void
177
 conv_f32_to_u24_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
178
        uint32_t n_samples)
179
 {
180
@@ -1273,6 +1431,20 @@
181
 }
182
 
183
 void
184
+conv_deinterleave_64_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
185
+       uint32_t n_samples)
186
+{
187
+   const uint64_t *s = src[0];
188
+   uint64_t **d = (uint64_t **) dst;
189
+   uint32_t i, j, n_channels = conv->n_channels;
190
+
191
+   for (j = 0; j < n_samples; j++) {
192
+       for (i = 0; i < n_channels; i++)
193
+           d[i][j] = *s++;
194
+   }
195
+}
196
+
197
+void
198
 conv_interleave_8_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
199
        uint32_t n_samples)
200
 {
201
@@ -1343,3 +1515,17 @@
202
            *d++ = bswap_32(s[i][j]);
203
    }
204
 }
205
+
206
+void
207
+conv_interleave_64_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
208
+       uint32_t n_samples)
209
+{
210
+   const int64_t **s = (const int64_t **) src;
211
+   uint64_t *d = dst[0];
212
+   uint32_t i, j, n_channels = conv->n_channels;
213
+
214
+   for (j = 0; j < n_samples; j++) {
215
+       for (i = 0; i < n_channels; i++)
216
+           *d++ = s[i][j];
217
+   }
218
+}
219
pipewire-0.3.43.tar.gz/spa/plugins/audioconvert/fmt-ops.c -> pipewire-0.3.44.tar.gz/spa/plugins/audioconvert/fmt-ops.c Changed
42
 
1
@@ -138,6 +138,13 @@
2
 
3
    { SPA_AUDIO_FORMAT_S24_32_OE, SPA_AUDIO_FORMAT_F32P, 0, 0, conv_s24_32s_to_f32d_c },
4
 
5
+   { SPA_AUDIO_FORMAT_F64, SPA_AUDIO_FORMAT_F32, 0, 0, conv_f64_to_f32_c },
6
+   { SPA_AUDIO_FORMAT_F64P, SPA_AUDIO_FORMAT_F32P, 0, 0, conv_f64d_to_f32d_c },
7
+   { SPA_AUDIO_FORMAT_F64, SPA_AUDIO_FORMAT_F32P, 0, 0, conv_f64_to_f32d_c },
8
+   { SPA_AUDIO_FORMAT_F64P, SPA_AUDIO_FORMAT_F32, 0, 0, conv_f64d_to_f32_c },
9
+
10
+   { SPA_AUDIO_FORMAT_F64_OE, SPA_AUDIO_FORMAT_F32P, 0, 0, conv_f64s_to_f32d_c },
11
+
12
    /* from f32 */
13
    { SPA_AUDIO_FORMAT_F32, SPA_AUDIO_FORMAT_U8, 0, 0, conv_f32_to_u8_c },
14
    { SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_U8P, 0, 0, conv_f32d_to_u8d_c },
15
@@ -219,6 +226,13 @@
16
 
17
    { SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_S24_32_OE, 0, 0, conv_f32d_to_s24_32s_c },
18
 
19
+   { SPA_AUDIO_FORMAT_F32, SPA_AUDIO_FORMAT_F64, 0, 0, conv_f32_to_f64_c },
20
+   { SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_F64P, 0, 0, conv_f32d_to_f64d_c },
21
+   { SPA_AUDIO_FORMAT_F32, SPA_AUDIO_FORMAT_F64P, 0, 0, conv_f32_to_f64d_c },
22
+   { SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_F64, 0, 0, conv_f32d_to_f64_c },
23
+
24
+   { SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_F64_OE, 0, 0, conv_f32d_to_f64s_c },
25
+
26
    /* u8 */
27
    { SPA_AUDIO_FORMAT_U8, SPA_AUDIO_FORMAT_U8, 0, 0, conv_copy8_c },
28
    { SPA_AUDIO_FORMAT_U8P, SPA_AUDIO_FORMAT_U8P, 0, 0, conv_copy8d_c },
29
@@ -259,6 +273,12 @@
30
    { SPA_AUDIO_FORMAT_S24_32P, SPA_AUDIO_FORMAT_S24_32P, 0, 0, conv_copy32d_c },
31
    { SPA_AUDIO_FORMAT_S24_32, SPA_AUDIO_FORMAT_S24_32P, 0, 0, conv_deinterleave_32_c },
32
    { SPA_AUDIO_FORMAT_S24_32P, SPA_AUDIO_FORMAT_S24_32, 0, 0, conv_interleave_32_c },
33
+
34
+   /* F64 */
35
+   { SPA_AUDIO_FORMAT_F64, SPA_AUDIO_FORMAT_F64, 0, 0, conv_copy64_c },
36
+   { SPA_AUDIO_FORMAT_F64P, SPA_AUDIO_FORMAT_F64P, 0, 0, conv_copy64d_c },
37
+   { SPA_AUDIO_FORMAT_F64, SPA_AUDIO_FORMAT_F64P, 0, 0, conv_deinterleave_64_c },
38
+   { SPA_AUDIO_FORMAT_F64P, SPA_AUDIO_FORMAT_F64, 0, 0, conv_interleave_64_c },
39
 };
40
 
41
 #define MATCH_CHAN(a,b)        ((a) == 0 || (a) == (b))
42
pipewire-0.3.43.tar.gz/spa/plugins/audioconvert/fmt-ops.h -> pipewire-0.3.44.tar.gz/spa/plugins/audioconvert/fmt-ops.h Changed
56
 
1
@@ -27,6 +27,7 @@
2
 #include <sys/endian.h>
3
 #define bswap_16 bswap16
4
 #define bswap_32 bswap32
5
+#define bswap_64 bswap64
6
 #else
7
 #include <byteswap.h>
8
 #endif
9
@@ -207,6 +208,8 @@
10
 DEFINE_FUNCTION(copy24, c);
11
 DEFINE_FUNCTION(copy32d, c);
12
 DEFINE_FUNCTION(copy32, c);
13
+DEFINE_FUNCTION(copy64d, c);
14
+DEFINE_FUNCTION(copy64, c);
15
 DEFINE_FUNCTION(u8d_to_f32d, c);
16
 DEFINE_FUNCTION(u8_to_f32, c);
17
 DEFINE_FUNCTION(u8_to_f32d, c);
18
@@ -245,6 +248,11 @@
19
 DEFINE_FUNCTION(s24_32_to_f32d, c);
20
 DEFINE_FUNCTION(s24_32s_to_f32d, c);
21
 DEFINE_FUNCTION(s24_32d_to_f32, c);
22
+DEFINE_FUNCTION(f64d_to_f32d, c);
23
+DEFINE_FUNCTION(f64_to_f32, c);
24
+DEFINE_FUNCTION(f64_to_f32d, c);
25
+DEFINE_FUNCTION(f64s_to_f32d, c);
26
+DEFINE_FUNCTION(f64d_to_f32, c);
27
 DEFINE_FUNCTION(f32d_to_u8d, c);
28
 DEFINE_FUNCTION(f32_to_u8, c);
29
 DEFINE_FUNCTION(f32_to_u8d, c);
30
@@ -283,16 +291,25 @@
31
 DEFINE_FUNCTION(f32_to_s24_32d, c);
32
 DEFINE_FUNCTION(f32d_to_s24_32, c);
33
 DEFINE_FUNCTION(f32d_to_s24_32s, c);
34
+DEFINE_FUNCTION(f32d_to_f64d, c);
35
+DEFINE_FUNCTION(f32_to_f64, c);
36
+DEFINE_FUNCTION(f32_to_f64d, c);
37
+DEFINE_FUNCTION(f32d_to_f64, c);
38
+DEFINE_FUNCTION(f32d_to_f64s, c);
39
 DEFINE_FUNCTION(deinterleave_8, c);
40
 DEFINE_FUNCTION(deinterleave_16, c);
41
 DEFINE_FUNCTION(deinterleave_24, c);
42
 DEFINE_FUNCTION(deinterleave_32, c);
43
 DEFINE_FUNCTION(deinterleave_32s, c);
44
+DEFINE_FUNCTION(deinterleave_64, c);
45
+DEFINE_FUNCTION(deinterleave_64s, c);
46
 DEFINE_FUNCTION(interleave_8, c);
47
 DEFINE_FUNCTION(interleave_16, c);
48
 DEFINE_FUNCTION(interleave_24, c);
49
 DEFINE_FUNCTION(interleave_32, c);
50
 DEFINE_FUNCTION(interleave_32s, c);
51
+DEFINE_FUNCTION(interleave_64, c);
52
+DEFINE_FUNCTION(interleave_64s, c);
53
 
54
 #if defined(HAVE_NEON)
55
 DEFINE_FUNCTION(s16_to_f32d_2, neon);
56
pipewire-0.3.43.tar.gz/spa/plugins/audioconvert/fmtconvert.c -> pipewire-0.3.44.tar.gz/spa/plugins/audioconvert/fmtconvert.c Changed
84
 
1
@@ -52,7 +52,6 @@
2
 #define DEFAULT_RATE       48000
3
 #define DEFAULT_CHANNELS   2
4
 
5
-#define MAX_SAMPLES    8192
6
 #define MAX_BUFFERS    32
7
 #define MAX_ALIGN  16
8
 #define MAX_DATAS  SPA_AUDIO_MAX_CHANNELS
9
@@ -118,6 +117,8 @@
10
 
11
    struct spa_log *log;
12
    struct spa_cpu *cpu;
13
+   uint32_t cpu_flags;
14
+   uint32_t quantum_limit;
15
 
16
    struct spa_io_position *io_position;
17
 
18
@@ -136,7 +137,6 @@
19
 
20
    struct spa_latency_info latency[2];
21
 
22
-   uint32_t cpu_flags;
23
    struct convert conv;
24
    unsigned int started:1;
25
    unsigned int is_passthrough:1;
26
@@ -400,11 +400,14 @@
27
                info.info.raw.format == SPA_AUDIO_FORMAT_F32P ||
28
                info.info.raw.format == SPA_AUDIO_FORMAT_F32) {
29
                spa_pod_builder_add(builder,
30
-                   SPA_FORMAT_AUDIO_format,   SPA_POD_CHOICE_ENUM_Id(26,
31
+                   SPA_FORMAT_AUDIO_format,   SPA_POD_CHOICE_ENUM_Id(29,
32
                                info.info.raw.format,
33
                                SPA_AUDIO_FORMAT_F32P,
34
                                SPA_AUDIO_FORMAT_F32,
35
                                SPA_AUDIO_FORMAT_F32_OE,
36
+                               SPA_AUDIO_FORMAT_F64P,
37
+                               SPA_AUDIO_FORMAT_F64,
38
+                               SPA_AUDIO_FORMAT_F64_OE,
39
                                SPA_AUDIO_FORMAT_S32P,
40
                                SPA_AUDIO_FORMAT_S32,
41
                                SPA_AUDIO_FORMAT_S32_OE,
42
@@ -542,7 +545,7 @@
43
                SPA_PARAM_BUFFERS_buffers, SPA_POD_CHOICE_RANGE_Int(2, 1, MAX_BUFFERS),
44
                SPA_PARAM_BUFFERS_blocks,  SPA_POD_Int(port->blocks),
45
                SPA_PARAM_BUFFERS_size,    SPA_POD_CHOICE_RANGE_Int(
46
-                               MAX_SAMPLES * 2 * port->stride,
47
+                               this->quantum_limit * 2 * port->stride,
48
                                16 * port->stride,
49
                                INT32_MAX),
50
                SPA_PARAM_BUFFERS_stride,  SPA_POD_Int(port->stride));
51
@@ -619,6 +622,10 @@
52
    case SPA_AUDIO_FORMAT_S24_OE:
53
    case SPA_AUDIO_FORMAT_U24:
54
        return 3;
55
+   case SPA_AUDIO_FORMAT_F64P:
56
+   case SPA_AUDIO_FORMAT_F64:
57
+   case SPA_AUDIO_FORMAT_F64_OE:
58
+       return 8;
59
    default:
60
        return 4;
61
    }
62
@@ -1070,6 +1077,7 @@
63
      uint32_t n_support)
64
 {
65
    struct impl *this;
66
+   uint32_t i;
67
 
68
    spa_return_val_if_fail(factory != NULL, -EINVAL);
69
    spa_return_val_if_fail(handle != NULL, -EINVAL);
70
@@ -1086,6 +1094,13 @@
71
    if (this->cpu)
72
        this->cpu_flags = spa_cpu_get_flags(this->cpu);
73
 
74
+   for (i = 0; info && i < info->n_items; i++) {
75
+       const char *k = info->items[i].key;
76
+       const char *s = info->items[i].value;
77
+       if (spa_streq(k, "clock.quantum-limit"))
78
+           spa_atou32(s, &this->quantum_limit, 0);
79
+   }
80
+
81
    this->node.iface = SPA_INTERFACE_INIT(
82
            SPA_TYPE_INTERFACE_Node,
83
            SPA_VERSION_NODE,
84
pipewire-0.3.43.tar.gz/spa/plugins/audioconvert/merger.c -> pipewire-0.3.44.tar.gz/spa/plugins/audioconvert/merger.c Changed
155
 
1
@@ -55,7 +55,6 @@
2
 #define DEFAULT_RATE       48000
3
 #define DEFAULT_CHANNELS   2
4
 
5
-#define MAX_SAMPLES    8192
6
 #define MAX_ALIGN  16
7
 #define MAX_BUFFERS    32
8
 #define MAX_DATAS  SPA_AUDIO_MAX_CHANNELS
9
@@ -146,6 +145,9 @@
10
    struct spa_log *log;
11
    struct spa_cpu *cpu;
12
 
13
+   uint32_t cpu_flags;
14
+   uint32_t quantum_limit;
15
+
16
    struct spa_io_position *io_position;
17
 
18
    uint64_t info_all;
19
@@ -167,7 +169,6 @@
20
    unsigned int have_profile:1;
21
 
22
    struct convert conv;
23
-   uint32_t cpu_flags;
24
    unsigned int is_passthrough:1;
25
    unsigned int started:1;
26
    unsigned int monitor:1;
27
@@ -181,7 +182,8 @@
28
 
29
    struct spa_latency_info latency[2];
30
 
31
-   float empty[MAX_SAMPLES + MAX_ALIGN];
32
+   uint32_t empty_size;
33
+   float *empty;
34
 };
35
 
36
 #define CHECK_IN_PORT(this,d,p)        ((d) == SPA_DIRECTION_INPUT && (p) < this->port_count)
37
@@ -622,7 +624,9 @@
38
 
39
        info.info.raw.rate = 0;
40
 
41
-       if (this->have_profile && memcmp(&this->format, &info, sizeof(info)) == 0)
42
+       if (this->have_profile &&
43
+           memcmp(&this->format, &info, sizeof(info)) == 0 &&
44
+           this->monitor == monitor)
45
            return 0;
46
 
47
        spa_log_debug(this->log, "%p: port config %d/%d %d", this,
48
@@ -775,11 +779,14 @@
49
                SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat,
50
                SPA_FORMAT_mediaType,      SPA_POD_Id(SPA_MEDIA_TYPE_audio),
51
                SPA_FORMAT_mediaSubtype,   SPA_POD_Id(SPA_MEDIA_SUBTYPE_raw),
52
-               SPA_FORMAT_AUDIO_format,   SPA_POD_CHOICE_ENUM_Id(22,
53
+               SPA_FORMAT_AUDIO_format,   SPA_POD_CHOICE_ENUM_Id(25,
54
                            SPA_AUDIO_FORMAT_F32P,
55
                            SPA_AUDIO_FORMAT_F32P,
56
                            SPA_AUDIO_FORMAT_F32,
57
                            SPA_AUDIO_FORMAT_F32_OE,
58
+                           SPA_AUDIO_FORMAT_F64P,
59
+                           SPA_AUDIO_FORMAT_F64,
60
+                           SPA_AUDIO_FORMAT_F64_OE,
61
                            SPA_AUDIO_FORMAT_S32P,
62
                            SPA_AUDIO_FORMAT_S32,
63
                            SPA_AUDIO_FORMAT_S32_OE,
64
@@ -869,7 +876,7 @@
65
            SPA_PARAM_BUFFERS_buffers, SPA_POD_CHOICE_RANGE_Int(1, 1, MAX_BUFFERS),
66
            SPA_PARAM_BUFFERS_blocks,  SPA_POD_Int(port->blocks),
67
            SPA_PARAM_BUFFERS_size,    SPA_POD_CHOICE_RANGE_Int(
68
-                               MAX_SAMPLES * port->stride,
69
+                               this->quantum_limit * port->stride,
70
                                16 * port->stride,
71
                                INT32_MAX),
72
            SPA_PARAM_BUFFERS_stride,  SPA_POD_Int(port->stride));
73
@@ -1008,6 +1015,10 @@
74
    case SPA_AUDIO_FORMAT_S24:
75
    case SPA_AUDIO_FORMAT_S24_OE:
76
        return 3;
77
+   case SPA_AUDIO_FORMAT_F64P:
78
+   case SPA_AUDIO_FORMAT_F64:
79
+   case SPA_AUDIO_FORMAT_F64_OE:
80
+       return 8;
81
    default:
82
        return 4;
83
    }
84
@@ -1024,7 +1035,11 @@
85
    enum spa_direction other = SPA_DIRECTION_REVERSE(direction);
86
    uint32_t i;
87
 
88
-   spa_log_debug(this->log, "%p: set latency direction:%d", this, direction);
89
+   spa_log_debug(this->log, "%p: set latency direction:%d id:%d",
90
+           this, direction, port_id);
91
+
92
+   if (direction == SPA_DIRECTION_OUTPUT && port_id != 0)
93
+       return 0;
94
 
95
    if (latency == NULL) {
96
        this->latency[other] = SPA_LATENCY_INFO(other);
97
@@ -1212,7 +1227,7 @@
98
 {
99
    struct impl *this = object;
100
    struct port *port;
101
-   uint32_t i, j;
102
+   uint32_t i, j, maxsize;
103
 
104
    spa_return_val_if_fail(this != NULL, -EINVAL);
105
 
106
@@ -1227,6 +1242,7 @@
107
 
108
    clear_buffers(this, port);
109
 
110
+   maxsize = 0;
111
    for (i = 0; i < n_buffers; i++) {
112
        struct buffer *b;
113
        uint32_t n_datas = buffers[i]->n_datas;
114
@@ -1257,11 +1273,19 @@
115
            if (direction == SPA_DIRECTION_OUTPUT &&
116
                !SPA_FLAG_IS_SET(d[j].flags, SPA_DATA_FLAG_DYNAMIC))
117
                this->is_passthrough = false;
118
-       }
119
 
120
+           maxsize = SPA_MAX(maxsize, d[j].maxsize);
121
+       }
122
        if (direction == SPA_DIRECTION_OUTPUT)
123
            queue_buffer(this, port, i);
124
    }
125
+   if (maxsize > this->empty_size) {
126
+       this->empty = realloc(this->empty, maxsize + MAX_ALIGN);
127
+       if (this->empty == NULL)
128
+           return -errno;
129
+       memset(this->empty, 0, maxsize + MAX_ALIGN);
130
+       this->empty_size = maxsize;
131
+   }
132
    port->n_buffers = n_buffers;
133
 
134
    return 0;
135
@@ -1519,6 +1543,7 @@
136
        free(this->in_ports[i]);
137
    for (i = 0; i < MAX_PORTS+1; i++)
138
        free(this->out_ports[i]);
139
+   free(this->empty);
140
    return 0;
141
 }
142
 
143
@@ -1557,7 +1582,10 @@
144
    for (i = 0; info && i < info->n_items; i++) {
145
        const char *k = info->items[i].key;
146
        const char *s = info->items[i].value;
147
-       merger_set_param(this, k, s);
148
+       if (spa_streq(k, "clock.quantum-limit"))
149
+           spa_atou32(s, &this->quantum_limit, 0);
150
+       else
151
+           merger_set_param(this, k, s);
152
    }
153
 
154
    this->latency[SPA_DIRECTION_INPUT] = SPA_LATENCY_INFO(SPA_DIRECTION_INPUT);
155
pipewire-0.3.43.tar.gz/spa/plugins/audioconvert/meson.build -> pipewire-0.3.44.tar.gz/spa/plugins/audioconvert/meson.build Changed
27
 
1
@@ -140,7 +140,7 @@
2
       install : installed_tests_enabled,
3
       install_dir : installed_tests_execdir / 'audioconvert'),
4
       env : [
5
-        'SPA_PLUGIN_DIR=@0@'.format(spa_dep.get_variable(internal: 'plugindir')),
6
+        'SPA_PLUGIN_DIR=@0@'.format(spa_dep.get_variable('plugindir')),
7
         ])
8
 
9
     if installed_tests_enabled
10
@@ -170,7 +170,7 @@
11
       install : installed_tests_enabled,
12
       install_dir : installed_tests_execdir / 'audioconvert'),
13
       env : [
14
-        'SPA_PLUGIN_DIR=@0@'.format(spa_dep.get_variable(internal: 'plugindir')),
15
+        'SPA_PLUGIN_DIR=@0@'.format(spa_dep.get_variable('plugindir')),
16
         ])
17
 
18
     if installed_tests_enabled
19
@@ -191,7 +191,6 @@
20
     ]
21
   executable('spa-resample',
22
     sparesample_sources,
23
-    c_args : [ simd_cargs ],
24
     link_with : [ test_lib ],
25
     dependencies : [ spa_dep, sndfile_dep, mathlib, audioconvert_dep ],
26
     install : true,
27
pipewire-0.3.43.tar.gz/spa/plugins/audioconvert/resample-peaks-impl.h -> pipewire-0.3.44.tar.gz/spa/plugins/audioconvert/resample-peaks-impl.h Changed
10
 
1
@@ -31,7 +31,7 @@
2
 struct peaks_data {
3
    uint32_t o_count;
4
    uint32_t i_count;
5
-   float max_f[0];
6
+   float max_f[];
7
 };
8
 
9
 #if defined (HAVE_SSE)
10
pipewire-0.3.43.tar.gz/spa/plugins/audioconvert/resample-peaks.c -> pipewire-0.3.44.tar.gz/spa/plugins/audioconvert/resample-peaks.c Changed
10
 
1
@@ -146,7 +146,7 @@
2
    r->delay = impl_peaks_delay;
3
    r->in_len = impl_peaks_in_len;
4
 
5
-   d = r->data = calloc(1, sizeof(struct peaks_data) * sizeof(float) * r->channels);
6
+   d = r->data = calloc(1, sizeof(struct peaks_data) + sizeof(float) * r->channels);
7
    if (r->data == NULL)
8
        return -errno;
9
 
10
pipewire-0.3.43.tar.gz/spa/plugins/audioconvert/resample.c -> pipewire-0.3.44.tar.gz/spa/plugins/audioconvert/resample.c Changed
375
 
1
@@ -48,7 +48,6 @@
2
 #define DEFAULT_RATE       48000
3
 #define DEFAULT_CHANNELS   2
4
 
5
-#define MAX_SAMPLES    8192u
6
 #define MAX_ALIGN  16
7
 #define MAX_BUFFERS    32
8
 
9
@@ -57,12 +56,14 @@
10
 struct props {
11
    double rate;
12
    int quality;
13
+   bool disabled;
14
 };
15
 
16
 static void props_reset(struct props *props)
17
 {
18
    props->rate = 1.0;
19
    props->quality = RESAMPLE_DEFAULT_QUALITY;
20
+   props->disabled = false;
21
 }
22
 
23
 struct buffer {
24
@@ -104,6 +105,8 @@
25
    struct spa_log *log;
26
    struct spa_cpu *cpu;
27
 
28
+   uint32_t quantum_limit;
29
+
30
    struct spa_io_position *io_position;
31
    struct spa_io_rate_match *io_rate_match;
32
 
33
@@ -127,8 +130,6 @@
34
    struct resample resample;
35
 
36
    double rate_scale;
37
-
38
-   float empty[MAX_SAMPLES + MAX_ALIGN];
39
 };
40
 
41
 #define CHECK_PORT(this,d,id)      (id == 0)
42
@@ -183,7 +184,147 @@
43
                 uint32_t id, uint32_t start, uint32_t num,
44
                 const struct spa_pod *filter)
45
 {
46
-   return -ENOTSUP;
47
+   struct impl *this = object;
48
+   struct spa_pod *param;
49
+   struct spa_pod_builder b = { 0 };
50
+   uint8_t buffer[4096];
51
+   struct spa_result_node_params result;
52
+   uint32_t count = 0;
53
+
54
+   spa_return_val_if_fail(this != NULL, -EINVAL);
55
+   spa_return_val_if_fail(num != 0, -EINVAL);
56
+
57
+   result.id = id;
58
+   result.next = start;
59
+      next:
60
+   result.index = result.next++;
61
+
62
+   spa_pod_builder_init(&b, buffer, sizeof(buffer));
63
+
64
+   switch (id) {
65
+   case SPA_PARAM_PropInfo:
66
+   {
67
+       struct props *p = &this->props;
68
+
69
+       switch (result.index) {
70
+       case 0:
71
+           param = spa_pod_builder_add_object(&b,
72
+               SPA_TYPE_OBJECT_PropInfo, id,
73
+               SPA_PROP_INFO_id, SPA_POD_Id(SPA_PROP_rate),
74
+               SPA_PROP_INFO_description, SPA_POD_String("Rate scaler"),
75
+               SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Double(p->rate, 0.0, 10.0));
76
+           break;
77
+       case 1:
78
+           param = spa_pod_builder_add_object(&b,
79
+               SPA_TYPE_OBJECT_PropInfo, id,
80
+               SPA_PROP_INFO_id, SPA_POD_Id(SPA_PROP_quality),
81
+               SPA_PROP_INFO_name, SPA_POD_String("resample.quality"),
82
+               SPA_PROP_INFO_description, SPA_POD_String("Resample Quality"),
83
+               SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Int(p->quality, 0, 14),
84
+               SPA_PROP_INFO_params, SPA_POD_Bool(true));
85
+           break;
86
+       case 2:
87
+           param = spa_pod_builder_add_object(&b,
88
+               SPA_TYPE_OBJECT_PropInfo, id,
89
+               SPA_PROP_INFO_name, SPA_POD_String("resample.disable"),
90
+               SPA_PROP_INFO_description, SPA_POD_String("Disable Resampling"),
91
+               SPA_PROP_INFO_type, SPA_POD_CHOICE_Bool(p->disabled),
92
+               SPA_PROP_INFO_params, SPA_POD_Bool(true));
93
+           break;
94
+       default:
95
+           return 0;
96
+       }
97
+       break;
98
+   }
99
+   case SPA_PARAM_Props:
100
+   {
101
+       struct props *p = &this->props;
102
+       struct spa_pod_frame f[2];
103
+
104
+       switch (result.index) {
105
+       case 0:
106
+           spa_pod_builder_push_object(&b, &f[0], SPA_TYPE_OBJECT_Props, id);
107
+           spa_pod_builder_add(&b,
108
+               SPA_PROP_rate,          SPA_POD_Double(p->rate),
109
+               SPA_PROP_quality,       SPA_POD_Int(p->quality),
110
+               0);
111
+           spa_pod_builder_prop(&b, SPA_PROP_params, 0);
112
+           spa_pod_builder_push_struct(&b, &f[1]);
113
+           spa_pod_builder_string(&b, "resample.quality");
114
+           spa_pod_builder_int(&b, p->quality);
115
+           spa_pod_builder_string(&b, "resample.disable");
116
+           spa_pod_builder_bool(&b, p->disabled);
117
+           spa_pod_builder_pop(&b, &f[1]);
118
+           param = spa_pod_builder_pop(&b, &f[0]);
119
+           break;
120
+       default:
121
+           return 0;
122
+       }
123
+       break;
124
+   }
125
+   default:
126
+       return -ENOENT;
127
+   }
128
+
129
+   if (spa_pod_filter(&b, &result.param, param, filter) < 0)
130
+       goto next;
131
+
132
+   spa_node_emit_result(&this->hooks, seq, 0, SPA_RESULT_TYPE_NODE_PARAMS, &result);
133
+
134
+   if (++count != num)
135
+       goto next;
136
+
137
+   return 0;
138
+}
139
+
140
+static int resample_set_param(struct impl *this, const char *k, const char *s)
141
+{
142
+   if (spa_streq(k, "resample.quality"))
143
+       this->props.quality = atoi(s);
144
+   else if (spa_streq(k, "resample.disable"))
145
+       this->props.disabled = spa_atob(s);
146
+   return 0;
147
+}
148
+
149
+static int parse_prop_params(struct impl *this, struct spa_pod *params)
150
+{
151
+   struct spa_pod_parser prs;
152
+   struct spa_pod_frame f;
153
+
154
+   spa_pod_parser_pod(&prs, params);
155
+   if (spa_pod_parser_push_struct(&prs, &f) < 0)
156
+       return 0;
157
+
158
+   while (true) {
159
+       const char *name;
160
+       struct spa_pod *pod;
161
+       char value[512];
162
+
163
+       if (spa_pod_parser_get_string(&prs, &name) < 0)
164
+           break;
165
+
166
+       if (spa_pod_parser_get_pod(&prs, &pod) < 0)
167
+           break;
168
+
169
+       if (spa_pod_is_string(pod)) {
170
+           spa_pod_copy_string(pod, sizeof(value), value);
171
+       } else if (spa_pod_is_float(pod)) {
172
+           snprintf(value, sizeof(value), "%f",
173
+                   SPA_POD_VALUE(struct spa_pod_float, pod));
174
+       } else if (spa_pod_is_int(pod)) {
175
+           snprintf(value, sizeof(value), "%d",
176
+                   SPA_POD_VALUE(struct spa_pod_int, pod));
177
+       } else if (spa_pod_is_bool(pod)) {
178
+           snprintf(value, sizeof(value), "%s",
179
+                   SPA_POD_VALUE(struct spa_pod_bool, pod) ?
180
+                   "true" : "false");
181
+       } else
182
+           continue;
183
+
184
+       spa_log_info(this->log, "key:'%s' val:'%s'", name, value);
185
+       resample_set_param(this, name, value);
186
+   }
187
+   return 0;
188
 }
189
 
190
 static int apply_props(struct impl *this, const struct spa_pod *param)
191
@@ -191,22 +332,28 @@
192
    struct spa_pod_prop *prop;
193
    struct spa_pod_object *obj = (struct spa_pod_object *) param;
194
    struct props *p = &this->props;
195
+   int changed = 0;
196
 
197
    SPA_POD_OBJECT_FOREACH(obj, prop) {
198
        switch (prop->key) {
199
        case SPA_PROP_rate:
200
            if (spa_pod_get_double(&prop->value, &p->rate) == 0) {
201
                resample_update_rate(&this->resample, p->rate);
202
+               changed++;
203
            }
204
            break;
205
        case SPA_PROP_quality:
206
-           spa_pod_get_int(&prop->value, &p->quality);
207
+           if (spa_pod_get_int(&prop->value, &p->quality) == 0)
208
+               changed++;
209
+           break;
210
+       case SPA_PROP_params:
211
+           changed += parse_prop_params(this, &prop->value);
212
            break;
213
        default:
214
            break;
215
        }
216
    }
217
-   return 0;
218
+   return changed;
219
 }
220
 
221
 static int impl_node_set_param(void *object, uint32_t id, uint32_t flags,
222
@@ -270,12 +417,16 @@
223
        resample_update_rate(&this->resample, this->rate_scale * this->props.rate);
224
    }
225
 }
226
+static inline bool is_passthrough(struct impl *this)
227
+{
228
+   return this->resample.i_rate == this->resample.o_rate && this->rate_scale == 1.0 &&
229
+       (this->io_rate_match == NULL || this->props.disabled ||
230
+        !SPA_FLAG_IS_SET(this->io_rate_match->flags, SPA_IO_RATE_MATCH_FLAG_ACTIVE));
231
+}
232
 
233
 static void recalc_rate_match(struct impl *this)
234
 {
235
-   bool passthrough = this->resample.i_rate == this->resample.o_rate &&
236
-       (this->io_rate_match == NULL ||
237
-        !SPA_FLAG_IS_SET(this->io_rate_match->flags, SPA_IO_RATE_MATCH_FLAG_ACTIVE));
238
+   bool passthrough = is_passthrough(this);
239
    uint32_t out_size = this->io_position ? this->io_position->clock.duration : 1024;
240
    update_rate_match(this, passthrough, out_size, 0);
241
 }
242
@@ -391,20 +542,24 @@
243
    struct impl *this = object;
244
    struct port *other;
245
    struct spa_pod_frame f;
246
+   uint32_t rate, min = 1, max = INT32_MAX;
247
 
248
    other = GET_PORT(this, SPA_DIRECTION_REVERSE(direction), 0);
249
 
250
    switch (index) {
251
    case 0:
252
        if (other->have_format) {
253
+           rate = other->format.info.raw.rate;
254
+           if (this->props.disabled)
255
+               min = max = rate;
256
+
257
            spa_pod_builder_push_object(builder, &f,
258
                SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat);
259
            spa_pod_builder_add(builder,
260
                SPA_FORMAT_mediaType,      SPA_POD_Id(SPA_MEDIA_TYPE_audio),
261
                SPA_FORMAT_mediaSubtype,   SPA_POD_Id(SPA_MEDIA_SUBTYPE_raw),
262
                SPA_FORMAT_AUDIO_format,   SPA_POD_Id(SPA_AUDIO_FORMAT_F32P),
263
-               SPA_FORMAT_AUDIO_rate,     SPA_POD_CHOICE_RANGE_Int(
264
-                               other->format.info.raw.rate, 1, INT32_MAX),
265
+               SPA_FORMAT_AUDIO_rate,     SPA_POD_CHOICE_RANGE_Int(rate, min, max),
266
                SPA_FORMAT_AUDIO_channels, SPA_POD_Int(other->format.info.raw.channels),
267
                0);
268
            spa_pod_builder_prop(builder, SPA_FORMAT_AUDIO_position, 0);
269
@@ -412,15 +567,17 @@
270
                    other->format.info.raw.channels, other->format.info.raw.position);
271
            *param = spa_pod_builder_pop(builder, &f);
272
        } else {
273
-           uint32_t rate = this->io_position ?
274
+           rate = this->io_position ?
275
                this->io_position->clock.rate.denom : DEFAULT_RATE;
276
+           if (this->props.disabled)
277
+               min = max = rate;
278
 
279
            *param = spa_pod_builder_add_object(builder,
280
                SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat,
281
                SPA_FORMAT_mediaType,      SPA_POD_Id(SPA_MEDIA_TYPE_audio),
282
                SPA_FORMAT_mediaSubtype,   SPA_POD_Id(SPA_MEDIA_SUBTYPE_raw),
283
                SPA_FORMAT_AUDIO_format,   SPA_POD_Id(SPA_AUDIO_FORMAT_F32P),
284
-               SPA_FORMAT_AUDIO_rate,     SPA_POD_CHOICE_RANGE_Int(rate, 1, INT32_MAX),
285
+               SPA_FORMAT_AUDIO_rate,     SPA_POD_CHOICE_RANGE_Int(rate, min, max),
286
                SPA_FORMAT_AUDIO_channels, SPA_POD_CHOICE_RANGE_Int(DEFAULT_CHANNELS, 1, INT32_MAX));
287
        }
288
        break;
289
@@ -497,9 +654,9 @@
290
            size = (other->size / other->stride) * rate;
291
        } else {
292
            buffers = 1;
293
-           size = MAX_SAMPLES * rate;
294
+           size = this->quantum_limit * rate;
295
        }
296
-       size = SPA_MAX(size, MAX_SAMPLES) * 2;
297
+       size = SPA_MAX(size, this->quantum_limit) * 2;
298
 
299
        param = spa_pod_builder_add_object(&b,
300
            SPA_TYPE_OBJECT_ParamBuffers, id,
301
@@ -878,10 +1035,16 @@
302
    src_datas = alloca(sizeof(void*) * this->resample.channels);
303
    dst_datas = alloca(sizeof(void*) * this->resample.channels);
304
 
305
+   if (inport->offset > size)
306
+       inport->offset = size;
307
+   if (outport->offset > maxsize)
308
+       outport->offset = maxsize;
309
+
310
    if (size == 0) {
311
-       size = MAX_SAMPLES * sizeof(float);
312
+       size = sb->datas[0].maxsize;
313
+       memset(sb->datas[0].data, 0, size);
314
        for (i = 0; i < sb->n_datas; i++)
315
-           src_datas[i] = SPA_PTR_ALIGN(this->empty, MAX_ALIGN, void);
316
+           src_datas[i] = sb->datas[0].data;
317
        inport->offset = 0;
318
        flush_in = draining = true;
319
    } else {
320
@@ -899,9 +1062,7 @@
321
    pin_len = in_len;
322
    pout_len = out_len;
323
 #endif
324
-   passthrough = this->resample.i_rate == this->resample.o_rate && this->rate_scale == 1.0 &&
325
-       (this->io_rate_match == NULL ||
326
-        !SPA_FLAG_IS_SET(this->io_rate_match->flags, SPA_IO_RATE_MATCH_FLAG_ACTIVE));
327
+   passthrough = is_passthrough(this);
328
 
329
    if (passthrough) {
330
        uint32_t len = SPA_MIN(in_len, out_len);
331
@@ -1021,7 +1182,7 @@
332
 {
333
    struct impl *this;
334
    struct port *port;
335
-   const char *str;
336
+   uint32_t i;
337
 
338
    spa_return_val_if_fail(factory != NULL, -EINVAL);
339
    spa_return_val_if_fail(handle != NULL, -EINVAL);
340
@@ -1040,20 +1201,25 @@
341
 
342
    props_reset(&this->props);
343
 
344
-   if (info != NULL) {
345
-       if ((str = spa_dict_lookup(info, "resample.quality")) != NULL)
346
-           this->props.quality = atoi(str);
347
-       if ((str = spa_dict_lookup(info, "resample.peaks")) != NULL)
348
-           this->peaks = spa_atob(str);
349
-       if ((str = spa_dict_lookup(info, "factory.mode")) != NULL) {
350
-           if (spa_streq(str, "split"))
351
+   for (i = 0; info && i < info->n_items; i++) {
352
+       const char *k = info->items[i].key;
353
+       const char *s = info->items[i].value;
354
+       if (spa_streq(k, "clock.quantum-limit"))
355
+           spa_atou32(s, &this->quantum_limit, 0);
356
+       else if (spa_streq(k, "resample.peaks"))
357
+           this->peaks = spa_atob(s);
358
+       else if (spa_streq(k, "factory.mode")) {
359
+           if (spa_streq(s, "split"))
360
                this->mode = MODE_SPLIT;
361
-           else if (spa_streq(str, "merge"))
362
+           else if (spa_streq(s, "merge"))
363
                this->mode = MODE_MERGE;
364
            else
365
                this->mode = MODE_CONVERT;
366
-       }
367
+       } else
368
+           resample_set_param(this, k, s);
369
+
370
    }
371
+
372
    spa_log_debug(this->log, "mode:%d", this->mode);
373
 
374
    this->node.iface = SPA_INTERFACE_INIT(
375
pipewire-0.3.43.tar.gz/spa/plugins/audioconvert/spa-resample.c -> pipewire-0.3.44.tar.gz/spa/plugins/audioconvert/spa-resample.c Changed
52
 
1
@@ -49,6 +49,7 @@
2
    int rate;
3
    int format;
4
    int quality;
5
+   int cpu_flags;
6
 
7
    const char *iname;
8
    SF_INFO iinfo;
9
@@ -61,7 +62,7 @@
10
 
11
 #define STR_FMTS "(s8|s16|s32|f32|f64)"
12
 
13
-#define OPTIONS        "hvr:f:q:"
14
+#define OPTIONS        "hvr:f:q:c:"
15
 static const struct option long_options[] = {
16
    { "help",   no_argument,        NULL, 'h'},
17
    { "verbose",    no_argument,        NULL, 'v'},
18
@@ -69,6 +70,7 @@
19
    { "rate",   required_argument,  NULL, 'r' },
20
    { "format", required_argument,  NULL, 'f' },
21
    { "quality",    required_argument,  NULL, 'q' },
22
+   { "cpuflags",   required_argument,  NULL, 'c' },
23
 
24
         { NULL, 0, NULL, 0 }
25
 };
26
@@ -88,6 +90,7 @@
27
        "  -r  --rate                            Output sample rate (default as input)\n"
28
        "  -f  --format                          Output sample format %s (default as input)\n"
29
        "  -q  --quality                         Resampler quality (default %u)\n"
30
+       "  -c  --cpuflags                        CPU flags (default 0)\n"
31
        "\n",
32
        STR_FMTS, DEFAULT_QUALITY);
33
 }
34
@@ -191,6 +194,7 @@
35
    bool flushing = false;
36
 
37
    spa_zero(r);
38
+   r.cpu_flags = d->cpu_flags;
39
    r.log = &logger.log;
40
    r.channels = channels;
41
    r.i_rate = d->iinfo.samplerate;
42
@@ -297,6 +301,9 @@
43
            }
44
            data.quality = ret;
45
            break;
46
+       case 'c':
47
+           data.cpu_flags = strtol(optarg, NULL, 0);
48
+           break;
49
                 default:
50
            fprintf(stderr, "error: unknown option '%c'\n", c);
51
            goto error_usage;
52
pipewire-0.3.43.tar.gz/spa/plugins/audioconvert/splitter.c -> pipewire-0.3.44.tar.gz/spa/plugins/audioconvert/splitter.c Changed
164
 
1
@@ -53,7 +53,6 @@
2
 #define DEFAULT_CHANNELS   2
3
 #define DEFAULT_MASK       (1LL << SPA_AUDIO_CHANNEL_FL) | (1LL << SPA_AUDIO_CHANNEL_FR)
4
 
5
-#define MAX_SAMPLES    8192
6
 #define MAX_ALIGN  16
7
 #define MAX_BUFFERS    32
8
 #define MAX_DATAS  SPA_AUDIO_MAX_CHANNELS
9
@@ -107,6 +106,9 @@
10
    struct spa_log *log;
11
    struct spa_cpu *cpu;
12
 
13
+   uint32_t cpu_flags;
14
+   uint32_t quantum_limit;
15
+
16
    struct spa_io_position *io_position;
17
 
18
    uint64_t info_all;
19
@@ -124,7 +126,6 @@
20
    struct spa_audio_info format;
21
    unsigned int have_profile:1;
22
 
23
-   uint32_t cpu_flags;
24
    struct convert conv;
25
    unsigned int is_passthrough:1;
26
    unsigned int started:1;
27
@@ -134,7 +135,8 @@
28
    uint32_t src_remap[SPA_AUDIO_MAX_CHANNELS];
29
    uint32_t dst_remap[SPA_AUDIO_MAX_CHANNELS];
30
 
31
-   float empty[MAX_SAMPLES + MAX_ALIGN];
32
+   uint32_t empty_size;
33
+   float *empty;
34
 };
35
 
36
 #define CHECK_OUT_PORT(this,d,p)   ((d) == SPA_DIRECTION_OUTPUT && (p) < this->port_count)
37
@@ -456,11 +458,14 @@
38
                SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat,
39
                SPA_FORMAT_mediaType,      SPA_POD_Id(SPA_MEDIA_TYPE_audio),
40
                SPA_FORMAT_mediaSubtype,   SPA_POD_Id(SPA_MEDIA_SUBTYPE_raw),
41
-               SPA_FORMAT_AUDIO_format,   SPA_POD_CHOICE_ENUM_Id(22,
42
+               SPA_FORMAT_AUDIO_format,   SPA_POD_CHOICE_ENUM_Id(25,
43
                            SPA_AUDIO_FORMAT_F32P,
44
                            SPA_AUDIO_FORMAT_F32P,
45
                            SPA_AUDIO_FORMAT_F32,
46
                            SPA_AUDIO_FORMAT_F32_OE,
47
+                           SPA_AUDIO_FORMAT_F64P,
48
+                           SPA_AUDIO_FORMAT_F64,
49
+                           SPA_AUDIO_FORMAT_F64_OE,
50
                            SPA_AUDIO_FORMAT_S32P,
51
                            SPA_AUDIO_FORMAT_S32,
52
                            SPA_AUDIO_FORMAT_S32_OE,
53
@@ -550,9 +555,9 @@
54
            SPA_PARAM_BUFFERS_buffers, SPA_POD_CHOICE_RANGE_Int(1, 1, MAX_BUFFERS),
55
            SPA_PARAM_BUFFERS_blocks,  SPA_POD_Int(port->blocks),
56
            SPA_PARAM_BUFFERS_size,    SPA_POD_CHOICE_RANGE_Int(
57
-                           MAX_SAMPLES * port->stride,
58
+                           this->quantum_limit * port->stride,
59
                            16 * port->stride,
60
-                           MAX_SAMPLES * port->stride),
61
+                           INT32_MAX),
62
            SPA_PARAM_BUFFERS_stride,  SPA_POD_Int(port->stride));
63
        break;
64
 
65
@@ -690,6 +695,10 @@
66
    case SPA_AUDIO_FORMAT_S24:
67
    case SPA_AUDIO_FORMAT_S24_OE:
68
        return 3;
69
+   case SPA_AUDIO_FORMAT_F64P:
70
+   case SPA_AUDIO_FORMAT_F64:
71
+   case SPA_AUDIO_FORMAT_F64_OE:
72
+       return 8;
73
    default:
74
        return 4;
75
    }
76
@@ -877,7 +886,7 @@
77
 {
78
    struct impl *this = object;
79
    struct port *port;
80
-   uint32_t i, j;
81
+   uint32_t i, j, maxsize;
82
 
83
    spa_return_val_if_fail(this != NULL, -EINVAL);
84
    spa_return_val_if_fail(CHECK_PORT(this, direction, port_id), -EINVAL);
85
@@ -890,6 +899,7 @@
86
 
87
    clear_buffers(this, port);
88
 
89
+   maxsize = 0;
90
    for (i = 0; i < n_buffers; i++) {
91
        struct buffer *b;
92
        uint32_t n_datas = buffers[i]->n_datas;
93
@@ -917,11 +927,19 @@
94
 
95
            spa_log_debug(this->log, "%p: buffer %d data %d flags:%08x %p",
96
                    this, i, j, d[j].flags, b->datas[j]);
97
-       }
98
 
99
+           maxsize = SPA_MAX(maxsize, d[j].maxsize);
100
+       }
101
        if (direction == SPA_DIRECTION_OUTPUT)
102
            queue_buffer(this, port, i);
103
    }
104
+   if (maxsize > this->empty_size) {
105
+       this->empty = realloc(this->empty, maxsize + MAX_ALIGN);
106
+       if (this->empty == NULL)
107
+           return -errno;
108
+       memset(this->empty, 0, maxsize + MAX_ALIGN);
109
+       this->empty_size = maxsize;
110
+   }
111
    port->n_buffers = n_buffers;
112
 
113
    return 0;
114
@@ -975,7 +993,6 @@
115
    uint32_t n_src_datas, n_dst_datas;
116
    const void **src_datas;
117
    void **dst_datas;
118
-   int res = 0;
119
 
120
    spa_return_val_if_fail(this != NULL, -EINVAL);
121
 
122
@@ -1063,10 +1080,8 @@
123
        convert_process(&this->conv, dst_datas, src_datas, n_samples);
124
 
125
    inio->status = SPA_STATUS_NEED_DATA;
126
-   res |= SPA_STATUS_NEED_DATA;
127
-   res |= SPA_STATUS_HAVE_DATA;
128
 
129
-   return res;
130
+   return SPA_STATUS_NEED_DATA | SPA_STATUS_HAVE_DATA;
131
 }
132
 
133
 static const struct spa_node_methods impl_node = {
134
@@ -1115,6 +1130,7 @@
135
 
136
    for (i = 0; i < MAX_PORTS; i++)
137
        free(this->out_ports[i]);
138
+   free(this->empty);
139
    return 0;
140
 }
141
 
142
@@ -1134,6 +1150,7 @@
143
 {
144
    struct impl *this;
145
    struct port *port;
146
+   uint32_t i;
147
 
148
    spa_return_val_if_fail(factory != NULL, -EINVAL);
149
    spa_return_val_if_fail(handle != NULL, -EINVAL);
150
@@ -1150,6 +1167,13 @@
151
    if (this->cpu)
152
        this->cpu_flags = spa_cpu_get_flags(this->cpu);
153
 
154
+   for (i = 0; info && i < info->n_items; i++) {
155
+       const char *k = info->items[i].key;
156
+       const char *s = info->items[i].value;
157
+       if (spa_streq(k, "clock.quantum-limit"))
158
+           spa_atou32(s, &this->quantum_limit, 0);
159
+   }
160
+
161
    spa_hook_list_init(&this->hooks);
162
 
163
    this->latency[SPA_DIRECTION_INPUT] = SPA_LATENCY_INFO(SPA_DIRECTION_INPUT);
164
pipewire-0.3.43.tar.gz/spa/plugins/audioconvert/test-channelmix.c -> pipewire-0.3.44.tar.gz/spa/plugins/audioconvert/test-channelmix.c Changed
10
 
1
@@ -162,7 +162,7 @@
2
    test_mix(4, _M(FL)|_M(FR)|_M(RL)|_M(RR), 4, _M(FL)|_M(FR)|_M(LFE)|_M(FC),
3
            MATRIX(1.0, 0.0, 0.707107, 0.0,
4
                   0.0, 1.0, 0.0, 0.707107,
5
-                  0.0, 0.0, 0.0, 0.0,
6
+                  0.707107, 0.707107, 0.0, 0.0,
7
                   0.0, 0.0, 0.0, 0.0));
8
 }
9
 
10
pipewire-0.3.43.tar.gz/spa/plugins/audioconvert/test-fmt-ops.c -> pipewire-0.3.44.tar.gz/spa/plugins/audioconvert/test-fmt-ops.c Changed
70
 
1
@@ -41,10 +41,10 @@
2
 
3
 static uint32_t cpu_flags;
4
 
5
-static uint8_t samp_in[N_SAMPLES * 4];
6
-static uint8_t samp_out[N_SAMPLES * 4];
7
-static uint8_t temp_in[N_SAMPLES * N_CHANNELS * 4];
8
-static uint8_t temp_out[N_SAMPLES * N_CHANNELS * 4];
9
+static uint8_t samp_in[N_SAMPLES * 8];
10
+static uint8_t samp_out[N_SAMPLES * 8];
11
+static uint8_t temp_in[N_SAMPLES * N_CHANNELS * 8];
12
+static uint8_t temp_out[N_SAMPLES * N_CHANNELS * 8];
13
 
14
 static void compare_mem(int i, int j, const void *m1, const void *m2, size_t size)
15
 {
16
@@ -92,6 +92,9 @@
17
        case 4:
18
            conv_interleave_32_c(&conv, tp, ip, N_SAMPLES);
19
            break;
20
+       case 8:
21
+           conv_interleave_64_c(&conv, tp, ip, N_SAMPLES);
22
+           break;
23
        default:
24
            fprintf(stderr, "unknown size %zd\n", in_size);
25
            return;
26
@@ -430,6 +433,35 @@
27
            false, false, conv_s24_32d_to_f32d_c);
28
 }
29
 
30
+static void test_f64_f32(void)
31
+{
32
+   static const double in[] = { 0.0, 1.0, -1.0, 0.4999999404, -0.4999999404, };
33
+   static const float out[] = { 0.0f, 1.0f, -1.0f, 0.4999999404f, -0.4999999404f, };
34
+
35
+   run_test("test_f64_f32d", in, sizeof(in[0]), out, sizeof(out[0]), SPA_N_ELEMENTS(out),
36
+           true, false, conv_f64_to_f32d_c);
37
+   run_test("test_f64d_f32", in, sizeof(in[0]), out, sizeof(out[0]), SPA_N_ELEMENTS(out),
38
+           false, true, conv_f64d_to_f32_c);
39
+   run_test("test_f64_f32", in, sizeof(in[0]), out, sizeof(out[0]), SPA_N_ELEMENTS(out),
40
+           true, true, conv_f64_to_f32_c);
41
+   run_test("test_f64d_f32d", in, sizeof(in[0]), out, sizeof(out[0]), SPA_N_ELEMENTS(out),
42
+           false, false, conv_f64d_to_f32d_c);
43
+}
44
+
45
+static void test_f32_f64(void)
46
+{
47
+   static const float in[] = { 0.0f, 1.0f, -1.0f, 0.5f, -0.5f, 1.1f, -1.1f };
48
+   static const double out[] = { 0.0, 1.0, -1.0, 0.5, -0.5, 1.1, -1.1 };
49
+
50
+   run_test("test_f32_f64", in, sizeof(in[0]), out, sizeof(out[0]), SPA_N_ELEMENTS(out),
51
+           true, true, conv_f32_to_f64_c);
52
+   run_test("test_f32d_f64", in, sizeof(in[0]), out, sizeof(out[0]), SPA_N_ELEMENTS(out),
53
+           false, true, conv_f32d_to_f64_c);
54
+   run_test("test_f32_f64d", in, sizeof(in[0]), out, sizeof(out[0]), SPA_N_ELEMENTS(out),
55
+           true, false, conv_f32_to_f64d_c);
56
+   run_test("test_f32d_f64d", in, sizeof(in[0]), out, sizeof(out[0]), SPA_N_ELEMENTS(out),
57
+           false, false, conv_f32d_to_f64d_c);
58
+}
59
 int main(int argc, char *argv[])
60
 {
61
    cpu_flags = get_cpu_flags();
62
@@ -453,5 +485,7 @@
63
    test_u24_32_f32();
64
    test_f32_s24_32();
65
    test_s24_32_f32();
66
+   test_f32_f64();
67
+   test_f64_f32();
68
    return 0;
69
 }
70
pipewire-0.3.43.tar.gz/spa/plugins/audioconvert/test-source.c -> pipewire-0.3.44.tar.gz/spa/plugins/audioconvert/test-source.c Changed
49
 
1
@@ -45,7 +45,6 @@
2
 #define DEFAULT_RATE       44100
3
 #define DEFAULT_CHANNELS   2
4
 
5
-#define MAX_SAMPLES    8192
6
 #define MAX_BUFFERS    32
7
 
8
 struct impl;
9
@@ -101,6 +100,8 @@
10
 
11
    struct spa_log *log;
12
 
13
+   uint32_t quantum_limit;
14
+
15
    struct spa_hook_list hooks;
16
 
17
    uint64_t info_all;
18
@@ -458,7 +459,7 @@
19
            SPA_PARAM_BUFFERS_buffers, SPA_POD_CHOICE_RANGE_Int(2, 1, MAX_BUFFERS),
20
            SPA_PARAM_BUFFERS_blocks,  SPA_POD_Int(port->blocks),
21
            SPA_PARAM_BUFFERS_size,    SPA_POD_CHOICE_RANGE_Int(
22
-                           MAX_SAMPLES * port->stride,
23
+                           this->quantum_limit * port->stride,
24
                            16 * port->stride,
25
                            INT32_MAX),
26
            SPA_PARAM_BUFFERS_stride,  SPA_POD_Int(port->stride));
27
@@ -830,6 +831,7 @@
28
 {
29
    struct impl *this;
30
    struct port *port;
31
+   uint32_t i;
32
 
33
    spa_return_val_if_fail(factory != NULL, -EINVAL);
34
    spa_return_val_if_fail(handle != NULL, -EINVAL);
35
@@ -841,6 +843,13 @@
36
 
37
    this->log = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_Log);
38
 
39
+   for (i = 0; info && i < info->n_items; i++) {
40
+       const char *k = info->items[i].key;
41
+       const char *s = info->items[i].value;
42
+       if (spa_streq(k, "clock.quantum-limit"))
43
+           spa_atou32(s, &this->quantum_limit, 0);
44
+   }
45
+
46
    spa_log_debug(this->log, NAME " %p: init", this);
47
    spa_hook_list_init(&this->hooks);
48
 
49
pipewire-0.3.43.tar.gz/spa/plugins/audiomixer/audiomixer.c -> pipewire-0.3.44.tar.gz/spa/plugins/audiomixer/audiomixer.c Changed
146
 
1
@@ -45,11 +45,9 @@
2
 #define SPA_LOG_TOPIC_DEFAULT log_topic
3
 static struct spa_log_topic *log_topic = &SPA_LOG_TOPIC(0, "spa.audiomixer");
4
 
5
-#define MAX_SAMPLES     8192
6
 #define MAX_BUFFERS     64
7
 #define MAX_PORTS       128
8
 #define MAX_CHANNELS    64
9
-#define MAX_BUFFER_SIZE    (MAX_SAMPLES * MAX_CHANNELS * 8)
10
 
11
 #define PORT_DEFAULT_VOLUME    1.0
12
 #define PORT_DEFAULT_MUTE  false
13
@@ -74,8 +72,6 @@
14
    struct spa_buffer *buffer;
15
    struct spa_meta_header *h;
16
    struct spa_buffer buf;
17
-   struct spa_data datas[1];
18
-   struct spa_chunk chunk[1];
19
 };
20
 
21
 struct port {
22
@@ -107,6 +103,7 @@
23
    struct spa_log *log;
24
    struct spa_cpu *cpu;
25
    uint32_t cpu_flags;
26
+   uint32_t quantum_limit;
27
 
28
    struct mix_ops ops;
29
 
30
@@ -128,9 +125,6 @@
31
    unsigned int started:1;
32
    uint32_t stride;
33
    uint32_t blocks;
34
-
35
-   uint8_t empty[MAX_BUFFER_SIZE];
36
-
37
 };
38
 
39
 #define PORT_VALID(p)                ((p) != NULL && (p)->valid)
40
@@ -421,7 +415,7 @@
41
            SPA_PARAM_BUFFERS_buffers, SPA_POD_CHOICE_RANGE_Int(1, 1, MAX_BUFFERS),
42
            SPA_PARAM_BUFFERS_blocks,  SPA_POD_Int(this->blocks),
43
            SPA_PARAM_BUFFERS_size,    SPA_POD_CHOICE_RANGE_Int(
44
-                               MAX_SAMPLES * this->stride,
45
+                               this->quantum_limit * this->stride,
46
                                16 * this->stride,
47
                                INT32_MAX),
48
            SPA_PARAM_BUFFERS_stride,  SPA_POD_Int(this->stride));
49
@@ -520,6 +514,10 @@
50
    case SPA_AUDIO_FORMAT_S24_OE:
51
    case SPA_AUDIO_FORMAT_U24:
52
        return 3;
53
+   case SPA_AUDIO_FORMAT_F64P:
54
+   case SPA_AUDIO_FORMAT_F64:
55
+   case SPA_AUDIO_FORMAT_F64_OE:
56
+       return 8;
57
    default:
58
        return 4;
59
    }
60
@@ -653,6 +651,7 @@
61
        b->flags = 0;
62
        b->id = i;
63
        b->h = spa_buffer_find_meta_data(buffers[i], SPA_META_Header, sizeof(*b->h));
64
+       b->buf = *buffers[i];
65
 
66
        if (d[0].data == NULL) {
67
            spa_log_error(this->log, "%p: invalid memory on buffer %p", this,
68
@@ -721,9 +720,9 @@
69
    struct impl *this = object;
70
    struct port *outport;
71
    struct spa_io_buffers *outio;
72
-   uint32_t n_samples, n_buffers, i, maxsize;
73
+   uint32_t n_buffers, i, maxsize;
74
    struct buffer **buffers;
75
-        struct buffer *outb;
76
+   struct buffer *outb;
77
    const void **datas;
78
 
79
    spa_return_val_if_fail(this != NULL, -EINVAL);
80
@@ -748,7 +747,7 @@
81
         datas = alloca(MAX_PORTS * sizeof(void *));
82
         n_buffers = 0;
83
 
84
-   maxsize = MAX_SAMPLES * this->stride;
85
+   maxsize = UINT32_MAX;
86
 
87
    for (i = 0; i < this->last_port; i++) {
88
        struct port *inport = GET_IN_PORT(this, i);
89
@@ -785,22 +784,22 @@
90
                 return -EPIPE;
91
         }
92
 
93
-   n_samples = maxsize / this->stride;
94
-
95
    if (n_buffers == 1) {
96
        *outb->buffer = *buffers[0]->buffer;
97
    }
98
    else {
99
-       outb->buffer->n_datas = 1;
100
-       outb->buffer->datas = outb->datas;
101
-       outb->datas[0].data = this->empty;
102
-       outb->datas[0].chunk = outb->chunk;
103
-       outb->datas[0].chunk->offset = 0;
104
-       outb->datas[0].chunk->size = n_samples * this->stride;
105
-       outb->datas[0].chunk->stride = this->stride;
106
-       outb->datas[0].maxsize = maxsize;
107
-
108
-       mix_ops_process(&this->ops, outb->datas[0].data, datas, n_buffers, n_samples);
109
+       struct spa_data *d = outb->buf.datas;
110
+
111
+       *outb->buffer = outb->buf;
112
+
113
+       maxsize = SPA_MIN(maxsize, d[0].maxsize);
114
+
115
+       d[0].chunk->offset = 0;
116
+       d[0].chunk->size = maxsize;
117
+       d[0].chunk->stride = this->stride;
118
+
119
+       mix_ops_process(&this->ops, d[0].data,
120
+               datas, n_buffers, maxsize / this->stride);
121
    }
122
 
123
    outio->buffer_id = outb->id;
124
@@ -875,6 +874,7 @@
125
 {
126
    struct impl *this;
127
    struct port *port;
128
+   uint32_t i;
129
 
130
    spa_return_val_if_fail(factory != NULL, -EINVAL);
131
    spa_return_val_if_fail(handle != NULL, -EINVAL);
132
@@ -891,6 +891,13 @@
133
    if (this->cpu)
134
        this->cpu_flags = spa_cpu_get_flags(this->cpu);
135
 
136
+   for (i = 0; info && i < info->n_items; i++) {
137
+       const char *k = info->items[i].key;
138
+       const char *s = info->items[i].value;
139
+       if (spa_streq(k, "clock.quantum-limit"))
140
+           spa_atou32(s, &this->quantum_limit, 0);
141
+   }
142
+
143
    spa_hook_list_init(&this->hooks);
144
 
145
    this->node.iface = SPA_INTERFACE_INIT(
146
pipewire-0.3.43.tar.gz/spa/plugins/audiomixer/mixer-dsp.c -> pipewire-0.3.44.tar.gz/spa/plugins/audiomixer/mixer-dsp.c Changed
138
 
1
@@ -47,7 +47,6 @@
2
 
3
 #define MAX_BUFFERS    64
4
 #define MAX_PORTS  128
5
-#define MAX_SAMPLES    8192
6
 #define MAX_ALIGN  64
7
 
8
 #define PORT_DEFAULT_VOLUME    1.0
9
@@ -73,8 +72,6 @@
10
    struct spa_buffer *buffer;
11
    struct spa_meta_header *h;
12
    struct spa_buffer buf;
13
-        struct spa_data datas[1];
14
-        struct spa_chunk chunk[1];
15
 };
16
 
17
 struct port {
18
@@ -107,6 +104,8 @@
19
    struct spa_cpu *cpu;
20
    uint32_t cpu_flags;
21
 
22
+   uint32_t quantum_limit;
23
+
24
    struct mix_ops ops;
25
 
26
    uint64_t info_all;
27
@@ -126,8 +125,6 @@
28
 
29
    unsigned int have_format:1;
30
    unsigned int started:1;
31
-
32
-   float empty[MAX_SAMPLES + MAX_ALIGN];
33
 };
34
 
35
 #define PORT_VALID(p)                ((p) != NULL && (p)->valid)
36
@@ -400,7 +397,7 @@
37
            SPA_PARAM_BUFFERS_buffers, SPA_POD_CHOICE_RANGE_Int(1, 1, MAX_BUFFERS),
38
            SPA_PARAM_BUFFERS_blocks,  SPA_POD_Int(1),
39
            SPA_PARAM_BUFFERS_size,    SPA_POD_CHOICE_RANGE_Int(
40
-                               MAX_SAMPLES * this->stride,
41
+                               this->quantum_limit * this->stride,
42
                                16 * this->stride,
43
                                INT32_MAX),
44
            SPA_PARAM_BUFFERS_stride,  SPA_POD_Int(this->stride));
45
@@ -601,12 +598,13 @@
46
        b->flags = 0;
47
        b->id = i;
48
        b->h = spa_buffer_find_meta_data(buffers[i], SPA_META_Header, sizeof(*b->h));
49
+       b->buf = *buffers[i];
50
 
51
        if (d[0].data == NULL) {
52
            spa_log_error(this->log, "%p: invalid memory on buffer %d", this, i);
53
            return -EINVAL;
54
        }
55
-       if (!SPA_IS_ALIGNED(d[0].data, 16)) {
56
+       if (!SPA_IS_ALIGNED(d[0].data, 32)) {
57
            spa_log_warn(this->log, "%p: memory on buffer %d not aligned", this, i);
58
        }
59
        if (direction == SPA_DIRECTION_OUTPUT)
60
@@ -668,9 +666,9 @@
61
    struct impl *this = object;
62
    struct port *outport;
63
    struct spa_io_buffers *outio;
64
-   uint32_t n_samples, n_buffers, i, maxsize;
65
-        struct buffer **buffers;
66
-        struct buffer *outb;
67
+   uint32_t n_buffers, i, maxsize;
68
+   struct buffer **buffers;
69
+   struct buffer *outb;
70
    const void **datas;
71
 
72
    spa_return_val_if_fail(this != NULL, -EINVAL);
73
@@ -695,7 +693,7 @@
74
         datas = alloca(MAX_PORTS * sizeof(void *));
75
         n_buffers = 0;
76
 
77
-   maxsize = MAX_SAMPLES * sizeof(float);
78
+   maxsize = UINT32_MAX;
79
 
80
    for (i = 0; i < this->last_port; i++) {
81
        struct port *inport = GET_IN_PORT(this, i);
82
@@ -732,21 +730,20 @@
83
                 return -EPIPE;
84
         }
85
 
86
-   n_samples = maxsize / sizeof(float);
87
-
88
    if (n_buffers == 1) {
89
        *outb->buffer = *buffers[0]->buffer;
90
-   }
91
-   else {
92
-       outb->buffer->n_datas = 1;
93
-       outb->buffer->datas = outb->datas;
94
-       outb->datas[0].data = SPA_PTR_ALIGN(this->empty, MAX_ALIGN, void);
95
-       outb->datas[0].chunk = outb->chunk;
96
-       outb->datas[0].chunk->offset = 0;
97
-       outb->datas[0].chunk->size = n_samples * sizeof(float);
98
-       outb->datas[0].chunk->stride = sizeof(float);
99
-
100
-       mix_ops_process(&this->ops, outb->datas[0].data, datas, n_buffers, n_samples);
101
+   } else {
102
+       struct spa_data *d = outb->buf.datas;
103
+       *outb->buffer = outb->buf;
104
+
105
+       maxsize = SPA_MIN(maxsize, d[0].maxsize);
106
+
107
+       d[0].chunk->offset = 0;
108
+       d[0].chunk->size = maxsize;
109
+       d[0].chunk->stride = sizeof(float);
110
+
111
+       mix_ops_process(&this->ops, d[0].data,
112
+               datas, n_buffers, maxsize / sizeof(float));
113
    }
114
 
115
    outio->buffer_id = outb->id;
116
@@ -820,6 +817,7 @@
117
 {
118
    struct impl *this;
119
    struct port *port;
120
+   uint32_t i;
121
 
122
    spa_return_val_if_fail(factory != NULL, -EINVAL);
123
    spa_return_val_if_fail(handle != NULL, -EINVAL);
124
@@ -836,6 +834,13 @@
125
    if (this->cpu)
126
        this->cpu_flags = spa_cpu_get_flags(this->cpu);
127
 
128
+   for (i = 0; info && i < info->n_items; i++) {
129
+       const char *k = info->items[i].key;
130
+       const char *s = info->items[i].value;
131
+       if (spa_streq(k, "clock.quantum-limit"))
132
+           spa_atou32(s, &this->quantum_limit, 0);
133
+   }
134
+
135
    spa_hook_list_init(&this->hooks);
136
 
137
    this->node.iface = SPA_INTERFACE_INIT(
138
pipewire-0.3.43.tar.gz/spa/plugins/audiotestsrc/audiotestsrc.c -> pipewire-0.3.44.tar.gz/spa/plugins/audiotestsrc/audiotestsrc.c Changed
48
 
1
@@ -75,7 +75,6 @@
2
    props->volume = DEFAULT_VOLUME;
3
 }
4
 
5
-#define MAX_SAMPLES    8192
6
 #define MAX_BUFFERS    16
7
 #define MAX_PORTS  1
8
 
9
@@ -119,6 +118,8 @@
10
    struct spa_loop *data_loop;
11
    struct spa_system *data_system;
12
 
13
+   uint32_t quantum_limit;
14
+
15
    uint64_t info_all;
16
    struct spa_node_info info;
17
    struct spa_param_info params[2];
18
@@ -646,7 +647,7 @@
19
            SPA_PARAM_BUFFERS_buffers, SPA_POD_CHOICE_RANGE_Int(1, 1, MAX_BUFFERS),
20
            SPA_PARAM_BUFFERS_blocks,  SPA_POD_Int(1),
21
            SPA_PARAM_BUFFERS_size,    SPA_POD_CHOICE_RANGE_Int(
22
-                           MAX_SAMPLES * port->bpf,
23
+                           this->quantum_limit * port->bpf,
24
                            16 * port->bpf,
25
                            INT32_MAX),
26
            SPA_PARAM_BUFFERS_stride,  SPA_POD_Int(port->bpf));
27
@@ -1014,6 +1015,7 @@
28
 {
29
    struct impl *this;
30
    struct port *port;
31
+   uint32_t i;
32
 
33
    spa_return_val_if_fail(factory != NULL, -EINVAL);
34
    spa_return_val_if_fail(handle != NULL, -EINVAL);
35
@@ -1027,6 +1029,12 @@
36
    this->data_loop = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_DataLoop);
37
    this->data_system = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_DataSystem);
38
 
39
+   for (i = 0; info && i < info->n_items; i++) {
40
+       const char *k = info->items[i].key;
41
+       const char *s = info->items[i].value;
42
+       if (spa_streq(k, "clock.quantum-limit"))
43
+           spa_atou32(s, &this->quantum_limit, 0);
44
+   }
45
    spa_hook_list_init(&this->hooks);
46
 
47
    this->node.iface = SPA_INTERFACE_INIT(
48
pipewire-0.3.43.tar.gz/spa/plugins/bluez5/backend-hsphfpd.c -> pipewire-0.3.44.tar.gz/spa/plugins/bluez5/backend-hsphfpd.c Changed
10
 
1
@@ -1088,7 +1088,7 @@
2
    }
3
 
4
    d = spa_bt_device_find_by_address(backend->monitor, endpoint->remote_address, endpoint->local_address);
5
-   if (!d) {
6
+   if (!d || !d->adapter) {
7
        spa_log_debug(backend->log, "No device for %s", endpoint->path);
8
        return DBUS_HANDLER_RESULT_HANDLED;
9
    }
10
pipewire-0.3.43.tar.gz/spa/plugins/bluez5/backend-native.c -> pipewire-0.3.44.tar.gz/spa/plugins/bluez5/backend-native.c Changed
127
 
1
@@ -137,6 +137,8 @@
2
    unsigned int msbc_supported_by_hfp:1;
3
    unsigned int hfp_ag_switching_codec:1;
4
    unsigned int hfp_ag_initial_codec_setup:2;
5
+   unsigned int cind_call_active:1;
6
+   unsigned int cind_call_notify:1;
7
    enum hfp_hf_state hf_state;
8
    enum hsp_hs_state hs_state;
9
    unsigned int codec;
10
@@ -676,6 +678,22 @@
11
    }
12
 }
13
 
14
+static void rfcomm_hfp_ag_set_cind(struct rfcomm *rfcomm, bool call_active)
15
+{
16
+   if (rfcomm->profile != SPA_BT_PROFILE_HFP_HF)
17
+       return;
18
+
19
+   if (call_active == rfcomm->cind_call_active)
20
+       return;
21
+
22
+   rfcomm->cind_call_active = call_active;
23
+
24
+   if (!rfcomm->cind_call_notify)
25
+       return;
26
+
27
+   rfcomm_send_reply(rfcomm, "+CIEV: 2,%d", rfcomm->cind_call_active);
28
+}
29
+
30
 static bool rfcomm_hfp_ag(struct rfcomm *rfcomm, char* buf)
31
 {
32
    struct impl *backend = rfcomm->backend;
33
@@ -762,12 +780,20 @@
34
        rfcomm_send_reply(rfcomm, "+CIND:(\"service\",(0-1)),(\"call\",(0-1)),(\"callsetup\",(0-3)),(\"callheld\",(0-2))");
35
        rfcomm_send_reply(rfcomm, "OK");
36
    } else if (spa_strstartswith(buf, "AT+CIND?")) {
37
-       rfcomm_send_reply(rfcomm, "+CIND: 0,0,0,0");
38
+       rfcomm_send_reply(rfcomm, "+CIND: 0,%d,0,0", rfcomm->cind_call_active);
39
        rfcomm_send_reply(rfcomm, "OK");
40
    } else if (spa_strstartswith(buf, "AT+CMER")) {
41
+       int mode, keyp, disp, ind;
42
+
43
        rfcomm->slc_configured = true;
44
        rfcomm_send_reply(rfcomm, "OK");
45
 
46
+       rfcomm->cind_call_active = false;
47
+       if (sscanf(buf, "AT+CMER= %d , %d , %d , %d", &mode, &keyp, &disp, &ind) == 4)
48
+           rfcomm->cind_call_notify = ind ? true : false;
49
+       else
50
+           rfcomm->cind_call_notify = false;
51
+
52
        /* switch codec to mSBC by sending unsolicited +BCS message */
53
        if (rfcomm->codec_negotiation_supported && rfcomm->msbc_supported_by_hfp) {
54
            spa_log_debug(backend->log, "RFCOMM initial codec setup");
55
@@ -785,7 +811,6 @@
56
                rfcomm_emit_volume_changed(rfcomm, -1, SPA_BT_VOLUME_INVALID);
57
            }
58
        }
59
-
60
    } else if (!rfcomm->slc_configured) {
61
        spa_log_warn(backend->log, "RFCOMM receive command before SLC completed: %s", buf);
62
        rfcomm_send_reply(rfcomm, "ERROR");
63
@@ -829,6 +854,11 @@
64
        rfcomm_send_reply(rfcomm, "OK");
65
        if (was_switching_codec)
66
            spa_bt_device_emit_codec_switched(rfcomm->device, 0);
67
+   } else if (spa_strstartswith(buf, "AT+BIA=")) {
68
+       /* We only support 'call' indicator, which HFP 4.35.1 defines as
69
+          always active (assuming CMER enabled it), so we don't need to
70
+          parse anything here. */
71
+       rfcomm_send_reply(rfcomm, "OK");
72
    } else if (sscanf(buf, "AT+VGM=%u", &gain) == 1) {
73
        if (gain <= SPA_BT_VOLUME_HS_MAX) {
74
            if (!rfcomm->broken_mic_hw_volume)
75
@@ -1172,12 +1202,17 @@
76
 static int sco_acquire_cb(void *data, bool optional)
77
 {
78
    struct spa_bt_transport *t = data;
79
+   struct transport_data *td = t->user_data;
80
    struct impl *backend = SPA_CONTAINER_OF(t->backend, struct impl, this);
81
    int sock;
82
    socklen_t len;
83
 
84
    spa_log_debug(backend->log, "transport %p: enter sco_acquire_cb", t);
85
 
86
+#ifdef HAVE_BLUEZ_5_BACKEND_HFP_NATIVE
87
+   rfcomm_hfp_ag_set_cind(td->rfcomm, true);
88
+#endif
89
+
90
    if (optional || t->fd > 0)
91
        sock = t->fd;
92
    else
93
@@ -1217,10 +1252,15 @@
94
 static int sco_release_cb(void *data)
95
 {
96
    struct spa_bt_transport *t = data;
97
+   struct transport_data *td = t->user_data;
98
    struct impl *backend = SPA_CONTAINER_OF(t->backend, struct impl, this);
99
 
100
    spa_log_info(backend->log, "Transport %s released", t->path);
101
 
102
+#ifdef HAVE_BLUEZ_5_BACKEND_HFP_NATIVE
103
+   rfcomm_hfp_ag_set_cind(td->rfcomm, false);
104
+#endif
105
+
106
    if (t->sco_io) {
107
        spa_bt_sco_io_destroy(t->sco_io);
108
        t->sco_io = NULL;
109
@@ -1689,7 +1729,7 @@
110
    dbus_message_iter_get_basic(&it[0], &path);
111
 
112
    d = spa_bt_device_find(backend->monitor, path);
113
-   if (d == NULL) {
114
+   if (d == NULL || d->adapter == NULL) {
115
        spa_log_warn(backend->log, "unknown device for path %s", path);
116
        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
117
    }
118
@@ -1816,7 +1856,7 @@
119
    dbus_message_iter_get_basic(&it[0], &path);
120
 
121
    d = spa_bt_device_find(backend->monitor, path);
122
-   if (d == NULL) {
123
+   if (d == NULL || d->adapter == NULL) {
124
        spa_log_warn(backend->log, "unknown device for path %s", path);
125
        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
126
    }
127
pipewire-0.3.43.tar.gz/spa/plugins/bluez5/backend-ofono.c -> pipewire-0.3.44.tar.gz/spa/plugins/bluez5/backend-ofono.c Changed
10
 
1
@@ -364,7 +364,7 @@
2
    }
3
 
4
    d = spa_bt_device_find_by_address(backend->monitor, remote_address, local_address);
5
-   if (!d) {
6
+   if (!d || !d->adapter) {
7
        spa_log_error(backend->log, "Device doesn’t exist for %s", path);
8
        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
9
    }
10
pipewire-0.3.43.tar.gz/spa/plugins/bluez5/bluez5-dbus.c -> pipewire-0.3.44.tar.gz/spa/plugins/bluez5/bluez5-dbus.c Changed
219
 
1
@@ -229,7 +229,7 @@
2
        device->battery_pending_call = NULL;
3
    }
4
 
5
-   if (!device->adapter->has_battery_provider || !device->has_battery)
6
+   if (!device->adapter || !device->adapter->has_battery_provider || !device->has_battery)
7
        return;
8
 
9
    spa_log_debug(device->monitor->log, "Removing virtual battery: %s", device->battery_path);
10
@@ -694,6 +694,22 @@
11
    return 0;
12
 }
13
 
14
+static void adapter_update_devices(struct spa_bt_adapter *adapter)
15
+{
16
+   struct spa_bt_monitor *monitor = adapter->monitor;
17
+   struct spa_bt_device *device;
18
+
19
+   /*
20
+    * Update devices when new adapter appears.
21
+    * Devices may appear on DBus before or after the adapter does.
22
+    */
23
+
24
+   spa_list_for_each(device, &monitor->device_list, link) {
25
+       if (device->adapter == NULL && spa_streq(device->adapter_path, adapter->path))
26
+           device->adapter = adapter;
27
+   }
28
+}
29
+
30
 static void adapter_register_player(struct spa_bt_adapter *adapter)
31
 {
32
    if (adapter->player_registered || !adapter->monitor->dummy_avrcp_player)
33
@@ -785,11 +801,20 @@
34
    return d;
35
 }
36
 
37
+static void device_free(struct spa_bt_device *device);
38
+
39
 static void adapter_free(struct spa_bt_adapter *adapter)
40
 {
41
    struct spa_bt_monitor *monitor = adapter->monitor;
42
+   struct spa_bt_device *d, *td;
43
+
44
    spa_log_debug(monitor->log, "%p", adapter);
45
 
46
+   /* Devices should be destroyed before their assigned adapter */
47
+   spa_list_for_each_safe(d, td, &monitor->device_list, link)
48
+       if (d->adapter == adapter)
49
+           device_free(d);
50
+
51
    spa_bt_player_destroy(adapter->dummy_player);
52
 
53
    spa_list_remove(&adapter->link);
54
@@ -1159,7 +1184,7 @@
55
 }
56
 
57
 #define DEVICE_RECONNECT_TIMEOUT_SEC 2
58
-#define DEVICE_PROFILE_TIMEOUT_SEC 3
59
+#define DEVICE_PROFILE_TIMEOUT_SEC 6
60
 
61
 static void device_timer_event(struct spa_source *source)
62
 {
63
@@ -1238,19 +1263,34 @@
64
 {
65
    struct spa_bt_monitor *monitor = device->monitor;
66
    uint32_t connected_profiles = device->connected_profiles;
67
+   uint32_t direction_masks[2] = {
68
+       SPA_BT_PROFILE_A2DP_SINK | SPA_BT_PROFILE_HEADSET_AUDIO,
69
+       SPA_BT_PROFILE_A2DP_SOURCE | SPA_BT_PROFILE_HEADSET_AUDIO_GATEWAY,
70
+   };
71
+   bool direction_connected = false;
72
+   bool all_connected;
73
+   size_t i;
74
 
75
    if (connected_profiles & SPA_BT_PROFILE_HEADSET_HEAD_UNIT)
76
        connected_profiles |= SPA_BT_PROFILE_HEADSET_HEAD_UNIT;
77
    if (connected_profiles & SPA_BT_PROFILE_HEADSET_AUDIO_GATEWAY)
78
        connected_profiles |= SPA_BT_PROFILE_HEADSET_AUDIO_GATEWAY;
79
 
80
+   for (i = 0; i < SPA_N_ELEMENTS(direction_masks); ++i) {
81
+       uint32_t mask = direction_masks[i] & device->profiles;
82
+       if (mask && (connected_profiles & mask) == mask)
83
+           direction_connected = true;
84
+   }
85
+
86
+   all_connected = (device->profiles & connected_profiles) == device->profiles;
87
+
88
    spa_log_debug(monitor->log, "device %p: profiles %08x %08x %d",
89
            device, device->profiles, connected_profiles, device->added);
90
 
91
    if (connected_profiles == 0 && spa_list_is_empty(&device->codec_switch_list)) {
92
        device_stop_timer(device);
93
        device_connected(monitor, device, BT_DEVICE_DISCONNECTED);
94
-   } else if (force || (device->profiles & connected_profiles) == device->profiles) {
95
+   } else if (force || direction_connected || all_connected) {
96
        device_stop_timer(device);
97
        device_connected(monitor, device, BT_DEVICE_CONNECTED);
98
    } else {
99
@@ -1349,7 +1389,7 @@
100
 
101
                device->adapter = adapter_find(monitor, value);
102
                if (device->adapter == NULL) {
103
-                   spa_log_warn(monitor->log, "unknown adapter %s", value);
104
+                   spa_log_info(monitor->log, "unknown adapter %s", value);
105
                }
106
            }
107
            else if (spa_streq(key, "Icon")) {
108
@@ -1455,6 +1495,15 @@
109
    return 0;
110
 }
111
 
112
+static bool device_props_ready(struct spa_bt_device *device)
113
+{
114
+   /*
115
+    * In some cases, BlueZ device props may be missing part of
116
+    * the information required when the interface first appears.
117
+    */
118
+   return device->adapter && device->address;
119
+}
120
+
121
 bool spa_bt_device_supports_a2dp_codec(struct spa_bt_device *device, const struct a2dp_codec *codec)
122
 {
123
    struct spa_bt_monitor *monitor = device->monitor;
124
@@ -2091,9 +2140,16 @@
125
                spa_bt_transport_set_state(transport, spa_bt_transport_state_from_string(value));
126
            }
127
            else if (spa_streq(key, "Device")) {
128
-               transport->device = spa_bt_device_find(monitor, value);
129
-               if (transport->device == NULL)
130
-                   spa_log_warn(monitor->log, "could not find device %s", value);
131
+               struct spa_bt_device *device = spa_bt_device_find(monitor, value);
132
+               if (transport->device != device) {
133
+                   if (transport->device != NULL)
134
+                       spa_list_remove(&transport->device_link);
135
+                   transport->device = device;
136
+                   if (device != NULL)
137
+                       spa_list_append(&device->transport_list, &transport->device_link);
138
+                   else
139
+                       spa_log_warn(monitor->log, "could not find device %s", value);
140
+               }
141
            }
142
        }
143
        else if (spa_streq(key, "Codec")) {
144
@@ -2874,7 +2930,6 @@
145
    DBusMessageIter it[2];
146
    DBusMessage *r;
147
    struct spa_bt_transport *transport;
148
-   bool is_new = false;
149
    const struct a2dp_codec *codec;
150
    int profile;
151
 
152
@@ -2897,9 +2952,8 @@
153
    dbus_message_iter_recurse(&it[0], &it[1]);
154
 
155
    transport = spa_bt_transport_find(monitor, transport_path);
156
-   is_new = transport == NULL;
157
 
158
-   if (is_new) {
159
+   if (transport == NULL) {
160
        char *tpath = strdup(transport_path);
161
 
162
        transport = spa_bt_transport_create(monitor, tpath, 0);
163
@@ -2928,14 +2982,10 @@
164
    transport->a2dp_codec = codec;
165
    transport_update_props(transport, &it[1], NULL);
166
 
167
-   if (transport->device == NULL) {
168
+   if (transport->device == NULL || transport->device->adapter == NULL) {
169
        spa_log_warn(monitor->log, "no device found for transport");
170
        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
171
    }
172
-   spa_bt_device_add_profile(transport->device, transport->profile);
173
-
174
-   if (is_new)
175
-       spa_list_append(&transport->device->transport_list, &transport->device_link);
176
 
177
    device_update_last_bluez_action_time(transport->device);
178
 
179
@@ -2966,6 +3016,8 @@
180
    spa_log_info(monitor->log, "%p: %s validate conf channels:%d",
181
            monitor, path, transport->n_channels);
182
 
183
+   spa_bt_device_add_profile(transport->device, transport->profile);
184
+
185
    spa_bt_device_connect_profile(transport->device, transport->profile);
186
 
187
    /* Sync initial volumes */
188
@@ -3585,6 +3637,7 @@
189
        adapter_update_props(a, props_iter, NULL);
190
        adapter_register_application(a);
191
        adapter_register_player(a);
192
+       adapter_update_devices(a);
193
    }
194
    else if (spa_streq(interface_name, BLUEZ_PROFILE_MANAGER_INTERFACE)) {
195
        if (monitor->backends[BACKEND_NATIVE])
196
@@ -3607,6 +3660,9 @@
197
        device_update_props(d, props_iter, NULL);
198
        d->reconnect_state = BT_DEVICE_RECONNECT_INIT;
199
 
200
+       if (!device_props_ready(d))
201
+           return;
202
+
203
        device_update_hw_volume_profiles(d);
204
 
205
        /* Trigger bluez device creation before bluez profile negotiation started so that
206
@@ -3963,6 +4019,12 @@
207
            spa_log_debug(monitor->log, "Properties changed in device %s", path);
208
 
209
            device_update_props(d, &it[1], NULL);
210
+
211
+           if (!device_props_ready(d))
212
+               goto finish;
213
+
214
+           device_update_hw_volume_profiles(d);
215
+
216
            spa_bt_device_add_profile(d, SPA_BT_PROFILE_NULL);
217
        }
218
        else if (spa_streq(iface, BLUEZ_MEDIA_ENDPOINT_INTERFACE)) {
219
pipewire-0.3.43.tar.gz/spa/plugins/bluez5/bluez5-device.c -> pipewire-0.3.44.tar.gz/spa/plugins/bluez5/bluez5-device.c Changed
149
 
1
@@ -137,6 +137,7 @@
2
 
3
    uint32_t profile;
4
    unsigned int switching_codec:1;
5
+   unsigned int save_profile:1;
6
    uint32_t prev_bt_connected_profiles;
7
 
8
    const struct a2dp_codec **supported_codecs;
9
@@ -757,7 +758,7 @@
10
 static bool validate_profile(struct impl *this, uint32_t profile,
11
        enum spa_bluetooth_audio_codec codec);
12
 
13
-static int set_profile(struct impl *this, uint32_t profile, enum spa_bluetooth_audio_codec codec)
14
+static int set_profile(struct impl *this, uint32_t profile, enum spa_bluetooth_audio_codec codec, bool save)
15
 {
16
    if (!validate_profile(this, profile, codec)) {
17
        spa_log_warn(this->log, "trying to set invalid profile %d, codec %d, %08x %08x",
18
@@ -766,6 +767,8 @@
19
        return -EINVAL;
20
    }
21
 
22
+   this->save_profile = save;
23
+
24
    if (this->profile == profile &&
25
        (this->profile != DEVICE_PROFILE_A2DP || codec == this->props.codec) &&
26
        (this->profile != DEVICE_PROFILE_HSP_HFP || codec == this->props.codec))
27
@@ -1104,6 +1107,8 @@
28
    /* If default profile is set to HSP/HFP, first try those and exit if found. */
29
    if (this->bt_dev->settings != NULL) {
30
        const char *str = spa_dict_lookup(this->bt_dev->settings, "bluez5.profile");
31
+       if (spa_streq(str, "off"))
32
+           goto off;
33
        if (spa_streq(str, "headset-head-unit") && set_initial_hsp_hfp_profile(this))
34
            return;
35
    }
36
@@ -1126,6 +1131,7 @@
37
    if (set_initial_hsp_hfp_profile(this))
38
        return;
39
 
40
+off:
41
    spa_log_debug(this->log, "initial profile off");
42
 
43
    this->profile = DEVICE_PROFILE_OFF;
44
@@ -1133,7 +1139,8 @@
45
 }
46
 
47
 static struct spa_pod *build_profile(struct impl *this, struct spa_pod_builder *b,
48
-       uint32_t id, uint32_t index, uint32_t profile_index, enum spa_bluetooth_audio_codec codec)
49
+       uint32_t id, uint32_t index, uint32_t profile_index, enum spa_bluetooth_audio_codec codec,
50
+       bool current)
51
 {
52
    struct spa_bt_device *device = this->bt_dev;
53
    struct spa_pod_frame f[2];
54
@@ -1266,6 +1273,10 @@
55
        }
56
        spa_pod_builder_pop(b, &f[1]);
57
    }
58
+   if (current) {
59
+                spa_pod_builder_prop(b, SPA_PARAM_PROFILE_save, 0);
60
+                spa_pod_builder_bool(b, this->save_profile);
61
+   }
62
 
63
    if (name_and_codec)
64
        free(name_and_codec);
65
@@ -1282,7 +1293,7 @@
66
    uint8_t buffer[1024];
67
 
68
    spa_pod_builder_init(&b, buffer, sizeof(buffer));
69
-   return (build_profile(this, &b, 0, 0, profile, codec) != NULL);
70
+   return (build_profile(this, &b, 0, 0, profile, codec, false) != NULL);
71
 }
72
 
73
 static struct spa_pod *build_route(struct impl *this, struct spa_pod_builder *b,
74
@@ -1597,7 +1608,7 @@
75
        case DEVICE_PROFILE_AG:
76
        case DEVICE_PROFILE_A2DP:
77
        case DEVICE_PROFILE_HSP_HFP:
78
-           param = build_profile(this, &b, id, result.index, profile, codec);
79
+           param = build_profile(this, &b, id, result.index, profile, codec, false);
80
            if (param == NULL)
81
                goto next;
82
            break;
83
@@ -1613,7 +1624,7 @@
84
        switch (result.index) {
85
        case 0:
86
            index = get_index_from_profile(this, this->profile, this->props.codec);
87
-           param = build_profile(this, &b, id, index, this->profile, this->props.codec);
88
+           param = build_profile(this, &b, id, index, this->profile, this->props.codec, true);
89
            if (param == NULL)
90
                return 0;
91
            break;
92
@@ -1858,13 +1869,15 @@
93
        uint32_t idx, next;
94
        uint32_t profile;
95
        enum spa_bluetooth_audio_codec codec;
96
+       bool save = false;
97
 
98
        if (param == NULL)
99
            return -EINVAL;
100
 
101
        if ((res = spa_pod_parse_object(param,
102
                SPA_TYPE_OBJECT_ParamProfile, NULL,
103
-               SPA_PARAM_PROFILE_index, SPA_POD_Int(&idx))) < 0) {
104
+               SPA_PARAM_PROFILE_index, SPA_POD_Int(&idx),
105
+               SPA_PARAM_PROFILE_save, SPA_POD_OPT_Bool(&save))) < 0) {
106
            spa_log_warn(this->log, "can't parse profile");
107
            spa_debug_pod(0, NULL, param);
108
            return res;
109
@@ -1874,8 +1887,8 @@
110
        if (profile == SPA_ID_INVALID)
111
            return -EINVAL;
112
 
113
-       spa_log_debug(this->log, "setting profile %d codec:%d", profile, codec);
114
-       return set_profile(this, profile, codec);
115
+       spa_log_debug(this->log, "setting profile %d codec:%d save:%d", profile, codec, (int)save);
116
+       return set_profile(this, profile, codec, save);
117
    }
118
    case SPA_PARAM_Route:
119
    {
120
@@ -1927,6 +1940,8 @@
121
            return res;
122
        }
123
 
124
+       spa_log_debug(this->log, "setting props codec:%d", codec_id);
125
+
126
        if (codec_id == SPA_ID_INVALID)
127
            return 0;
128
 
129
@@ -1934,16 +1949,16 @@
130
            size_t j;
131
            for (j = 0; j < this->supported_codec_count; ++j) {
132
                if (this->supported_codecs[j]->id == codec_id) {
133
-                   return set_profile(this, this->profile, codec_id);
134
+                   return set_profile(this, this->profile, codec_id, true);
135
                }
136
            }
137
        } else if (this->profile == DEVICE_PROFILE_HSP_HFP) {
138
            if (codec_id == SPA_BLUETOOTH_AUDIO_CODEC_CVSD &&
139
                    spa_bt_device_supports_hfp_codec(this->bt_dev, HFP_AUDIO_CODEC_CVSD) == 1) {
140
-               return set_profile(this, this->profile, codec_id);
141
+               return set_profile(this, this->profile, codec_id, true);
142
            } else if (codec_id == SPA_BLUETOOTH_AUDIO_CODEC_MSBC &&
143
                    spa_bt_device_supports_hfp_codec(this->bt_dev, HFP_AUDIO_CODEC_MSBC) == 1) {
144
-               return set_profile(this, this->profile, codec_id);
145
+               return set_profile(this, this->profile, codec_id, true);
146
            }
147
        }
148
        return -EINVAL;
149
pipewire-0.3.43.tar.gz/spa/plugins/bluez5/quirks.c -> pipewire-0.3.44.tar.gz/spa/plugins/bluez5/quirks.c Changed
19
 
1
@@ -332,7 +332,7 @@
2
    }
3
 
4
    /* Adapter */
5
-   if (this->adapter_rules) {
6
+   if (this->adapter_rules && adapter) {
7
        uint32_t no_features = 0;
8
        int nitems = 0;
9
        char vendor_id[64], product_id[64], address[64];
10
@@ -357,7 +357,7 @@
11
    }
12
 
13
    /* Device */
14
-   if (this->device_rules) {
15
+   if (this->device_rules && device) {
16
        uint32_t no_features = 0;
17
        int nitems = 0;
18
        char vendor_id[64], product_id[64], version_id[64], address[64];
19
pipewire-0.3.43.tar.gz/spa/plugins/support/loop.c -> pipewire-0.3.44.tar.gz/spa/plugins/support/loop.c Changed
10
 
1
@@ -187,7 +187,7 @@
2
    int32_t filled;
3
    uint32_t avail, idx, offset, l0;
4
 
5
-   if (pthread_equal(impl->thread, pthread_self()))
6
+   if (impl->thread == 0 || pthread_equal(impl->thread, pthread_self()))
7
        return loop_invoke_inthread(impl, func, seq, data, size, block, user_data);
8
 
9
    filled = spa_ringbuffer_get_write_index(&impl->buffer, &idx);
10
pipewire-0.3.43.tar.gz/spa/plugins/support/null-audio-sink.c -> pipewire-0.3.44.tar.gz/spa/plugins/support/null-audio-sink.c Changed
46
 
1
@@ -70,7 +70,6 @@
2
 #define DEFAULT_CHANNELS   2
3
 #define DEFAULT_RATE       44100
4
 
5
-#define MAX_SAMPLES    8192
6
 #define MAX_BUFFERS    16
7
 #define MAX_PORTS  1
8
 
9
@@ -107,6 +106,8 @@
10
    struct spa_loop *data_loop;
11
    struct spa_system *data_system;
12
 
13
+   uint32_t quantum_limit;
14
+
15
    struct props props;
16
 
17
    uint64_t info_all;
18
@@ -538,7 +539,7 @@
19
            SPA_PARAM_BUFFERS_buffers, SPA_POD_CHOICE_RANGE_Int(1, 1, MAX_BUFFERS),
20
            SPA_PARAM_BUFFERS_blocks,  SPA_POD_Int(port->blocks),
21
            SPA_PARAM_BUFFERS_size,    SPA_POD_CHOICE_RANGE_Int(
22
-                           MAX_SAMPLES * port->bpf,
23
+                           this->quantum_limit * port->bpf,
24
                            16 * port->bpf,
25
                            INT32_MAX),
26
            SPA_PARAM_BUFFERS_stride,  SPA_POD_Int(port->bpf));
27
@@ -856,7 +857,6 @@
28
        spa_log_error(this->log, "a data_system is needed");
29
        return -EINVAL;
30
    }
31
-
32
    spa_hook_list_init(&this->hooks);
33
 
34
    this->node.iface = SPA_INTERFACE_INIT(
35
@@ -904,7 +904,9 @@
36
    for (i = 0; info && i < info->n_items; i++) {
37
        const char *k = info->items[i].key;
38
        const char *s = info->items[i].value;
39
-       if (spa_streq(k, SPA_KEY_AUDIO_CHANNELS)) {
40
+       if (spa_streq(k, "clock.quantum-limit")) {
41
+           spa_atou32(s, &this->quantum_limit, 0);
42
+       } else if (spa_streq(k, SPA_KEY_AUDIO_CHANNELS)) {
43
            this->props.channels = atoi(s);
44
        } else if (spa_streq(k, SPA_KEY_AUDIO_RATE)) {
45
            this->props.rate = atoi(s);
46
pipewire-0.3.43.tar.gz/spa/plugins/v4l2/v4l2-udev.c -> pipewire-0.3.44.tar.gz/spa/plugins/v4l2/v4l2-udev.c Changed
29
 
1
@@ -311,18 +311,17 @@
2
        }
3
    }
4
 
5
-   str = udev_device_get_property_value(dev, "ID_V4L_PRODUCT");
6
+   str = udev_device_get_property_value(dev, "ID_MODEL_FROM_DATABASE");
7
    if (!(str && *str)) {
8
-       str = udev_device_get_property_value(dev, "ID_MODEL_FROM_DATABASE");
9
+       str = udev_device_get_property_value(dev, "ID_MODEL_ENC");
10
        if (!(str && *str)) {
11
-           str = udev_device_get_property_value(dev, "ID_MODEL_ENC");
12
-           if (!(str && *str)) {
13
-               str = udev_device_get_property_value(dev, "ID_MODEL");
14
-           } else {
15
-               char *t = alloca(strlen(str) + 1);
16
-               unescape(str, t);
17
-               str = t;
18
-           }
19
+           str = udev_device_get_property_value(dev, "ID_MODEL");
20
+           if (!(str && *str))
21
+               str = udev_device_get_property_value(dev, "ID_V4L_PRODUCT");
22
+       } else {
23
+           char *t = alloca(strlen(str) + 1);
24
+           unescape(str, t);
25
+           str = t;
26
        }
27
    }
28
    if (str && *str)
29
pipewire-0.3.43.tar.gz/spa/plugins/volume/volume.c -> pipewire-0.3.44.tar.gz/spa/plugins/volume/volume.c Changed
48
 
1
@@ -53,7 +53,6 @@
2
    props->mute = DEFAULT_MUTE;
3
 }
4
 
5
-#define MAX_SAMPLES     8192
6
 #define MAX_BUFFERS     16
7
 
8
 struct buffer {
9
@@ -90,6 +89,7 @@
10
    struct spa_node node;
11
 
12
    struct spa_log *log;
13
+   uint32_t quantum_limit;
14
 
15
    uint64_t info_all;
16
    struct spa_node_info info;
17
@@ -386,7 +386,7 @@
18
            SPA_PARAM_BUFFERS_buffers, SPA_POD_CHOICE_RANGE_Int(2, 1, MAX_BUFFERS),
19
            SPA_PARAM_BUFFERS_blocks,  SPA_POD_Int(1),
20
            SPA_PARAM_BUFFERS_size,    SPA_POD_CHOICE_RANGE_Int(
21
-                           MAX_SAMPLES * this->bpf,
22
+                           this->quantum_limit * this->bpf,
23
                            16 * this->bpf,
24
                            INT32_MAX),
25
            SPA_PARAM_BUFFERS_stride,  SPA_POD_Int(this->bpf));
26
@@ -777,6 +777,7 @@
27
 {
28
    struct impl *this;
29
    struct port *port;
30
+   uint32_t i;
31
 
32
    spa_return_val_if_fail(factory != NULL, -EINVAL);
33
    spa_return_val_if_fail(handle != NULL, -EINVAL);
34
@@ -788,6 +789,13 @@
35
 
36
    this->log = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_Log);
37
 
38
+   for (i = 0; info && i < info->n_items; i++) {
39
+       const char *k = info->items[i].key;
40
+       const char *s = info->items[i].value;
41
+       if (spa_streq(k, "clock.quantum-limit"))
42
+           spa_atou32(s, &this->quantum_limit, 0);
43
+   }
44
+
45
    spa_hook_list_init(&this->hooks);
46
 
47
    this->node.iface = SPA_INTERFACE_INIT(
48
pipewire-0.3.43.tar.gz/spa/tests/meson.build -> pipewire-0.3.44.tar.gz/spa/tests/meson.build Changed
32
 
1
@@ -9,15 +9,16 @@
2
                             '-name', '*.h',
3
                             '-not', '-name', 'type-info.h',
4
                             '-type', 'f',
5
-                            '-printf', '%P\n')
6
+                            '-printf', '%P\n',
7
+                            check: false)
8
   foreach spa_header : spa_headers.stdout().split('\n')
9
     if spa_header.endswith('.h')  # skip empty lines
10
       ext = have_cpp ? 'cpp' : 'c'
11
-      c = configuration_data()
12
-      c.set('INCLUDE', spa_header)
13
       src = configure_file(input: 'spa-include-test-template.c',
14
-                          output: 'spa-include-test-@0@.@1@'.format(spa_header.underscorify(), ext),
15
-                          configuration: c)
16
+                           output: 'spa-include-test-@0@.@1@'.format(spa_header.underscorify(), ext),
17
+                           configuration: {
18
+                             'INCLUDE': spa_header,
19
+                           })
20
       executable('spa-include-test-@0@'.format(spa_header.underscorify()),
21
                  src,
22
                  dependencies: [ spa_dep ],
23
@@ -40,7 +41,7 @@
24
       install_dir : installed_tests_execdir,
25
     ),
26
     env : [
27
-      'SPA_PLUGIN_DIR=@0@'.format(spa_dep.get_variable(internal: 'plugindir')),
28
+      'SPA_PLUGIN_DIR=@0@'.format(spa_dep.get_variable('plugindir')),
29
     ]
30
   )
31
 
32
pipewire-0.3.43.tar.gz/spa/tests/stress-ringbuffer.c -> pipewire-0.3.44.tar.gz/spa/tests/stress-ringbuffer.c Changed
11
 
1
@@ -13,7 +13,8 @@
2
 
3
 #ifdef __FreeBSD__
4
 #include <sys/param.h>
5
-#if __FreeBSD_version < 1400043
6
+#if (__FreeBSD_version >= 1400000 && __FreeBSD_version < 1400043) \
7
+    || (__FreeBSD_version < 1300523)
8
 static int sched_getcpu(void) { return -1; };
9
 #endif
10
 #endif
11
pipewire-0.3.43.tar.gz/src/daemon/client-rt.conf.in -> pipewire-0.3.44.tar.gz/src/daemon/client-rt.conf.in Changed
37
 
1
@@ -9,6 +9,8 @@
2
     #mem.allow-mlock = true
3
     #mem.mlock-all   = false
4
     log.level        = 0
5
+
6
+    #default.clock.quantum-limit = 8192
7
 }
8
 
9
 context.spa-libs = {
10
@@ -32,13 +34,12 @@
11
     # If ifexists is given, the module is ignored when it is not found.
12
     # If nofail is given, module initialization failures are ignored.
13
     #
14
-    # Uses RTKit to boost the data thread priority.
15
-    { name = libpipewire-module-rtkit
16
+    # Uses realtime scheduling to boost the audio thread priorities
17
+    { name = libpipewire-module-rt
18
         args = {
19
-            #nice.level   = -11
20
             #rt.prio      = 88
21
-            #rt.time.soft = 2000000
22
-            #rt.time.hard = 2000000
23
+            #rt.time.soft = -1
24
+            #rt.time.hard = -1
25
         }
26
         flags = [ ifexists nofail ]
27
     }
28
@@ -75,7 +76,7 @@
29
     #node.latency          = 1024/48000
30
     #node.autoconnect      = true
31
     #resample.quality      = 4
32
-    #channelmix.normalize  = false
33
+    #channelmix.normalize  = true
34
     #channelmix.mix-lfe    = true
35
     #channelmix.upmix      = false
36
     #channelmix.lfe-cutoff = 0
37
pipewire-0.3.43.tar.gz/src/daemon/client.conf.in -> pipewire-0.3.44.tar.gz/src/daemon/client.conf.in Changed
19
 
1
@@ -9,6 +9,8 @@
2
     #mem.allow-mlock = true
3
     #mem.mlock-all   = false
4
     log.level        = 0
5
+
6
+    #default.clock.quantum-limit = 8192
7
 }
8
 
9
 context.spa-libs = {
10
@@ -65,7 +67,7 @@
11
     #node.latency          = 1024/48000
12
     #node.autoconnect      = true
13
     #resample.quality      = 4
14
-    #channelmix.normalize  = false
15
+    #channelmix.normalize  = true
16
     #channelmix.mix-lfe    = false
17
     #channelmix.upmix      = false
18
     #channelmix.lfe-cutoff = 0
19
pipewire-0.3.43.tar.gz/src/daemon/filter-chain/demonic.conf -> pipewire-0.3.44.tar.gz/src/daemon/filter-chain/demonic.conf Changed
19
 
1
@@ -19,13 +19,12 @@
2
 }
3
 
4
 context.modules = [
5
-    # Uses RTKit to boost the data thread priority.
6
-    { name = libpipewire-module-rtkit
7
+    # Uses realtime scheduling to boost the audio thread priorities
8
+    { name = libpipewire-module-rt
9
         args = {
10
-            #nice.level   = -11
11
             #rt.prio      = 88
12
-            #rt.time.soft = 2000000
13
-            #rt.time.hard = 2000000
14
+            #rt.time.soft = -1
15
+            #rt.time.hard = -1
16
         }
17
         flags = [ ifexists nofail ]
18
     }
19
pipewire-0.3.43.tar.gz/src/daemon/filter-chain/sink-dolby-surround.conf -> pipewire-0.3.44.tar.gz/src/daemon/filter-chain/sink-dolby-surround.conf Changed
17
 
1
@@ -12,12 +12,11 @@
2
 }
3
 
4
 context.modules = [
5
-    { name = libpipewire-module-rtkit
6
+    { name = libpipewire-module-rt
7
         args = {
8
-            #nice.level   = -11
9
             #rt.prio      = 88
10
-            #rt.time.soft = 2000000
11
-            #rt.time.hard = 2000000
12
+            #rt.time.soft = -1
13
+            #rt.time.hard = -1
14
         }
15
         flags = [ ifexists nofail ]
16
     }
17
pipewire-0.3.43.tar.gz/src/daemon/filter-chain/sink-eq6.conf -> pipewire-0.3.44.tar.gz/src/daemon/filter-chain/sink-eq6.conf Changed
17
 
1
@@ -12,12 +12,11 @@
2
 }
3
 
4
 context.modules = [
5
-    { name = libpipewire-module-rtkit
6
+    { name = libpipewire-module-rt
7
         args = {
8
-            #nice.level   = -11
9
             #rt.prio      = 88
10
-            #rt.time.soft = 2000000
11
-            #rt.time.hard = 2000000
12
+            #rt.time.soft = -1
13
+            #rt.time.hard = -1
14
         }
15
         flags = [ ifexists nofail ]
16
     }
17
pipewire-0.3.43.tar.gz/src/daemon/filter-chain/sink-matrix-spatialiser.conf -> pipewire-0.3.44.tar.gz/src/daemon/filter-chain/sink-matrix-spatialiser.conf Changed
17
 
1
@@ -13,12 +13,11 @@
2
 }
3
 
4
 context.modules = [
5
-    { name = libpipewire-module-rtkit
6
+    { name = libpipewire-module-rt
7
         args = {
8
-            #nice.level   = -11
9
             #rt.prio      = 88
10
-            #rt.time.soft = 2000000
11
-            #rt.time.hard = 2000000
12
+            #rt.time.soft = -1
13
+            #rt.time.hard = -1
14
         }
15
         flags = [ ifexists nofail ]
16
     }
17
pipewire-0.3.43.tar.gz/src/daemon/filter-chain/sink-virtual-surround-5.1-kemar.conf -> pipewire-0.3.44.tar.gz/src/daemon/filter-chain/sink-virtual-surround-5.1-kemar.conf Changed
17
 
1
@@ -12,12 +12,11 @@
2
 }
3
 
4
 context.modules = [
5
-    { name = libpipewire-module-rtkit
6
+    { name = libpipewire-module-rt
7
         args = {
8
-            #nice.level   = -11
9
             #rt.prio      = 88
10
-            #rt.time.soft = 2000000
11
-            #rt.time.hard = 2000000
12
+            #rt.time.soft = -1
13
+            #rt.time.hard = -1
14
         }
15
         flags = [ ifexists nofail ]
16
     }
17
pipewire-0.3.43.tar.gz/src/daemon/filter-chain/sink-virtual-surround-7.1-hesuvi.conf -> pipewire-0.3.44.tar.gz/src/daemon/filter-chain/sink-virtual-surround-7.1-hesuvi.conf Changed
17
 
1
@@ -12,12 +12,11 @@
2
 }
3
 
4
 context.modules = [
5
-    { name = libpipewire-module-rtkit
6
+    { name = libpipewire-module-rt
7
         args = {
8
-            #nice.level   = -11
9
             #rt.prio      = 88
10
-            #rt.time.soft = 2000000
11
-            #rt.time.hard = 2000000
12
+            #rt.time.soft = -1
13
+            #rt.time.hard = -1
14
         }
15
         flags = [ ifexists nofail ]
16
     }
17
pipewire-0.3.43.tar.gz/src/daemon/filter-chain/source-rnnoise.conf -> pipewire-0.3.44.tar.gz/src/daemon/filter-chain/source-rnnoise.conf Changed
17
 
1
@@ -12,12 +12,11 @@
2
 }
3
 
4
 context.modules = [
5
-    { name = libpipewire-module-rtkit
6
+    { name = libpipewire-module-rt
7
         args = {
8
-            #nice.level   = -11
9
             #rt.prio      = 88
10
-            #rt.time.soft = 2000000
11
-            #rt.time.hard = 2000000
12
+            #rt.time.soft = -1
13
+            #rt.time.hard = -1
14
         }
15
         flags = [ ifexists nofail ]
16
     }
17
pipewire-0.3.43.tar.gz/src/daemon/jack.conf.in -> pipewire-0.3.44.tar.gz/src/daemon/jack.conf.in Changed
23
 
1
@@ -9,6 +9,8 @@
2
     #mem.allow-mlock = true
3
     #mem.mlock-all   = false
4
     log.level        = 0
5
+
6
+    #default.clock.quantum-limit = 8192
7
 }
8
 
9
 context.spa-libs = {
10
@@ -35,10 +37,9 @@
11
     # Boost the data thread priority.
12
     { name = libpipewire-module-rt
13
         args = {
14
-            #nice.level   = -11
15
             #rt.prio      = 88
16
-            #rt.time.soft = 2000000
17
-            #rt.time.hard = 2000000
18
+            #rt.time.soft = -1
19
+            #rt.time.hard = -1
20
         }
21
         flags = [ ifexists nofail ]
22
     }
23
pipewire-0.3.43.tar.gz/src/daemon/meson.build -> pipewire-0.3.44.tar.gz/src/daemon/meson.build Changed
9
 
1
@@ -68,6 +68,7 @@
2
  'client.conf',
3
  'client-rt.conf',
4
  'jack.conf',
5
+ 'minimal.conf',
6
  'pipewire-pulse.conf',
7
 ]
8
 
9
pipewire-0.3.44.tar.gz/src/daemon/minimal.conf.in Added
299
 
1
@@ -0,0 +1,297 @@
2
+# Simple daemon config file for PipeWire version @VERSION@ #
3
+#
4
+# Copy and edit this file in @PIPEWIRE_CONFIG_DIR@ for system-wide changes
5
+# or in ~/.config/pipewire for local changes.
6
+
7
+context.properties = {
8
+    ## Configure properties in the system.
9
+    #library.name.system                   = support/libspa-support
10
+    #context.data-loop.library.name.system = support/libspa-support
11
+    #support.dbus                          = true
12
+    #link.max-buffers                      = 64
13
+    link.max-buffers                       = 16                       # version < 3 clients can't handle more
14
+    #mem.warn-mlock                        = false
15
+    #mem.allow-mlock                       = true
16
+    #mem.mlock-all                         = false
17
+    #clock.power-of-two-quantum            = true
18
+    #log.level                             = 2
19
+    #cpu.zero.denormals                    = true
20
+
21
+    core.daemon = true              # listening for socket connections
22
+    core.name   = pipewire-0        # core name and socket name
23
+
24
+    ## Properties for the DSP configuration.
25
+    #default.clock.rate          = 48000
26
+    #default.clock.allowed-rates = [ 48000 ]
27
+    #default.clock.quantum       = 1024
28
+    #default.clock.min-quantum   = 32
29
+    #default.clock.max-quantum   = 2048
30
+    #default.clock.quantum-limit = 8192
31
+    #default.video.width         = 640
32
+    #default.video.height        = 480
33
+    #default.video.rate.num      = 25
34
+    #default.video.rate.denom    = 1
35
+    #
36
+    settings.check-quantum      = true
37
+    settings.check-rate         = true
38
+    #
39
+    # These overrides are only applied when running in a vm.
40
+    vm.overrides = {
41
+        default.clock.min-quantum = 1024
42
+    }
43
+}
44
+
45
+context.spa-libs = {
46
+    #<factory-name regex> = <library-name>
47
+    #
48
+    # Used to find spa factory names. It maps an spa factory name
49
+    # regular expression to a library name that should contain
50
+    # that factory.
51
+    #
52
+    audio.convert.* = audioconvert/libspa-audioconvert
53
+    api.alsa.*      = alsa/libspa-alsa
54
+    support.*       = support/libspa-support
55
+}
56
+
57
+context.modules = [
58
+    #{ name = <module-name>
59
+    #    [ args  = { <key> = <value> ... } ]
60
+    #    [ flags = [ [ ifexists ] [ nofail ] ]
61
+    #}
62
+    #
63
+    # Loads a module with the given parameters.
64
+    # If ifexists is given, the module is ignored when it is not found.
65
+    # If nofail is given, module initialization failures are ignored.
66
+    #
67
+
68
+    # Uses realtime scheduling to boost the audio thread priorities. This uses
69
+    # RTKit if the user doesn't have permission to use regular realtime
70
+    # scheduling.
71
+    { name = libpipewire-module-rt
72
+        args = {
73
+            nice.level   = -11
74
+            #rt.prio      = 88
75
+            #rt.time.soft = -1
76
+            #rt.time.hard = -1
77
+        }
78
+        flags = [ ifexists nofail ]
79
+    }
80
+
81
+    # The native communication protocol.
82
+    { name = libpipewire-module-protocol-native }
83
+
84
+    # The profile module. Allows application to access profiler
85
+    # and performance data. It provides an interface that is used
86
+    # by pw-top and pw-profiler.
87
+    { name = libpipewire-module-profiler }
88
+
89
+    # Allows applications to create metadata objects. It creates
90
+    # a factory for Metadata objects.
91
+    { name = libpipewire-module-metadata }
92
+
93
+    # Creates a factory for making nodes that run in the
94
+    # context of the PipeWire server.
95
+    { name = libpipewire-module-spa-node-factory }
96
+
97
+    # Allows creating nodes that run in the context of the
98
+    # client. Is used by all clients that want to provide
99
+    # data to PipeWire.
100
+    { name = libpipewire-module-client-node }
101
+
102
+    # The access module can perform access checks and block
103
+    # new clients.
104
+    { name = libpipewire-module-access
105
+        args = {
106
+            # access.allowed to list an array of paths of allowed
107
+            # apps.
108
+            #access.allowed = [
109
+            #    @session_manager_path@
110
+            #]
111
+
112
+            # An array of rejected paths.
113
+            #access.rejected = [ ]
114
+
115
+            # An array of paths with restricted access.
116
+            #access.restricted = [ ]
117
+
118
+            # Anything not in the above lists gets assigned the
119
+            # access.force permission.
120
+            #access.force = flatpak
121
+        }
122
+    }
123
+
124
+    # Makes a factory for wrapping nodes in an adapter with a
125
+    # converter and resampler.
126
+    { name = libpipewire-module-adapter }
127
+
128
+    # Makes a factory for creating links between ports.
129
+    { name = libpipewire-module-link-factory }
130
+]
131
+
132
+context.objects = [
133
+    #{ factory = <factory-name>
134
+    #    [ args  = { <key> = <value> ... } ]
135
+    #    [ flags = [ [ nofail ] ]
136
+    #}
137
+    #
138
+    # Creates an object from a PipeWire factory with the given parameters.
139
+    # If nofail is given, errors are ignored (and no object is created).
140
+    #
141
+    #{ factory = spa-node-factory   args = { factory.name = videotestsrc node.name = videotestsrc Spa:Pod:Object:Param:Props:patternType = 1 } }
142
+    #{ factory = spa-device-factory args = { factory.name = api.jack.device foo=bar } flags = [ nofail ] }
143
+    #{ factory = spa-device-factory args = { factory.name = api.alsa.enum.udev } }
144
+    #{ factory = spa-node-factory   args = { factory.name = api.alsa.seq.bridge node.name = Internal-MIDI-Bridge } }
145
+    #{ factory = adapter            args = { factory.name = audiotestsrc node.name = my-test } }
146
+    #{ factory = spa-node-factory   args = { factory.name = api.vulkan.compute.source node.name = my-compute-source } }
147
+
148
+    # Make a default metadata store
149
+    { factory = metadata            args = { metadata.name = default } }
150
+
151
+    # A default dummy driver. This handles nodes marked with the "node.always-driver"
152
+    # property when no other driver is currently active. JACK clients need this.
153
+    { factory = spa-node-factory
154
+        args = {
155
+            factory.name    = support.node.driver
156
+            node.name       = Dummy-Driver
157
+            node.group      = pipewire.dummy
158
+            priority.driver = 20000
159
+        }
160
+    }
161
+    { factory = spa-node-factory
162
+        args = {
163
+            factory.name    = support.node.driver
164
+            node.name       = Freewheel-Driver
165
+            priority.driver = 19000
166
+            node.group      = pipewire.freewheel
167
+            node.freewheel  = true
168
+        }
169
+    }
170
+
171
+    # This creates a single PCM source device for the given
172
+    # alsa device path hw:0. You can change source to sink
173
+    # to make a sink in the same way.
174
+    { factory = adapter
175
+        args = {
176
+            factory.name           = api.alsa.pcm.source
177
+            node.name              = "system"
178
+            node.description       = "system"
179
+            media.class            = "Audio/Source"
180
+            api.alsa.path          = "hw:0"
181
+            #api.alsa.period-size   = 0
182
+            #api.alsa.period-num    = 0
183
+            #api.alsa.headroom      = 0
184
+            #api.alsa.start-delay   = 0
185
+            #api.alsa.disable-mmap  = false
186
+            #api.alsa.disable-batch = false
187
+       #api.alsa.use-chmap     = false
188
+       #api.alsa.multirate     = true
189
+       #latency.internal.rate  = 0
190
+       #latency.internal.ns    = 0
191
+       #clock.name             = api.alsa.0
192
+            node.suspend-on-idle   = true
193
+            #audio.format           = "S32"
194
+            #audio.rate             = 48000
195
+            #audio.allowed-rates    = [ ]
196
+            #audio.channels         = 4
197
+            #audio.position         = [ FL FR RL RR ]
198
+            #resample.quality       = 4
199
+            resample.disable       = true
200
+            #monitor.channel-volumes = false
201
+            #channelmix.normalize   = true
202
+            #channelmix.mix-lfe     = false
203
+            #channelmix.upmix       = false
204
+            #channelmix.lfe-cutoff  = 0
205
+            channelmix.disable     = true
206
+            #node.param.Props      = {
207
+            #    params = [
208
+            #        audio.channels 6
209
+            #    ]
210
+            #}
211
+            adapter.auto-port-config = {
212
+                mode = dsp
213
+                monitor = false
214
+                position = unknown   # aux, preserve
215
+            }
216
+            #node.param.PortConfig    = {
217
+            #    direction = Output
218
+            #    mode = dsp
219
+            #    format = {
220
+            #        mediaType = audio
221
+            #        mediaSubtype = raw
222
+            #        format = F32
223
+            #        rate = 48000
224
+            #        channels = 4
225
+            #        position = [ FL FR RL RR ]
226
+            #    }
227
+            #}
228
+        }
229
+    }
230
+    { factory = adapter
231
+        args = {
232
+            factory.name           = api.alsa.pcm.sink
233
+            node.name              = "system"
234
+            node.description       = "system"
235
+            media.class            = "Audio/Sink"
236
+            api.alsa.path          = "hw:0"
237
+            #api.alsa.period-size   = 0
238
+            #api.alsa.period-num    = 0
239
+            #api.alsa.headroom      = 0
240
+            #api.alsa.start-delay   = 0
241
+            #api.alsa.disable-mmap  = false
242
+            #api.alsa.disable-batch = false
243
+            #api.alsa.use-chmap     = false
244
+            #api.alsa.multirate     = true
245
+            #latency.internal.rate  = 0
246
+            #latency.internal.ns    = 0
247
+            #clock.name             = api.alsa.0
248
+            node.suspend-on-idle     = true
249
+            #audio.format           = "S32"
250
+            #audio.rate             = 48000
251
+            #audio.allowed-rates    = [ ]
252
+            #audio.channels         = 2
253
+            #audio.position         = "FL,FR"
254
+            #resample.quality      = 4
255
+            resample.disable      = true
256
+            #channelmix.normalize  = true
257
+            #channelmix.mix-lfe    = false
258
+            #channelmix.upmix      = false
259
+            #channelmix.lfe-cutoff = 0
260
+            channelmix.disable     = true
261
+            #node.param.Props      = {
262
+            #    params = [
263
+            #        audio.format  S16
264
+            #    ]
265
+            #}
266
+            adapter.auto-port-config = {
267
+                mode = dsp
268
+                monitor = false
269
+                position = unknown   # aux, preserve
270
+            }
271
+            #node.param.PortConfig    = {
272
+            #    direction = Input
273
+            #    mode = dsp
274
+            #    monitor = true
275
+            #    format = {
276
+            #        mediaType = audio
277
+            #        mediaSubtype = raw
278
+            #        format = F32
279
+            #        rate = 48000
280
+            #        channels = 4
281
+            #    }
282
+            #}
283
+        }
284
+    }
285
+]
286
+
287
+context.exec = [
288
+    #{ path = <program-name> [ args = "<arguments>" ] }
289
+    #
290
+    # Execute the given program with arguments.
291
+    #
292
+    # You can optionally start the pulseaudio-server here as well
293
+    # but it is better to start it as a systemd service.
294
+    # It can be interesting to start another daemon here that listens
295
+    # on another address with the -a option (eg. -a tcp:4713).
296
+    #
297
+    #@pulse_comment@{ path = "@pipewire_path@" args = "-c pipewire-pulse.conf" }
298
+]
299
pipewire-0.3.43.tar.gz/src/daemon/pipewire-pulse.conf.in -> pipewire-0.3.44.tar.gz/src/daemon/pipewire-pulse.conf.in Changed
93
 
1
@@ -9,6 +9,8 @@
2
     #mem.allow-mlock = true
3
     #mem.mlock-all   = false
4
     #log.level       = 2
5
+
6
+    #default.clock.quantum-limit = 8192
7
 }
8
 
9
 context.spa-libs = {
10
@@ -17,12 +19,12 @@
11
 }
12
 
13
 context.modules = [
14
-    { name = libpipewire-module-rtkit
15
+    { name = libpipewire-module-rt
16
         args = {
17
-            #nice.level   = -11
18
+            nice.level   = -11
19
             #rt.prio      = 88
20
-            #rt.time.soft = 2000000
21
-            #rt.time.hard = 2000000
22
+            #rt.time.soft = -1
23
+            #rt.time.hard = -1
24
         }
25
         flags = [ ifexists nofail ]
26
     }
27
@@ -42,7 +44,7 @@
28
                 #"tcp:127.0.0.1:8888"               # IPv4 on a single address
29
                 #
30
                 #{ address = "tcp:4713"             # address
31
-                #  max-clients = 64                 # maximume number of clients
32
+                #  max-clients = 64                 # maximum number of clients
33
                 #  listen-backlog = 32              # backlog in the server listen queue
34
                 #  client.access = "restricted"     # permissions for clients
35
                 #}
36
@@ -73,8 +75,55 @@
37
     #node.latency          = 1024/48000
38
     #node.autoconnect      = true
39
     #resample.quality      = 4
40
-    #channelmix.normalize  = false
41
+    #channelmix.normalize  = true
42
     #channelmix.mix-lfe    = false
43
     #channelmix.upmix      = false
44
     #channelmix.lfe-cutoff = 0
45
 }
46
+
47
+# client/stream specific properties
48
+pulse.rules = [
49
+    {
50
+        matches = [
51
+            {
52
+                # all keys must match the value. ~ starts regex.
53
+                #client.name                = "Firefox"
54
+                #application.process.binary = "teams"
55
+                #application.name           = "~speech-dispatcher.*"
56
+            }
57
+        ]
58
+        actions = {
59
+            update-props = {
60
+                #node.latency = 512/48000
61
+            }
62
+            # Possible quirks:"
63
+            #    force-s16-info                 forces sink and source info as S16 format
64
+            #    remove-capture-dont-move       removes the capture DONT_MOVE flag
65
+            #quirks = [ ]
66
+        }
67
+    }
68
+    {
69
+        # skype does not want to use devices that don't have an S16 sample format.
70
+        matches = [
71
+             { application.process.binary = "teams" }
72
+             { application.process.binary = "skypeforlinux" }
73
+        ]
74
+        actions = { quirks = [ force-s16-info ] }
75
+    }
76
+    {
77
+        # firefox marks the capture streams as don't move and then they
78
+        # can't be moved with pavucontrol or other tools.
79
+        matches = [ { application.process.binary = "firefox" } ]
80
+        actions = { quirks = [ remove-capture-dont-move ] }
81
+    }
82
+    {
83
+        # speech dispatcher asks for too small latency and then underruns.
84
+        matches = [ { application.name = "~speech-dispatcher*" } ]
85
+        actions = {
86
+            update-props = {
87
+                pulse.min.req          = 1024/48000     # 21ms
88
+                pulse.min.quantum      = 1024/48000     # 21ms
89
+            }
90
+        }
91
+    }
92
+]
93
pipewire-0.3.43.tar.gz/src/daemon/pipewire.conf.in -> pipewire-0.3.44.tar.gz/src/daemon/pipewire.conf.in Changed
72
 
1
@@ -25,12 +25,16 @@
2
     #default.clock.allowed-rates = [ 48000 ]
3
     #default.clock.quantum       = 1024
4
     #default.clock.min-quantum   = 32
5
-    #default.clock.max-quantum   = 8192
6
+    #default.clock.max-quantum   = 2048
7
+    #default.clock.quantum-limit = 8192
8
     #default.video.width         = 640
9
     #default.video.height        = 480
10
     #default.video.rate.num      = 25
11
     #default.video.rate.denom    = 1
12
     #
13
+    #settings.check-quantum      = false
14
+    #settings.check-rate         = false
15
+    #
16
     # These overrides are only applied when running in a vm.
17
     vm.overrides = {
18
         default.clock.min-quantum = 1024
19
@@ -67,28 +71,19 @@
20
     # If nofail is given, module initialization failures are ignored.
21
     #
22
 
23
-    # Uses RTKit to boost the data thread priority.
24
-    { name = libpipewire-module-rtkit
25
+    # Uses realtime scheduling to boost the audio thread priorities. This uses
26
+    # RTKit if the user doesn't have permission to use regular realtime
27
+    # scheduling.
28
+    { name = libpipewire-module-rt
29
         args = {
30
-            #nice.level   = -11
31
+            nice.level    = -11
32
             #rt.prio      = 88
33
-            #rt.time.soft = 2000000
34
-            #rt.time.hard = 2000000
35
+            #rt.time.soft = -1
36
+            #rt.time.hard = -1
37
         }
38
         flags = [ ifexists nofail ]
39
     }
40
 
41
-    # Set thread priorities without using RTKit.
42
-    #{ name = libpipewire-module-rt
43
-    #    args = {
44
-    #        nice.level   = -11
45
-    #        rt.prio      = 88
46
-    #        rt.time.soft = 2000000
47
-    #        rt.time.hard = 2000000
48
-    #    }
49
-    #    flags = [ ifexists nofail ]
50
-    #}
51
-
52
     # The native communication protocol.
53
     { name = libpipewire-module-protocol-native }
54
 
55
@@ -156,6 +151,16 @@
56
 
57
     # Provides factories to make session manager objects.
58
     { name = libpipewire-module-session-manager }
59
+
60
+    # Use libcanberra to play X11 Bell
61
+    #{ name = libpipewire-module-x11-bell
62
+    #  args = {
63
+    #      #sink.name = "@DEFAULT_SINK@"
64
+    #      #sample.name = "bell-window-system"
65
+    #      #x11.display = null
66
+    #      #x11.xauthority = null
67
+    #  }
68
+    #}
69
 ]
70
 
71
 context.objects = [
72
pipewire-0.3.43.tar.gz/src/daemon/systemd/system/meson.build -> pipewire-0.3.44.tar.gz/src/daemon/systemd/system/meson.build Changed
10
 
1
@@ -1,4 +1,7 @@
2
-systemd_system_services_dir = systemd.get_variable(pkgconfig: 'systemdsystemunitdir', pkgconfig_define : [ 'rootprefix', prefix])
3
+systemd_system_services_dir = systemd.get_variable('systemdsystemunitdir', pkgconfig_define : [ 'rootprefix', prefix])
4
+if get_option('systemd-system-unit-dir') != ''
5
+  systemd_system_services_dir = get_option('systemd-system-unit-dir')
6
+endif
7
 
8
 install_data(sources : 'pipewire.socket',
9
              install_dir : systemd_system_services_dir)
10
pipewire-0.3.43.tar.gz/src/daemon/systemd/user/meson.build -> pipewire-0.3.44.tar.gz/src/daemon/systemd/user/meson.build Changed
7
 
1
@@ -1,4 +1,4 @@
2
-systemd_user_services_dir = systemd.get_variable(pkgconfig: 'systemduserunitdir', pkgconfig_define : [ 'prefix', prefix])
3
+systemd_user_services_dir = systemd.get_variable('systemduserunitdir', pkgconfig_define : [ 'prefix', prefix])
4
 if get_option('systemd-user-unit-dir') != ''
5
   systemd_user_services_dir = get_option('systemd-user-unit-dir')
6
 endif
7
pipewire-0.3.43.tar.gz/src/modules/meson.build -> pipewire-0.3.44.tar.gz/src/modules/meson.build Changed
89
 
1
@@ -21,12 +21,12 @@
2
   'module-protocol-simple.c',
3
   'module-pulse-tunnel.c',
4
   'module-rt.c',
5
-  'module-rtkit.c',
6
   'module-raop-discover.c',
7
   'module-session-manager.c',
8
   'module-zeroconf-discover.c',
9
   'module-roc-source.c',
10
   'module-roc-sink.c',
11
+  'module-x11-bell.c',
12
 ]
13
 
14
 pipewire_module_access = shared_library('pipewire-module-access', [ 'module-access.c' ],
15
@@ -137,21 +137,18 @@
16
   dependencies : [spa_dep, mathlib, dl_lib, pipewire_dep],
17
 )
18
 
19
-build_module_rt = build_machine.system() == 'linux'
20
+build_module_rt = dbus_dep.found()
21
 if build_module_rt
22
 pipewire_module_rt = shared_library('pipewire-module-rt', [ 'module-rt.c' ],
23
   include_directories : [configinc],
24
   install : true,
25
   install_dir : modules_install_dir,
26
   install_rpath: modules_install_dir,
27
-  dependencies : [dl_lib, pipewire_dep],
28
+  dependencies : [dbus_dep, mathlib, dl_lib, pipewire_dep],
29
 )
30
-endif
31
-summary({'rt': build_module_rt}, bool_yn: true, section: 'Optional Modules')
32
-
33
-build_module_rtkit = dbus_dep.found()
34
-if build_module_rtkit
35
-pipewire_module_rtkit = shared_library('pipewire-module-rtkit', [ 'module-rtkit.c' ],
36
+# TODO: This serves as a temporary alias to prevent breaking existing setups
37
+#       while `module-rtkit` is being migrated to `module-rt`
38
+pipewire_module_rtkit = shared_library('pipewire-module-rtkit', [ 'module-rt.c' ],
39
   include_directories : [configinc],
40
   install : true,
41
   install_dir : modules_install_dir,
42
@@ -159,7 +156,7 @@
43
   dependencies : [dbus_dep, mathlib, dl_lib, pipewire_dep],
44
 )
45
 endif
46
-summary({'rtkit': build_module_rtkit}, bool_yn: true, section: 'Optional Modules')
47
+summary({'rt': build_module_rt}, bool_yn: true, section: 'Optional Modules')
48
 
49
 build_module_portal = dbus_dep.found()
50
 if build_module_portal
51
@@ -259,6 +256,7 @@
52
   'module-protocol-pulse/modules/module-switch-on-connect.c',
53
   'module-protocol-pulse/modules/module-tunnel-sink.c',
54
   'module-protocol-pulse/modules/module-tunnel-source.c',
55
+  'module-protocol-pulse/modules/module-x11-bell.c',
56
   'module-protocol-pulse/modules/module-zeroconf-discover.c',
57
 ]
58
 
59
@@ -370,9 +368,9 @@
60
     install_dir : installed_tests_execdir,
61
   ),
62
   env : [
63
-    'SPA_PLUGIN_DIR=@0@'.format(spa_dep.get_variable(internal: 'plugindir')),
64
-    'PIPEWIRE_CONFIG_DIR=@0@'.format(pipewire_dep.get_variable(internal: 'confdatadir')),
65
-    'PIPEWIRE_MODULE_DIR=@0@'.format(pipewire_dep.get_variable(internal: 'moduledir')),
66
+    'SPA_PLUGIN_DIR=@0@'.format(spa_dep.get_variable('plugindir')),
67
+    'PIPEWIRE_CONFIG_DIR=@0@'.format(pipewire_dep.get_variable('confdatadir')),
68
+    'PIPEWIRE_MODULE_DIR=@0@'.format(pipewire_dep.get_variable('moduledir')),
69
   ]
70
 )
71
 
72
@@ -488,3 +486,16 @@
73
 endif
74
 summary({'roc-sink': build_module_roc}, bool_yn: true, section: 'Optional Modules')
75
 summary({'roc-source': build_module_roc}, bool_yn: true, section: 'Optional Modules')
76
+
77
+build_module_x11_bell = x11_dep.found() and canberra_dep.found()
78
+if build_module_x11_bell
79
+pipewire_module_x11_bell = shared_library('pipewire-module-x11-bell',
80
+  [ 'module-x11-bell.c' ],
81
+  include_directories : [configinc],
82
+  install : true,
83
+  install_dir : modules_install_dir,
84
+  install_rpath: modules_install_dir,
85
+  dependencies : [mathlib, dl_lib, rt_lib, pipewire_dep, x11_dep, canberra_dep],
86
+)
87
+endif
88
+summary({'x11-bell': build_module_x11_bell}, bool_yn: true, section: 'Optional Modules')
89
pipewire-0.3.43.tar.gz/src/modules/module-adapter/adapter.c -> pipewire-0.3.44.tar.gz/src/modules/module-adapter/adapter.c Changed
205
 
1
@@ -38,10 +38,15 @@
2
 #include <spa/utils/string.h>
3
 #include <spa/utils/type-info.h>
4
 #include <spa/param/format.h>
5
+#include <spa/param/audio/format.h>
6
+#include <spa/param/audio/format-utils.h>
7
 #include <spa/param/format-utils.h>
8
 #include <spa/debug/types.h>
9
+#include <spa/debug/pod.h>
10
+#include <spa/utils/json-pod.h>
11
 
12
 #include "pipewire/pipewire.h"
13
+#include "pipewire/private.h"
14
 
15
 #include "modules/spa/spa-node.h"
16
 
17
@@ -170,6 +175,29 @@
18
    .port_init = node_port_init,
19
 };
20
 
21
+static int handle_node_param(struct pw_impl_node *node, const char *key, const char *value)
22
+{
23
+   const struct spa_type_info *ti;
24
+   uint8_t buffer[1024];
25
+   struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer));
26
+   struct spa_pod *pod;
27
+   int res;
28
+
29
+   ti = spa_debug_type_find_short(spa_type_param, key);
30
+   if (ti == NULL)
31
+       return -ENOENT;
32
+
33
+   if ((res = spa_json_to_pod(&b, 0, ti, value, strlen(value))) < 0)
34
+       return res;
35
+
36
+   if ((pod = spa_pod_builder_deref(&b, 0)) == NULL)
37
+       return -ENOSPC;
38
+
39
+   if ((res = pw_impl_node_set_param(node, ti->type, 0, pod)) < 0)
40
+       return res;
41
+
42
+   return 0;
43
+}
44
 
45
 static int find_format(struct pw_impl_node *node, enum pw_direction direction,
46
        uint32_t *media_type, uint32_t *media_subtype)
47
@@ -201,6 +229,113 @@
48
    return 0;
49
 }
50
 
51
+static int do_auto_port_config(struct node *n, const char *str)
52
+{
53
+   uint32_t state = 0, i;
54
+   uint8_t buffer[4096];
55
+   struct spa_pod_builder b;
56
+#define POSITION_PRESERVE 0
57
+#define POSITION_AUX 1
58
+#define POSITION_UNKNOWN 2
59
+   int res, position = POSITION_PRESERVE;
60
+   struct spa_pod *param;
61
+   uint32_t media_type, media_subtype;
62
+   bool have_format = false, monitor = false;
63
+   struct spa_audio_info format = { 0, };
64
+   enum spa_param_port_config_mode mode = SPA_PARAM_PORT_CONFIG_MODE_none;
65
+   struct spa_json it[2];
66
+   char key[1024], val[256];
67
+
68
+   spa_json_init(&it[0], str, strlen(str));
69
+   if (spa_json_enter_object(&it[0], &it[1]) <= 0)
70
+       return -EINVAL;
71
+
72
+   while (spa_json_get_string(&it[1], key, sizeof(key)) > 0) {
73
+       if (spa_json_get_string(&it[1], val, sizeof(val)) <= 0)
74
+           break;
75
+
76
+       if (spa_streq(key, "mode")) {
77
+           mode = spa_debug_type_find_type_short(spa_type_param_port_config_mode, val);
78
+           if (mode == SPA_ID_INVALID)
79
+               mode = SPA_PARAM_PORT_CONFIG_MODE_none;
80
+       } else if (spa_streq(key, "monitor")) {
81
+           monitor = spa_atob(val);
82
+       } else if (spa_streq(key, "position")) {
83
+           if (spa_streq(val, "unknown"))
84
+               position = POSITION_UNKNOWN;
85
+           else if (spa_streq(val, "aux"))
86
+               position = POSITION_AUX;
87
+           else
88
+               position = POSITION_PRESERVE;
89
+       }
90
+        }
91
+
92
+   while (true) {
93
+       struct spa_audio_info info = { 0, };
94
+       struct spa_pod *position = NULL;
95
+       uint32_t n_position = 0;
96
+
97
+       spa_pod_builder_init(&b, buffer, sizeof(buffer));
98
+       if ((res = spa_node_port_enum_params_sync(pw_impl_node_get_implementation(n->follower),
99
+                   n->direction == PW_DIRECTION_INPUT ?
100
+                       SPA_DIRECTION_INPUT :
101
+                       SPA_DIRECTION_OUTPUT, 0,
102
+                   SPA_PARAM_EnumFormat, &state,
103
+                   NULL, &param, &b)) != 1)
104
+           break;
105
+
106
+       if ((res = spa_format_parse(param, &media_type, &media_subtype)) < 0)
107
+           continue;
108
+
109
+       if (media_type != SPA_MEDIA_TYPE_audio ||
110
+           media_subtype != SPA_MEDIA_SUBTYPE_raw)
111
+           continue;
112
+
113
+       spa_pod_object_fixate((struct spa_pod_object*)param);
114
+
115
+       if (spa_pod_parse_object(param,
116
+               SPA_TYPE_OBJECT_Format, NULL,
117
+               SPA_FORMAT_AUDIO_format,        SPA_POD_Id(&info.info.raw.format),
118
+               SPA_FORMAT_AUDIO_rate,          SPA_POD_Int(&info.info.raw.rate),
119
+               SPA_FORMAT_AUDIO_channels,      SPA_POD_Int(&info.info.raw.channels),
120
+               SPA_FORMAT_AUDIO_position,      SPA_POD_OPT_Pod(&position)) < 0)
121
+           continue;
122
+
123
+       if (position != NULL)
124
+           n_position = spa_pod_copy_array(position, SPA_TYPE_Id,
125
+                   info.info.raw.position, SPA_AUDIO_MAX_CHANNELS);
126
+       if (n_position == 0 || n_position != info.info.raw.channels)
127
+           SPA_FLAG_SET(info.info.raw.flags, SPA_AUDIO_FLAG_UNPOSITIONED);
128
+
129
+       if (format.info.raw.channels >= info.info.raw.channels)
130
+           continue;
131
+
132
+       format = info;
133
+       have_format = true;
134
+   }
135
+   if (!have_format)
136
+       return -ENOENT;
137
+
138
+   if (position == POSITION_AUX) {
139
+       for (i = 0; i < format.info.raw.channels; i++)
140
+           format.info.raw.position[i] = SPA_AUDIO_CHANNEL_START_Aux + i;
141
+   } else if (position == POSITION_UNKNOWN) {
142
+       for (i = 0; i < format.info.raw.channels; i++)
143
+           format.info.raw.position[i] = SPA_AUDIO_CHANNEL_UNKNOWN;
144
+   }
145
+
146
+   spa_pod_builder_init(&b, buffer, sizeof(buffer));
147
+   param = spa_format_audio_raw_build(&b, SPA_PARAM_Format, &format.info.raw);
148
+   param = spa_pod_builder_add_object(&b,
149
+       SPA_TYPE_OBJECT_ParamPortConfig, SPA_PARAM_PortConfig,
150
+       SPA_PARAM_PORT_CONFIG_direction, SPA_POD_Id(n->direction),
151
+       SPA_PARAM_PORT_CONFIG_mode,      SPA_POD_Id(mode),
152
+       SPA_PARAM_PORT_CONFIG_monitor,   SPA_POD_Bool(monitor),
153
+       SPA_PARAM_PORT_CONFIG_format,    SPA_POD_Pod(param));
154
+   pw_impl_node_set_param(n->node, SPA_PARAM_PortConfig, 0, param);
155
+
156
+   return 0;
157
+}
158
 
159
 struct pw_impl_node *pw_adapter_new(struct pw_context *context,
160
        struct pw_impl_node *follower,
161
@@ -214,6 +349,8 @@
162
    enum pw_direction direction;
163
    int res;
164
    uint32_t media_type, media_subtype;
165
+   const struct spa_dict_item *it;
166
+   struct pw_properties *copy;
167
 
168
    info = pw_impl_node_get_info(follower);
169
    if (info == NULL) {
170
@@ -272,11 +409,16 @@
171
        goto error;
172
    }
173
 
174
+   copy = pw_properties_new(NULL, NULL);
175
+   spa_dict_for_each(it, &props->dict) {
176
+       if (!spa_strstartswith(it->key, "node.param.") &&
177
+           !spa_strstartswith(it->key, "port.param."))
178
+           pw_properties_set(copy, it->key, it->value);
179
+   }
180
    node = pw_spa_node_load(context,
181
                factory_name,
182
                PW_SPA_NODE_FLAG_ACTIVATE | PW_SPA_NODE_FLAG_NO_REGISTER,
183
-               pw_properties_copy(props),
184
-               sizeof(struct node) + user_data_size);
185
+               copy, sizeof(struct node) + user_data_size);
186
         if (node == NULL) {
187
        res = -errno;
188
        pw_log_error("can't load spa node: %m");
189
@@ -298,6 +440,15 @@
190
 
191
    pw_impl_node_add_listener(node, &n->node_listener, &node_events, n);
192
 
193
+   if ((str = pw_properties_get(props, "adapter.auto-port-config")) != NULL)
194
+       do_auto_port_config(n, str);
195
+
196
+   spa_dict_for_each(it, &props->dict) {
197
+       if (spa_strstartswith(it->key, "node.param.")) {
198
+           if ((res = handle_node_param(node, &it->key[11], it->value)) < 0)
199
+               pw_log_warn("can't set node param: %s", spa_strerror(res));
200
+       }
201
+   }
202
    return node;
203
 
204
 error:
205
pipewire-0.3.43.tar.gz/src/modules/module-client-node/client-node.c -> pipewire-0.3.44.tar.gz/src/modules/module-client-node/client-node.c Changed
27
 
1
@@ -219,6 +219,8 @@
2
    if (mix_id >= len) {
3
        size_t need = sizeof(struct mix) * (mix_id + 1 - len);
4
        void *ptr = pw_array_add(&p->mix, need);
5
+       if (ptr == NULL)
6
+           return NULL;
7
        memset(ptr, 0, need);
8
    }
9
    mix = pw_array_get_unchecked(&p->mix, mix_id, struct mix);
10
@@ -1388,8 +1390,15 @@
11
        return -ENOMEM;
12
 
13
    mix->id = pw_map_insert_new(&impl->io_map, NULL);
14
-   if (mix->id == SPA_ID_INVALID)
15
+   if (mix->id == SPA_ID_INVALID) {
16
+       m->valid = false;
17
        return -errno;
18
+   }
19
+   if (mix->id > MAX_AREAS) {
20
+       pw_map_remove(&impl->io_map, mix->id);
21
+       m->valid = false;
22
+       return -ENOMEM;
23
+   }
24
 
25
    mix->io = SPA_PTROFF(impl->io_areas->map->ptr,
26
            mix->id * sizeof(struct spa_io_buffers), void);
27
pipewire-0.3.43.tar.gz/src/modules/module-echo-cancel.c -> pipewire-0.3.44.tar.gz/src/modules/module-echo-cancel.c Changed
167
 
1
@@ -109,6 +109,15 @@
2
  *
3
  */
4
 
5
+/**
6
+ * .--------.     .---------.     .--------.     .----------.     .-------.
7
+ * | source | --> | capture | --> |        | --> |  source  | --> |  app  |
8
+ * '--------'     '---------'     | echo   |     '----------'     '-------'
9
+ *                                | cancel |
10
+ * .--------.     .---------.     |        |     .----------.     .--------.
11
+ * |  app   | --> |  sink   | --> |        | --> | playback | --> |  sink  |
12
+ * '--------'     '---------'     '--------'     '----------'     '--------'
13
+ */
14
 #define NAME "echo-cancel"
15
 
16
 PW_LOG_TOPIC_STATIC(mod_topic, "mod." NAME);
17
@@ -117,6 +126,7 @@
18
 /* Hopefully this is enough for any combination of AEC engine and resampler
19
  * input requirement for rate matching */
20
 #define MAX_BUFSIZE_MS 100
21
+#define DELAY_MS 0
22
 
23
 static const struct spa_dict_item module_props[] = {
24
    { PW_KEY_MODULE_AUTHOR, "Wim Taymans <wim.taymans@gmail.com>" },
25
@@ -126,6 +136,8 @@
26
                "[ audio.rate=<sample rate> ] "
27
                "[ audio.channels=<number of channels> ] "
28
                "[ audio.position=<channel map> ] "
29
+               "[ buffer.max_size=<max buffer size in ms> ] "
30
+               "[ buffer.play_delay=<play delay in ms> ] "
31
                "[ aec.method=<aec method> ] "
32
                "[ aec.args=<aec arguments> ] "
33
                "[ source.props=<properties> ] "
34
@@ -166,6 +178,7 @@
35
    void *play_buffer[SPA_AUDIO_MAX_CHANNELS];
36
    uint32_t play_ringsize;
37
    struct spa_ringbuffer play_ring;
38
+   struct spa_ringbuffer play_delayed_ring;
39
    struct spa_io_rate_match *play_rate_match;
40
 
41
    void *out_buffer[SPA_AUDIO_MAX_CHANNELS];
42
@@ -181,6 +194,9 @@
43
 
44
    unsigned int do_disconnect:1;
45
    unsigned int unloading:1;
46
+
47
+   uint32_t max_buffer_size;
48
+   uint32_t buffer_delay;
49
 };
50
 
51
 static void do_unload_module(void *obj, void *data, int res, uint32_t id)
52
@@ -202,13 +218,15 @@
53
    struct pw_buffer *pout;
54
    float rec_buf[impl->info.channels][impl->aec_blocksize / sizeof(float)];
55
    float play_buf[impl->info.channels][impl->aec_blocksize / sizeof(float)];
56
+   float play_delayed_buf[impl->info.channels][impl->aec_blocksize / sizeof(float)];
57
    float out_buf[impl->info.channels][impl->aec_blocksize / sizeof(float)];
58
    const float *rec[impl->info.channels];
59
    const float *play[impl->info.channels];
60
+   const float *play_delayed[impl->info.channels];
61
    float *out[impl->info.channels];
62
    struct spa_data *dd;
63
    uint32_t i, size;
64
-   uint32_t rindex, pindex, oindex, avail;
65
+   uint32_t rindex, pindex, oindex, pdindex, avail;
66
    int32_t stride = 0;
67
 
68
    if ((pout = pw_stream_dequeue_buffer(impl->playback)) == NULL) {
69
@@ -222,12 +240,15 @@
70
 
71
    spa_ringbuffer_get_read_index(&impl->rec_ring, &rindex);
72
    spa_ringbuffer_get_read_index(&impl->play_ring, &pindex);
73
+   spa_ringbuffer_get_read_index(&impl->play_delayed_ring, &pdindex);
74
 
75
    for (i = 0; i < impl->info.channels; i++) {
76
        /* captured samples, with echo from sink */
77
        rec[i] = &rec_buf[i][0];
78
        /* echo from sink */
79
        play[i] = &play_buf[i][0];
80
+       /* echo from sink delayed */
81
+       play_delayed[i] = &play_delayed_buf[i][0];
82
        /* filtered samples, without echo from sink */
83
        out[i] = &out_buf[i][0];
84
 
85
@@ -241,6 +262,11 @@
86
                impl->play_ringsize, pindex % impl->play_ringsize,
87
                (void *)play[i], size);
88
 
89
+       stride = 0;
90
+       spa_ringbuffer_read_data(&impl->play_delayed_ring, impl->play_buffer[i],
91
+               impl->play_ringsize, pdindex % impl->play_ringsize,
92
+               (void *)play_delayed[i], size);
93
+
94
        /* output to sink, just copy */
95
        dd = &pout->buffer->datas[i];
96
        memcpy(dd->data, play[i], size);
97
@@ -252,11 +278,12 @@
98
 
99
    spa_ringbuffer_read_update(&impl->rec_ring, rindex + size);
100
    spa_ringbuffer_read_update(&impl->play_ring, pindex + size);
101
+   spa_ringbuffer_read_update(&impl->play_delayed_ring, pdindex + size);
102
 
103
    pw_stream_queue_buffer(impl->playback, pout);
104
 
105
    /* Now run the canceller */
106
-   echo_cancel_run(impl->aec_info, impl->aec, rec, play, out, size / sizeof(float));
107
+   echo_cancel_run(impl->aec_info, impl->aec, rec, play_delayed, out, size / sizeof(float));
108
 
109
    /* Next, copy over the output to the output ringbuffer */
110
    avail = spa_ringbuffer_get_write_index(&impl->out_ring, &oindex);
111
@@ -544,6 +571,9 @@
112
        spa_ringbuffer_get_read_index(&impl->play_ring, &rindex);
113
        spa_ringbuffer_read_update(&impl->play_ring, rindex + drop);
114
 
115
+       spa_ringbuffer_get_read_index(&impl->play_delayed_ring, &rindex);
116
+       spa_ringbuffer_read_update(&impl->play_delayed_ring, rindex + drop);
117
+
118
        avail += drop;
119
    }
120
 
121
@@ -604,6 +634,7 @@
122
    struct spa_pod_builder b;
123
    struct pw_properties *props;
124
    const char *str;
125
+   uint32_t index;
126
 
127
    props = pw_properties_new(
128
            PW_KEY_NODE_NAME, "echo-cancel-capture",
129
@@ -710,9 +741,9 @@
130
            params, n_params)) < 0)
131
        return res;
132
 
133
-   impl->rec_ringsize = sizeof(float) * MAX_BUFSIZE_MS * impl->info.rate / 1000;
134
-   impl->play_ringsize = sizeof(float) * MAX_BUFSIZE_MS * impl->info.rate / 1000;
135
-   impl->out_ringsize = sizeof(float) * MAX_BUFSIZE_MS * impl->info.rate / 1000;
136
+   impl->rec_ringsize = sizeof(float) * impl->max_buffer_size * impl->info.rate / 1000;
137
+   impl->play_ringsize = sizeof(float) * (impl->max_buffer_size + impl->buffer_delay) * impl->info.rate / 1000;
138
+   impl->out_ringsize = sizeof(float) * impl->max_buffer_size * impl->info.rate / 1000;
139
    for (i = 0; i < impl->info.channels; i++) {
140
        impl->rec_buffer[i] = malloc(impl->rec_ringsize);
141
        impl->play_buffer[i] = malloc(impl->play_ringsize);
142
@@ -720,8 +751,14 @@
143
    }
144
    spa_ringbuffer_init(&impl->rec_ring);
145
    spa_ringbuffer_init(&impl->play_ring);
146
+   spa_ringbuffer_init(&impl->play_delayed_ring);
147
    spa_ringbuffer_init(&impl->out_ring);
148
 
149
+   spa_ringbuffer_get_write_index(&impl->play_ring, &index);
150
+   spa_ringbuffer_write_update(&impl->play_ring, index + (sizeof(float) * (impl->buffer_delay) * impl->info.rate / 1000));
151
+   spa_ringbuffer_get_read_index(&impl->play_ring, &index);
152
+   spa_ringbuffer_read_update(&impl->play_ring, index + (sizeof(float) * (impl->buffer_delay) * impl->info.rate / 1000));
153
+
154
    return 0;
155
 }
156
 
157
@@ -997,6 +1034,9 @@
158
    copy_props(impl, props, PW_KEY_NODE_VIRTUAL);
159
    copy_props(impl, props, PW_KEY_NODE_LATENCY);
160
 
161
+   impl->max_buffer_size = pw_properties_get_uint32(props,"buffer.max_size", MAX_BUFSIZE_MS);
162
+   impl->buffer_delay = pw_properties_get_uint32(props,"buffer.play_delay", DELAY_MS);
163
+
164
    pw_properties_free(props);
165
 
166
    pw_proxy_add_listener((struct pw_proxy*)impl->core,
167
pipewire-0.3.43.tar.gz/src/modules/module-filter-chain.c -> pipewire-0.3.44.tar.gz/src/modules/module-filter-chain.c Changed
84
 
1
@@ -343,7 +343,7 @@
2
    char *col, *node_name, *port_name, *str;
3
    struct port *ports;
4
    const struct fc_descriptor *d;
5
-   uint32_t i, n_ports;
6
+   uint32_t i, n_ports, port_id = SPA_ID_INVALID;
7
 
8
    str = strdupa(name);
9
    col = strchr(str, ':');
10
@@ -359,6 +359,9 @@
11
    if (node == NULL)
12
        return NULL;
13
 
14
+   if (!spa_atou32(port_name, &port_id, 0))
15
+       port_id = SPA_ID_INVALID;
16
+
17
    if (FC_IS_PORT_INPUT(descriptor)) {
18
        if (FC_IS_PORT_CONTROL(descriptor)) {
19
            ports = node->control_port;
20
@@ -381,7 +384,8 @@
21
    d = node->desc->desc;
22
    for (i = 0; i < n_ports; i++) {
23
        struct port *port = &ports[i];
24
-       if (spa_streq(d->ports[port->p].name, port_name))
25
+       if (i == port_id ||
26
+           spa_streq(d->ports[port->p].name, port_name))
27
            return port;
28
    }
29
    return NULL;
30
@@ -1701,11 +1705,8 @@
31
    if (pw_properties_get(props, PW_KEY_NODE_VIRTUAL) == NULL)
32
        pw_properties_set(props, PW_KEY_NODE_VIRTUAL, "true");
33
 
34
-   if (pw_properties_get(props, PW_KEY_NODE_NAME) == NULL)
35
-       pw_properties_setf(props, PW_KEY_NODE_NAME, "filter-chain-%u", id);
36
    if (pw_properties_get(props, PW_KEY_NODE_DESCRIPTION) == NULL)
37
-       pw_properties_set(props, PW_KEY_NODE_DESCRIPTION,
38
-               pw_properties_get(props, PW_KEY_NODE_NAME));
39
+       pw_properties_setf(props, PW_KEY_NODE_DESCRIPTION, "filter-chain-%u", id);
40
 
41
    if ((str = pw_properties_get(props, "capture.props")) != NULL)
42
        pw_properties_update_string(impl->capture_props, str, strlen(str));
43
@@ -1715,7 +1716,6 @@
44
    copy_props(impl, props, PW_KEY_AUDIO_RATE);
45
    copy_props(impl, props, PW_KEY_AUDIO_CHANNELS);
46
    copy_props(impl, props, SPA_KEY_AUDIO_POSITION);
47
-   copy_props(impl, props, PW_KEY_NODE_NAME);
48
    copy_props(impl, props, PW_KEY_NODE_DESCRIPTION);
49
    copy_props(impl, props, PW_KEY_NODE_GROUP);
50
    copy_props(impl, props, PW_KEY_NODE_LINK_GROUP);
51
@@ -1726,18 +1726,25 @@
52
    parse_audio_info(impl->capture_props, &impl->capture_info);
53
    parse_audio_info(impl->playback_props, &impl->playback_info);
54
 
55
+   if (pw_properties_get(impl->capture_props, PW_KEY_NODE_NAME) == NULL)
56
+       pw_properties_setf(impl->capture_props, PW_KEY_NODE_NAME,
57
+               "input.filter-chain-%u", id);
58
+   if (pw_properties_get(impl->playback_props, PW_KEY_NODE_NAME) == NULL)
59
+       pw_properties_setf(impl->playback_props, PW_KEY_NODE_NAME,
60
+               "output.filter-chain-%u", id);
61
+
62
+   if (pw_properties_get(impl->capture_props, PW_KEY_MEDIA_NAME) == NULL)
63
+       pw_properties_setf(impl->capture_props, PW_KEY_MEDIA_NAME, "%s input",
64
+               pw_properties_get(impl->capture_props, PW_KEY_NODE_DESCRIPTION));
65
+   if (pw_properties_get(impl->playback_props, PW_KEY_MEDIA_NAME) == NULL)
66
+       pw_properties_setf(impl->playback_props, PW_KEY_MEDIA_NAME, "%s output",
67
+               pw_properties_get(impl->playback_props, PW_KEY_NODE_DESCRIPTION));
68
+
69
    if ((res = load_graph(&impl->graph, props)) < 0) {
70
        pw_log_error("can't load graph: %s", spa_strerror(res));
71
        goto error;
72
    }
73
 
74
-   if (pw_properties_get(impl->capture_props, PW_KEY_MEDIA_NAME) == NULL)
75
-       pw_properties_setf(impl->capture_props, PW_KEY_MEDIA_NAME, "filter input %s",
76
-               pw_properties_get(impl->capture_props, PW_KEY_NODE_NAME));
77
-   if (pw_properties_get(impl->playback_props, PW_KEY_MEDIA_NAME) == NULL)
78
-       pw_properties_setf(impl->playback_props, PW_KEY_MEDIA_NAME, "filter output %s",
79
-               pw_properties_get(impl->playback_props, PW_KEY_NODE_NAME));
80
-
81
    impl->core = pw_context_get_object(impl->context, PW_TYPE_INTERFACE_Core);
82
    if (impl->core == NULL) {
83
        str = pw_properties_get(props, PW_KEY_REMOTE_NAME);
84
pipewire-0.3.43.tar.gz/src/modules/module-loopback.c -> pipewire-0.3.44.tar.gz/src/modules/module-loopback.c Changed
53
 
1
@@ -461,11 +461,9 @@
2
    if (pw_properties_get(props, PW_KEY_NODE_VIRTUAL) == NULL)
3
        pw_properties_set(props, PW_KEY_NODE_VIRTUAL, "true");
4
 
5
-   if (pw_properties_get(props, PW_KEY_NODE_NAME) == NULL)
6
-       pw_properties_setf(props, PW_KEY_NODE_NAME, "loopback-%u", id);
7
    if (pw_properties_get(props, PW_KEY_NODE_DESCRIPTION) == NULL)
8
-       pw_properties_set(props, PW_KEY_NODE_DESCRIPTION,
9
-               pw_properties_get(props, PW_KEY_NODE_NAME));
10
+       pw_properties_setf(props, PW_KEY_NODE_DESCRIPTION,
11
+               "loopback-%u", id);
12
 
13
    if ((str = pw_properties_get(props, "capture.props")) != NULL)
14
        pw_properties_update_string(impl->capture_props, str, strlen(str));
15
@@ -475,25 +473,29 @@
16
    copy_props(impl, props, PW_KEY_AUDIO_RATE);
17
    copy_props(impl, props, PW_KEY_AUDIO_CHANNELS);
18
    copy_props(impl, props, SPA_KEY_AUDIO_POSITION);
19
-   copy_props(impl, props, PW_KEY_NODE_NAME);
20
    copy_props(impl, props, PW_KEY_NODE_DESCRIPTION);
21
    copy_props(impl, props, PW_KEY_NODE_GROUP);
22
    copy_props(impl, props, PW_KEY_NODE_LINK_GROUP);
23
    copy_props(impl, props, PW_KEY_NODE_LATENCY);
24
    copy_props(impl, props, PW_KEY_NODE_VIRTUAL);
25
+   copy_props(impl, props, PW_KEY_MEDIA_NAME);
26
+
27
+   if (pw_properties_get(impl->capture_props, PW_KEY_NODE_NAME) == NULL)
28
+       pw_properties_setf(impl->capture_props, PW_KEY_NODE_NAME,
29
+               "input.loopback-%u", id);
30
+   if (pw_properties_get(impl->playback_props, PW_KEY_NODE_NAME) == NULL)
31
+       pw_properties_setf(impl->playback_props, PW_KEY_NODE_NAME,
32
+               "output.loopback-%u", id);
33
 
34
    parse_audio_info(impl->capture_props, &impl->capture_info);
35
    parse_audio_info(impl->playback_props, &impl->playback_info);
36
 
37
    if (pw_properties_get(impl->capture_props, PW_KEY_MEDIA_NAME) == NULL)
38
-       pw_properties_setf(impl->capture_props, PW_KEY_MEDIA_NAME,
39
-               "loopback input %s",
40
-               pw_properties_get(impl->capture_props, PW_KEY_NODE_NAME));
41
-
42
+       pw_properties_setf(impl->capture_props, PW_KEY_MEDIA_NAME, "%s input",
43
+               pw_properties_get(impl->capture_props, PW_KEY_NODE_DESCRIPTION));
44
    if (pw_properties_get(impl->playback_props, PW_KEY_MEDIA_NAME) == NULL)
45
-       pw_properties_setf(impl->playback_props, PW_KEY_MEDIA_NAME,
46
-               "loopback output %s",
47
-               pw_properties_get(impl->playback_props, PW_KEY_NODE_NAME));
48
+       pw_properties_setf(impl->playback_props, PW_KEY_MEDIA_NAME, "%s output",
49
+               pw_properties_get(impl->playback_props, PW_KEY_NODE_DESCRIPTION));
50
 
51
    impl->core = pw_context_get_object(impl->context, PW_TYPE_INTERFACE_Core);
52
    if (impl->core == NULL) {
53
pipewire-0.3.43.tar.gz/src/modules/module-metadata.c -> pipewire-0.3.44.tar.gz/src/modules/module-metadata.c Changed
90
 
1
@@ -74,43 +74,70 @@
2
               uint32_t new_id)
3
 {
4
    struct factory_data *data = _data;
5
+   struct pw_context *context = pw_impl_module_get_context(data->module);
6
    void *result;
7
-   struct pw_resource *metadata_resource;
8
-   struct pw_impl_client *client = pw_resource_get_client(resource);
9
+   struct pw_resource *metadata_resource = NULL;
10
+   struct pw_impl_client *client = resource ? pw_resource_get_client(resource) : NULL;
11
    int res;
12
 
13
-   metadata_resource = pw_resource_new(client, new_id, PW_PERM_ALL, type, version, 0);
14
-   if (metadata_resource == NULL) {
15
-       res = -errno;
16
-       goto error_resource;
17
-   }
18
+   if (properties == NULL)
19
+       properties = pw_properties_new(NULL, NULL);
20
+   if (properties == NULL)
21
+       return NULL;
22
+
23
+   pw_properties_setf(properties, PW_KEY_FACTORY_ID, "%d",
24
+           pw_impl_factory_get_info(data->this)->id);
25
+   pw_properties_setf(properties, PW_KEY_MODULE_ID, "%d",
26
+           pw_impl_module_get_info(data->module)->id);
27
+
28
+   if (pw_properties_get(properties, PW_KEY_METADATA_NAME) == NULL)
29
+       pw_properties_set(properties, PW_KEY_METADATA_NAME, "default");
30
+
31
+   if (client) {
32
+       metadata_resource = pw_resource_new(client, new_id, PW_PERM_ALL, type, version, 0);
33
+       if (metadata_resource == NULL) {
34
+           res = -errno;
35
+           goto error_resource;
36
+       }
37
 
38
-   if (properties) {
39
-       pw_properties_setf(properties, PW_KEY_FACTORY_ID, "%d",
40
-               pw_impl_factory_get_info(data->this)->id);
41
        pw_properties_setf(properties, PW_KEY_CLIENT_ID, "%d",
42
                pw_impl_client_get_info(client)->id);
43
-   }
44
 
45
-   result = pw_metadata_new(pw_impl_client_get_context(client), metadata_resource, properties);
46
-   if (result == NULL) {
47
-       res = -errno;
48
-       goto error_node;
49
+       result = pw_metadata_new(context, metadata_resource, properties);
50
+       if (result == NULL) {
51
+           properties = NULL;
52
+           res = -errno;
53
+           goto error_node;
54
+       }
55
+   } else {
56
+       result = pw_context_create_metadata(context, NULL, properties, 0);
57
+       if (result == NULL) {
58
+           properties = NULL;
59
+           res = -errno;
60
+           goto error_node;
61
+       }
62
+       pw_impl_metadata_register(result, NULL);
63
    }
64
    return result;
65
 
66
 error_resource:
67
    pw_log_error("can't create resource: %s", spa_strerror(res));
68
-   pw_resource_errorf_id(resource, new_id, res, "can't create resource: %s", spa_strerror(res));
69
+   if (resource)
70
+       pw_resource_errorf_id(resource, new_id, res,
71
+               "can't create resource: %s", spa_strerror(res));
72
    goto error_exit;
73
 error_node:
74
    pw_log_error("can't create metadata: %s", spa_strerror(res));
75
-   pw_resource_errorf_id(resource, new_id, res, "can't create metadata: %s", spa_strerror(res));
76
+   if (resource)
77
+       pw_resource_errorf_id(resource, new_id, res,
78
+               "can't create metadata: %s", spa_strerror(res));
79
    goto error_exit_free;
80
 
81
 error_exit_free:
82
-   pw_resource_remove(metadata_resource);
83
+   if (metadata_resource)
84
+       pw_resource_remove(metadata_resource);
85
 error_exit:
86
+   pw_properties_free(properties);
87
    errno = -res;
88
    return NULL;
89
 }
90
pipewire-0.3.43.tar.gz/src/modules/module-metadata/metadata.c -> pipewire-0.3.44.tar.gz/src/modules/module-metadata/metadata.c Changed
11
 
1
@@ -271,9 +271,6 @@
2
        return NULL;
3
    }
4
 
5
-   if (pw_properties_get(properties, PW_KEY_METADATA_NAME) == NULL)
6
-       pw_properties_set(properties, PW_KEY_METADATA_NAME, "default");
7
-
8
    pw_resource_install_marshal(resource, true);
9
 
10
    impl->global = pw_global_new(context,
11
pipewire-0.3.43.tar.gz/src/modules/module-profiler.c -> pipewire-0.3.44.tar.gz/src/modules/module-profiler.c Changed
27
 
1
@@ -379,6 +379,10 @@
2
    struct pw_properties *props;
3
    struct impl *impl;
4
    struct pw_loop *main_loop = pw_context_get_main_loop(context);
5
+   static const char * const keys[] = {
6
+       PW_KEY_OBJECT_SERIAL,
7
+       NULL
8
+   };
9
 
10
    PW_LOG_TOPIC_INIT(mod_topic);
11
 
12
@@ -409,9 +413,14 @@
13
        free(impl);
14
        return -errno;
15
    }
16
+   pw_properties_setf(impl->properties, PW_KEY_OBJECT_ID, "%d", impl->global->id);
17
+   pw_properties_setf(impl->properties, PW_KEY_OBJECT_SERIAL, "%"PRIu64,
18
+           pw_global_get_serial(impl->global));
19
 
20
    impl->flush_timeout = pw_loop_add_timer(main_loop, flush_timeout, impl);
21
 
22
+   pw_global_update_keys(impl->global, &impl->properties->dict, keys);
23
+
24
    pw_impl_module_add_listener(module, &impl->module_listener, &module_events, impl);
25
 
26
    pw_impl_module_update_properties(module, &SPA_DICT_INIT_ARRAY(module_props));
27
pipewire-0.3.43.tar.gz/src/modules/module-protocol-native/connection.c -> pipewire-0.3.44.tar.gz/src/modules/module-protocol-native/connection.c Changed
77
 
1
@@ -175,10 +175,37 @@
2
        pw_log_error("connection %p: could not recvmsg on fd:%d: %s", conn, conn->fd, strerror(res));
3
 }
4
 
5
+static size_t cmsg_data_length(const struct cmsghdr *cmsg)
6
+{
7
+   const void *begin = CMSG_DATA(cmsg);
8
+   const void *end = SPA_PTROFF(cmsg, cmsg->cmsg_len, void);
9
+
10
+   spa_assert(begin <= end);
11
+
12
+   return SPA_PTRDIFF(end, begin);
13
+}
14
+
15
+static void close_all_fds(struct msghdr *msg, struct cmsghdr *from)
16
+{
17
+   for (; from != NULL; from = CMSG_NXTHDR(msg, from)) {
18
+       if (from->cmsg_level != SOL_SOCKET || from->cmsg_type != SCM_RIGHTS)
19
+           continue;
20
+
21
+       size_t n_fds = cmsg_data_length(from) / sizeof(int);
22
+       for (size_t i = 0; i < n_fds; i++) {
23
+           const void *p = SPA_PTROFF(CMSG_DATA(from), sizeof(int) * i, void);
24
+           int fd;
25
+
26
+           memcpy(&fd, p, sizeof(fd));
27
+           close(fd);
28
+       }
29
+   }
30
+}
31
+
32
 static int refill_buffer(struct pw_protocol_native_connection *conn, struct buffer *buf)
33
 {
34
    ssize_t len;
35
-   struct cmsghdr *cmsg;
36
+   struct cmsghdr *cmsg = NULL;
37
    struct msghdr msg = { 0 };
38
    struct iovec iov[1];
39
    char cmsgbuf[CMSG_SPACE(MAX_FDS_MSG * sizeof(int))];
40
@@ -198,7 +225,7 @@
41
    while (true) {
42
        len = recvmsg(conn->fd, &msg, msg.msg_flags);
43
        if (msg.msg_flags & MSG_CTRUNC)
44
-           return -EPROTO;
45
+           goto cmsgs_truncated;
46
        if (len == 0 && avail != 0)
47
            return -EPIPE;
48
        else if (len < 0) {
49
@@ -218,10 +245,9 @@
50
        if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS)
51
            continue;
52
 
53
-       n_fds =
54
-           (cmsg->cmsg_len - ((char *) CMSG_DATA(cmsg) - (char *) cmsg)) / sizeof(int);
55
+       n_fds = cmsg_data_length(cmsg) / sizeof(int);
56
        if (n_fds + buf->n_fds > MAX_FDS)
57
-           return -EPROTO;
58
+           goto too_many_fds;
59
        memcpy(&buf->fds[buf->n_fds], CMSG_DATA(cmsg), n_fds * sizeof(int));
60
        buf->n_fds += n_fds;
61
    }
62
@@ -234,6 +260,14 @@
63
 recv_error:
64
    handle_connection_error(conn, errno);
65
    return -errno;
66
+
67
+cmsgs_truncated:
68
+   close_all_fds(&msg, CMSG_FIRSTHDR(&msg));
69
+   return -EPROTO;
70
+
71
+too_many_fds:
72
+   close_all_fds(&msg, cmsg);
73
+   return -EPROTO;
74
 }
75
 
76
 static void clear_buffer(struct buffer *buf, bool fds)
77
pipewire-0.3.43.tar.gz/src/modules/module-protocol-pulse/client.c -> pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/client.c Changed
116
 
1
@@ -295,23 +295,34 @@
2
    return 0;
3
 }
4
 
5
-/* returns true if an event with the (mask, event, id) triplet should be dropped because it is redundant */
6
-static bool client_prune_subscribe_events(struct client *client, uint32_t mask, uint32_t event, uint32_t id)
7
+static bool drop_from_out_queue(struct client *client, struct message *m)
8
 {
9
-   struct impl *impl = client->impl;
10
-   struct message *m, *t, *first;
11
+   spa_assert(!spa_list_is_empty(&client->out_messages));
12
 
13
-   if ((event & SUBSCRIPTION_EVENT_TYPE_MASK) == SUBSCRIPTION_EVENT_NEW)
14
+   struct message *first = spa_list_first(&client->out_messages, struct message, link);
15
+   if (m == first && client->out_index > 0)
16
        return false;
17
 
18
-   first = spa_list_first(&client->out_messages, struct message, link);
19
+   message_free(client->impl, m, true, false);
20
+
21
+   return true;
22
+}
23
+
24
+/* returns true if an event with the (mask, event, index) triplet should be dropped because it is redundant */
25
+static bool client_prune_subscribe_events(struct client *client, uint32_t mask, uint32_t event, uint32_t index)
26
+{
27
+   struct message *m, *t;
28
+
29
+   if ((event & SUBSCRIPTION_EVENT_TYPE_MASK) == SUBSCRIPTION_EVENT_NEW)
30
+       return false;
31
 
32
+   /* NOTE: reverse iteration */
33
    spa_list_for_each_safe_reverse(m, t, &client->out_messages, link) {
34
        if (m->extra[0] != COMMAND_SUBSCRIBE_EVENT)
35
            continue;
36
        if ((m->extra[1] ^ event) & SUBSCRIPTION_EVENT_FACILITY_MASK)
37
            continue;
38
-       if (m->extra[2] != id)
39
+       if (m->extra[2] != index)
40
            continue;
41
 
42
        if ((event & SUBSCRIPTION_EVENT_TYPE_MASK) == SUBSCRIPTION_EVENT_REMOVE) {
43
@@ -319,25 +330,39 @@
44
             * point in keeping the old events regarding
45
             * entry in the queue. */
46
 
47
-           /* if the first message has already been partially sent, do not drop it */
48
-           if (m != first || client->out_index == 0) {
49
-               message_free(impl, m, true, false);
50
-               pw_log_debug("client %p: dropped redundant event due to remove event", client);
51
+           bool is_new = (m->extra[1] & SUBSCRIPTION_EVENT_TYPE_MASK) == SUBSCRIPTION_EVENT_NEW;
52
+
53
+           if (drop_from_out_queue(client, m)) {
54
+               pw_log_debug("client %p: dropped redundant event due to remove event for object %u",
55
+                        client, index);
56
+
57
+               /* if the NEW event for the current object could successfully be dropped,
58
+                  there is no need to deliver the REMOVE event */
59
+               if (is_new)
60
+                   goto drop;
61
            }
62
+
63
+           /* stop if the NEW event for the current object is reached */
64
+           if (is_new)
65
+               break;
66
        }
67
 
68
        if ((event & SUBSCRIPTION_EVENT_TYPE_MASK) == SUBSCRIPTION_EVENT_CHANGE) {
69
            /* This object has changed. If a "new" or "change" event for
70
             * this object is still in the queue we can exit. */
71
-           pw_log_debug("client %p: dropped redundant event due to change event", client);
72
-           return true;
73
+           goto drop;
74
        }
75
    }
76
 
77
    return false;
78
+
79
+drop:
80
+   pw_log_debug("client %p: dropped redundant event for object %u", client, index);
81
+
82
+   return true;
83
 }
84
 
85
-int client_queue_subscribe_event(struct client *client, uint32_t mask, uint32_t event, uint32_t id)
86
+int client_queue_subscribe_event(struct client *client, uint32_t mask, uint32_t event, uint32_t index)
87
 {
88
    if (client->disconnect)
89
        return -ENOTCONN;
90
@@ -345,21 +370,21 @@
91
    if (!(client->subscribed & mask))
92
        return 0;
93
 
94
-   pw_log_debug("client %p: SUBSCRIBE event:%08x id:%u", client, event, id);
95
+   pw_log_debug("client %p: SUBSCRIBE event:%08x index:%u", client, event, index);
96
 
97
-   if (client_prune_subscribe_events(client, mask, event, id))
98
+   if (client_prune_subscribe_events(client, mask, event, index))
99
        return 0;
100
 
101
    struct message *reply = message_alloc(client->impl, -1, 0);
102
    reply->extra[0] = COMMAND_SUBSCRIBE_EVENT;
103
    reply->extra[1] = event;
104
-   reply->extra[2] = id;
105
+   reply->extra[2] = index;
106
 
107
    message_put(reply,
108
        TAG_U32, COMMAND_SUBSCRIBE_EVENT,
109
        TAG_U32, -1,
110
        TAG_U32, event,
111
-       TAG_U32, id,
112
+       TAG_U32, index,
113
        TAG_INVALID);
114
 
115
    return client_queue_message(client, reply);
116
pipewire-0.3.43.tar.gz/src/modules/module-protocol-pulse/collect.c -> pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/collect.c Changed
201
 
1
@@ -58,19 +58,41 @@
2
            continue;
3
        if (o->id == s->id)
4
            return o;
5
+       if (o->index == s->index)
6
+           return o;
7
        if (s->accumulate)
8
            s->accumulate(s, o);
9
        if (o->props && s->key != NULL && s->value != NULL &&
10
            (str = pw_properties_get(o->props, s->key)) != NULL &&
11
            spa_streq(str, s->value))
12
            return o;
13
-       if (s->value != NULL && (uint32_t)atoi(s->value) == o->id)
14
+       if (s->value != NULL && (uint32_t)atoi(s->value) == o->index)
15
            return o;
16
    }
17
    return s->best;
18
 }
19
 
20
-bool collect_is_linked(struct pw_manager *m, uint32_t obj_id, enum pw_direction direction)
21
+uint32_t id_to_index(struct pw_manager *m, uint32_t id)
22
+{
23
+   struct pw_manager_object *o;
24
+   spa_list_for_each(o, &m->object_list, link) {
25
+       if (o->id == id)
26
+           return o->index;
27
+   }
28
+   return SPA_ID_INVALID;
29
+}
30
+
31
+uint32_t index_to_id(struct pw_manager *m, uint32_t index)
32
+{
33
+   struct pw_manager_object *o;
34
+   spa_list_for_each(o, &m->object_list, link) {
35
+       if (o->index == index)
36
+           return o->id;
37
+   }
38
+   return SPA_ID_INVALID;
39
+}
40
+
41
+bool collect_is_linked(struct pw_manager *m, uint32_t id, enum pw_direction direction)
42
 {
43
    struct pw_manager_object *o;
44
    uint32_t in_node, out_node;
45
@@ -83,14 +105,14 @@
46
                     pw_properties_fetch_uint32(o->props, PW_KEY_LINK_INPUT_NODE, &in_node) != 0)
47
                         continue;
48
 
49
-       if ((direction == PW_DIRECTION_OUTPUT && obj_id == out_node) ||
50
-           (direction == PW_DIRECTION_INPUT && obj_id == in_node))
51
+       if ((direction == PW_DIRECTION_OUTPUT && id == out_node) ||
52
+           (direction == PW_DIRECTION_INPUT && id == in_node))
53
            return true;
54
    }
55
    return false;
56
 }
57
 
58
-struct pw_manager_object *find_linked(struct pw_manager *m, uint32_t obj_id, enum pw_direction direction)
59
+struct pw_manager_object *find_linked(struct pw_manager *m, uint32_t id, enum pw_direction direction)
60
 {
61
    struct pw_manager_object *o, *p;
62
    uint32_t in_node, out_node;
63
@@ -103,12 +125,12 @@
64
                     pw_properties_fetch_uint32(o->props, PW_KEY_LINK_INPUT_NODE, &in_node) != 0)
65
                         continue;
66
 
67
-       if (direction == PW_DIRECTION_OUTPUT && obj_id == out_node) {
68
+       if (direction == PW_DIRECTION_OUTPUT && id == out_node) {
69
            struct selector sel = { .id = in_node, .type = pw_manager_object_is_sink, };
70
            if ((p = select_object(m, &sel)) != NULL)
71
                return p;
72
        }
73
-       if (direction == PW_DIRECTION_INPUT && obj_id == in_node) {
74
+       if (direction == PW_DIRECTION_INPUT && id == in_node) {
75
            struct selector sel = { .id = out_node, .type = pw_manager_object_is_recordable, };
76
            if ((p = select_object(m, &sel)) != NULL)
77
                return p;
78
@@ -157,7 +179,7 @@
79
 
80
        if (spa_pod_parse_object(p->param,
81
                SPA_TYPE_OBJECT_ParamProfile, NULL,
82
-               SPA_PARAM_PROFILE_index, SPA_POD_Int(&pi->id),
83
+               SPA_PARAM_PROFILE_index, SPA_POD_Int(&pi->index),
84
                SPA_PARAM_PROFILE_name,  SPA_POD_String(&pi->name),
85
                SPA_PARAM_PROFILE_description,  SPA_POD_OPT_String(&pi->description),
86
                SPA_PARAM_PROFILE_priority,  SPA_POD_OPT_Int(&pi->priority),
87
@@ -167,7 +189,7 @@
88
        }
89
        if (pi->description == NULL)
90
            pi->description = pi->name;
91
-       if (pi->id == card_info->active_profile)
92
+       if (pi->index == card_info->active_profile)
93
            card_info->active_profile_name = pi->name;
94
 
95
        if (classes != NULL) {
96
@@ -198,12 +220,12 @@
97
    return n;
98
 }
99
 
100
-uint32_t find_profile_id(struct pw_manager_object *card, const char *name)
101
+uint32_t find_profile_index(struct pw_manager_object *card, const char *name)
102
 {
103
    struct pw_manager_param *p;
104
 
105
    spa_list_for_each(p, &card->param_list, link) {
106
-       uint32_t id;
107
+       uint32_t index;
108
        const char *test_name;
109
 
110
        if (p->id != SPA_PARAM_EnumProfile)
111
@@ -211,12 +233,12 @@
112
 
113
        if (spa_pod_parse_object(p->param,
114
                SPA_TYPE_OBJECT_ParamProfile, NULL,
115
-               SPA_PARAM_PROFILE_index, SPA_POD_Int(&id),
116
+               SPA_PARAM_PROFILE_index, SPA_POD_Int(&index),
117
                SPA_PARAM_PROFILE_name,  SPA_POD_String(&test_name)) < 0)
118
            continue;
119
 
120
        if (spa_streq(test_name, name))
121
-           return id;
122
+           return index;
123
 
124
    }
125
    return SPA_ID_INVALID;
126
@@ -229,7 +251,7 @@
127
 
128
    if (card && !monitor) {
129
        spa_list_for_each(p, &card->param_list, link) {
130
-           uint32_t id, dev;
131
+           uint32_t index, dev;
132
            struct spa_pod *props;
133
 
134
            if (p->id != SPA_PARAM_Route)
135
@@ -237,13 +259,13 @@
136
 
137
            if (spa_pod_parse_object(p->param,
138
                    SPA_TYPE_OBJECT_ParamRoute, NULL,
139
-                   SPA_PARAM_ROUTE_index, SPA_POD_Int(&id),
140
+                   SPA_PARAM_ROUTE_index, SPA_POD_Int(&index),
141
                    SPA_PARAM_ROUTE_device,  SPA_POD_Int(&dev),
142
                    SPA_PARAM_ROUTE_props,  SPA_POD_OPT_Pod(&props)) < 0)
143
                continue;
144
            if (dev != dev_info->device)
145
                continue;
146
-           dev_info->active_port = id;
147
+           dev_info->active_port = index;
148
            if (props) {
149
                volume_parse_param(props, &dev_info->volume_info, monitor);
150
                dev_info->have_volume = true;
151
@@ -316,7 +338,7 @@
152
 
153
        if (spa_pod_parse_object(p->param,
154
                SPA_TYPE_OBJECT_ParamRoute, NULL,
155
-               SPA_PARAM_ROUTE_index, SPA_POD_Int(&pi->id),
156
+               SPA_PARAM_ROUTE_index, SPA_POD_Int(&pi->index),
157
                SPA_PARAM_ROUTE_direction, SPA_POD_Id(&pi->direction),
158
                SPA_PARAM_ROUTE_name,  SPA_POD_String(&pi->name),
159
                SPA_PARAM_ROUTE_description,  SPA_POD_OPT_String(&pi->description),
160
@@ -341,7 +363,7 @@
161
                continue;
162
            if (!array_contains(pi->devices, pi->n_devices, dev_info->device))
163
                continue;
164
-           if (pi->id == dev_info->active_port)
165
+           if (pi->index == dev_info->active_port)
166
                dev_info->active_port_name = pi->name;
167
        }
168
 
169
@@ -377,12 +399,12 @@
170
    return n;
171
 }
172
 
173
-uint32_t find_port_id(struct pw_manager_object *card, uint32_t direction, const char *port_name)
174
+uint32_t find_port_index(struct pw_manager_object *card, uint32_t direction, const char *port_name)
175
 {
176
    struct pw_manager_param *p;
177
 
178
    spa_list_for_each(p, &card->param_list, link) {
179
-       uint32_t id, dir;
180
+       uint32_t index, dir;
181
        const char *name;
182
 
183
        if (p->id != SPA_PARAM_EnumRoute)
184
@@ -390,14 +412,14 @@
185
 
186
        if (spa_pod_parse_object(p->param,
187
                SPA_TYPE_OBJECT_ParamRoute, NULL,
188
-               SPA_PARAM_ROUTE_index, SPA_POD_Int(&id),
189
+               SPA_PARAM_ROUTE_index, SPA_POD_Int(&index),
190
                SPA_PARAM_ROUTE_direction, SPA_POD_Id(&dir),
191
                SPA_PARAM_ROUTE_name, SPA_POD_String(&name)) < 0)
192
            continue;
193
        if (dir != direction)
194
            continue;
195
        if (spa_streq(name, port_name))
196
-           return id;
197
+           return index;
198
 
199
    }
200
    return SPA_ID_INVALID;
201
pipewire-0.3.43.tar.gz/src/modules/module-protocol-pulse/collect.h -> pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/collect.h Changed
50
 
1
@@ -44,6 +44,7 @@
2
 struct selector {
3
    bool (*type) (struct pw_manager_object *o);
4
    uint32_t id;
5
+   uint32_t index;
6
    const char *key;
7
    const char *value;
8
    void (*accumulate) (struct selector *sel, struct pw_manager_object *o);
9
@@ -52,6 +53,8 @@
10
 };
11
 
12
 struct pw_manager_object *select_object(struct pw_manager *m, struct selector *s);
13
+uint32_t id_to_index(struct pw_manager *m, uint32_t id);
14
+uint32_t index_to_id(struct pw_manager *m, uint32_t index);
15
 void select_best(struct selector *s, struct pw_manager_object *o);
16
 
17
 /* ========================================================================== */
18
@@ -103,7 +106,7 @@
19
 /* ========================================================================== */
20
 
21
 struct profile_info {
22
-   uint32_t id;
23
+   uint32_t index;
24
    const char *name;
25
    const char *description;
26
    uint32_t priority;
27
@@ -118,7 +121,7 @@
28
 /* ========================================================================== */
29
 
30
 struct port_info {
31
-   uint32_t id;
32
+   uint32_t index;
33
    uint32_t direction;
34
    const char *name;
35
    const char *description;
36
@@ -154,9 +157,9 @@
37
 /* ========================================================================== */
38
 
39
 struct spa_dict *collect_props(struct spa_pod *info, struct spa_dict *dict);
40
-uint32_t find_profile_id(struct pw_manager_object *card, const char *name);
41
-uint32_t find_port_id(struct pw_manager_object *card, uint32_t direction, const char *port_name);
42
-struct pw_manager_object *find_linked(struct pw_manager *m, uint32_t obj_id, enum pw_direction direction);
43
-bool collect_is_linked(struct pw_manager *m, uint32_t obj_id, enum pw_direction direction);
44
+uint32_t find_profile_index(struct pw_manager_object *card, const char *name);
45
+uint32_t find_port_index(struct pw_manager_object *card, uint32_t direction, const char *port_name);
46
+struct pw_manager_object *find_linked(struct pw_manager *m, uint32_t id, enum pw_direction direction);
47
+bool collect_is_linked(struct pw_manager *m, uint32_t id, enum pw_direction direction);
48
 
49
 #endif
50
pipewire-0.3.43.tar.gz/src/modules/module-protocol-pulse/defs.h -> pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/defs.h Changed
15
 
1
@@ -56,10 +56,9 @@
2
 
3
 #define SCACHE_ENTRY_SIZE_MAX  (1024*1024*16)
4
 
5
-#define INDEX_MASK     0xffffu
6
-#define MONITOR_FLAG       (1u << 16)
7
-#define EXTENSION_FLAG     (1u << 17)
8
-#define MODULE_FLAG        (1u << 18)
9
+#define MODULE_INDEX_MASK  0xfffffffu
10
+#define MODULE_EXTENSION_FLAG  (1u << 28)
11
+#define MODULE_FLAG        (1u << 29)
12
 
13
 #define DEFAULT_SINK       "@DEFAULT_SINK@"
14
 #define DEFAULT_SOURCE     "@DEFAULT_SOURCE@"
15
pipewire-0.3.43.tar.gz/src/modules/module-protocol-pulse/extension.c -> pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/extension.c Changed
24
 
1
@@ -30,17 +30,17 @@
2
 #include "extensions/registry.h"
3
 
4
 static const struct extension extensions[] = {
5
-   { "module-stream-restore", 0 | EXTENSION_FLAG, do_extension_stream_restore, },
6
-   { "module-device-restore", 1 | EXTENSION_FLAG, do_extension_device_restore, },
7
-   { "module-device-manager", 2 | EXTENSION_FLAG, do_extension_device_manager, },
8
+   { "module-stream-restore", 0 | MODULE_EXTENSION_FLAG, do_extension_stream_restore, },
9
+   { "module-device-restore", 1 | MODULE_EXTENSION_FLAG, do_extension_device_restore, },
10
+   { "module-device-manager", 2 | MODULE_EXTENSION_FLAG, do_extension_device_manager, },
11
 };
12
 
13
-const struct extension *extension_find(uint32_t idx, const char *name)
14
+const struct extension *extension_find(uint32_t index, const char *name)
15
 {
16
    const struct extension *ext;
17
 
18
    SPA_FOR_EACH_ELEMENT(extensions, ext) {
19
-       if (idx == ext->idx || spa_streq(name, ext->name))
20
+       if (index == ext->index || spa_streq(name, ext->name))
21
            return ext;
22
    }
23
 
24
pipewire-0.3.43.tar.gz/src/modules/module-protocol-pulse/extension.h -> pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/extension.h Changed
14
 
1
@@ -38,10 +38,10 @@
2
 
3
 struct extension {
4
    const char *name;
5
-   uint32_t idx;
6
+   uint32_t index;
7
    int (*process)(struct client *client, uint32_t tag, struct message *m);
8
 };
9
 
10
-const struct extension *extension_find(uint32_t idx, const char *name);
11
+const struct extension *extension_find(uint32_t index, const char *name);
12
 
13
 #endif /* PULSE_SERVER_EXTENSION_H */
14
pipewire-0.3.43.tar.gz/src/modules/module-protocol-pulse/extensions/ext-device-restore.c -> pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/extensions/ext-device-restore.c Changed
46
 
1
@@ -108,7 +108,7 @@
2
    }
3
    message_put(d->reply,
4
        TAG_U32, DEVICE_TYPE_SINK,
5
-       TAG_U32, o->id,
6
+       TAG_U32, o->index,          /* sink index */
7
        TAG_U8, n_info,             /* n_formats */
8
        TAG_INVALID);
9
    for (i = 0; i < n_info; i++) {
10
@@ -157,7 +157,7 @@
11
    }
12
 
13
    spa_zero(sel);
14
-   sel.id = sink_index;
15
+   sel.index = sink_index;
16
    sel.type = pw_manager_object_is_sink;
17
 
18
    o = select_object(manager, &sel);
19
@@ -173,7 +173,7 @@
20
    return client_queue_message(client, data.reply);
21
 }
22
 
23
-static int set_card_codecs(struct pw_manager_object *o, uint32_t id,
24
+static int set_card_codecs(struct pw_manager_object *o, uint32_t port_index,
25
        uint32_t device_id, uint32_t n_codecs, uint32_t *codecs)
26
 {
27
    char buf[1024];
28
@@ -190,7 +190,7 @@
29
    spa_pod_builder_push_object(&b, &f[0],
30
            SPA_TYPE_OBJECT_ParamRoute, SPA_PARAM_Route);
31
    spa_pod_builder_add(&b,
32
-           SPA_PARAM_ROUTE_index, SPA_POD_Int(id),
33
+           SPA_PARAM_ROUTE_index, SPA_POD_Int(port_index),
34
            SPA_PARAM_ROUTE_device, SPA_POD_Int(device_id),
35
            0);
36
    spa_pod_builder_prop(&b, SPA_PARAM_ROUTE_props, 0);
37
@@ -279,7 +279,7 @@
38
        return -ENOTSUP;
39
 
40
    spa_zero(sel);
41
-   sel.id = sink_index;
42
+   sel.index = sink_index;
43
    sel.type = pw_manager_object_is_sink;
44
 
45
    o = select_object(manager, &sel);
46
pipewire-0.3.43.tar.gz/src/modules/module-protocol-pulse/internal.h -> pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/internal.h Changed
10
 
1
@@ -51,7 +51,7 @@
2
    struct spa_fraction min_quantum;
3
    struct sample_spec sample_spec;
4
    struct channel_map channel_map;
5
-   uint32_t max_quantum;
6
+   uint32_t quantum_limit;
7
 };
8
 
9
 struct stats {
10
pipewire-0.3.43.tar.gz/src/modules/module-protocol-pulse/manager.c -> pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/manager.c Changed
106
 
1
@@ -64,7 +64,7 @@
2
 
3
 struct object_data {
4
    struct spa_list link;
5
-   const char *id;
6
+   const char *key;
7
    size_t size;
8
 };
9
 
10
@@ -163,7 +163,7 @@
11
 }
12
 
13
 
14
-static struct object *find_object(struct manager *m, uint32_t id)
15
+static struct object *find_object_by_id(struct manager *m, uint32_t id)
16
 {
17
    struct object *o;
18
    spa_list_for_each(o, &m->this.object_list, this.link) {
19
@@ -586,6 +586,7 @@
20
    struct manager *m = data;
21
    struct object *o;
22
    const struct object_info *info;
23
+   const char *str;
24
    struct pw_proxy *proxy;
25
 
26
    info = find_info(type, version);
27
@@ -603,10 +604,15 @@
28
        pw_proxy_destroy(proxy);
29
        return;
30
    }
31
+   str = props ? spa_dict_lookup(props, PW_KEY_OBJECT_SERIAL) : NULL;
32
+   if (!spa_atou64(str, &o->this.serial, 0))
33
+       o->this.serial = SPA_ID_INVALID;
34
+
35
    o->this.id = id;
36
    o->this.permissions = permissions;
37
    o->this.type = info->type;
38
    o->this.version = version;
39
+   o->this.index = o->this.serial < (1ULL<<32) ? o->this.serial : SPA_ID_INVALID;
40
    o->this.props = props ? pw_properties_new_dict(props) : NULL;
41
    o->this.proxy = proxy;
42
    o->this.creating = true;
43
@@ -638,7 +644,7 @@
44
    struct manager *m = object;
45
    struct object *o;
46
 
47
-   if ((o = find_object(m, id)) == NULL)
48
+   if ((o = find_object_by_id(m, id)) == NULL)
49
        return;
50
 
51
    o->this.removing = true;
52
@@ -757,7 +763,7 @@
53
    char buf[1024];
54
    char *value;
55
 
56
-   if ((s = find_object(m, subject)) == NULL)
57
+   if ((s = find_object_by_id(m, subject)) == NULL)
58
        return -ENOENT;
59
    if (!SPA_FLAG_IS_SET(s->this.permissions, PW_PERM_M))
60
        return -EACCES;
61
@@ -793,7 +799,7 @@
62
    int res;
63
 
64
    spa_list_for_each(o, &m->this.object_list, this.link) {
65
-       if (o->this.creating)
66
+       if (o->this.creating || o->this.removing)
67
            continue;
68
        if ((res = callback(data, &o->this)) != 0)
69
            return res;
70
@@ -820,22 +826,22 @@
71
    free(m);
72
 }
73
 
74
-static struct object_data *object_find_data(struct object *o, const char *id)
75
+static struct object_data *object_find_data(struct object *o, const char *key)
76
 {
77
    struct object_data *d;
78
    spa_list_for_each(d, &o->data_list, link) {
79
-       if (spa_streq(d->id, id))
80
+       if (spa_streq(d->key, key))
81
            return d;
82
    }
83
    return NULL;
84
 }
85
 
86
-void *pw_manager_object_add_data(struct pw_manager_object *obj, const char *id, size_t size)
87
+void *pw_manager_object_add_data(struct pw_manager_object *obj, const char *key, size_t size)
88
 {
89
    struct object *o = SPA_CONTAINER_OF(obj, struct object, this);
90
    struct object_data *d;
91
 
92
-   d = object_find_data(o, id);
93
+   d = object_find_data(o, key);
94
    if (d != NULL) {
95
        if (d->size == size)
96
            goto done;
97
@@ -844,7 +850,7 @@
98
    }
99
 
100
    d = calloc(1, sizeof(struct object_data) + size);
101
-   d->id = id;
102
+   d->key = key;
103
    d->size = size;
104
 
105
    spa_list_append(&o->data_list, &d->link);
106
pipewire-0.3.43.tar.gz/src/modules/module-protocol-pulse/manager.h -> pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/manager.h Changed
25
 
1
@@ -75,10 +75,12 @@
2
 
3
 struct pw_manager_object {
4
    struct spa_list link;           /**< link in manager object_list */
5
+   uint64_t serial;
6
    uint32_t id;
7
    uint32_t permissions;
8
    const char *type;
9
    uint32_t version;
10
+   uint32_t index;
11
    struct pw_properties *props;
12
    struct pw_proxy *proxy;
13
    char *message_object_path;
14
@@ -111,8 +113,8 @@
15
        int (*callback) (void *data, struct pw_manager_object *object),
16
        void *data);
17
 
18
-void *pw_manager_object_add_data(struct pw_manager_object *o, const char *id, size_t size);
19
-void *pw_manager_object_get_data(struct pw_manager_object *obj, const char *id);
20
+void *pw_manager_object_add_data(struct pw_manager_object *o, const char *key, size_t size);
21
+void *pw_manager_object_get_data(struct pw_manager_object *obj, const char *key);
22
 
23
 bool pw_manager_object_is_client(struct pw_manager_object *o);
24
 bool pw_manager_object_is_module(struct pw_manager_object *o);
25
pipewire-0.3.43.tar.gz/src/modules/module-protocol-pulse/message-handler.c -> pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/message-handler.c Changed
10
 
1
@@ -122,7 +122,7 @@
2
 {
3
    const char *str;
4
 
5
-   if (o->id == 0) {
6
+   if (o->id == PW_ID_CORE) {
7
        free(o->message_object_path);
8
        o->message_object_path = strdup("/core");
9
        o->message_handler = core_object_message_handler;
10
pipewire-0.3.43.tar.gz/src/modules/module-protocol-pulse/module.c -> pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/module.c Changed
73
 
1
@@ -42,7 +42,7 @@
2
 #include "log.h"
3
 #include "module.h"
4
 
5
-static void on_module_unload(void *obj, void *data, int res, uint32_t id)
6
+static void on_module_unload(void *obj, void *data, int res, uint32_t index)
7
 {
8
    struct module *module = obj;
9
    module_unload(NULL, module);
10
@@ -83,7 +83,7 @@
11
 
12
 int module_load(struct client *client, struct module *module)
13
 {
14
-   pw_log_info("load module id:%u name:%s", module->idx, module->name);
15
+   pw_log_info("load module index:%u name:%s", module->index, module->name);
16
    if (module->methods->load == NULL)
17
        return -ENOTSUP;
18
    /* subscription event is sent when the module does a
19
@@ -97,8 +97,8 @@
20
 
21
    module_emit_destroy(module);
22
 
23
-   if (module->idx != SPA_ID_INVALID)
24
-       pw_map_remove(&impl->modules, module->idx & INDEX_MASK);
25
+   if (module->index != SPA_ID_INVALID)
26
+       pw_map_remove(&impl->modules, module->index & MODULE_INDEX_MASK);
27
 
28
    spa_hook_list_clean(&module->listener_list);
29
    pw_work_queue_cancel(impl->work_queue, module, SPA_ID_INVALID);
30
@@ -118,7 +118,7 @@
31
    /* Note that client can be NULL (when the module is being unloaded
32
     * internally and not by a client request */
33
 
34
-   pw_log_info("unload module id:%u name:%s", module->idx, module->name);
35
+   pw_log_info("unload module index:%u name:%s", module->index, module->name);
36
 
37
    if (module->methods->unload)
38
        res = module->methods->unload(client, module);
39
@@ -127,7 +127,7 @@
40
        broadcast_subscribe_event(impl,
41
            SUBSCRIPTION_MASK_MODULE,
42
            SUBSCRIPTION_EVENT_REMOVE | SUBSCRIPTION_EVENT_MODULE,
43
-           module->idx);
44
+           module->index);
45
 
46
    module_free(module);
47
 
48
@@ -270,6 +270,7 @@
49
 #endif
50
    { "module-roc-sink", create_module_roc_sink, },
51
    { "module-roc-source", create_module_roc_source, },
52
+   { "module-x11-bell", create_module_x11_bell, },
53
 };
54
 
55
 static const struct module_info *find_module_info(const char *name)
56
@@ -299,13 +300,13 @@
57
    if (module == NULL)
58
        return NULL;
59
 
60
-   module->idx = pw_map_insert_new(&impl->modules, module);
61
-   if (module->idx == SPA_ID_INVALID) {
62
+   module->index = pw_map_insert_new(&impl->modules, module);
63
+   if (module->index == SPA_ID_INVALID) {
64
        module_unload(client, module);
65
        return NULL;
66
    }
67
    module->name = strdup(name);
68
    module->args = args ? strdup(args) : NULL;
69
-   module->idx |= MODULE_FLAG;
70
+   module->index |= MODULE_FLAG;
71
    return module;
72
 }
73
pipewire-0.3.43.tar.gz/src/modules/module-protocol-pulse/module.h -> pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/module.h Changed
10
 
1
@@ -57,7 +57,7 @@
2
 };
3
 
4
 struct module {
5
-   uint32_t idx;
6
+   uint32_t index;
7
    const char *name;
8
    const char *args;
9
    struct pw_properties *props;
10
pipewire-0.3.43.tar.gz/src/modules/module-protocol-pulse/modules/module-combine-sink.c -> pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/modules/module-combine-sink.c Changed
27
 
1
@@ -262,11 +262,11 @@
2
 
3
    props = pw_properties_new(NULL, NULL);
4
    pw_properties_setf(props, PW_KEY_NODE_NAME,
5
-           "combine_output.sink-%u.%s", data->module->idx, sink_name);
6
+           "combine_output.sink-%u.%s", data->module->index, sink_name);
7
    pw_properties_set(props, PW_KEY_NODE_DESCRIPTION, data->sink_name);
8
    pw_properties_set(props, PW_KEY_NODE_TARGET, sink_name);
9
-   pw_properties_setf(props, PW_KEY_NODE_GROUP, "combine_sink-%u", data->module->idx);
10
-   pw_properties_setf(props, PW_KEY_NODE_LINK_GROUP, "combine_sink-%u", data->module->idx);
11
+   pw_properties_setf(props, PW_KEY_NODE_GROUP, "combine_sink-%u", data->module->index);
12
+   pw_properties_setf(props, PW_KEY_NODE_LINK_GROUP, "combine_sink-%u", data->module->index);
13
    pw_properties_set(props, PW_KEY_NODE_DONT_RECONNECT, "true");
14
    pw_properties_set(props, PW_KEY_NODE_VIRTUAL, "true");
15
    pw_properties_set(props, PW_KEY_NODE_PASSIVE, "true");
16
@@ -351,8 +351,8 @@
17
    pw_properties_set(props, PW_KEY_NODE_NAME, data->sink_name);
18
    pw_properties_set(props, PW_KEY_NODE_DESCRIPTION, data->sink_name);
19
    pw_properties_set(props, PW_KEY_MEDIA_CLASS, "Audio/Sink");
20
-   pw_properties_setf(props, PW_KEY_NODE_GROUP, "combine_sink-%u", data->module->idx);
21
-   pw_properties_setf(props, PW_KEY_NODE_LINK_GROUP, "combine_sink-%u", data->module->idx);
22
+   pw_properties_setf(props, PW_KEY_NODE_GROUP, "combine_sink-%u", data->module->index);
23
+   pw_properties_setf(props, PW_KEY_NODE_LINK_GROUP, "combine_sink-%u", data->module->index);
24
    pw_properties_set(props, PW_KEY_NODE_VIRTUAL, "true");
25
 
26
    if ((str = pw_properties_get(module->props, "sink_properties")) != NULL)
27
pipewire-0.3.43.tar.gz/src/modules/module-protocol-pulse/modules/module-ladspa-sink.c -> pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/modules/module-ladspa-sink.c Changed
47
 
1
@@ -73,8 +73,8 @@
2
    if ((label = pw_properties_get(module->props, "label")) == NULL)
3
        return -EINVAL;
4
 
5
-   pw_properties_setf(data->capture_props, PW_KEY_NODE_GROUP, "ladspa-sink-%u", module->idx);
6
-   pw_properties_setf(data->playback_props, PW_KEY_NODE_GROUP, "ladspa-sink-%u", module->idx);
7
+   pw_properties_setf(data->capture_props, PW_KEY_NODE_GROUP, "ladspa-sink-%u", module->index);
8
+   pw_properties_setf(data->playback_props, PW_KEY_NODE_GROUP, "ladspa-sink-%u", module->index);
9
 
10
    f = open_memstream(&args, &size);
11
    fprintf(f, "{");
12
@@ -84,11 +84,24 @@
13
    fprintf(f, " type = ladspa ");
14
    fprintf(f, " plugin = \"%s\" ", plugin);
15
    fprintf(f, " label = \"%s\" ", label);
16
+   if ((str = pw_properties_get(module->props, "control")) != NULL) {
17
+       size_t len;
18
+       const char *s, *state = NULL;
19
+       int count = 0;
20
+
21
+       fprintf(f, " control = {");
22
+       while ((s = pw_split_walk(str, ", ", &len, &state))) {
23
+           fprintf(f, " \"%d\" = %.*s", count, (int)len, s);
24
+           count++;
25
+       }
26
+       fprintf(f, " }");
27
+   }
28
+   fprintf(f, " } ]");
29
    if ((str = pw_properties_get(module->props, "inputs")) != NULL)
30
        fprintf(f, " inputs = [ %s ] ", str);
31
    if ((str = pw_properties_get(module->props, "outputs")) != NULL)
32
        fprintf(f, " outputs = [ %s ] ", str);
33
-   fprintf(f, " } ] }");
34
+   fprintf(f, " }");
35
    fprintf(f, " capture.props = {");
36
    pw_properties_serialize_dict(f, &data->capture_props->dict, 0);
37
    fprintf(f, " } playback.props = {");
38
@@ -190,7 +203,7 @@
39
        module_args_add_props(props, argument);
40
 
41
    if ((str = pw_properties_get(props, "sink_name")) != NULL) {
42
-       pw_properties_set(props, PW_KEY_NODE_NAME, str);
43
+       pw_properties_set(capture_props, PW_KEY_NODE_NAME, str);
44
        pw_properties_set(props, "sink_name", NULL);
45
    }
46
    if ((str = pw_properties_get(props, "sink_properties")) != NULL) {
47
pipewire-0.3.43.tar.gz/src/modules/module-protocol-pulse/modules/module-ladspa-source.c -> pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/modules/module-ladspa-source.c Changed
48
 
1
@@ -73,8 +73,8 @@
2
    if ((label = pw_properties_get(module->props, "label")) == NULL)
3
        return -EINVAL;
4
 
5
-   pw_properties_setf(data->capture_props, PW_KEY_NODE_GROUP, "ladspa-source-%u", module->idx);
6
-   pw_properties_setf(data->playback_props, PW_KEY_NODE_GROUP, "ladspa-source-%u", module->idx);
7
+   pw_properties_setf(data->capture_props, PW_KEY_NODE_GROUP, "ladspa-source-%u", module->index);
8
+   pw_properties_setf(data->playback_props, PW_KEY_NODE_GROUP, "ladspa-source-%u", module->index);
9
 
10
    f = open_memstream(&args, &size);
11
    fprintf(f, "{");
12
@@ -84,11 +84,24 @@
13
    fprintf(f, " type = ladspa ");
14
    fprintf(f, " plugin = \"%s\" ", plugin);
15
    fprintf(f, " label = \"%s\" ", label);
16
+   if ((str = pw_properties_get(module->props, "control")) != NULL) {
17
+       size_t len;
18
+       const char *s, *state = NULL;
19
+       int count = 0;
20
+
21
+       fprintf(f, " control = {");
22
+       while ((s = pw_split_walk(str, ", ", &len, &state))) {
23
+           fprintf(f, " \"%d\" = %.*s", count, (int)len, s);
24
+           count++;
25
+       }
26
+       fprintf(f, " }");
27
+   }
28
+   fprintf(f, " } ]");
29
    if ((str = pw_properties_get(module->props, "inputs")) != NULL)
30
        fprintf(f, " inputs = [ %s ] ", str);
31
    if ((str = pw_properties_get(module->props, "outputs")) != NULL)
32
        fprintf(f, " outputs = [ %s ] ", str);
33
-   fprintf(f, " } ] }");
34
+   fprintf(f, " }");
35
    fprintf(f, " capture.props = {");
36
    pw_properties_serialize_dict(f, &data->capture_props->dict, 0);
37
    fprintf(f, " } playback.props = {");
38
@@ -190,8 +203,7 @@
39
        module_args_add_props(props, argument);
40
 
41
    if ((str = pw_properties_get(props, "source_name")) != NULL) {
42
-       pw_properties_set(props, PW_KEY_NODE_NAME, str);
43
-       pw_properties_set(props, PW_KEY_NODE_DESCRIPTION, str);
44
+       pw_properties_set(capture_props, PW_KEY_NODE_NAME, str);
45
        pw_properties_set(props, "source_name", NULL);
46
    }
47
    if ((str = pw_properties_get(props, "source_properties")) != NULL) {
48
pipewire-0.3.43.tar.gz/src/modules/module-protocol-pulse/modules/module-loopback.c -> pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/modules/module-loopback.c Changed
12
 
1
@@ -70,8 +70,8 @@
2
    char *args;
3
    size_t size, i;
4
 
5
-   pw_properties_setf(data->capture_props, PW_KEY_NODE_GROUP, "loopback-%u", module->idx);
6
-   pw_properties_setf(data->playback_props, PW_KEY_NODE_GROUP, "loopback-%u", module->idx);
7
+   pw_properties_setf(data->capture_props, PW_KEY_NODE_GROUP, "loopback-%u", module->index);
8
+   pw_properties_setf(data->playback_props, PW_KEY_NODE_GROUP, "loopback-%u", module->index);
9
 
10
    f = open_memstream(&args, &size);
11
    fprintf(f, "{");
12
pipewire-0.3.43.tar.gz/src/modules/module-protocol-pulse/modules/module-remap-sink.c -> pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/modules/module-remap-sink.c Changed
21
 
1
@@ -67,8 +67,8 @@
2
    char *args;
3
    size_t size;
4
 
5
-   pw_properties_setf(data->capture_props, PW_KEY_NODE_GROUP, "remap-sink-%u", module->idx);
6
-   pw_properties_setf(data->playback_props, PW_KEY_NODE_GROUP, "remap-sink-%u", module->idx);
7
+   pw_properties_setf(data->capture_props, PW_KEY_NODE_GROUP, "remap-sink-%u", module->index);
8
+   pw_properties_setf(data->playback_props, PW_KEY_NODE_GROUP, "remap-sink-%u", module->index);
9
 
10
    f = open_memstream(&args, &size);
11
    fprintf(f, "{");
12
@@ -169,7 +169,7 @@
13
        module_args_add_props(props, argument);
14
 
15
    if ((str = pw_properties_get(props, "sink_name")) != NULL) {
16
-       pw_properties_set(props, PW_KEY_NODE_NAME, str);
17
+       pw_properties_set(capture_props, PW_KEY_NODE_NAME, str);
18
        pw_properties_set(props, "sink_name", NULL);
19
    }
20
    if ((str = pw_properties_get(props, "sink_properties")) != NULL) {
21
pipewire-0.3.43.tar.gz/src/modules/module-protocol-pulse/modules/module-remap-source.c -> pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/modules/module-remap-source.c Changed
21
 
1
@@ -67,8 +67,8 @@
2
    char *args;
3
    size_t size;
4
 
5
-   pw_properties_setf(data->capture_props, PW_KEY_NODE_GROUP, "remap-source-%u", module->idx);
6
-   pw_properties_setf(data->playback_props, PW_KEY_NODE_GROUP, "remap-source-%u", module->idx);
7
+   pw_properties_setf(data->capture_props, PW_KEY_NODE_GROUP, "remap-source-%u", module->index);
8
+   pw_properties_setf(data->playback_props, PW_KEY_NODE_GROUP, "remap-source-%u", module->index);
9
 
10
    f = open_memstream(&args, &size);
11
    fprintf(f, "{");
12
@@ -169,7 +169,7 @@
13
        module_args_add_props(props, argument);
14
 
15
    if ((str = pw_properties_get(props, "source_name")) != NULL) {
16
-       pw_properties_set(props, PW_KEY_NODE_NAME, str);
17
+       pw_properties_set(playback_props, PW_KEY_NODE_NAME, str);
18
        pw_properties_set(props, "source_name", NULL);
19
    }
20
    if ((str = pw_properties_get(props, "source_properties")) != NULL) {
21
pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/modules/module-x11-bell.c Added
147
 
1
@@ -0,0 +1,145 @@
2
+/* PipeWire
3
+ *
4
+ * Copyright © 2022 Wim Taymans <wim.taymans@gmail.com>
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a
7
+ * copy of this software and associated documentation files (the "Software"),
8
+ * to deal in the Software without restriction, including without limitation
9
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
+ * and/or sell copies of the Software, and to permit persons to whom the
11
+ * Software is furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice (including the next
14
+ * paragraph) shall be included in all copies or substantial portions of the
15
+ * Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23
+ * DEALINGS IN THE SOFTWARE.
24
+ */
25
+
26
+#include <pipewire/pipewire.h>
27
+
28
+#include "../module.h"
29
+
30
+#define NAME "x11-bell"
31
+
32
+PW_LOG_TOPIC_STATIC(mod_topic, "mod." NAME);
33
+#define PW_LOG_TOPIC_DEFAULT mod_topic
34
+
35
+struct module_x11_bell_data {
36
+   struct module *module;
37
+
38
+   struct pw_impl_module *mod;
39
+   struct spa_hook mod_listener;
40
+};
41
+
42
+static void module_destroy(void *data)
43
+{
44
+   struct module_x11_bell_data *d = data;
45
+   spa_hook_remove(&d->mod_listener);
46
+   d->mod = NULL;
47
+   module_schedule_unload(d->module);
48
+}
49
+
50
+static const struct pw_impl_module_events module_events = {
51
+   PW_VERSION_IMPL_MODULE_EVENTS,
52
+   .destroy = module_destroy
53
+};
54
+
55
+static int module_x11_bell_load(struct client *client, struct module *module)
56
+{
57
+   struct module_x11_bell_data *data = module->user_data;
58
+   FILE *f;
59
+   char *args;
60
+   const char *str;
61
+   size_t size;
62
+
63
+   f = open_memstream(&args, &size);
64
+   fprintf(f, "{");
65
+   if ((str = pw_properties_get(module->props, "sink")) != NULL)
66
+       fprintf(f, " sink.name = \"%s\"", str);
67
+   if ((str = pw_properties_get(module->props, "sample")) != NULL)
68
+       fprintf(f, " sample.name = \"%s\"", str);
69
+   if ((str = pw_properties_get(module->props, "display")) != NULL)
70
+       fprintf(f, " x11.display = \"%s\"", str);
71
+   if ((str = pw_properties_get(module->props, "xauthority")) != NULL)
72
+       fprintf(f, " x11.xauthority = \"%s\"", str);
73
+   fprintf(f, " }");
74
+   fclose(f);
75
+
76
+   data->mod = pw_context_load_module(module->impl->context,
77
+           "libpipewire-module-x11-bell",
78
+           args, NULL);
79
+   free(args);
80
+
81
+   if (data->mod == NULL)
82
+       return -errno;
83
+
84
+   pw_impl_module_add_listener(data->mod,
85
+           &data->mod_listener,
86
+           &module_events, data);
87
+   return 0;
88
+}
89
+
90
+static int module_x11_bell_unload(struct client *client, struct module *module)
91
+{
92
+   struct module_x11_bell_data *d = module->user_data;
93
+
94
+   if (d->mod) {
95
+       spa_hook_remove(&d->mod_listener);
96
+       pw_impl_module_destroy(d->mod);
97
+       d->mod = NULL;
98
+   }
99
+   return 0;
100
+}
101
+
102
+static const struct module_methods module_x11_bell_methods = {
103
+   VERSION_MODULE_METHODS,
104
+   .load = module_x11_bell_load,
105
+   .unload = module_x11_bell_unload,
106
+};
107
+
108
+static const struct spa_dict_item module_x11_bell_info[] = {
109
+   { PW_KEY_MODULE_AUTHOR, "Wim Taymans <wim.taymans@gmail.com>" },
110
+   { PW_KEY_MODULE_DESCRIPTION, "X11 bell interceptor" },
111
+   { PW_KEY_MODULE_USAGE,  "sink=<sink to connect to> "
112
+               "sample=<the sample to play> "
113
+               "display=<X11 display> "
114
+               "xauthority=<X11 Authority>" },
115
+   { PW_KEY_MODULE_VERSION, PACKAGE_VERSION },
116
+};
117
+
118
+struct module *create_module_x11_bell(struct impl *impl, const char *argument)
119
+{
120
+   struct module *module;
121
+   struct pw_properties *props = NULL;
122
+   int res;
123
+
124
+   PW_LOG_TOPIC_INIT(mod_topic);
125
+
126
+   props = pw_properties_new_dict(&SPA_DICT_INIT_ARRAY(module_x11_bell_info));
127
+   if (props == NULL) {
128
+       res = -EINVAL;
129
+       goto out;
130
+   }
131
+   if (argument)
132
+       module_args_add_props(props, argument);
133
+
134
+   module = module_new(impl, &module_x11_bell_methods, sizeof(struct module_x11_bell_data));
135
+   if (module == NULL) {
136
+       res = -errno;
137
+       goto out;
138
+   }
139
+   module->props = props;
140
+
141
+   return module;
142
+out:
143
+   pw_properties_free(props);
144
+   errno = -res;
145
+   return NULL;
146
+}
147
pipewire-0.3.43.tar.gz/src/modules/module-protocol-pulse/modules/registry.h -> pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/modules/registry.h Changed
8
 
1
@@ -48,5 +48,6 @@
2
 struct module *create_module_zeroconf_publish(struct impl *impl, const char *argument);
3
 struct module *create_module_roc_sink(struct impl *impl, const char *argument);
4
 struct module *create_module_roc_source(struct impl *impl, const char *argument);
5
+struct module *create_module_x11_bell(struct impl *impl, const char *argument);
6
 
7
 #endif
8
pipewire-0.3.43.tar.gz/src/modules/module-protocol-pulse/pulse-server.c -> pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/pulse-server.c Changed
1445
 
1
@@ -97,12 +97,12 @@
2
    unsigned int initialized:1;
3
 };
4
 
5
-static struct sample *find_sample(struct impl *impl, uint32_t idx, const char *name)
6
+static struct sample *find_sample(struct impl *impl, uint32_t index, const char *name)
7
 {
8
    union pw_map_item *item;
9
 
10
-   if (idx != SPA_ID_INVALID)
11
-       return pw_map_lookup(&impl->samples, idx);
12
+   if (index != SPA_ID_INVALID)
13
+       return pw_map_lookup(&impl->samples, index);
14
 
15
    pw_array_for_each(item, &impl->samples.items) {
16
        struct sample *s = item->data;
17
@@ -113,13 +113,13 @@
18
    return NULL;
19
 }
20
 
21
-void broadcast_subscribe_event(struct impl *impl, uint32_t mask, uint32_t event, uint32_t id)
22
+void broadcast_subscribe_event(struct impl *impl, uint32_t mask, uint32_t event, uint32_t index)
23
 {
24
    struct server *s;
25
    spa_list_for_each(s, &impl->servers, link) {
26
        struct client *c;
27
        spa_list_for_each(c, &s->clients, link)
28
-           client_queue_subscribe_event(c, mask, event, id);
29
+           client_queue_subscribe_event(c, mask, event, index);
30
    }
31
 }
32
 
33
@@ -159,23 +159,25 @@
34
 
35
 static int reply_set_client_name(struct client *client, uint32_t tag)
36
 {
37
+   struct pw_manager *manager = client->manager;
38
    struct message *reply;
39
    struct pw_client *c;
40
-   uint32_t id;
41
+   uint32_t id, index;
42
 
43
    c = pw_core_get_client(client->core);
44
    if (c == NULL)
45
        return -ENOENT;
46
 
47
    id = pw_proxy_get_bound_id((struct pw_proxy*)c);
48
+   index = id_to_index(manager, id);
49
 
50
-   pw_log_info("[%s] reply tag:%u id:%u", client->name, tag, id);
51
+   pw_log_info("[%s] reply tag:%u id:%u index:%u", client->name, tag, id, index);
52
 
53
    reply = reply_new(client, tag);
54
 
55
    if (client->version >= 13) {
56
        message_put(reply,
57
-           TAG_U32, id,        /* client index */
58
+           TAG_U32, index,     /* client index */
59
            TAG_INVALID);
60
    }
61
    return client_queue_message(client, reply);
62
@@ -196,13 +198,13 @@
63
        operation_complete(o);
64
 }
65
 
66
-static struct stream *find_stream(struct client *client, uint32_t id)
67
+static struct stream *find_stream(struct client *client, uint32_t index)
68
 {
69
    union pw_map_item *item;
70
    pw_array_for_each(item, &client->streams.items) {
71
        struct stream *s = item->data;
72
        if (!pw_map_item_is_free(item) &&
73
-           s->id == id)
74
+           s->index == index)
75
            return s;
76
    }
77
    return NULL;
78
@@ -211,17 +213,15 @@
79
 static int send_object_event(struct client *client, struct pw_manager_object *o,
80
        uint32_t facility)
81
 {
82
-   uint32_t event = 0, mask = 0, res_id = o->id;
83
+   uint32_t event = 0, mask = 0, res_index = o->index;
84
 
85
    if (pw_manager_object_is_sink(o)) {
86
        client_queue_subscribe_event(client,
87
                SUBSCRIPTION_MASK_SINK,
88
                SUBSCRIPTION_EVENT_SINK | facility,
89
-               res_id);
90
+               res_index);
91
    }
92
    if (pw_manager_object_is_source_or_monitor(o)) {
93
-       if (!pw_manager_object_is_source(o))
94
-           res_id |= MONITOR_FLAG;
95
        mask = SUBSCRIPTION_MASK_SOURCE;
96
        event = SUBSCRIPTION_EVENT_SOURCE;
97
    }
98
@@ -251,12 +251,12 @@
99
        client_queue_subscribe_event(client,
100
                mask,
101
                event | facility,
102
-               res_id);
103
+               res_index);
104
    return 0;
105
 }
106
 
107
 static struct pw_manager_object *find_device(struct client *client,
108
-       uint32_t id, const char *name, bool sink, bool *is_monitor);
109
+       uint32_t index, const char *name, bool sink, bool *is_monitor);
110
 
111
 static int64_t get_node_latency_offset(struct pw_manager_object *o)
112
 {
113
@@ -276,6 +276,7 @@
114
 
115
 static void send_latency_offset_subscribe_event(struct client *client, struct pw_manager_object *o)
116
 {
117
+   struct pw_manager *manager = client->manager;
118
    struct latency_offset_data *d;
119
    struct pw_node_info *info;
120
    const char *str;
121
@@ -310,7 +311,7 @@
122
        client_queue_subscribe_event(client,
123
                SUBSCRIPTION_MASK_CARD,
124
                SUBSCRIPTION_EVENT_CARD | SUBSCRIPTION_EVENT_CHANGE,
125
-               card_id);
126
+               id_to_index(manager, card_id));
127
 }
128
 
129
 static void send_default_change_subscribe_event(struct client *client, bool sink, bool source)
130
@@ -370,8 +371,8 @@
131
    struct defs *defs = &s->impl->defs;
132
 
133
    frame_size = s->frame_size;
134
-   minreq = frac_to_bytes_round_up(defs->min_req, &s->ss);
135
-   max_latency = defs->max_quantum * frame_size;
136
+   minreq = frac_to_bytes_round_up(s->min_req, &s->ss);
137
+   max_latency = defs->quantum_limit * frame_size;
138
 
139
    if (attr->maxlength == (uint32_t) -1 || attr->maxlength > MAXLENGTH)
140
        attr->maxlength = MAXLENGTH;
141
@@ -379,7 +380,7 @@
142
    attr->maxlength = SPA_MAX(attr->maxlength, frame_size);
143
 
144
    if (attr->tlength == (uint32_t) -1)
145
-       attr->tlength = frac_to_bytes_round_up(defs->default_tlength, &s->ss);
146
+       attr->tlength = frac_to_bytes_round_up(s->default_tlength, &s->ss);
147
    if (attr->tlength > attr->maxlength)
148
        attr->tlength = attr->maxlength;
149
    attr->tlength -= attr->tlength % frame_size;
150
@@ -387,7 +388,7 @@
151
    attr->tlength = SPA_MAX(attr->tlength, minreq);
152
 
153
    if (attr->minreq == (uint32_t) -1) {
154
-       uint32_t process = frac_to_bytes_round_up(defs->default_req, &s->ss);
155
+       uint32_t process = frac_to_bytes_round_up(s->default_req, &s->ss);
156
        /* With low-latency, tlength/4 gives a decent default in all of traditional,
157
         * adjust latency and early request modes. */
158
        uint32_t m = attr->tlength / 4;
159
@@ -434,7 +435,6 @@
160
        attr->prebuf = max_prebuf;
161
    attr->prebuf -= attr->prebuf % frame_size;
162
 
163
-   s->missing = attr->tlength;
164
    attr->fragsize = 0;
165
 
166
    pw_log_info("[%s] maxlength:%u tlength:%u minreq:%u/%u prebuf:%u latency:%u %u",
167
@@ -447,8 +447,9 @@
168
 static int reply_create_playback_stream(struct stream *stream, struct pw_manager_object *peer)
169
 {
170
    struct client *client = stream->client;
171
+   struct pw_manager *manager = client->manager;
172
    struct message *reply;
173
-   uint32_t missing, peer_id;
174
+   uint32_t missing, peer_index;
175
    struct spa_dict_item items[5];
176
    char latency[32];
177
    char attr_maxlength[32];
178
@@ -458,7 +459,6 @@
179
    const char *peer_name;
180
    struct spa_fraction lat;
181
    uint64_t lat_usec;
182
-   struct defs *defs = &stream->impl->defs;
183
 
184
    lat.denom = stream->ss.rate;
185
    lat.num = fix_playback_buffer_attr(stream, &stream->attr);
186
@@ -467,9 +467,9 @@
187
    if (stream->buffer == NULL)
188
        return -errno;
189
 
190
-   if (lat.num * defs->min_quantum.denom / lat.denom < defs->min_quantum.num)
191
-       lat.num = (defs->min_quantum.num * lat.denom +
192
-               (defs->min_quantum.denom -1)) / defs->min_quantum.denom;
193
+   if (lat.num * stream->min_quantum.denom / lat.denom < stream->min_quantum.num)
194
+       lat.num = (stream->min_quantum.num * lat.denom +
195
+               (stream->min_quantum.denom -1)) / stream->min_quantum.denom;
196
    lat_usec = lat.num * SPA_USEC_PER_SEC / lat.denom;
197
 
198
    snprintf(latency, sizeof(latency), "%u/%u", lat.num, lat.denom);
199
@@ -489,22 +489,23 @@
200
        stream->in_prebuf = true;
201
 
202
    missing = stream_pop_missing(stream);
203
+   stream->index = id_to_index(manager, stream->id);
204
 
205
-   pw_log_info("[%s] reply CREATE_PLAYBACK_STREAM tag:%u missing:%u latency:%s",
206
-           client->name, stream->create_tag, missing, latency);
207
+   pw_log_info("[%s] reply CREATE_PLAYBACK_STREAM tag:%u index:%u missing:%u latency:%s",
208
+           client->name, stream->create_tag, stream->index, missing, latency);
209
 
210
    reply = reply_new(client, stream->create_tag);
211
    message_put(reply,
212
        TAG_U32, stream->channel,       /* stream index/channel */
213
-       TAG_U32, stream->id,            /* sink_input/stream index */
214
+       TAG_U32, stream->index,         /* sink_input/stream index */
215
        TAG_U32, missing,           /* missing/requested bytes */
216
        TAG_INVALID);
217
 
218
    if (peer && pw_manager_object_is_sink(peer)) {
219
-       peer_id = peer->id;
220
+       peer_index = peer->index;
221
        peer_name = pw_properties_get(peer->props, PW_KEY_NODE_NAME);
222
    } else {
223
-       peer_id = SPA_ID_INVALID;
224
+       peer_index = SPA_ID_INVALID;
225
        peer_name = NULL;
226
    }
227
 
228
@@ -520,7 +521,7 @@
229
        message_put(reply,
230
            TAG_SAMPLE_SPEC, &stream->ss,
231
            TAG_CHANNEL_MAP, &stream->map,
232
-           TAG_U32, peer_id,       /* sink index */
233
+           TAG_U32, peer_index,        /* sink index */
234
            TAG_STRING, peer_name,      /* sink name */
235
            TAG_BOOLEAN, false,     /* sink suspended state */
236
            TAG_INVALID);
237
@@ -547,7 +548,6 @@
238
 static uint32_t fix_record_buffer_attr(struct stream *s, struct buffer_attr *attr)
239
 {
240
    uint32_t frame_size, minfrag, latency;
241
-   struct defs *defs = &s->impl->defs;
242
 
243
    frame_size = s->frame_size;
244
 
245
@@ -556,10 +556,10 @@
246
    attr->maxlength -= attr->maxlength % frame_size;
247
    attr->maxlength = SPA_MAX(attr->maxlength, frame_size);
248
 
249
-   minfrag = frac_to_bytes_round_up(defs->min_frag, &s->ss);
250
+   minfrag = frac_to_bytes_round_up(s->min_frag, &s->ss);
251
 
252
    if (attr->fragsize == (uint32_t) -1 || attr->fragsize == 0)
253
-       attr->fragsize = frac_to_bytes_round_up(defs->default_frag, &s->ss);
254
+       attr->fragsize = frac_to_bytes_round_up(s->default_frag, &s->ss);
255
    attr->fragsize -= attr->fragsize % frame_size;
256
    attr->fragsize = SPA_MAX(attr->fragsize, minfrag);
257
    attr->fragsize = SPA_MAX(attr->fragsize, frame_size);
258
@@ -594,10 +594,9 @@
259
    char attr_maxlength[32];
260
    char attr_fragsize[32];
261
    const char *peer_name, *name;
262
-   uint32_t peer_id;
263
+   uint32_t peer_index;
264
    struct spa_fraction lat;
265
    uint64_t lat_usec;
266
-   struct defs *defs = &stream->impl->defs;
267
 
268
    lat.denom = stream->ss.rate;
269
    lat.num = fix_record_buffer_attr(stream, &stream->attr);
270
@@ -606,9 +605,9 @@
271
    if (stream->buffer == NULL)
272
        return -errno;
273
 
274
-   if (lat.num * defs->min_quantum.denom / lat.denom < defs->min_quantum.num)
275
-       lat.num = (defs->min_quantum.num * lat.denom +
276
-               (defs->min_quantum.denom -1)) / defs->min_quantum.denom;
277
+   if (lat.num * stream->min_quantum.denom / lat.denom < stream->min_quantum.num)
278
+       lat.num = (stream->min_quantum.num * lat.denom +
279
+               (stream->min_quantum.denom -1)) / stream->min_quantum.denom;
280
    lat_usec = lat.num * SPA_USEC_PER_SEC / lat.denom;
281
 
282
    snprintf(latency, sizeof(latency), "%u/%u", lat.num, lat.denom);
283
@@ -622,13 +621,15 @@
284
    pw_stream_update_properties(stream->stream,
285
            &SPA_DICT_INIT(items, 3));
286
 
287
-   pw_log_info("[%s] reply CREATE_RECORD_STREAM tag:%u latency:%s",
288
-           client->name, stream->create_tag, latency);
289
+   stream->index = id_to_index(manager, stream->id);
290
+
291
+   pw_log_info("[%s] reply CREATE_RECORD_STREAM tag:%u index:%u latency:%s",
292
+           client->name, stream->create_tag, stream->index, latency);
293
 
294
    reply = reply_new(client, stream->create_tag);
295
    message_put(reply,
296
        TAG_U32, stream->channel,   /* stream index/channel */
297
-       TAG_U32, stream->id,        /* source_output/stream index */
298
+       TAG_U32, stream->index,     /* source_output/stream index */
299
        TAG_INVALID);
300
 
301
    if (peer && pw_manager_object_is_sink_input(peer))
302
@@ -637,15 +638,15 @@
303
        name = pw_properties_get(peer->props, PW_KEY_NODE_NAME);
304
        if (!pw_manager_object_is_source(peer)) {
305
            size_t len = (name ? strlen(name) : 5) + 10;
306
-           peer_id = peer->id | MONITOR_FLAG;
307
+           peer_index = peer->index;
308
            peer_name = tmp = alloca(len);
309
            snprintf(tmp, len, "%s.monitor", name ? name : "sink");
310
        } else {
311
-           peer_id = peer->id;
312
+           peer_index = peer->index;
313
            peer_name = name;
314
        }
315
    } else {
316
-       peer_id = SPA_ID_INVALID;
317
+       peer_index = SPA_ID_INVALID;
318
        peer_name = NULL;
319
    }
320
 
321
@@ -659,7 +660,7 @@
322
        message_put(reply,
323
            TAG_SAMPLE_SPEC, &stream->ss,
324
            TAG_CHANNEL_MAP, &stream->map,
325
-           TAG_U32, peer_id,       /* source index */
326
+           TAG_U32, peer_index,        /* source index */
327
            TAG_STRING, peer_name,      /* source name */
328
            TAG_BOOLEAN, false,     /* source suspended state */
329
            TAG_INVALID);
330
@@ -703,8 +704,8 @@
331
        if (info->props) {
332
            if ((str = spa_dict_lookup(info->props, "default.clock.rate")) != NULL)
333
                client->impl->defs.sample_spec.rate = atoi(str);
334
-           if ((str = spa_dict_lookup(info->props, "default.clock.max-quantum")) != NULL)
335
-               client->impl->defs.max_quantum = atoi(str);
336
+           if ((str = spa_dict_lookup(info->props, "default.clock.quantum-limit")) != NULL)
337
+               client->impl->defs.quantum_limit = atoi(str);
338
        }
339
    }
340
 
341
@@ -884,6 +885,8 @@
342
    pw_log_info("[%s] %s tag:%d", client->name,
343
            commands[command].name, tag);
344
 
345
+   client_update_quirks(client);
346
+
347
    if (client->core == NULL) {
348
        client->core = pw_context_connect(impl->context,
349
                pw_properties_copy(client->props), 0);
350
@@ -907,8 +910,6 @@
351
            res = reply_set_client_name(client, tag);
352
    }
353
 
354
-   client_update_quirks(client);
355
-
356
    return res;
357
 error:
358
    pw_log_error("%p: failed to connect client: %s", impl, spa_strerror(res));
359
@@ -995,11 +996,12 @@
360
 {
361
    const struct spa_pod *param;
362
    uint32_t blocks, buffers, size, maxsize, stride;
363
+   struct defs *defs = &s->impl->defs;
364
 
365
    blocks = 1;
366
    stride = s->frame_size;
367
 
368
-   maxsize = 8192 * 32 * s->frame_size;
369
+   maxsize = defs->quantum_limit * 32 * s->frame_size;
370
    if (s->direction == PW_DIRECTION_OUTPUT) {
371
        size = attr->minreq;
372
    } else {
373
@@ -1098,7 +1100,6 @@
374
    uint32_t write_inc;
375
    uint32_t underrun_for;
376
    uint32_t playing_for;
377
-   uint32_t missing;
378
    uint32_t minreq;
379
    uint32_t quantum;
380
    unsigned int underrun:1;
381
@@ -1138,12 +1139,10 @@
382
            stream->underrun_for = 0;
383
            stream->playing_for = 0;
384
            if (pd->underrun)
385
-               stream_send_underflow(stream, stream->read_index, pd->underrun_for);
386
+               stream_send_underflow(stream, stream->read_index);
387
            else
388
                stream_send_started(stream);
389
        }
390
-       stream->missing += pd->missing;
391
-       stream->missing = SPA_MIN(stream->missing, (int64_t)stream->attr.tlength);
392
        stream->playing_for += pd->playing_for;
393
        if (stream->underrun_for != (uint64_t)-1)
394
            stream->underrun_for += pd->underrun_for;
395
@@ -1246,7 +1245,7 @@
396
            size = SPA_MIN(buf->datas[0].maxsize, minreq);
397
            memset(p, 0, size);
398
 
399
-           if (stream->draining) {
400
+           if (stream->draining && !stream->corked) {
401
                stream->draining = false;
402
                do_flush = true;
403
            } else {
404
@@ -1254,16 +1253,15 @@
405
                pd.underrun = true;
406
            }
407
            if ((stream->attr.prebuf == 0 || do_flush) && !stream->corked) {
408
-               pd.missing = size;
409
-               pd.playing_for = size;
410
                if (avail > 0) {
411
                    spa_ringbuffer_read_data(&stream->ring,
412
                        stream->buffer, stream->attr.maxlength,
413
                        index % stream->attr.maxlength,
414
                        p, avail);
415
-                   index += avail;
416
-                   pd.read_inc = avail;
417
                }
418
+               pd.playing_for = size;
419
+               pd.read_inc = size;
420
+               index += size;
421
                spa_ringbuffer_read_update(&stream->ring, index);
422
            }
423
            pw_log_debug("%p: [%s] underrun read:%u avail:%d max:%u",
424
@@ -1293,7 +1291,6 @@
425
            spa_ringbuffer_read_update(&stream->ring, index);
426
 
427
            pd.playing_for = size;
428
-           pd.missing = size;
429
            pd.underrun = false;
430
        }
431
        buf->datas[0].chunk->offset = 0;
432
@@ -1376,6 +1373,7 @@
433
 static int do_create_playback_stream(struct client *client, uint32_t command, uint32_t tag, struct message *m)
434
 {
435
    struct impl *impl = client->impl;
436
+   struct pw_manager *manager = client->manager;
437
    const char *name = NULL;
438
    int res;
439
    struct sample_spec ss;
440
@@ -1436,7 +1434,7 @@
441
            TAG_INVALID) < 0)
442
        goto error_protocol;
443
 
444
-   pw_log_info("[%s] CREATE_PLAYBACK_STREAM tag:%u corked:%u sink-name:%s sink-idx:%u",
445
+   pw_log_info("[%s] CREATE_PLAYBACK_STREAM tag:%u corked:%u sink-name:%s sink-index:%u",
446
            client->name, tag, corked, sink_name, sink_index);
447
 
448
    if (sink_index != SPA_ID_INVALID && sink_name != NULL)
449
@@ -1580,12 +1578,18 @@
450
    if (no_move)
451
        flags |= PW_STREAM_FLAG_DONT_RECONNECT;
452
 
453
-   if (sink_name != NULL)
454
+   if (sink_name != NULL) {
455
        pw_properties_set(props,
456
                PW_KEY_NODE_TARGET, sink_name);
457
-   else if (sink_index != SPA_ID_INVALID && sink_index != 0)
458
+       pw_properties_set(props,
459
+               PW_KEY_TARGET_OBJECT, sink_name);
460
+   } else if (sink_index != SPA_ID_INVALID && sink_index != 0) {
461
+       pw_properties_setf(props,
462
+               PW_KEY_NODE_TARGET, "%u",
463
+               index_to_id(manager, sink_index));
464
        pw_properties_setf(props,
465
-               PW_KEY_NODE_TARGET, "%u", sink_index);
466
+               PW_KEY_TARGET_OBJECT, "%u", sink_index);
467
+   }
468
 
469
    stream->stream = pw_stream_new(client->core, name, props);
470
    props = NULL;
471
@@ -1632,6 +1636,7 @@
472
 static int do_create_record_stream(struct client *client, uint32_t command, uint32_t tag, struct message *m)
473
 {
474
    struct impl *impl = client->impl;
475
+   struct pw_manager *manager = client->manager;
476
    const char *name = NULL;
477
    int res;
478
    struct sample_spec ss;
479
@@ -1840,20 +1845,26 @@
480
            source_index = id;
481
    }
482
    if (source_index != SPA_ID_INVALID && source_index != 0) {
483
-       if (source_index & MONITOR_FLAG)
484
-           source_index &= INDEX_MASK;
485
        pw_properties_setf(props,
486
-               PW_KEY_NODE_TARGET, "%u", source_index);
487
+               PW_KEY_NODE_TARGET, "%u",
488
+               index_to_id(manager, source_index));
489
+       pw_properties_setf(props,
490
+               PW_KEY_TARGET_OBJECT, "%u", source_index);
491
    } else if (source_name != NULL) {
492
        if (spa_strendswith(source_name, ".monitor")) {
493
            pw_properties_setf(props,
494
                    PW_KEY_NODE_TARGET,
495
                    "%.*s", (int)strlen(source_name)-8, source_name);
496
+           pw_properties_setf(props,
497
+                   PW_KEY_TARGET_OBJECT,
498
+                   "%.*s", (int)strlen(source_name)-8, source_name);
499
            pw_properties_set(props,
500
                    PW_KEY_STREAM_CAPTURE_SINK, "true");
501
        } else {
502
            pw_properties_set(props,
503
                    PW_KEY_NODE_TARGET, source_name);
504
+           pw_properties_set(props,
505
+                   PW_KEY_TARGET_OBJECT, source_name);
506
        }
507
    }
508
 
509
@@ -2233,10 +2244,11 @@
510
 }
511
 
512
 static struct pw_manager_object *find_device(struct client *client,
513
-       uint32_t id, const char *name, bool sink, bool *is_monitor)
514
+       uint32_t index, const char *name, bool sink, bool *is_monitor)
515
 {
516
    struct selector sel;
517
    bool monitor = false, find_default = false;
518
+   struct pw_manager_object *o;
519
 
520
    if (name != NULL) {
521
        if (spa_streq(name, DEFAULT_MONITOR)) {
522
@@ -2252,45 +2264,44 @@
523
            if (!sink)
524
                return NULL;
525
            find_default = true;
526
-       } else if (spa_atou32(name, &id, 0)) {
527
+       } else if (spa_atou32(name, &index, 0)) {
528
            name = NULL;
529
        }
530
    }
531
-   if (name == NULL && (id == SPA_ID_INVALID || id == 0))
532
+   if (name == NULL && (index == SPA_ID_INVALID || index == 0))
533
        find_default = true;
534
 
535
    if (find_default) {
536
        name = get_default(client, sink);
537
-       id = SPA_ID_INVALID;
538
+       index = SPA_ID_INVALID;
539
    }
540
 
541
-   if (id != SPA_ID_INVALID) {
542
-       if (id & MONITOR_FLAG) {
543
-           if (sink)
544
-               return NULL;
545
-           monitor = true;
546
-           id &= ~MONITOR_FLAG;
547
-       }
548
-   } else if (name != NULL) {
549
+   if (name != NULL) {
550
        if (spa_strendswith(name, ".monitor")) {
551
            name = strndupa(name, strlen(name)-8);
552
            monitor = true;
553
        }
554
-   } else
555
+   } else if (index == SPA_ID_INVALID)
556
        return NULL;
557
 
558
-   if (is_monitor)
559
-       *is_monitor = monitor;
560
 
561
    spa_zero(sel);
562
    sel.type = sink ?
563
        pw_manager_object_is_sink :
564
        pw_manager_object_is_source_or_monitor;
565
-   sel.id = id;
566
+   sel.index = index;
567
    sel.key = PW_KEY_NODE_NAME;
568
    sel.value = name;
569
 
570
-   return select_object(client->manager, &sel);
571
+   o = select_object(client->manager, &sel);
572
+   if (o != NULL) {
573
+       if (!sink && pw_manager_object_is_monitor(o))
574
+           monitor = true;
575
+   }
576
+   if (is_monitor)
577
+       *is_monitor = monitor;
578
+
579
+   return o;
580
 }
581
 
582
 static void sample_play_ready(void *data, uint32_t index)
583
@@ -2390,6 +2401,7 @@
584
        goto error_noent;
585
 
586
    pw_properties_setf(props, PW_KEY_NODE_TARGET, "%u", o->id);
587
+   pw_properties_setf(props, PW_KEY_TARGET_OBJECT, "%"PRIu64, o->serial);
588
 
589
    play = sample_play_new(client->core, sample, props, sizeof(struct pending_sample));
590
    props = NULL;
591
@@ -2485,6 +2497,7 @@
592
    } else {
593
        stream->playing_for = 0;
594
        stream->underrun_for = -1;
595
+       stream_send_request(stream);
596
    }
597
 
598
    return reply_simple_ack(client, tag);
599
@@ -2563,7 +2576,7 @@
600
    return 0;
601
 }
602
 
603
-static int set_card_volume_mute_delay(struct pw_manager_object *o, uint32_t id,
604
+static int set_card_volume_mute_delay(struct pw_manager_object *o, uint32_t port_index,
605
        uint32_t device_id, struct volume *vol, bool *mute, int64_t *latency_offset)
606
 {
607
    char buf[1024];
608
@@ -2580,7 +2593,7 @@
609
    spa_pod_builder_push_object(&b, &f[0],
610
            SPA_TYPE_OBJECT_ParamRoute, SPA_PARAM_Route);
611
    spa_pod_builder_add(&b,
612
-           SPA_PARAM_ROUTE_index, SPA_POD_Int(id),
613
+           SPA_PARAM_ROUTE_index, SPA_POD_Int(port_index),
614
            SPA_PARAM_ROUTE_device, SPA_POD_Int(device_id),
615
            0);
616
    spa_pod_builder_prop(&b, SPA_PARAM_ROUTE_props, 0);
617
@@ -2609,7 +2622,7 @@
618
 }
619
 
620
 static int set_card_port(struct pw_manager_object *o, uint32_t device_id,
621
-       uint32_t port_id)
622
+       uint32_t port_index)
623
 {
624
    char buf[1024];
625
    struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buf, sizeof(buf));
626
@@ -2624,7 +2637,7 @@
627
            SPA_PARAM_Route, 0,
628
            spa_pod_builder_add_object(&b,
629
                SPA_TYPE_OBJECT_ParamRoute, SPA_PARAM_Route,
630
-               SPA_PARAM_ROUTE_index, SPA_POD_Int(port_id),
631
+               SPA_PARAM_ROUTE_index, SPA_POD_Int(port_index),
632
                SPA_PARAM_ROUTE_device, SPA_POD_Int(device_id),
633
                SPA_PARAM_ROUTE_save, SPA_POD_Bool(true)));
634
 
635
@@ -2634,21 +2647,21 @@
636
 static int do_set_stream_volume(struct client *client, uint32_t command, uint32_t tag, struct message *m)
637
 {
638
    struct pw_manager *manager = client->manager;
639
-   uint32_t id;
640
+   uint32_t index;
641
    struct stream *stream;
642
    struct volume volume;
643
    int res;
644
 
645
    if ((res = message_get(m,
646
-           TAG_U32, &id,
647
+           TAG_U32, &index,
648
            TAG_CVOLUME, &volume,
649
            TAG_INVALID)) < 0)
650
        return -EPROTO;
651
 
652
    pw_log_info("[%s] %s tag:%u index:%u",
653
-           client->name, commands[command].name, tag, id);
654
+           client->name, commands[command].name, tag, index);
655
 
656
-   stream = find_stream(client, id);
657
+   stream = find_stream(client, index);
658
    if (stream != NULL) {
659
 
660
        if (volume_compare(&stream->volume, &volume) == 0)
661
@@ -2662,7 +2675,7 @@
662
        struct pw_manager_object *o;
663
 
664
        spa_zero(sel);
665
-       sel.id = id;
666
+       sel.index = index;
667
        if (command == COMMAND_SET_SINK_INPUT_VOLUME)
668
            sel.type = pw_manager_object_is_sink_input;
669
        else
670
@@ -2682,21 +2695,21 @@
671
 static int do_set_stream_mute(struct client *client, uint32_t command, uint32_t tag, struct message *m)
672
 {
673
    struct pw_manager *manager = client->manager;
674
-   uint32_t id;
675
+   uint32_t index;
676
    struct stream *stream;
677
    int res;
678
    bool mute;
679
 
680
    if ((res = message_get(m,
681
-           TAG_U32, &id,
682
+           TAG_U32, &index,
683
            TAG_BOOLEAN, &mute,
684
            TAG_INVALID)) < 0)
685
        return -EPROTO;
686
 
687
-   pw_log_info("[%s] DO_SET_STREAM_MUTE tag:%u id:%u mute:%u",
688
-           client->name, tag, id, mute);
689
+   pw_log_info("[%s] DO_SET_STREAM_MUTE tag:%u index:%u mute:%u",
690
+           client->name, tag, index, mute);
691
 
692
-   stream = find_stream(client, id);
693
+   stream = find_stream(client, index);
694
    if (stream != NULL) {
695
        float val;
696
 
697
@@ -2712,7 +2725,7 @@
698
        struct pw_manager_object *o;
699
 
700
        spa_zero(sel);
701
-       sel.id = id;
702
+       sel.index = index;
703
        if (command == COMMAND_SET_SINK_INPUT_MUTE)
704
            sel.type = pw_manager_object_is_sink_input;
705
        else
706
@@ -2734,7 +2747,7 @@
707
    struct impl *impl = client->impl;
708
    struct pw_manager *manager = client->manager;
709
    struct pw_node_info *info;
710
-   uint32_t id, card_id = SPA_ID_INVALID;
711
+   uint32_t index, card_id = SPA_ID_INVALID;
712
    const char *name, *str;
713
    struct volume volume;
714
    struct pw_manager_object *o, *card = NULL;
715
@@ -2744,17 +2757,17 @@
716
    bool is_monitor;
717
 
718
    if ((res = message_get(m,
719
-           TAG_U32, &id,
720
+           TAG_U32, &index,
721
            TAG_STRING, &name,
722
            TAG_CVOLUME, &volume,
723
            TAG_INVALID)) < 0)
724
        return -EPROTO;
725
 
726
    pw_log_info("[%s] %s tag:%u index:%u name:%s",
727
-           client->name, commands[command].name, tag, id, name);
728
+           client->name, commands[command].name, tag, index, name);
729
 
730
-   if ((id == SPA_ID_INVALID && name == NULL) ||
731
-       (id != SPA_ID_INVALID && name != NULL))
732
+   if ((index == SPA_ID_INVALID && name == NULL) ||
733
+       (index != SPA_ID_INVALID && name != NULL))
734
        return -EINVAL;
735
 
736
    if (command == COMMAND_SET_SINK_VOLUME)
737
@@ -2762,7 +2775,7 @@
738
    else
739
        direction = PW_DIRECTION_INPUT;
740
 
741
-   o = find_device(client, id, name, direction == PW_DIRECTION_OUTPUT, &is_monitor);
742
+   o = find_device(client, index, name, direction == PW_DIRECTION_OUTPUT, &is_monitor);
743
    if (o == NULL || (info = o->info) == NULL || info->props == NULL)
744
        return -ENOENT;
745
 
746
@@ -2800,7 +2813,7 @@
747
    struct impl *impl = client->impl;
748
    struct pw_manager *manager = client->manager;
749
    struct pw_node_info *info;
750
-   uint32_t id, card_id = SPA_ID_INVALID;
751
+   uint32_t index, card_id = SPA_ID_INVALID;
752
    const char *name, *str;
753
    bool mute;
754
    struct pw_manager_object *o, *card = NULL;
755
@@ -2810,17 +2823,17 @@
756
    bool is_monitor;
757
 
758
    if ((res = message_get(m,
759
-           TAG_U32, &id,
760
+           TAG_U32, &index,
761
            TAG_STRING, &name,
762
            TAG_BOOLEAN, &mute,
763
            TAG_INVALID)) < 0)
764
        return -EPROTO;
765
 
766
    pw_log_info("[%s] %s tag:%u index:%u name:%s mute:%d",
767
-           client->name, commands[command].name, tag, id, name, mute);
768
+           client->name, commands[command].name, tag, index, name, mute);
769
 
770
-   if ((id == SPA_ID_INVALID && name == NULL) ||
771
-       (id != SPA_ID_INVALID && name != NULL))
772
+   if ((index == SPA_ID_INVALID && name == NULL) ||
773
+       (index != SPA_ID_INVALID && name != NULL))
774
        return -EINVAL;
775
 
776
    if (command == COMMAND_SET_SINK_MUTE)
777
@@ -2828,7 +2841,7 @@
778
    else
779
        direction = PW_DIRECTION_INPUT;
780
 
781
-   o = find_device(client, id, name, direction == PW_DIRECTION_OUTPUT, &is_monitor);
782
+   o = find_device(client, index, name, direction == PW_DIRECTION_OUTPUT, &is_monitor);
783
    if (o == NULL || (info = o->info) == NULL || info->props == NULL)
784
        return -ENOENT;
785
 
786
@@ -2864,25 +2877,25 @@
787
 {
788
    struct pw_manager *manager = client->manager;
789
    struct pw_node_info *info;
790
-   uint32_t id, card_id = SPA_ID_INVALID, device_id = SPA_ID_INVALID;
791
-   uint32_t port_id = SPA_ID_INVALID;
792
+   uint32_t index, card_id = SPA_ID_INVALID, device_id = SPA_ID_INVALID;
793
+   uint32_t port_index = SPA_ID_INVALID;
794
    const char *name, *str, *port_name;
795
    struct pw_manager_object *o, *card = NULL;
796
    int res;
797
    enum pw_direction direction;
798
 
799
    if ((res = message_get(m,
800
-           TAG_U32, &id,
801
+           TAG_U32, &index,
802
            TAG_STRING, &name,
803
            TAG_STRING, &port_name,
804
            TAG_INVALID)) < 0)
805
        return -EPROTO;
806
 
807
    pw_log_info("[%s] %s tag:%u index:%u name:%s port:%s",
808
-           client->name, commands[command].name, tag, id, name, port_name);
809
+           client->name, commands[command].name, tag, index, name, port_name);
810
 
811
-   if ((id == SPA_ID_INVALID && name == NULL) ||
812
-       (id != SPA_ID_INVALID && name != NULL))
813
+   if ((index == SPA_ID_INVALID && name == NULL) ||
814
+       (index != SPA_ID_INVALID && name != NULL))
815
        return -EINVAL;
816
 
817
    if (command == COMMAND_SET_SINK_PORT)
818
@@ -2890,7 +2903,7 @@
819
    else
820
        direction = PW_DIRECTION_INPUT;
821
 
822
-   o = find_device(client, id, name, direction == PW_DIRECTION_OUTPUT, NULL);
823
+   o = find_device(client, index, name, direction == PW_DIRECTION_OUTPUT, NULL);
824
    if (o == NULL || (info = o->info) == NULL || info->props == NULL)
825
        return -ENOENT;
826
 
827
@@ -2905,11 +2918,11 @@
828
    if (card == NULL || device_id == SPA_ID_INVALID)
829
        return -ENOENT;
830
 
831
-   port_id = find_port_id(card, direction, port_name);
832
-   if (port_id == SPA_ID_INVALID)
833
+   port_index = find_port_index(card, direction, port_name);
834
+   if (port_index == SPA_ID_INVALID)
835
        return -ENOENT;
836
 
837
-   if ((res = set_card_port(card, device_id, port_id)) < 0)
838
+   if ((res = set_card_port(card, device_id, port_index)) < 0)
839
        return res;
840
 
841
    return operation_new(client, tag);
842
@@ -2934,7 +2947,7 @@
843
    sel.type = pw_manager_object_is_card;
844
 
845
    if ((res = message_get(m,
846
-           TAG_U32, &sel.id,
847
+           TAG_U32, &sel.index,
848
            TAG_STRING, &sel.value,
849
            TAG_STRING, &port_name,
850
            TAG_S64, &offset,
851
@@ -2942,10 +2955,10 @@
852
        return -EPROTO;
853
 
854
    pw_log_info("[%s] %s tag:%u index:%u card_name:%s port_name:%s offset:%"PRIi64,
855
-           client->name, commands[command].name, tag, sel.id, sel.value, port_name, offset);
856
+           client->name, commands[command].name, tag, sel.index, sel.value, port_name, offset);
857
 
858
-   if ((sel.id == SPA_ID_INVALID && sel.value == NULL) ||
859
-       (sel.id != SPA_ID_INVALID && sel.value != NULL))
860
+   if ((sel.index == SPA_ID_INVALID && sel.value == NULL) ||
861
+       (sel.index != SPA_ID_INVALID && sel.value != NULL))
862
        return -EINVAL;
863
    if (port_name == NULL)
864
        return -EINVAL;
865
@@ -2971,7 +2984,7 @@
866
 
867
        res = 0;
868
        for (j = 0; j < pi->n_devices; ++j) {
869
-           res = set_card_volume_mute_delay(card, pi->id, pi->devices[j], NULL, NULL, &value);
870
+           res = set_card_volume_mute_delay(card, pi->index, pi->devices[j], NULL, NULL, &value);
871
            if (res < 0)
872
                break;
873
        }
874
@@ -3208,7 +3221,7 @@
875
 
876
    reply = reply_new(client, tag);
877
    message_put(reply,
878
-       TAG_U32, is_monitor ? o->id | MONITOR_FLAG : o->id,
879
+       TAG_U32, o->index,
880
        TAG_INVALID);
881
 
882
    return client_queue_message(client, reply);
883
@@ -3240,6 +3253,7 @@
884
        struct pw_manager_object *o)
885
 {
886
    struct pw_client_info *info = o->info;
887
+   struct pw_manager *manager = client->manager;
888
    const char *str;
889
    uint32_t module_id = SPA_ID_INVALID;
890
 
891
@@ -3250,10 +3264,10 @@
892
        module_id = (uint32_t)atoi(str);
893
 
894
    message_put(m,
895
-       TAG_U32, o->id,             /* client index */
896
+       TAG_U32, o->index,              /* client index */
897
        TAG_STRING, pw_properties_get(o->props, PW_KEY_APP_NAME),
898
-       TAG_U32, module_id,         /* module */
899
-       TAG_STRING, "PipeWire",         /* driver */
900
+       TAG_U32, id_to_index(manager, module_id),   /* module index */
901
+       TAG_STRING, "PipeWire",             /* driver */
902
        TAG_INVALID);
903
    if (client->version >= 13) {
904
        message_put(m,
905
@@ -3272,7 +3286,7 @@
906
        return -ENOENT;
907
 
908
    message_put(m,
909
-       TAG_U32, o->id,             /* module index */
910
+       TAG_U32, o->index,          /* module index */
911
        TAG_STRING, info->name,
912
        TAG_STRING, info->args,
913
        TAG_U32, -1,                /* n_used */
914
@@ -3295,7 +3309,7 @@
915
        struct module *module)
916
 {
917
    message_put(m,
918
-       TAG_U32, module->idx,           /* module index */
919
+       TAG_U32, module->index,         /* module index */
920
        TAG_STRING, module->name,
921
        TAG_STRING, module->args,
922
        TAG_U32, -1,                /* n_used */
923
@@ -3360,6 +3374,7 @@
924
 static int fill_card_info(struct client *client, struct message *m,
925
        struct pw_manager_object *o)
926
 {
927
+   struct pw_manager *manager = client->manager;
928
    struct pw_device_info *info = o->info;
929
    const char *str, *drv_name;
930
    uint32_t module_id = SPA_ID_INVALID, n_profiles, n;
931
@@ -3377,9 +3392,9 @@
932
        drv_name = "module-bluez5-device.c"; /* blueman needs this */
933
 
934
    message_put(m,
935
-       TAG_U32, o->id,             /* card index */
936
+       TAG_U32, o->index,          /* card index */
937
        TAG_STRING, spa_dict_lookup(info->props, PW_KEY_DEVICE_NAME),
938
-       TAG_U32, module_id,
939
+       TAG_U32, id_to_index(manager, module_id),
940
        TAG_STRING, drv_name,
941
        TAG_INVALID);
942
 
943
@@ -3464,7 +3479,7 @@
944
                const char *name = "off";
945
 
946
                for (j = 0; j < n_profiles; ++j) {
947
-                   if (profile_info[j].id == pi->profiles[i]) {
948
+                   if (profile_info[j].index == pi->profiles[i]) {
949
                        name = profile_info[j].name;
950
                        break;
951
                    }
952
@@ -3564,15 +3579,15 @@
953
        dev_info.ss.format = SPA_AUDIO_FORMAT_S16;
954
 
955
    message_put(m,
956
-       TAG_U32, o->id,             /* sink index */
957
+       TAG_U32, o->index,          /* sink index */
958
        TAG_STRING, name,
959
        TAG_STRING, desc,
960
        TAG_SAMPLE_SPEC, &dev_info.ss,
961
        TAG_CHANNEL_MAP, &dev_info.map,
962
-       TAG_U32, module_id,         /* module index */
963
+       TAG_U32, id_to_index(manager, module_id),   /* module index */
964
        TAG_CVOLUME, &dev_info.volume_info.volume,
965
        TAG_BOOLEAN, dev_info.volume_info.mute,
966
-       TAG_U32, o->id | MONITOR_FLAG,      /* monitor source */
967
+       TAG_U32, o->index,          /* monitor source index */
968
        TAG_STRING, monitor_name,       /* monitor source name */
969
        TAG_USEC, 0LL,              /* latency */
970
        TAG_STRING, "PipeWire",         /* driver */
971
@@ -3598,7 +3613,7 @@
972
            TAG_VOLUME, dev_info.volume_info.base,  /* base volume */
973
            TAG_U32, state,             /* state */
974
            TAG_U32, dev_info.volume_info.steps,    /* n_volume_steps */
975
-           TAG_U32, card_id,           /* card index */
976
+           TAG_U32, card ? card->index : SPA_ID_INVALID,   /* card index */
977
            TAG_INVALID);
978
    }
979
    if (client->version >= 16) {
980
@@ -3670,6 +3685,27 @@
981
    return 0;
982
 }
983
 
984
+static int fill_source_info_proplist(struct message *m, struct pw_manager_object *o,
985
+       struct pw_node_info *info)
986
+{
987
+   struct pw_properties *props = NULL;
988
+   struct spa_dict *props_dict = info->props;
989
+
990
+   if (pw_manager_object_is_monitor(o)) {
991
+       props = pw_properties_new_dict(info->props);
992
+       if (props == NULL)
993
+           return -ENOMEM;
994
+
995
+       pw_properties_set(props, PW_KEY_DEVICE_CLASS, "monitor");
996
+       props_dict = &props->dict;
997
+   }
998
+
999
+   message_put(m, TAG_PROPLIST, props_dict, TAG_INVALID);
1000
+   pw_properties_free(props);
1001
+
1002
+   return 0;
1003
+}
1004
+
1005
 static int fill_source_info(struct client *client, struct message *m,
1006
        struct pw_manager_object *o)
1007
 {
1008
@@ -3746,15 +3782,15 @@
1009
        dev_info.ss.format = SPA_AUDIO_FORMAT_S16;
1010
 
1011
    message_put(m,
1012
-       TAG_U32, is_monitor ? o->id | MONITOR_FLAG: o->id,  /* source index */
1013
+       TAG_U32, o->index,              /* source index */
1014
        TAG_STRING, is_monitor ? monitor_name : name,
1015
        TAG_STRING, is_monitor ? monitor_desc : desc,
1016
        TAG_SAMPLE_SPEC, &dev_info.ss,
1017
        TAG_CHANNEL_MAP, &dev_info.map,
1018
-       TAG_U32, module_id,             /* module index */
1019
+       TAG_U32, id_to_index(manager, module_id),   /* module index */
1020
        TAG_CVOLUME, &dev_info.volume_info.volume,
1021
        TAG_BOOLEAN, dev_info.volume_info.mute,
1022
-       TAG_U32, is_monitor ? o->id : SPA_ID_INVALID,   /* monitor of sink */
1023
+       TAG_U32, is_monitor ? o->index : SPA_ID_INVALID,/* monitor of sink */
1024
        TAG_STRING, is_monitor ? name : NULL,       /* monitor of sink name */
1025
        TAG_USEC, 0LL,                  /* latency */
1026
        TAG_STRING, "PipeWire",             /* driver */
1027
@@ -3762,8 +3798,10 @@
1028
        TAG_INVALID);
1029
 
1030
    if (client->version >= 13) {
1031
+       int res;
1032
+       if ((res = fill_source_info_proplist(m, o, info)) < 0)
1033
+           return res;
1034
        message_put(m,
1035
-           TAG_PROPLIST, info->props,
1036
            TAG_USEC, 0LL,          /* requested latency */
1037
            TAG_INVALID);
1038
    }
1039
@@ -3780,7 +3818,7 @@
1040
            TAG_VOLUME, dev_info.volume_info.base,  /* base volume */
1041
            TAG_U32, state,             /* state */
1042
            TAG_U32, dev_info.volume_info.steps,    /* n_volume_steps */
1043
-           TAG_U32, card_id,           /* card index */
1044
+           TAG_U32, card ? card->index : SPA_ID_INVALID,   /* card index */
1045
            TAG_INVALID);
1046
    }
1047
    if (client->version >= 16) {
1048
@@ -3846,6 +3884,7 @@
1049
    struct pw_manager_object *peer;
1050
    const char *str;
1051
    uint32_t module_id = SPA_ID_INVALID, client_id = SPA_ID_INVALID;
1052
+   uint32_t peer_index;
1053
    struct device_info dev_info = DEVICE_INFO_INIT(PW_DIRECTION_OUTPUT);
1054
 
1055
    if (!pw_manager_object_is_sink_input(o) || info == NULL || info->props == NULL)
1056
@@ -3865,13 +3904,17 @@
1057
        return -ENOENT;
1058
 
1059
    peer = find_linked(manager, o->id, PW_DIRECTION_OUTPUT);
1060
+   if (peer && pw_manager_object_is_sink(peer))
1061
+       peer_index = peer->index;
1062
+   else
1063
+       peer_index = SPA_ID_INVALID;
1064
 
1065
    message_put(m,
1066
-       TAG_U32, o->id,                 /* sink_input index */
1067
+       TAG_U32, o->index,              /* sink_input index */
1068
        TAG_STRING, get_media_name(info),
1069
-       TAG_U32, module_id,             /* module index */
1070
-       TAG_U32, client_id,             /* client index */
1071
-       TAG_U32, peer ? peer->id : SPA_ID_INVALID,  /* sink index */
1072
+       TAG_U32, id_to_index(manager, module_id),   /* module index */
1073
+       TAG_U32, id_to_index(manager, client_id),   /* client index */
1074
+       TAG_U32, peer_index,                /* sink index */
1075
        TAG_SAMPLE_SPEC, &dev_info.ss,
1076
        TAG_CHANNEL_MAP, &dev_info.map,
1077
        TAG_CVOLUME, &dev_info.volume_info.volume,
1078
@@ -3917,7 +3960,7 @@
1079
    struct pw_manager_object *peer;
1080
    const char *str;
1081
    uint32_t module_id = SPA_ID_INVALID, client_id = SPA_ID_INVALID;
1082
-   uint32_t peer_id;
1083
+   uint32_t peer_index;
1084
    struct device_info dev_info = DEVICE_INFO_INIT(PW_DIRECTION_INPUT);
1085
 
1086
    if (!pw_manager_object_is_source_output(o) || info == NULL || info->props == NULL)
1087
@@ -3937,20 +3980,17 @@
1088
        return -ENOENT;
1089
 
1090
    peer = find_linked(manager, o->id, PW_DIRECTION_INPUT);
1091
-   if (peer && pw_manager_object_is_source_or_monitor(peer)) {
1092
-       peer_id = peer->id;
1093
-       if (!pw_manager_object_is_source(peer))
1094
-           peer_id |= MONITOR_FLAG;
1095
-   } else {
1096
-       peer_id = SPA_ID_INVALID;
1097
-   }
1098
+   if (peer && pw_manager_object_is_source_or_monitor(peer))
1099
+       peer_index = peer->index;
1100
+   else
1101
+       peer_index = SPA_ID_INVALID;
1102
 
1103
    message_put(m,
1104
-       TAG_U32, o->id,                 /* source_output index */
1105
+       TAG_U32, o->index,              /* source_output index */
1106
        TAG_STRING, get_media_name(info),
1107
-       TAG_U32, module_id,             /* module index */
1108
-       TAG_U32, client_id,             /* client index */
1109
-       TAG_U32, peer_id,               /* source index */
1110
+       TAG_U32, id_to_index(manager, module_id),   /* module index */
1111
+       TAG_U32, id_to_index(manager, client_id),   /* client index */
1112
+       TAG_U32, peer_index,                /* source index */
1113
        TAG_SAMPLE_SPEC, &dev_info.ss,
1114
        TAG_CHANNEL_MAP, &dev_info.map,
1115
        TAG_USEC, 0LL,              /* latency */
1116
@@ -3994,15 +4034,15 @@
1117
    spa_zero(sel);
1118
 
1119
    if (message_get(m,
1120
-           TAG_U32, &sel.id,
1121
+           TAG_U32, &sel.index,
1122
            TAG_INVALID) < 0)
1123
        goto error_protocol;
1124
 
1125
    reply = reply_new(client, tag);
1126
 
1127
-   if (command == COMMAND_GET_MODULE_INFO && (sel.id & MODULE_FLAG) != 0) {
1128
+   if (command == COMMAND_GET_MODULE_INFO && (sel.index & MODULE_FLAG) != 0) {
1129
        struct module *module;
1130
-       module = pw_map_lookup(&impl->modules, sel.id & INDEX_MASK);
1131
+       module = pw_map_lookup(&impl->modules, sel.index & MODULE_INDEX_MASK);
1132
        if (module == NULL)
1133
            goto error_noentity;
1134
        fill_ext_module_info(client, reply, module);
1135
@@ -4051,17 +4091,17 @@
1136
    if (fill_func == NULL)
1137
        goto error_invalid;
1138
 
1139
-   if (sel.id != SPA_ID_INVALID && sel.value != NULL)
1140
+   if (sel.index != SPA_ID_INVALID && sel.value != NULL)
1141
        goto error_invalid;
1142
 
1143
-   pw_log_info("[%s] %s tag:%u idx:%u name:%s", client->name,
1144
-           commands[command].name, tag, sel.id, sel.value);
1145
+   pw_log_info("[%s] %s tag:%u index:%u name:%s", client->name,
1146
+           commands[command].name, tag, sel.index, sel.value);
1147
 
1148
    if (command == COMMAND_GET_SINK_INFO || command == COMMAND_GET_SOURCE_INFO) {
1149
-       o = find_device(client, sel.id, sel.value,
1150
+       o = find_device(client, sel.index, sel.value,
1151
                command == COMMAND_GET_SINK_INFO, NULL);
1152
    } else {
1153
-       if (sel.value == NULL && sel.id == SPA_ID_INVALID)
1154
+       if (sel.value == NULL && sel.index == SPA_ID_INVALID)
1155
            goto error_invalid;
1156
        o = select_object(manager, &sel);
1157
    }
1158
@@ -4131,25 +4171,25 @@
1159
 {
1160
    struct impl *impl = client->impl;
1161
    struct message *reply = NULL;
1162
-   uint32_t id;
1163
+   uint32_t index;
1164
    const char *name;
1165
    struct sample *sample;
1166
    int res;
1167
 
1168
    if (message_get(m,
1169
-           TAG_U32, &id,
1170
+           TAG_U32, &index,
1171
            TAG_STRING, &name,
1172
            TAG_INVALID) < 0)
1173
        return -EPROTO;
1174
 
1175
-   if ((id == SPA_ID_INVALID && name == NULL) ||
1176
-       (id != SPA_ID_INVALID && name != NULL))
1177
+   if ((index == SPA_ID_INVALID && name == NULL) ||
1178
+       (index != SPA_ID_INVALID && name != NULL))
1179
        return -EINVAL;
1180
 
1181
-   pw_log_info("[%s] %s tag:%u idx:%u name:%s", client->name,
1182
-           commands[command].name, tag, id, name);
1183
+   pw_log_info("[%s] %s tag:%u index:%u name:%s", client->name,
1184
+           commands[command].name, tag, index, name);
1185
 
1186
-   if ((sample = find_sample(impl, id, name)) == NULL)
1187
+   if ((sample = find_sample(impl, index, name)) == NULL)
1188
        return -ENOENT;
1189
 
1190
    reply = reply_new(client, tag);
1191
@@ -4368,24 +4408,24 @@
1192
 
1193
 static int do_extension(struct client *client, uint32_t command, uint32_t tag, struct message *m)
1194
 {
1195
-   uint32_t idx;
1196
+   uint32_t index;
1197
    const char *name;
1198
    const struct extension *ext;
1199
 
1200
    if (message_get(m,
1201
-           TAG_U32, &idx,
1202
+           TAG_U32, &index,
1203
            TAG_STRING, &name,
1204
            TAG_INVALID) < 0)
1205
        return -EPROTO;
1206
 
1207
-   pw_log_info("[%s] %s tag:%u id:%u name:%s", client->name,
1208
-           commands[command].name, tag, idx, name);
1209
+   pw_log_info("[%s] %s tag:%u index:%u name:%s", client->name,
1210
+           commands[command].name, tag, index, name);
1211
 
1212
-   if ((idx == SPA_ID_INVALID && name == NULL) ||
1213
-       (idx != SPA_ID_INVALID && name != NULL))
1214
+   if ((index == SPA_ID_INVALID && name == NULL) ||
1215
+       (index != SPA_ID_INVALID && name != NULL))
1216
        return -EINVAL;
1217
 
1218
-   ext = extension_find(idx, name);
1219
+   ext = extension_find(index, name);
1220
    if (ext == NULL)
1221
        return -ENOENT;
1222
 
1223
@@ -4397,7 +4437,7 @@
1224
    struct pw_manager *manager = client->manager;
1225
    struct pw_manager_object *o;
1226
    const char *profile_name;
1227
-   uint32_t profile_id = SPA_ID_INVALID;
1228
+   uint32_t profile_index = SPA_ID_INVALID;
1229
    struct selector sel;
1230
    char buf[1024];
1231
    struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buf, sizeof(buf));
1232
@@ -4407,17 +4447,17 @@
1233
    sel.type = pw_manager_object_is_card;
1234
 
1235
    if (message_get(m,
1236
-           TAG_U32, &sel.id,
1237
+           TAG_U32, &sel.index,
1238
            TAG_STRING, &sel.value,
1239
            TAG_STRING, &profile_name,
1240
            TAG_INVALID) < 0)
1241
        return -EPROTO;
1242
 
1243
-   pw_log_info("[%s] %s tag:%u id:%u name:%s profile:%s", client->name,
1244
-           commands[command].name, tag, sel.id, sel.value, profile_name);
1245
+   pw_log_info("[%s] %s tag:%u index:%u name:%s profile:%s", client->name,
1246
+           commands[command].name, tag, sel.index, sel.value, profile_name);
1247
 
1248
-   if ((sel.id == SPA_ID_INVALID && sel.value == NULL) ||
1249
-       (sel.id != SPA_ID_INVALID && sel.value != NULL))
1250
+   if ((sel.index == SPA_ID_INVALID && sel.value == NULL) ||
1251
+       (sel.index != SPA_ID_INVALID && sel.value != NULL))
1252
        return -EINVAL;
1253
    if (profile_name == NULL)
1254
        return -EINVAL;
1255
@@ -4425,7 +4465,7 @@
1256
    if ((o = select_object(manager, &sel)) == NULL)
1257
        return -ENOENT;
1258
 
1259
-   if ((profile_id = find_profile_id(o, profile_name)) == SPA_ID_INVALID)
1260
+   if ((profile_index = find_profile_index(o, profile_name)) == SPA_ID_INVALID)
1261
        return -ENOENT;
1262
 
1263
    if (!SPA_FLAG_IS_SET(o->permissions, PW_PERM_W | PW_PERM_X))
1264
@@ -4438,7 +4478,7 @@
1265
            SPA_PARAM_Profile, 0,
1266
            spa_pod_builder_add_object(&b,
1267
                SPA_TYPE_OBJECT_ParamProfile, SPA_PARAM_Profile,
1268
-               SPA_PARAM_PROFILE_index, SPA_POD_Int(profile_id),
1269
+               SPA_PARAM_PROFILE_index, SPA_POD_Int(profile_index),
1270
                SPA_PARAM_PROFILE_save, SPA_POD_Bool(true)));
1271
 
1272
    return operation_new(client, tag);
1273
@@ -4489,20 +4529,20 @@
1274
 {
1275
    struct pw_manager_object *o;
1276
    const char *name;
1277
-   uint32_t id, cmd;
1278
+   uint32_t index, cmd;
1279
    bool sink = command == COMMAND_SUSPEND_SINK, suspend;
1280
 
1281
    if (message_get(m,
1282
-           TAG_U32, &id,
1283
+           TAG_U32, &index,
1284
            TAG_STRING, &name,
1285
            TAG_BOOLEAN, &suspend,
1286
            TAG_INVALID) < 0)
1287
        return -EPROTO;
1288
 
1289
-   pw_log_info("[%s] %s tag:%u id:%u name:%s", client->name,
1290
-           commands[command].name, tag, id, name);
1291
+   pw_log_info("[%s] %s tag:%u index:%u name:%s", client->name,
1292
+           commands[command].name, tag, index, name);
1293
 
1294
-   if ((o = find_device(client, id, name, sink, NULL)) == NULL)
1295
+   if ((o = find_device(client, index, name, sink, NULL)) == NULL)
1296
        return -ENOENT;
1297
 
1298
    if (o->proxy == NULL)
1299
@@ -4519,7 +4559,7 @@
1300
 {
1301
    struct pw_manager *manager = client->manager;
1302
    struct pw_manager_object *o, *dev, *dev_default;
1303
-   uint32_t id, id_device;
1304
+   uint32_t index, index_device;
1305
    int target_id;
1306
    const char *name_device;
1307
    struct selector sel;
1308
@@ -4527,28 +4567,28 @@
1309
    bool sink = command == COMMAND_MOVE_SINK_INPUT;
1310
 
1311
    if (message_get(m,
1312
-           TAG_U32, &id,
1313
-           TAG_U32, &id_device,
1314
+           TAG_U32, &index,
1315
+           TAG_U32, &index_device,
1316
            TAG_STRING, &name_device,
1317
            TAG_INVALID) < 0)
1318
        return -EPROTO;
1319
 
1320
-   if ((id_device == SPA_ID_INVALID && name_device == NULL) ||
1321
-       (id_device != SPA_ID_INVALID && name_device != NULL))
1322
+   if ((index_device == SPA_ID_INVALID && name_device == NULL) ||
1323
+       (index_device != SPA_ID_INVALID && name_device != NULL))
1324
        return -EINVAL;
1325
 
1326
-   pw_log_info("[%s] %s tag:%u idx:%u device:%d name:%s", client->name,
1327
-           commands[command].name, tag, id, id_device, name_device);
1328
+   pw_log_info("[%s] %s tag:%u index:%u device:%d name:%s", client->name,
1329
+           commands[command].name, tag, index, index_device, name_device);
1330
 
1331
    spa_zero(sel);
1332
-   sel.id = id;
1333
+   sel.index = index;
1334
    sel.type = sink ? pw_manager_object_is_sink_input: pw_manager_object_is_source_output;
1335
 
1336
    o = select_object(manager, &sel);
1337
    if (o == NULL)
1338
        return -ENOENT;
1339
 
1340
-   if ((dev = find_device(client, id_device, name_device, sink, NULL)) == NULL)
1341
+   if ((dev = find_device(client, index_device, name_device, sink, NULL)) == NULL)
1342
        return -ENOENT;
1343
 
1344
    dev_default = find_device(client, SPA_ID_INVALID, NULL, sink, NULL);
1345
@@ -4576,19 +4616,19 @@
1346
 {
1347
    struct pw_manager *manager = client->manager;
1348
    struct pw_manager_object *o;
1349
-   uint32_t id;
1350
+   uint32_t index;
1351
    struct selector sel;
1352
 
1353
    if (message_get(m,
1354
-           TAG_U32, &id,
1355
+           TAG_U32, &index,
1356
            TAG_INVALID) < 0)
1357
        return -EPROTO;
1358
 
1359
-   pw_log_info("[%s] %s tag:%u id:%u", client->name,
1360
-           commands[command].name, tag, id);
1361
+   pw_log_info("[%s] %s tag:%u index:%u", client->name,
1362
+           commands[command].name, tag, index);
1363
 
1364
    spa_zero(sel);
1365
-   sel.id = id;
1366
+   sel.index = index;
1367
    switch (command) {
1368
    case COMMAND_KILL_CLIENT:
1369
        sel.type = pw_manager_object_is_client;
1370
@@ -4619,29 +4659,29 @@
1371
    spa_assert(!SPA_RESULT_IS_ASYNC(result));
1372
 
1373
    if (SPA_RESULT_IS_OK(result)) {
1374
-       pw_log_info("[%s] loaded module id:%u name:%s",
1375
-               client_name, module->idx, module->name);
1376
+       pw_log_info("[%s] loaded module index:%u name:%s",
1377
+               client_name, module->index, module->name);
1378
 
1379
        module->loaded = true;
1380
 
1381
        broadcast_subscribe_event(impl,
1382
            SUBSCRIPTION_MASK_MODULE,
1383
            SUBSCRIPTION_EVENT_NEW | SUBSCRIPTION_EVENT_MODULE,
1384
-           module->idx);
1385
+           module->index);
1386
 
1387
        if (client != NULL) {
1388
            struct message *reply = reply_new(client, tag);
1389
 
1390
            message_put(reply,
1391
-               TAG_U32, module->idx,
1392
+               TAG_U32, module->index,
1393
                TAG_INVALID);
1394
            client_queue_message(client, reply);
1395
        }
1396
    }
1397
    else {
1398
-       pw_log_warn("%p: [%s] failed to load module id:%u name:%s result:%d (%s)",
1399
+       pw_log_warn("%p: [%s] failed to load module index:%u name:%s result:%d (%s)",
1400
                impl, client_name,
1401
-               module->idx, module->name,
1402
+               module->index, module->name,
1403
                result, spa_strerror(result));
1404
 
1405
        module_schedule_unload(module);
1406
@@ -4744,22 +4784,22 @@
1407
 {
1408
    struct impl *impl = client->impl;
1409
    struct module *module;
1410
-   uint32_t module_idx;
1411
+   uint32_t module_index;
1412
 
1413
    if (message_get(m,
1414
-           TAG_U32, &module_idx,
1415
+           TAG_U32, &module_index,
1416
            TAG_INVALID) < 0)
1417
        return -EPROTO;
1418
 
1419
-   pw_log_info("[%s] %s tag:%u id:%u", client->name,
1420
-           commands[command].name, tag, module_idx);
1421
+   pw_log_info("[%s] %s tag:%u index:%u", client->name,
1422
+           commands[command].name, tag, module_index);
1423
 
1424
-   if (module_idx == SPA_ID_INVALID)
1425
+   if (module_index == SPA_ID_INVALID)
1426
        return -EINVAL;
1427
-   if ((module_idx & MODULE_FLAG) == 0)
1428
+   if ((module_index & MODULE_FLAG) == 0)
1429
        return -EPERM;
1430
 
1431
-   module = pw_map_lookup(&impl->modules, module_idx & INDEX_MASK);
1432
+   module = pw_map_lookup(&impl->modules, module_index & MODULE_INDEX_MASK);
1433
    if (module == NULL)
1434
        return -ENOENT;
1435
 
1436
@@ -5124,7 +5164,7 @@
1437
    parse_format(props, "pulse.default.format", DEFAULT_FORMAT, &def->sample_spec);
1438
    parse_position(props, "pulse.default.position", DEFAULT_POSITION, &def->channel_map);
1439
    def->sample_spec.channels = def->channel_map.channels;
1440
-   def->max_quantum = 8192;
1441
+   def->quantum_limit = 8192;
1442
 }
1443
 
1444
 struct pw_protocol_pulse *pw_protocol_pulse_new(struct pw_context *context,
1445
pipewire-0.3.43.tar.gz/src/modules/module-protocol-pulse/quirks.c -> pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/quirks.c Changed
204
 
1
@@ -30,23 +30,7 @@
2
 
3
 #include "log.h"
4
 #include "quirks.h"
5
-
6
-#define QUOTE(...) #__VA_ARGS__
7
-
8
-static const char quirks_rules[] =
9
-"# List of quirks"
10
-"#"
11
-"# All key/value pairs need to match before the quirks are applied."
12
-"#"
13
-"# Possible quirks:"
14
-"#    force-s16-info       forces sink and source info as S16 format"
15
-"#    remove-capture-dont-move removes the capture DONT_MOVE flag"
16
-"#\n"
17
-"["
18
-"    { application.process.binary = teams, quirks = [ force-s16-info ] },"
19
-"    { application.process.binary = skypeforlinux, quirks = [ force-s16-info ] },"
20
-"    { application.process.binary = firefox, quirks = [ remove-capture-dont-move ] },"
21
-"]";
22
+#include "internal.h"
23
 
24
 static uint64_t parse_quirks(const char *str)
25
 {
26
@@ -62,72 +46,139 @@
27
    return 0;
28
 }
29
 
30
-static int match(const char *rules, struct spa_dict *dict, uint64_t *quirks)
31
+static bool find_match(struct spa_json *arr, const struct spa_dict *props)
32
 {
33
-   struct spa_json rules_json = SPA_JSON_INIT(rules, strlen(rules));
34
-   struct spa_json rules_arr, it[2];
35
-
36
-   if (spa_json_enter_array(&rules_json, &rules_arr) <= 0)
37
-       return -EINVAL;
38
+   struct spa_json it[1];
39
 
40
-   while (spa_json_enter_object(&rules_arr, &it[0]) > 0) {
41
-       char key[256];
42
-       int match = true;
43
-       uint64_t quirks_cur = 0;
44
+   while (spa_json_enter_object(arr, &it[0]) > 0) {
45
+       char key[256], val[1024];
46
+       const char *str, *value;
47
+       int match = 0, fail = 0;
48
+       int len;
49
 
50
        while (spa_json_get_string(&it[0], key, sizeof(key)) > 0) {
51
-           char val[4096];
52
-           const char *str, *value;
53
-           int len;
54
            bool success = false;
55
 
56
-           if (spa_streq(key, "quirks")) {
57
-               if (spa_json_enter_array(&it[0], &it[1]) > 0) {
58
-                   while (spa_json_get_string(&it[1], val, sizeof(val)) > 0)
59
-                       quirks_cur |= parse_quirks(val);
60
-               }
61
-               continue;
62
-           }
63
            if ((len = spa_json_next(&it[0], &value)) <= 0)
64
                break;
65
 
66
+           str = spa_dict_lookup(props, key);
67
+
68
            if (spa_json_is_null(value, len)) {
69
-               value = NULL;
70
+               success = str == NULL;
71
            } else {
72
                if (spa_json_parse_stringn(value, len, val, sizeof(val)) < 0)
73
                    continue;
74
                value = val;
75
+               len = strlen(val);
76
            }
77
-           str = spa_dict_lookup(dict, key);
78
-           if (value == NULL) {
79
-               success = str == NULL;
80
-           } else if (str != NULL) {
81
+           if (str != NULL) {
82
                if (value[0] == '~') {
83
-                   regex_t r;
84
-                   if (regcomp(&r, value+1, REG_EXTENDED | REG_NOSUB) == 0) {
85
-                       if (regexec(&r, str, 0, NULL, 0) == 0)
86
+                   regex_t preg;
87
+                   if (regcomp(&preg, value+1, REG_EXTENDED | REG_NOSUB) == 0) {
88
+                       if (regexec(&preg, str, 0, NULL, 0) == 0)
89
                            success = true;
90
-                       regfree(&r);
91
+                       regfree(&preg);
92
                    }
93
-               } else if (spa_streq(str, value)) {
94
+               } else if (strncmp(str, value, len) == 0 &&
95
+                   strlen(str) == (size_t)len) {
96
                    success = true;
97
                }
98
            }
99
+           if (success) {
100
+               match++;
101
+               pw_log_debug("'%s' match '%s' < > '%.*s'", key, str, len, value);
102
+           }
103
+           else
104
+               fail++;
105
+       }
106
+       if (match > 0 && fail == 0)
107
+           return true;
108
+   }
109
+   return false;
110
+}
111
 
112
-           if (!success) {
113
-               match = false;
114
-               break;
115
+static int pw_conf_match_rules(const char *rules, size_t size, const struct spa_dict *props,
116
+       int (*matched) (void *data, const char *action, const char *val, int len),
117
+       void *data)
118
+{
119
+   const char *val;
120
+   struct spa_json it[4], actions;
121
+   int count = 0;
122
+
123
+   spa_json_init(&it[0], rules, size);
124
+   if (spa_json_enter_array(&it[0], &it[1]) < 0)
125
+       return 0;
126
+
127
+   while (spa_json_enter_object(&it[1], &it[2]) > 0) {
128
+       char key[64];
129
+       bool have_match = false, have_actions = false;
130
+
131
+       while (spa_json_get_string(&it[2], key, sizeof(key)) > 0) {
132
+           if (spa_streq(key, "matches")) {
133
+               if (spa_json_enter_array(&it[2], &it[3]) < 0)
134
+                   break;
135
+
136
+               have_match = find_match(&it[3], props);
137
            }
138
-                }
139
-       if (match) {
140
-           *quirks = quirks_cur;
141
-           return 1;
142
+           else if (spa_streq(key, "actions")) {
143
+               if (spa_json_enter_object(&it[2], &actions) > 0)
144
+                   have_actions = true;
145
+           }
146
+           else if (spa_json_next(&it[2], &val) <= 0)
147
+                                break;
148
+       }
149
+       if (!have_match || !have_actions)
150
+           continue;
151
+
152
+       while (spa_json_get_string(&actions, key, sizeof(key)) > 0) {
153
+           int res, len;
154
+           pw_log_debug("action %s", key);
155
+
156
+           if ((len = spa_json_next(&actions, &val)) <= 0)
157
+               break;
158
+
159
+           if (spa_json_is_container(val, len))
160
+               len = spa_json_container_len(&actions, val, len);
161
+
162
+           if ((res = matched(data, key, val, len)) < 0)
163
+               return res;
164
+
165
+           count += res;
166
+       }
167
+   }
168
+   return count;
169
+}
170
+
171
+static int client_rule_matched(void *data, const char *action, const char *val, int len)
172
+{
173
+   struct client *client = data;
174
+
175
+   if (spa_streq(action, "update-props")) {
176
+       pw_properties_update_string(client->props, val, len);
177
+   } else if (spa_streq(action, "quirks")) {
178
+       struct spa_json quirks = SPA_JSON_INIT(val, len), it[1];
179
+       uint64_t quirks_cur = 0;
180
+       char v[128];
181
+
182
+       if (spa_json_enter_array(&quirks, &it[0]) > 0) {
183
+           while (spa_json_get_string(&it[0], v, sizeof(v)) > 0)
184
+               quirks_cur |= parse_quirks(v);
185
        }
186
+       client->quirks = quirks_cur;
187
    }
188
    return 0;
189
 }
190
 
191
 int client_update_quirks(struct client *client)
192
 {
193
-   return match(quirks_rules, &client->props->dict, &client->quirks);
194
+   struct impl *impl = client->impl;
195
+   struct pw_context *context = impl->context;
196
+   const char *rules;
197
+
198
+   if ((rules = pw_context_get_conf_section(context, "pulse.rules")) == NULL)
199
+       return 0;
200
+
201
+   return pw_conf_match_rules(rules, strlen(rules), &client->props->dict,
202
+           client_rule_matched, client);
203
 }
204
pipewire-0.3.43.tar.gz/src/modules/module-protocol-pulse/server.c -> pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/server.c Changed
55
 
1
@@ -167,7 +167,6 @@
2
    index += diff;
3
    filled += diff;
4
    stream->write_index += diff;
5
-   stream->missing -= diff;
6
 
7
    if (filled < 0) {
8
        /* underrun, reported on reader side */
9
@@ -188,6 +187,8 @@
10
    spa_ringbuffer_write_update(&stream->ring, index);
11
    stream->requested -= SPA_MIN(msg->length, stream->requested);
12
 
13
+   stream_send_request(stream);
14
+
15
 finish:
16
    message_free(impl, msg, false, false);
17
    return res;
18
@@ -378,7 +379,7 @@
19
        goto error;
20
    }
21
 
22
-   if (server->n_clients >= MAX_CLIENTS) {
23
+   if (server->n_clients >= server->max_clients) {
24
        close(client_fd);
25
        errno = ECONNREFUSED;
26
        goto error;
27
@@ -943,7 +944,7 @@
28
    while ((len = spa_json_next(&it[1], &v)) > 0) {
29
        char addr_str[FORMATTED_SOCKET_ADDR_STRLEN] = { 0 };
30
        char key[128], client_access[64] = { 0 };
31
-       struct sockaddr_storage addr[2];
32
+       struct sockaddr_storage addrs[2];
33
        int i, max_clients = MAX_CLIENTS, listen_backlog = LISTEN_BACKLOG, n_addr;
34
 
35
        if (spa_json_is_object(v, len)) {
36
@@ -966,7 +967,7 @@
37
            spa_json_parse_stringn(v, len, addr_str, sizeof(addr_str));
38
        }
39
 
40
-       n_addr = parse_address(addr_str, addr, 2);
41
+       n_addr = parse_address(addr_str, addrs, SPA_N_ELEMENTS(addrs));
42
        if (n_addr < 0) {
43
            pw_log_warn("pulse-server %p: failed to parse address '%s': %s",
44
                    impl, addr_str, spa_strerror(n_addr));
45
@@ -976,7 +977,9 @@
46
 
47
        /* try to create sockets for each address in the list */
48
        for (i = 0; i < n_addr; i++) {
49
+           const struct sockaddr_storage *addr = &addrs[i];
50
            struct server * const server = server_new(impl);
51
+
52
            if (server == NULL) {
53
                UPDATE_ERR(-errno);
54
                continue;
55
pipewire-0.3.43.tar.gz/src/modules/module-protocol-pulse/stream.c -> pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/stream.c Changed
117
 
1
@@ -44,11 +44,25 @@
2
 #include "reply.h"
3
 #include "stream.h"
4
 
5
+static int parse_frac(struct pw_properties *props, const char *key,
6
+       const struct spa_fraction *def, struct spa_fraction *res)
7
+{
8
+   const char *str;
9
+   if (props == NULL ||
10
+       (str = pw_properties_get(props, key)) == NULL ||
11
+       sscanf(str, "%u/%u", &res->num, &res->denom) != 2 ||
12
+        res->denom == 0) {
13
+       *res = *def;
14
+   }
15
+   return 0;
16
+}
17
+
18
 struct stream *stream_new(struct client *client, enum stream_type type, uint32_t create_tag,
19
              const struct sample_spec *ss, const struct channel_map *map,
20
              const struct buffer_attr *attr)
21
 {
22
    int res;
23
+   struct defs *defs = &client->impl->defs;
24
 
25
    struct stream *stream = calloc(1, sizeof(*stream));
26
    if (stream == NULL)
27
@@ -67,6 +81,13 @@
28
    stream->attr = *attr;
29
    spa_ringbuffer_init(&stream->ring);
30
 
31
+   parse_frac(client->props, "pulse.min.req", &defs->min_req, &stream->min_req);
32
+   parse_frac(client->props, "pulse.min.frag", &defs->min_frag, &stream->min_frag);
33
+   parse_frac(client->props, "pulse.min.quantum", &defs->min_quantum, &stream->min_quantum);
34
+   parse_frac(client->props, "pulse.default.req", &defs->default_req, &stream->default_req);
35
+   parse_frac(client->props, "pulse.default.frag", &defs->default_frag, &stream->default_frag);
36
+   parse_frac(client->props, "pulse.default.tlength", &defs->default_tlength, &stream->default_tlength);
37
+
38
    switch (type) {
39
    case STREAM_TYPE_RECORD:
40
        stream->direction = PW_DIRECTION_INPUT;
41
@@ -136,9 +157,6 @@
42
        stream->ring.writeindex = stream->ring.readindex;
43
        stream->write_index = stream->read_index;
44
 
45
-       stream->missing = stream->attr.tlength -
46
-           SPA_MIN(stream->requested, stream->attr.tlength);
47
-
48
        if (stream->attr.prebuf > 0)
49
            stream->in_prebuf = true;
50
 
51
@@ -153,13 +171,8 @@
52
    }
53
 }
54
 
55
-static bool stream_prebuf_active(struct stream *stream)
56
+static bool stream_prebuf_active(struct stream *stream, int32_t avail)
57
 {
58
-   uint32_t index;
59
-   int32_t avail;
60
-
61
-   avail = spa_ringbuffer_get_write_index(&stream->ring, &index);
62
-
63
    if (stream->in_prebuf) {
64
        if (avail >= (int32_t) stream->attr.prebuf)
65
            stream->in_prebuf = false;
66
@@ -172,30 +185,34 @@
67
 
68
 uint32_t stream_pop_missing(struct stream *stream)
69
 {
70
-   uint32_t missing;
71
+   int64_t missing, avail;
72
+
73
+   avail = stream->write_index - stream->read_index;
74
+
75
+   missing = stream->attr.tlength;
76
+   missing -= stream->requested;
77
+   missing -= avail;
78
 
79
-   if (stream->missing <= 0)
80
+   if (missing <= 0)
81
        return 0;
82
 
83
-   if (stream->missing < stream->attr.minreq && !stream_prebuf_active(stream))
84
+   if (missing < stream->attr.minreq && !stream_prebuf_active(stream, avail))
85
        return 0;
86
 
87
-   missing = stream->missing;
88
    stream->requested += missing;
89
-   stream->missing = 0;
90
 
91
    return missing;
92
 }
93
 
94
-int stream_send_underflow(struct stream *stream, int64_t offset, uint32_t underrun_for)
95
+int stream_send_underflow(struct stream *stream, int64_t offset)
96
 {
97
    struct client *client = stream->client;
98
    struct impl *impl = client->impl;
99
    struct message *reply;
100
 
101
    if (ratelimit_test(&impl->rate_limit, stream->timestamp, SPA_LOG_LEVEL_INFO)) {
102
-       pw_log_info("[%s]: UNDERFLOW channel:%u offset:%" PRIi64 " underrun:%u",
103
-               client->name, stream->channel, offset, underrun_for);
104
+       pw_log_info("[%s]: UNDERFLOW channel:%u offset:%" PRIi64,
105
+               client->name, stream->channel, offset);
106
    }
107
 
108
    reply = message_alloc(impl, -1, 0);
109
@@ -314,7 +331,6 @@
110
    if (new_tlength <= old_tlength)
111
        return 0;
112
 
113
-   stream->missing += new_tlength - old_tlength;
114
    stream->attr.tlength = new_tlength;
115
 
116
    if (client->version >= 15) {
117
pipewire-0.3.43.tar.gz/src/modules/module-protocol-pulse/stream.h -> pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/stream.h Changed
35
 
1
@@ -58,6 +58,7 @@
2
    uint32_t create_tag;
3
    uint32_t channel;   /* index in map */
4
    uint32_t id;        /* id of global */
5
+   uint32_t index;     /* index */
6
 
7
    struct impl *impl;
8
    struct client *client;
9
@@ -83,9 +84,15 @@
10
    int64_t delay;
11
 
12
    uint32_t last_quantum;
13
-   int64_t missing;
14
    int64_t requested;
15
 
16
+   struct spa_fraction min_req;
17
+   struct spa_fraction default_req;
18
+   struct spa_fraction min_frag;
19
+   struct spa_fraction default_frag;
20
+   struct spa_fraction default_tlength;
21
+   struct spa_fraction min_quantum;
22
+
23
    struct sample_spec ss;
24
    struct channel_map map;
25
    struct buffer_attr attr;
26
@@ -116,7 +123,7 @@
27
 void stream_flush(struct stream *stream);
28
 uint32_t stream_pop_missing(struct stream *stream);
29
 
30
-int stream_send_underflow(struct stream *stream, int64_t offset, uint32_t underrun_for);
31
+int stream_send_underflow(struct stream *stream, int64_t offset);
32
 int stream_send_overflow(struct stream *stream);
33
 int stream_send_killed(struct stream *stream);
34
 int stream_send_started(struct stream *stream);
35
pipewire-0.3.43.tar.gz/src/modules/module-protocol-simple.c -> pipewire-0.3.44.tar.gz/src/modules/module-protocol-simple.c Changed
28
 
1
@@ -111,7 +111,7 @@
2
         struct spa_hook core_proxy_listener;
3
 
4
    struct spa_source *source;
5
-   char name[512];
6
+   char name[128];
7
 
8
    struct pw_stream *capture;
9
    struct spa_hook capture_listener;
10
@@ -477,7 +477,7 @@
11
 {
12
    struct server *server = data;
13
    struct impl *impl = server->impl;
14
-   struct sockaddr addr;
15
+   struct sockaddr_in addr;
16
    socklen_t addrlen;
17
    int client_fd, val;
18
    struct client *client = NULL;
19
@@ -503,7 +503,7 @@
20
    spa_list_append(&server->client_list, &client->link);
21
    server->n_clients++;
22
 
23
-   if (inet_ntop(addr.sa_family, addr.sa_data, client->name, sizeof(client->name)) == NULL)
24
+   if (inet_ntop(addr.sin_family, &addr.sin_addr.s_addr, client->name, sizeof(client->name)) == NULL)
25
        snprintf(client->name, sizeof(client->name), "client %d", client_fd);
26
 
27
    client->source = pw_loop_add_io(impl->loop,
28
pipewire-0.3.43.tar.gz/src/modules/module-raop/rtsp-client.c -> pipewire-0.3.44.tar.gz/src/modules/module-raop/rtsp-client.c Changed
29
 
1
@@ -203,9 +203,12 @@
2
        if (res == 0)
3
            return -EPIPE;
4
        if (res < 0) {
5
-           if (res == EAGAIN)
6
-               return 0;
7
-           return -errno;
8
+           res = -errno;
9
+           if (res == -EINTR)
10
+               continue;
11
+           if (res != -EAGAIN && res != -EWOULDBLOCK)
12
+               return res;
13
+           return 0;
14
        }
15
        if (c == '\n') {
16
            client->line_buf[client->line_pos] = '\0';
17
@@ -435,9 +438,10 @@
18
            true, on_source_io, client);
19
 
20
    if (client->source == NULL) {
21
+       res = -errno;
22
        pw_log_error("%p: source create failed: %m", client);
23
        close(fd);
24
-       return -errno;
25
+       return res;
26
    }
27
    client->connecting = true;
28
    free(client->session_id);
29
pipewire-0.3.43.tar.gz/src/modules/module-roc-sink.c -> pipewire-0.3.44.tar.gz/src/modules/module-roc-sink.c Changed
10
 
1
@@ -441,8 +441,6 @@
2
        pw_properties_set(capture_props, PW_KEY_NODE_VIRTUAL, "true");
3
    if (pw_properties_get(capture_props, PW_KEY_NODE_NETWORK) == NULL)
4
        pw_properties_set(capture_props, PW_KEY_NODE_NETWORK, "true");
5
-   if (pw_properties_get(capture_props, PW_KEY_NODE_PASSIVE) == NULL)
6
-       pw_properties_set(capture_props, PW_KEY_NODE_PASSIVE, "true");
7
    if ((str = pw_properties_get(capture_props, PW_KEY_MEDIA_CLASS)) == NULL)
8
        pw_properties_set(capture_props, PW_KEY_MEDIA_CLASS, "Audio/Sink");
9
 
10
pipewire-0.3.43.tar.gz/src/modules/module-roc-source.c -> pipewire-0.3.44.tar.gz/src/modules/module-roc-source.c Changed
10
 
1
@@ -486,8 +486,6 @@
2
        pw_properties_set(playback_props, PW_KEY_NODE_VIRTUAL, "true");
3
    if (pw_properties_get(playback_props, PW_KEY_NODE_NETWORK) == NULL)
4
        pw_properties_set(playback_props, PW_KEY_NODE_NETWORK, "true");
5
-   if (pw_properties_get(playback_props, PW_KEY_NODE_PASSIVE) == NULL)
6
-       pw_properties_set(playback_props, PW_KEY_NODE_PASSIVE, "true");
7
    if ((str = pw_properties_get(playback_props, PW_KEY_MEDIA_CLASS)) == NULL)
8
        pw_properties_set(playback_props, PW_KEY_MEDIA_CLASS, "Audio/Source");
9
 
10
pipewire-0.3.43.tar.gz/src/modules/module-rt.c -> pipewire-0.3.44.tar.gz/src/modules/module-rt.c Changed
924
 
1
@@ -1,6 +1,6 @@
2
 /* PipeWire
3
  *
4
- * Copyright © 2021 Axis Communications AB
5
+ * Copyright © 2018 Wim Taymans
6
  *
7
  * Permission is hereby granted, free of charge, to any person obtaining a
8
  * copy of this software and associated documentation files (the "Software"),
9
@@ -22,76 +22,452 @@
10
  * DEALINGS IN THE SOFTWARE.
11
  */
12
 
13
-#include <errno.h>
14
-#include <sched.h>
15
-#include <stdbool.h>
16
 #include <stdlib.h>
17
-#include <unistd.h>
18
-#include <sys/types.h>
19
+#include <stdbool.h>
20
+#include <string.h>
21
+#include <stdio.h>
22
+#include <errno.h>
23
 #include <sys/stat.h>
24
-#include <sys/syscall.h>
25
-#include <sys/time.h>
26
-#include <sys/resource.h>
27
+#ifdef __FreeBSD__
28
+#include <sys/thr.h>
29
+#endif
30
+#include <fcntl.h>
31
+#include <unistd.h>
32
 #include <pthread.h>
33
+#include <sys/resource.h>
34
 
35
-#include <spa/utils/dict.h>
36
+#include "config.h"
37
+
38
+#include <spa/support/dbus.h>
39
 #include <spa/utils/result.h>
40
+#include <spa/utils/string.h>
41
 
42
 #include <pipewire/impl.h>
43
 #include <pipewire/thread.h>
44
 
45
-#include "config.h"
46
-
47
 /** \page page_module_rt PipeWire Module: RT
48
+ *
49
+ * The `rt` module uses the operating system's scheduler to enable realtime
50
+ * scheduling for certain threads to assist with low latency audio processing.
51
+ * This requires `RLIMIT_RTPRIO` to be set to a value that's equal to this
52
+ * module's `rt.prio` parameter or higher. Most distros will come with some
53
+ * package that configures this for certain groups or users. If this is not set
54
+ * up and DBus is available, then this module will fall back to using RTKit.
55
  */
56
 
57
-
58
 #define NAME "rt"
59
 
60
 PW_LOG_TOPIC_STATIC(mod_topic, "mod." NAME);
61
 #define PW_LOG_TOPIC_DEFAULT mod_topic
62
 
63
-#define DEFAULT_POLICY SCHED_FIFO
64
+#define REALTIME_POLICY         SCHED_FIFO
65
+#ifdef SCHED_RESET_ON_FORK
66
+#define PW_SCHED_RESET_ON_FORK  SCHED_RESET_ON_FORK
67
+#else
68
+/* FreeBSD compat */
69
+#define PW_SCHED_RESET_ON_FORK  0
70
+#endif
71
 
72
-#define DEFAULT_NICE_LEVEL -11
73
-#define DEFAULT_RT_PRIO 88
74
-#define DEFAULT_RT_TIME_SOFT 2000000
75
-#define DEFAULT_RT_TIME_HARD 2000000
76
+#define IS_VALID_NICE_LEVEL(l) ((l)>=-20 && (l)<=19)
77
 
78
-#define MODULE_USAGE \
79
-   "[nice.level=<priority: default " SPA_STRINGIFY(DEFAULT_NICE_LEVEL) ">] " \
80
-   "[rt.prio=<priority: default " SPA_STRINGIFY(DEFAULT_RT_PRIO) ">] " \
81
-   "[rt.time.soft=<in usec: default " SPA_STRINGIFY(DEFAULT_RT_TIME_SOFT)"] " \
82
-   "[rt.time.hard=<in usec: default " SPA_STRINGIFY(DEFAULT_RT_TIME_HARD)"] "
83
+#define DEFAULT_NICE_LEVEL      20
84
+#define DEFAULT_RT_PRIO        88
85
+#define DEFAULT_RT_TIME_SOFT   -1
86
+#define DEFAULT_RT_TIME_HARD   -1
87
 
88
-#ifndef RLIMIT_RTTIME
89
-#define RLIMIT_RTTIME 15
90
-#endif
91
+#define MODULE_USAGE   "[nice.level=<priority: default "SPA_STRINGIFY(DEFAULT_NICE_LEVEL)"(don't change)>] "   \
92
+           "[rt.prio=<priority: default "SPA_STRINGIFY(DEFAULT_RT_PRIO)">] "       \
93
+           "[rt.time.soft=<in usec: default "SPA_STRINGIFY(DEFAULT_RT_TIME_SOFT)"] "   \
94
+           "[rt.time.hard=<in usec: default "SPA_STRINGIFY(DEFAULT_RT_TIME_HARD)"] "
95
 
96
 static const struct spa_dict_item module_props[] = {
97
-   { PW_KEY_MODULE_AUTHOR, "Jonas Holmberg <jonashg@axis.com>" },
98
-   { PW_KEY_MODULE_DESCRIPTION, "Set thread priorities" },
99
+   { PW_KEY_MODULE_AUTHOR, "Wim Taymans <wim.taymans@gmail.com>" },
100
+   { PW_KEY_MODULE_DESCRIPTION, "Use realtime thread scheduling, falling back to RTKit" },
101
    { PW_KEY_MODULE_USAGE, MODULE_USAGE },
102
    { PW_KEY_MODULE_VERSION, PACKAGE_VERSION },
103
 };
104
 
105
+struct pw_rtkit_bus;
106
+
107
+struct thread {
108
+   struct impl *impl;
109
+   struct spa_list link;
110
+   pthread_t thread;
111
+   pid_t pid;
112
+   void *(*start)(void*);
113
+   void *arg;
114
+};
115
+
116
 struct impl {
117
    struct pw_context *context;
118
 
119
    struct spa_thread_utils thread_utils;
120
 
121
+   int nice_level;
122
    int rt_prio;
123
    rlim_t rt_time_soft;
124
    rlim_t rt_time_hard;
125
 
126
    struct spa_hook module_listener;
127
+
128
+   bool use_rtkit;
129
+   struct pw_rtkit_bus *system_bus;
130
+
131
+   /* These are only for the RTKit implementation to fill in the `thread`
132
+    * struct. Since there's barely any overhead here we'll do this
133
+    * regardless of which backend is used. */
134
+   pthread_mutex_t lock;
135
+   pthread_cond_t cond;
136
+   struct spa_list threads_list;
137
 };
138
 
139
+/***
140
+  Copyright 2009 Lennart Poettering
141
+  Copyright 2010 David Henningsson <diwic@ubuntu.com>
142
+
143
+  Permission is hereby granted, free of charge, to any person
144
+  obtaining a copy of this software and associated documentation files
145
+  (the "Software"), to deal in the Software without restriction,
146
+  including without limitation the rights to use, copy, modify, merge,
147
+  publish, distribute, sublicense, and/or sell copies of the Software,
148
+  and to permit persons to whom the Software is furnished to do so,
149
+  subject to the following conditions:
150
+
151
+  The above copyright notice and this permission notice shall be
152
+  included in all copies or substantial portions of the Software.
153
+
154
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
155
+  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
156
+  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
157
+  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
158
+  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
159
+  ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
160
+  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
161
+  SOFTWARE.
162
+***/
163
+
164
+#include <dbus/dbus.h>
165
+
166
+#include "config.h"
167
+
168
+#include <sys/syscall.h>
169
+
170
+#define RTKIT_SERVICE_NAME "org.freedesktop.RealtimeKit1"
171
+#define RTKIT_OBJECT_PATH "/org/freedesktop/RealtimeKit1"
172
+
173
+#ifndef RLIMIT_RTTIME
174
+#define RLIMIT_RTTIME 15
175
+#endif
176
+
177
+/** \cond */
178
+struct pw_rtkit_bus {
179
+   DBusConnection *bus;
180
+};
181
+/** \endcond */
182
+
183
+struct pw_rtkit_bus *pw_rtkit_bus_get_system(void)
184
+{
185
+   struct pw_rtkit_bus *bus;
186
+   DBusError error;
187
+
188
+   if (getenv("DISABLE_RTKIT")) {
189
+       errno = ENOTSUP;
190
+       return NULL;
191
+   }
192
+
193
+   dbus_error_init(&error);
194
+
195
+   bus = calloc(1, sizeof(struct pw_rtkit_bus));
196
+   if (bus == NULL)
197
+       return NULL;
198
+
199
+   bus->bus = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error);
200
+   if (bus->bus == NULL)
201
+       goto error;
202
+
203
+   dbus_connection_set_exit_on_disconnect(bus->bus, false);
204
+
205
+   return bus;
206
+
207
+error:
208
+   free(bus);
209
+   pw_log_error("Failed to connect to system bus: %s", error.message);
210
+   dbus_error_free(&error);
211
+   errno = ECONNREFUSED;
212
+   return NULL;
213
+}
214
+
215
+void pw_rtkit_bus_free(struct pw_rtkit_bus *system_bus)
216
+{
217
+   dbus_connection_close(system_bus->bus);
218
+   dbus_connection_unref(system_bus->bus);
219
+   free(system_bus);
220
+}
221
+
222
+static pid_t _gettid(void)
223
+{
224
+#if defined(HAVE_GETTID)
225
+   return (pid_t) gettid();
226
+#elif defined(__linux__)
227
+   return syscall(SYS_gettid);
228
+#elif defined(__FreeBSD__)
229
+   long pid;
230
+   thr_self(&pid);
231
+   return (pid_t)pid;
232
+#else
233
+#error "No gettid impl"
234
+#endif
235
+}
236
+
237
+static int translate_error(const char *name)
238
+{
239
+   pw_log_warn("RTKit error: %s", name);
240
+
241
+   if (spa_streq(name, DBUS_ERROR_NO_MEMORY))
242
+       return -ENOMEM;
243
+   if (spa_streq(name, DBUS_ERROR_SERVICE_UNKNOWN) ||
244
+       spa_streq(name, DBUS_ERROR_NAME_HAS_NO_OWNER))
245
+       return -ENOENT;
246
+   if (spa_streq(name, DBUS_ERROR_ACCESS_DENIED) ||
247
+       spa_streq(name, DBUS_ERROR_AUTH_FAILED))
248
+       return -EACCES;
249
+
250
+   return -EIO;
251
+}
252
+
253
+static long long rtkit_get_int_property(struct pw_rtkit_bus *connection, const char *propname,
254
+                   long long *propval)
255
+{
256
+   DBusMessage *m = NULL, *r = NULL;
257
+   DBusMessageIter iter, subiter;
258
+   dbus_int64_t i64;
259
+   dbus_int32_t i32;
260
+   DBusError error;
261
+   int current_type;
262
+   long long ret;
263
+   const char *interfacestr = "org.freedesktop.RealtimeKit1";
264
+
265
+   dbus_error_init(&error);
266
+
267
+   if (!(m = dbus_message_new_method_call(RTKIT_SERVICE_NAME,
268
+                          RTKIT_OBJECT_PATH,
269
+                          "org.freedesktop.DBus.Properties", "Get"))) {
270
+       ret = -ENOMEM;
271
+       goto finish;
272
+   }
273
+
274
+   if (!dbus_message_append_args(m,
275
+                     DBUS_TYPE_STRING, &interfacestr,
276
+                     DBUS_TYPE_STRING, &propname, DBUS_TYPE_INVALID)) {
277
+       ret = -ENOMEM;
278
+       goto finish;
279
+   }
280
+
281
+   if (!(r = dbus_connection_send_with_reply_and_block(connection->bus, m, -1, &error))) {
282
+       ret = translate_error(error.name);
283
+       goto finish;
284
+   }
285
+
286
+   if (dbus_set_error_from_message(&error, r)) {
287
+       ret = translate_error(error.name);
288
+       goto finish;
289
+   }
290
+
291
+   ret = -EBADMSG;
292
+   dbus_message_iter_init(r, &iter);
293
+   while ((current_type = dbus_message_iter_get_arg_type(&iter)) != DBUS_TYPE_INVALID) {
294
+
295
+       if (current_type == DBUS_TYPE_VARIANT) {
296
+           dbus_message_iter_recurse(&iter, &subiter);
297
+
298
+           while ((current_type =
299
+               dbus_message_iter_get_arg_type(&subiter)) != DBUS_TYPE_INVALID) {
300
+
301
+               if (current_type == DBUS_TYPE_INT32) {
302
+                   dbus_message_iter_get_basic(&subiter, &i32);
303
+                   *propval = i32;
304
+                   ret = 0;
305
+               }
306
+
307
+               if (current_type == DBUS_TYPE_INT64) {
308
+                   dbus_message_iter_get_basic(&subiter, &i64);
309
+                   *propval = i64;
310
+                   ret = 0;
311
+               }
312
+
313
+               dbus_message_iter_next(&subiter);
314
+           }
315
+       }
316
+       dbus_message_iter_next(&iter);
317
+   }
318
+
319
+finish:
320
+
321
+   if (m)
322
+       dbus_message_unref(m);
323
+
324
+   if (r)
325
+       dbus_message_unref(r);
326
+
327
+   dbus_error_free(&error);
328
+
329
+   return ret;
330
+}
331
+
332
+int pw_rtkit_get_max_realtime_priority(struct pw_rtkit_bus *connection)
333
+{
334
+   long long retval;
335
+   int err;
336
+
337
+   err = rtkit_get_int_property(connection, "MaxRealtimePriority", &retval);
338
+   return err < 0 ? err : retval;
339
+}
340
+
341
+int pw_rtkit_get_min_nice_level(struct pw_rtkit_bus *connection, int *min_nice_level)
342
+{
343
+   long long retval;
344
+   int err;
345
+
346
+   err = rtkit_get_int_property(connection, "MinNiceLevel", &retval);
347
+   if (err >= 0)
348
+       *min_nice_level = retval;
349
+   return err;
350
+}
351
+
352
+long long pw_rtkit_get_rttime_usec_max(struct pw_rtkit_bus *connection)
353
+{
354
+   long long retval;
355
+   int err;
356
+
357
+   err = rtkit_get_int_property(connection, "RTTimeUSecMax", &retval);
358
+   return err < 0 ? err : retval;
359
+}
360
+
361
+int pw_rtkit_make_realtime(struct pw_rtkit_bus *connection, pid_t thread, int priority)
362
+{
363
+   DBusMessage *m = NULL, *r = NULL;
364
+   dbus_uint64_t u64;
365
+   dbus_uint32_t u32;
366
+   DBusError error;
367
+   int ret;
368
+
369
+   dbus_error_init(&error);
370
+
371
+   if (thread == 0)
372
+       thread = _gettid();
373
+
374
+   if (!(m = dbus_message_new_method_call(RTKIT_SERVICE_NAME,
375
+                          RTKIT_OBJECT_PATH,
376
+                          "org.freedesktop.RealtimeKit1",
377
+                          "MakeThreadRealtime"))) {
378
+       ret = -ENOMEM;
379
+       goto finish;
380
+   }
381
+
382
+   u64 = (dbus_uint64_t) thread;
383
+   u32 = (dbus_uint32_t) priority;
384
+
385
+   if (!dbus_message_append_args(m,
386
+                     DBUS_TYPE_UINT64, &u64,
387
+                     DBUS_TYPE_UINT32, &u32, DBUS_TYPE_INVALID)) {
388
+       ret = -ENOMEM;
389
+       goto finish;
390
+   }
391
+
392
+   if (!(r = dbus_connection_send_with_reply_and_block(connection->bus, m, -1, &error))) {
393
+       ret = translate_error(error.name);
394
+       goto finish;
395
+   }
396
+
397
+
398
+   if (dbus_set_error_from_message(&error, r)) {
399
+       ret = translate_error(error.name);
400
+       goto finish;
401
+   }
402
+
403
+   ret = 0;
404
+
405
+finish:
406
+
407
+   if (m)
408
+       dbus_message_unref(m);
409
+
410
+   if (r)
411
+       dbus_message_unref(r);
412
+
413
+   dbus_error_free(&error);
414
+
415
+   return ret;
416
+}
417
+
418
+int pw_rtkit_make_high_priority(struct pw_rtkit_bus *connection, pid_t thread, int nice_level)
419
+{
420
+   DBusMessage *m = NULL, *r = NULL;
421
+   dbus_uint64_t u64;
422
+   dbus_int32_t s32;
423
+   DBusError error;
424
+   int ret;
425
+
426
+   dbus_error_init(&error);
427
+
428
+   if (thread == 0)
429
+       thread = _gettid();
430
+
431
+   if (!(m = dbus_message_new_method_call(RTKIT_SERVICE_NAME,
432
+                          RTKIT_OBJECT_PATH,
433
+                          "org.freedesktop.RealtimeKit1",
434
+                          "MakeThreadHighPriority"))) {
435
+       ret = -ENOMEM;
436
+       goto finish;
437
+   }
438
+
439
+   u64 = (dbus_uint64_t) thread;
440
+   s32 = (dbus_int32_t) nice_level;
441
+
442
+   if (!dbus_message_append_args(m,
443
+                     DBUS_TYPE_UINT64, &u64,
444
+                     DBUS_TYPE_INT32, &s32, DBUS_TYPE_INVALID)) {
445
+       ret = -ENOMEM;
446
+       goto finish;
447
+   }
448
+
449
+
450
+
451
+   if (!(r = dbus_connection_send_with_reply_and_block(connection->bus, m, -1, &error))) {
452
+       ret = translate_error(error.name);
453
+       goto finish;
454
+   }
455
+
456
+
457
+   if (dbus_set_error_from_message(&error, r)) {
458
+       ret = translate_error(error.name);
459
+       goto finish;
460
+   }
461
+
462
+   ret = 0;
463
+
464
+finish:
465
+
466
+   if (m)
467
+       dbus_message_unref(m);
468
+
469
+   if (r)
470
+       dbus_message_unref(r);
471
+
472
+   dbus_error_free(&error);
473
+
474
+   return ret;
475
+}
476
+
477
 static void module_destroy(void *data)
478
 {
479
    struct impl *impl = data;
480
+
481
    pw_thread_utils_set(NULL);
482
    spa_hook_remove(&impl->module_listener);
483
+
484
+   if (impl->system_bus)
485
+       pw_rtkit_bus_free(impl->system_bus);
486
    free(impl);
487
 }
488
 
489
@@ -100,25 +476,69 @@
490
    .destroy = module_destroy,
491
 };
492
 
493
-static int set_nice(struct impl *impl, int nice_level)
494
+/**
495
+ * Check if the current user has permissions to use realtime scheduling at the
496
+ * specified priority.
497
+ */
498
+static bool check_realtime_priviliges(rlim_t priority)
499
 {
500
-   long tid;
501
-   int res = 0;
502
+   int old_policy;
503
+   struct sched_param old_sched_params;
504
+   int new_policy = REALTIME_POLICY;
505
+   struct sched_param new_sched_params;
506
+
507
+   /* We could check `RLIMIT_RTPRIO`, but the BSDs generally don't have
508
+    * that available, and there are also other ways to use realtime
509
+    * scheduling without that rlimit being set such as `CAP_SYS_NICE` or
510
+    * running as root. Instead of checking a bunch of preconditions, we
511
+    * just try if setting realtime scheduling works or not. */
512
+   if ((old_policy = sched_getscheduler(0)) < 0 ||
513
+       sched_getparam(0, &old_sched_params) != 0) {
514
+       return false;
515
+   }
516
 
517
-   tid = syscall(SYS_gettid);
518
-   if (tid < 0) {
519
-       pw_log_warn("could not get main thread id: %m");
520
-       tid = 0; /* means current thread in setpriority() on linux */
521
+   /* If the current scheduling policy has `SCHED_RESET_ON_FORK` set, then
522
+    * this also needs to be set here or `sched_setscheduler()` will return
523
+    * an error code. Similarly, if it is not set, then we don't want to set
524
+    * it here as it would irreversible change the current thread's
525
+    * scheduling policy. */
526
+   spa_zero(new_sched_params);
527
+   new_sched_params.sched_priority = priority;
528
+   if ((old_policy & PW_SCHED_RESET_ON_FORK) != 0) {
529
+       new_policy |= PW_SCHED_RESET_ON_FORK;
530
    }
531
-   if (setpriority(PRIO_PROCESS, (id_t)tid, nice_level) < 0)
532
-       res = -errno;
533
 
534
-   if (res < 0)
535
-       pw_log_warn("could not set nice-level to %d: %s",
536
-               nice_level, spa_strerror(res));
537
-   else
538
-       pw_log_info("main thread nice level set to %d",
539
-               nice_level);
540
+   if (sched_setscheduler(0, new_policy, &new_sched_params) == 0) {
541
+       sched_setscheduler(0, old_policy, &old_sched_params);
542
+       return true;
543
+   } else {
544
+       return false;
545
+   }
546
+}
547
+
548
+static int set_nice(struct impl *impl, int nice_level)
549
+{
550
+   int res = 0;
551
+   pid_t tid;
552
+
553
+   if (impl->use_rtkit) {
554
+       if ((res = pw_rtkit_make_high_priority(impl->system_bus, 0, nice_level)) < 0) {
555
+           pw_log_warn("could not set nice-level to %d: %s",
556
+                   nice_level, spa_strerror(res));
557
+       } else {
558
+           pw_log_info("main thread nice level set to %d", nice_level);
559
+       }
560
+   } else {
561
+       tid = _gettid();
562
+       if (setpriority(PRIO_PROCESS, tid, nice_level) == 0) {
563
+           pw_log_info("main thread nice level set to %d",
564
+                   nice_level);
565
+       } else {
566
+           res = -errno;
567
+           pw_log_warn("could not set nice-level to %d: %s",
568
+                   nice_level, spa_strerror(res));
569
+       }
570
+   }
571
 
572
    return res;
573
 }
574
@@ -126,74 +546,193 @@
575
 static int set_rlimit(struct impl *impl)
576
 {
577
    struct rlimit rl;
578
+   long long rttime;
579
    int res = 0;
580
 
581
+   spa_zero(rl);
582
    rl.rlim_cur = impl->rt_time_soft;
583
    rl.rlim_max = impl->rt_time_hard;
584
 
585
+   if (impl->use_rtkit) {
586
+       rttime = pw_rtkit_get_rttime_usec_max(impl->system_bus);
587
+       if (rttime >= 0) {
588
+           if ((rlim_t)rttime < rl.rlim_cur) {
589
+               pw_log_debug("clamping rt.time.soft from %ld to %lld because of RTKit",
590
+                        rl.rlim_cur, rttime);
591
+           }
592
+
593
+           rl.rlim_cur = SPA_MIN(rl.rlim_cur, (rlim_t)rttime);
594
+           rl.rlim_max = SPA_MIN(rl.rlim_max, (rlim_t)rttime);
595
+       }
596
+   }
597
+
598
    if (setrlimit(RLIMIT_RTTIME, &rl) < 0)
599
        res = -errno;
600
 
601
    if (res < 0)
602
-       pw_log_warn("could not set rlimit: %s", spa_strerror(res));
603
+       pw_log_debug("setrlimit() failed: %s", spa_strerror(res));
604
    else
605
-       pw_log_debug("rt.time.soft %"PRIi64", rt.time.hard %"PRIi64,
606
+       pw_log_debug("rt.time.soft:%"PRIi64" rt.time.hard:%"PRIi64,
607
                (int64_t)rl.rlim_cur, (int64_t)rl.rlim_max);
608
 
609
    return res;
610
 }
611
 
612
-static struct spa_thread *impl_create(void *data,
613
-           const struct spa_dict *props,
614
-           void *(*start)(void*), void *arg)
615
+static struct thread *find_thread_by_pt(struct impl *impl, pthread_t pt)
616
+{
617
+   struct thread *t;
618
+
619
+   spa_list_for_each(t, &impl->threads_list, link) {
620
+       if (pthread_equal(t->thread, pt))
621
+           return t;
622
+   }
623
+   return NULL;
624
+}
625
+
626
+static void *custom_start(void *data)
627
+{
628
+   struct thread *this = data;
629
+   struct impl *impl = this->impl;
630
+
631
+   pthread_mutex_lock(&impl->lock);
632
+   this->pid = _gettid();
633
+   pthread_cond_broadcast(&impl->cond);
634
+   pthread_mutex_unlock(&impl->lock);
635
+
636
+   return this->start(this->arg);
637
+}
638
+
639
+static struct spa_thread *impl_create(void *data, const struct spa_dict *props,
640
+       void *(*start_routine)(void*), void *arg)
641
 {
642
-   pthread_t pt;
643
+   struct impl *impl = data;
644
+   struct thread *this;
645
    int err;
646
-   if ((err = pthread_create(&pt, NULL, start, arg)) != 0) {
647
+
648
+   this = calloc(1, sizeof(*this));
649
+   this->impl = impl;
650
+   this->start = start_routine;
651
+   this->arg = arg;
652
+
653
+   /* This thread list is only used for the RTKit implementation */
654
+   pthread_mutex_lock(&impl->lock);
655
+   err = pthread_create(&this->thread, NULL, custom_start, this);
656
+   if (err != 0)
657
+       goto exit;
658
+
659
+   pthread_cond_wait(&impl->cond, &impl->lock);
660
+
661
+   spa_list_append(&impl->threads_list, &this->link);
662
+exit:
663
+   pthread_mutex_unlock(&impl->lock);
664
+
665
+   if (err != 0) {
666
        errno = err;
667
+       free(this);
668
        return NULL;
669
    }
670
-   return (struct spa_thread*)pt;
671
+   return (struct spa_thread*)this->thread;
672
 }
673
 
674
 static int impl_join(void *data, struct spa_thread *thread, void **retval)
675
 {
676
+   struct impl *impl = data;
677
    pthread_t pt = (pthread_t)thread;
678
+   struct thread *thr;
679
+
680
+   pthread_mutex_lock(&impl->lock);
681
+   if ((thr = find_thread_by_pt(impl, pt)) != NULL) {
682
+       spa_list_remove(&thr->link);
683
+       free(thr);
684
+   }
685
+   pthread_mutex_unlock(&impl->lock);
686
+
687
    return pthread_join(pt, retval);
688
 }
689
 
690
 static int impl_get_rt_range(void *data, const struct spa_dict *props,
691
        int *min, int *max)
692
 {
693
-   int policy = DEFAULT_POLICY;
694
-   if (min)
695
-       *min = sched_get_priority_min(policy);
696
-   if (max)
697
-       *max = sched_get_priority_max(policy);
698
+   struct impl *impl = data;
699
+   if (impl->use_rtkit) {
700
+       if (min)
701
+           *min = 1;
702
+       if (max)
703
+           *max = pw_rtkit_get_max_realtime_priority(impl->system_bus);
704
+   } else {
705
+       if (min)
706
+           *min = sched_get_priority_min(REALTIME_POLICY);
707
+       if (max)
708
+           *max = sched_get_priority_max(REALTIME_POLICY);
709
+   }
710
+
711
    return 0;
712
 }
713
 
714
+static pid_t impl_gettid(struct impl *impl, pthread_t pt)
715
+{
716
+   struct thread *thr;
717
+   pid_t pid;
718
+
719
+   pthread_mutex_lock(&impl->lock);
720
+   if ((thr = find_thread_by_pt(impl, pt)) != NULL)
721
+       pid = thr->pid;
722
+   else
723
+       pid = _gettid();
724
+   pthread_mutex_unlock(&impl->lock);
725
+
726
+   return pid;
727
+}
728
+
729
 static int impl_acquire_rt(void *data, struct spa_thread *thread, int priority)
730
 {
731
-   int err, policy = DEFAULT_POLICY;
732
-   int rtprio = priority;
733
+   struct impl *impl = data;
734
    struct sched_param sp;
735
+   int err, rtprio_limit;
736
    pthread_t pt = (pthread_t)thread;
737
+   pid_t pid;
738
 
739
-        if (rtprio < sched_get_priority_min(policy) ||
740
-            rtprio > sched_get_priority_max(policy)) {
741
-       pw_log_warn("invalid priority %d for policy %d", rtprio, policy);
742
-       return -EINVAL;
743
+   /* See the docstring on `spa_thread_utils_methods::acquire_rt` */
744
+   if (priority == -1) {
745
+       priority = impl->rt_prio;
746
+   }
747
+
748
+   if (impl->use_rtkit) {
749
+       pid = impl_gettid(impl, pt);
750
+       rtprio_limit = pw_rtkit_get_max_realtime_priority(impl->system_bus);
751
+       if (rtprio_limit >= 0 && rtprio_limit < priority) {
752
+           pw_log_info("dropping requested priority %d for thread %d down to %d because of RTKit limits", priority, pid, rtprio_limit);
753
+           priority = rtprio_limit;
754
+       }
755
+
756
+       spa_zero(sp);
757
+       sp.sched_priority = priority;
758
+
759
+       if (pthread_setschedparam(pt, SCHED_OTHER | PW_SCHED_RESET_ON_FORK, &sp) == 0) {
760
+           pw_log_debug("SCHED_OTHER|SCHED_RESET_ON_FORK worked.");
761
+       }
762
+
763
+       if ((err = pw_rtkit_make_realtime(impl->system_bus, pid, priority)) < 0) {
764
+           pw_log_warn("could not make thread %d realtime using RTKit: %s", pid, spa_strerror(err));
765
+       } else {
766
+           pw_log_info("acquired realtime priority %d for thread %d using RTKit", priority, pid);
767
+       }
768
+   } else {
769
+       if (priority < sched_get_priority_min(REALTIME_POLICY) ||
770
+           priority > sched_get_priority_max(REALTIME_POLICY)) {
771
+           pw_log_warn("invalid priority %d for policy %d", priority, REALTIME_POLICY);
772
+           return -EINVAL;
773
+       }
774
+
775
+       spa_zero(sp);
776
+       sp.sched_priority = priority;
777
+       if ((err = pthread_setschedparam(pt, REALTIME_POLICY | PW_SCHED_RESET_ON_FORK, &sp)) != 0) {
778
+           pw_log_warn("could not make thread %p realtime: %s", thread, strerror(err));
779
+           return -err;
780
+       }
781
+       pw_log_info("acquired realtime priority %d for thread %p", priority, thread);
782
    }
783
 
784
-   spa_zero(sp);
785
-   sp.sched_priority = rtprio;
786
-   if ((err = pthread_setschedparam(pt, policy | SCHED_RESET_ON_FORK,
787
-                                &sp)) != 0) {
788
-       pw_log_warn("%p: could not make thread realtime: %s", thread, strerror(err));
789
-       return -err;
790
-        }
791
-   pw_log_info("thread %p has realtime priority %d", thread, rtprio);
792
    return 0;
793
 }
794
 
795
@@ -204,11 +743,11 @@
796
    int err;
797
 
798
    spa_zero(sp);
799
-   if ((err = pthread_setschedparam(pt,
800
-               SCHED_OTHER | SCHED_RESET_ON_FORK, &sp)) != 0) {
801
-       pw_log_warn("%p: could not drop realtime: %s", thread, strerror(err));
802
+   if ((err = pthread_setschedparam(pt, SCHED_OTHER | PW_SCHED_RESET_ON_FORK, &sp)) != 0) {
803
+       pw_log_debug("thread %p: SCHED_OTHER|SCHED_RESET_ON_FORK failed: %s",
804
+               thread, strerror(err));
805
        return -err;
806
-        }
807
+   }
808
    pw_log_info("thread %p dropped realtime priority", thread);
809
    return 0;
810
 }
811
@@ -222,56 +761,100 @@
812
    .drop_rt = impl_drop_rt,
813
 };
814
 
815
+
816
 SPA_EXPORT
817
 int pipewire__module_init(struct pw_impl_module *module, const char *args)
818
 {
819
    struct pw_context *context = pw_impl_module_get_context(module);
820
    struct impl *impl;
821
+   const struct pw_properties *context_props;
822
    struct pw_properties *props;
823
-   int nice_level;
824
-   int res;
825
+   const char *str;
826
+   bool use_rtkit = true;
827
+   int res = 0;
828
 
829
    PW_LOG_TOPIC_INIT(mod_topic);
830
 
831
+   if ((context_props = pw_context_get_properties(context)) != NULL &&
832
+       (str = pw_properties_get(context_props, "support.dbus")) != NULL &&
833
+       !pw_properties_parse_bool(str))
834
+       use_rtkit = false;
835
+
836
    impl = calloc(1, sizeof(struct impl));
837
    if (impl == NULL)
838
        return -ENOMEM;
839
 
840
-   pw_log_debug("module %p: new %s", impl, args);
841
+   spa_list_init(&impl->threads_list);
842
+   pthread_mutex_init(&impl->lock, NULL);
843
+   pthread_cond_init(&impl->cond, NULL);
844
+
845
+   pw_log_debug("module %p: new", impl);
846
 
847
-   impl->context = context;
848
    props = args ? pw_properties_new_string(args) : pw_properties_new(NULL, NULL);
849
-   if (props == NULL) {
850
+   if (!props) {
851
        res = -errno;
852
        goto error;
853
    }
854
 
855
-   nice_level = pw_properties_get_int32(props, "nice.level", DEFAULT_NICE_LEVEL);
856
-   set_nice(impl, nice_level);
857
-
858
+   impl->context = context;
859
+   impl->nice_level = pw_properties_get_int32(props, "nice.level", DEFAULT_NICE_LEVEL);
860
    impl->rt_prio = pw_properties_get_int32(props, "rt.prio", DEFAULT_RT_PRIO);
861
    impl->rt_time_soft = pw_properties_get_int32(props, "rt.time.soft", DEFAULT_RT_TIME_SOFT);
862
    impl->rt_time_hard = pw_properties_get_int32(props, "rt.time.hard", DEFAULT_RT_TIME_HARD);
863
 
864
+   /* If the user has permissions to use regular realtime scheduling, then
865
+    * we'll use that instead of RTKit */
866
+   if (check_realtime_priviliges(impl->rt_prio)) {
867
+       use_rtkit = false;
868
+   } else {
869
+       if (!use_rtkit) {
870
+           res = -ENOTSUP;
871
+           pw_log_warn("neither regular realtime scheduling nor RTKit are available");
872
+           goto error;
873
+       }
874
+
875
+       /* TODO: Should this be pw_log_warn or pw_log_debug instead? */
876
+       pw_log_info("could not use realtime scheduling, falling back to using RTKit instead");
877
+   }
878
+
879
+   impl->use_rtkit = use_rtkit;
880
+   if (impl->use_rtkit) {
881
+       impl->system_bus = pw_rtkit_bus_get_system();
882
+       if (impl->system_bus == NULL) {
883
+           res = -errno;
884
+           pw_log_warn("could not get system bus: %m");
885
+           goto error;
886
+       }
887
+   }
888
+
889
+   if (IS_VALID_NICE_LEVEL(impl->nice_level))
890
+       set_nice(impl, impl->nice_level);
891
    set_rlimit(impl);
892
 
893
    impl->thread_utils.iface = SPA_INTERFACE_INIT(
894
            SPA_TYPE_INTERFACE_ThreadUtils,
895
            SPA_VERSION_THREAD_UTILS,
896
            &impl_thread_utils, impl);
897
-
898
    pw_thread_utils_set(&impl->thread_utils);
899
 
900
    pw_impl_module_add_listener(module, &impl->module_listener, &module_events, impl);
901
 
902
    pw_impl_module_update_properties(module, &SPA_DICT_INIT_ARRAY(module_props));
903
    pw_impl_module_update_properties(module, &props->dict);
904
-   pw_properties_free(props);
905
 
906
-   return 0;
907
+   if (impl->use_rtkit) {
908
+       pw_log_debug("initialized using RTKit");
909
+   } else {
910
+       pw_log_debug("initialized using regular realtime scheduling");
911
+   }
912
+   goto done;
913
 
914
 error:
915
-   pw_properties_free(props);
916
+   if (impl->system_bus)
917
+       pw_rtkit_bus_free(impl->system_bus);
918
    free(impl);
919
+done:
920
+   pw_properties_free(props);
921
+
922
    return res;
923
 }
924
pipewire-0.3.44.tar.gz/src/modules/module-x11-bell.c Added
293
 
1
@@ -0,0 +1,291 @@
2
+/* PipeWire
3
+ *
4
+ * Copyright © 2022 Wim Taymans <wim.taymans@gmail.com>
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a
7
+ * copy of this software and associated documentation files (the "Software"),
8
+ * to deal in the Software without restriction, including without limitation
9
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
+ * and/or sell copies of the Software, and to permit persons to whom the
11
+ * Software is furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice (including the next
14
+ * paragraph) shall be included in all copies or substantial portions of the
15
+ * Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23
+ * DEALINGS IN THE SOFTWARE.
24
+ */
25
+
26
+#include <string.h>
27
+#include <stdio.h>
28
+#include <errno.h>
29
+#include <sys/types.h>
30
+#include <sys/stat.h>
31
+#include <fcntl.h>
32
+#include <unistd.h>
33
+
34
+#include "config.h"
35
+
36
+#include <spa/utils/string.h>
37
+
38
+#include <X11/Xlib.h>
39
+#include <X11/Xlib-xcb.h>
40
+#include <X11/XKBlib.h>
41
+
42
+#include <canberra.h>
43
+
44
+#include "pipewire/pipewire.h"
45
+#include "pipewire/impl.h"
46
+
47
+/** \page page_module_x11_bell PipeWire Module: X11 Bell
48
+ *
49
+ * The `x11-bell` module intercept the X11 bell events and uses libcanberra to
50
+ * play a sound.
51
+ *
52
+ * ## Module Options
53
+ *
54
+ * - `sink.name = <str>`: node.name of the sink to connect to
55
+ * - `sample.name = <str>`: the name of the sample to play, default 'bell-window-system'
56
+ * - `x11.display = <str>`: the X11 display to use
57
+ * - `x11.xauthority = <str>`: the X11 XAuthority string placed in XAUTHORITY env
58
+ *
59
+ * ## General options
60
+ *
61
+ * There are no general options for this module.
62
+ *
63
+ * ## Example configuration
64
+ *\code{.unparsed}
65
+ * context.modules = [
66
+ *  {   name = libpipewire-x11-bell }
67
+ *      args = {
68
+ *          #sink.name = @DEFAULT_SINK@
69
+ *          sample.name = "bell-window-system"
70
+ *          #x11.display = ":1"
71
+ *          #x11.xauthority = "test"
72
+ * ]
73
+ *\endcode
74
+ *
75
+ */
76
+
77
+#define NAME "x11-bell"
78
+
79
+PW_LOG_TOPIC_STATIC(mod_topic, "mod." NAME);
80
+#define PW_LOG_TOPIC_DEFAULT mod_topic
81
+
82
+struct impl {
83
+   struct pw_context *context;
84
+   struct pw_thread_loop *thread_loop;
85
+   struct pw_loop *loop;
86
+   struct spa_source *source;
87
+
88
+   struct pw_properties *properties;
89
+
90
+   struct spa_hook module_listener;
91
+
92
+   Display *display;
93
+   int xkb_event_base;
94
+};
95
+
96
+static int play_sample(struct impl *impl, const char *sample)
97
+{
98
+   int res;
99
+   ca_context *ca;
100
+
101
+   if ((res = ca_context_create(&ca)) < 0) {
102
+       pw_log_error("canberra context create error: %s", ca_strerror(res));
103
+       res = -EIO;
104
+       goto exit;
105
+   }
106
+   if ((res = ca_context_open(ca)) < 0) {
107
+       pw_log_error("canberra context open error: %s", ca_strerror(res));
108
+       res = -EIO;
109
+       goto exit_destroy;
110
+   }
111
+   if ((res = ca_context_play(ca, 0,
112
+           CA_PROP_EVENT_ID, sample,
113
+           CA_PROP_MEDIA_NAME, "X11 bell event",
114
+           CA_PROP_CANBERRA_CACHE_CONTROL, "permanent",
115
+           NULL)) < 0) {
116
+       pw_log_warn("can't play sample (%s): %s", sample, ca_strerror(res));
117
+   }
118
+
119
+exit_destroy:
120
+   ca_context_destroy(ca);
121
+exit:
122
+   return res;
123
+}
124
+static void display_io(void *data, int fd, uint32_t mask)
125
+{
126
+   struct impl *impl = data;
127
+   XEvent e;
128
+   const char *sample = NULL;
129
+
130
+   while (XPending(impl->display)) {
131
+       XNextEvent(impl->display, &e);
132
+
133
+       if (((XkbEvent*) &e)->any.xkb_type != XkbBellNotify)
134
+           continue;
135
+
136
+       if (impl->properties)
137
+           sample = pw_properties_get(impl->properties, "sample.name");
138
+       if (sample == NULL)
139
+           sample = "bell-window-system";
140
+
141
+       pw_log_debug("play sample %s", sample);
142
+       play_sample(impl, sample);
143
+   }
144
+}
145
+
146
+static void x11_close(struct impl *impl)
147
+{
148
+   if (impl->source) {
149
+       pw_loop_destroy_source(impl->loop, impl->source);
150
+       impl->source = NULL;
151
+   }
152
+   if (impl->display) {
153
+       XCloseDisplay(impl->display);
154
+       impl->display = NULL;
155
+   }
156
+}
157
+
158
+static int x11_connect(struct impl *impl, const char *name)
159
+{
160
+   int res, major, minor;
161
+   unsigned int auto_ctrls, auto_values;
162
+
163
+   if (!(impl->display = XOpenDisplay(name))) {
164
+       pw_log_warn("XOpenDisplay() failed");
165
+       res = -EIO;
166
+       goto error;
167
+   }
168
+
169
+   impl->source = pw_loop_add_io(impl->loop,
170
+           ConnectionNumber(impl->display),
171
+           SPA_IO_IN, false, display_io, impl);
172
+
173
+   major = XkbMajorVersion;
174
+   minor = XkbMinorVersion;
175
+
176
+   if (!XkbLibraryVersion(&major, &minor)) {
177
+       pw_log_warn("XkbLibraryVersion() failed");
178
+       res = -EIO;
179
+       goto error;
180
+   }
181
+
182
+   major = XkbMajorVersion;
183
+   minor = XkbMinorVersion;
184
+
185
+   if (!XkbQueryExtension(impl->display, NULL, &impl->xkb_event_base,
186
+               NULL, &major, &minor)) {
187
+       res = -EIO;
188
+       pw_log_warn("XkbQueryExtension() failed");
189
+       goto error;
190
+   }
191
+
192
+   XkbSelectEvents(impl->display, XkbUseCoreKbd, XkbBellNotifyMask, XkbBellNotifyMask);
193
+   auto_ctrls = auto_values = XkbAudibleBellMask;
194
+   XkbSetAutoResetControls(impl->display, XkbAudibleBellMask, &auto_ctrls, &auto_values);
195
+   XkbChangeEnabledControls(impl->display, XkbUseCoreKbd, XkbAudibleBellMask, 0);
196
+
197
+   res = 0;
198
+error:
199
+   if (res < 0)
200
+       x11_close(impl);
201
+   return res;
202
+}
203
+
204
+static void module_destroy(void *data)
205
+{
206
+   struct impl *impl = data;
207
+
208
+   spa_hook_remove(&impl->module_listener);
209
+
210
+   if (impl->thread_loop)
211
+       pw_thread_loop_lock(impl->thread_loop);
212
+
213
+   x11_close(impl);
214
+
215
+   if (impl->thread_loop) {
216
+       pw_thread_loop_unlock(impl->thread_loop);
217
+       pw_thread_loop_destroy(impl->thread_loop);
218
+   }
219
+
220
+   pw_properties_free(impl->properties);
221
+
222
+   free(impl);
223
+}
224
+
225
+static const struct pw_impl_module_events module_events = {
226
+   PW_VERSION_IMPL_MODULE_EVENTS,
227
+   .destroy = module_destroy,
228
+};
229
+
230
+static const struct spa_dict_item module_x11_bell_info[] = {
231
+   { PW_KEY_MODULE_AUTHOR, "Wim Taymans <wim.taymans@gmail.com>" },
232
+   { PW_KEY_MODULE_DESCRIPTION, "X11 Bell interceptor" },
233
+   { PW_KEY_MODULE_USAGE,  "sink.name=<name for the sink> "
234
+               "sample.name=<the sample name> "
235
+               "x11.display=<the X11 display> "
236
+               "x11.xauthority=<the X11 XAuthority> " },
237
+   { PW_KEY_MODULE_VERSION, PACKAGE_VERSION },
238
+};
239
+SPA_EXPORT
240
+int pipewire__module_init(struct pw_impl_module *module, const char *args)
241
+{
242
+   struct pw_context *context = pw_impl_module_get_context(module);
243
+   struct impl *impl;
244
+   const char *name = NULL, *str;
245
+   int res;
246
+
247
+   PW_LOG_TOPIC_INIT(mod_topic);
248
+
249
+   impl = calloc(1, sizeof(struct impl));
250
+   if (impl == NULL)
251
+       return -ENOMEM;
252
+
253
+   pw_log_debug("module %p: new", impl);
254
+
255
+   impl->context = context;
256
+   impl->thread_loop = pw_thread_loop_new("X11 Bell", NULL);
257
+   if (impl->thread_loop == NULL) {
258
+       res = -errno;
259
+       pw_log_error("can't create thread loop: %m");
260
+       goto error;
261
+   }
262
+   impl->loop = pw_thread_loop_get_loop(impl->thread_loop);
263
+   impl->properties = args ? pw_properties_new_string(args) : NULL;
264
+
265
+   pw_impl_module_add_listener(module, &impl->module_listener, &module_events, impl);
266
+   pw_impl_module_update_properties(module, &SPA_DICT_INIT_ARRAY(module_x11_bell_info));
267
+
268
+   if (impl->properties) {
269
+       if ((str = pw_properties_get(impl->properties, "x11.xauthority")) != NULL) {
270
+           if (setenv("XAUTHORITY", str, 1)) {
271
+               res = -errno;
272
+               pw_log_error("XAUTHORITY setenv failed: %m");
273
+               goto error;
274
+           }
275
+       }
276
+       name = pw_properties_get(impl->properties, "x11.display");
277
+   }
278
+
279
+   /* we need to use a thread loop because this module will connect
280
+    * to pipewire eventually and will then block the mainloop. */
281
+   pw_thread_loop_start(impl->thread_loop);
282
+
283
+   pw_thread_loop_lock(impl->thread_loop);
284
+   x11_connect(impl, name);
285
+   pw_thread_loop_unlock(impl->thread_loop);
286
+
287
+   return 0;
288
+error:
289
+   module_destroy(impl);
290
+   return res;
291
+
292
+}
293
pipewire-0.3.43.tar.gz/src/modules/spa/spa-node.c -> pipewire-0.3.44.tar.gz/src/modules/spa/spa-node.c Changed
15
 
1
@@ -242,6 +242,13 @@
2
    int res;
3
    struct spa_handle *handle;
4
    void *iface;
5
+   const struct pw_properties *p;
6
+
7
+   if (properties) {
8
+       p = pw_context_get_properties(context);
9
+       pw_properties_set(properties, "clock.quantum-limit",
10
+               pw_properties_get(p, "default.clock.quantum-limit"));
11
+   }
12
 
13
    handle = pw_context_load_spa_handle(context,
14
            factory_name,
15
pipewire-0.3.43.tar.gz/src/pipewire/conf.c -> pipewire-0.3.44.tar.gz/src/pipewire/conf.c Changed
19
 
1
@@ -49,7 +49,7 @@
2
 PW_LOG_TOPIC_EXTERN(log_conf);
3
 #define PW_LOG_TOPIC_DEFAULT log_conf
4
 
5
-static int make_path(char *path, int size, const char *paths[])
6
+static int make_path(char *path, size_t size, const char *paths[])
7
 {
8
    int i, len;
9
    char *p = path;
10
@@ -57,7 +57,7 @@
11
        len = snprintf(p, size, "%s%s", i == 0 ? "" : "/", paths[i]);
12
        if (len < 0)
13
            return -errno;
14
-       if (len >= size)
15
+       if ((size_t)len >= size)
16
            return -ENOSPC;
17
        p += len;
18
        size -= len;
19
pipewire-0.3.43.tar.gz/src/pipewire/context.c -> pipewire-0.3.44.tar.gz/src/pipewire/context.c Changed
140
 
1
@@ -134,7 +134,8 @@
2
        res = pw_thread_utils_drop_rt(thr);
3
    } else {
4
        pw_log_info("%p: exit freewheel", context);
5
-       res = pw_thread_utils_acquire_rt(thr, 88);
6
+       // Use the priority as configured within the realtime module
7
+       res = pw_thread_utils_acquire_rt(thr, -1);
8
    }
9
    if (res < 0)
10
        pw_log_info("%p: freewheel error:%s", context, spa_strerror(res));
11
@@ -893,24 +894,31 @@
12
    return pw_impl_node_set_state(node, state);
13
 }
14
 
15
-static int collect_nodes(struct pw_context *context, struct pw_impl_node *driver)
16
+static int collect_nodes(struct pw_context *context, struct pw_impl_node *node)
17
 {
18
    struct spa_list queue;
19
-   struct pw_impl_node *n, *t;
20
+   struct pw_impl_node *n, *t, *driver;
21
    struct pw_impl_port *p;
22
    struct pw_impl_link *l;
23
 
24
-   spa_list_consume(t, &driver->follower_list, follower_link) {
25
-       spa_list_remove(&t->follower_link);
26
-       spa_list_init(&t->follower_link);
27
-   }
28
+   pw_log_debug("node %p: '%s'", node, node->name);
29
 
30
-   pw_log_debug("driver %p: '%s'", driver, driver->name);
31
+   if (node->driver) {
32
+       driver = node;
33
+       spa_list_consume(t, &driver->follower_list, follower_link) {
34
+           spa_list_remove(&t->follower_link);
35
+           spa_list_init(&t->follower_link);
36
+       }
37
+   } else {
38
+       driver = node->driver_node;
39
+       if (driver == NULL)
40
+           return -EINVAL;
41
+   }
42
 
43
-   /* start with driver in the queue */
44
+   /* start with node in the queue */
45
    spa_list_init(&queue);
46
-   spa_list_append(&queue, &driver->sort_link);
47
-   driver->visited = true;
48
+   spa_list_append(&queue, &node->sort_link);
49
+   node->visited = true;
50
 
51
    /* now follow all the links from the nodes in the queue
52
     * and add the peers to the queue. */
53
@@ -980,26 +988,32 @@
54
 }
55
 
56
 static inline void get_quantums(struct pw_context *context, uint32_t *def,
57
-       uint32_t *min, uint32_t *max, uint32_t *rate)
58
+       uint32_t *min, uint32_t *max, uint32_t *limit, uint32_t *rate)
59
 {
60
    struct settings *s = &context->settings;
61
-   *def = s->clock_force_quantum == 0 ? s->clock_quantum : s->clock_force_quantum;
62
-   *min = s->clock_force_quantum == 0 ? s->clock_min_quantum : s->clock_force_quantum;
63
-   *max = s->clock_force_quantum == 0 ? s->clock_max_quantum : s->clock_force_quantum;
64
-   *rate = s->clock_force_quantum == 0 ? s->clock_rate : s->clock_force_rate;
65
+   if (s->clock_force_quantum != 0) {
66
+       *def = *min = *max = s->clock_force_quantum;
67
+       *rate = 0;
68
+   } else {
69
+       *def = s->clock_quantum;
70
+       *min = s->clock_min_quantum;
71
+       *max = s->clock_max_quantum;
72
+       *rate = s->clock_rate;
73
+   }
74
+   *limit = s->clock_quantum_limit;
75
 }
76
 
77
 static inline uint32_t *get_rates(struct pw_context *context, uint32_t *def, uint32_t *n_rates,
78
-       bool *force_rate)
79
+       bool *force)
80
 {
81
    struct settings *s = &context->settings;
82
    if (s->clock_force_rate != 0) {
83
-       *force_rate = true;
84
+       *force = true;
85
        *n_rates = 1;
86
        *def = s->clock_force_rate;
87
        return &s->clock_force_rate;
88
    } else {
89
-       *force_rate = false;
90
+       *force = false;
91
        *n_rates = s->n_clock_rates;
92
        *def = s->clock_rate;
93
        return s->clock_rates;
94
@@ -1053,7 +1067,7 @@
95
 {
96
    struct impl *impl = SPA_CONTAINER_OF(context, struct impl, this);
97
    struct pw_impl_node *n, *s, *target, *fallback;
98
-   uint32_t max_quantum, min_quantum, def_quantum, rate_quantum;
99
+   uint32_t max_quantum, min_quantum, def_quantum, lim_quantum, rate_quantum;
100
    uint32_t *rates, n_rates, def_rate;
101
    bool freewheel = false, force_rate;
102
 
103
@@ -1067,7 +1081,7 @@
104
 again:
105
    impl->recalc = true;
106
 
107
-   get_quantums(context, &def_quantum, &min_quantum, &max_quantum, &rate_quantum);
108
+   get_quantums(context, &def_quantum, &min_quantum, &max_quantum, &lim_quantum, &rate_quantum);
109
    rates = get_rates(context, &def_rate, &n_rates, &force_rate);
110
 
111
    /* start from all drivers and group all nodes that are linked
112
@@ -1135,8 +1149,10 @@
113
            pw_impl_node_set_driver(n, t);
114
            if (t == NULL)
115
                ensure_state(n, false);
116
-           else
117
+           else {
118
                t->passive = false;
119
+               collect_nodes(context, n);
120
+           }
121
        }
122
        n->visited = false;
123
    }
124
@@ -1221,6 +1237,7 @@
125
        if (rate_quantum != 0 && current_rate != rate_quantum) {
126
            def_quantum = def_quantum * current_rate / rate_quantum;
127
            min_quantum = min_quantum * current_rate / rate_quantum;
128
+           max_quantum = max_quantum * current_rate / rate_quantum;
129
        }
130
 
131
        /* calculate desired quantum */
132
@@ -1234,6 +1251,7 @@
133
        if (latency.denom != 0)
134
            quantum = (latency.num * current_rate / latency.denom);
135
        quantum = SPA_CLAMP(quantum, min_quantum, max_quantum);
136
+       quantum = SPA_MIN(quantum, lim_quantum);
137
 
138
        if (context->settings.clock_power_of_two_quantum)
139
            quantum = flp2(quantum);
140
pipewire-0.3.43.tar.gz/src/pipewire/filter.c -> pipewire-0.3.44.tar.gz/src/pipewire/filter.c Changed
36
 
1
@@ -52,7 +52,6 @@
2
 #define MASK_BUFFERS   (MAX_BUFFERS-1)
3
 #define MAX_PORTS  1024
4
 
5
-static float empty[MAX_SAMPLES];
6
 static bool mlock_warned = false;
7
 
8
 static uint32_t mappable_dataTypes = (1<<SPA_DATA_MemFd);
9
@@ -1223,6 +1222,17 @@
10
    }
11
    if ((str = getenv("PIPEWIRE_LATENCY")) != NULL)
12
        pw_properties_set(props, PW_KEY_NODE_LATENCY, str);
13
+   if ((str = getenv("PIPEWIRE_RATE")) != NULL)
14
+       pw_properties_set(props, PW_KEY_NODE_RATE, str);
15
+   if ((str = getenv("PIPEWIRE_QUANTUM")) != NULL) {
16
+       struct spa_fraction q;
17
+       if (sscanf(str, "%u/%u", &q.num, &q.denom) == 2 && q.denom != 0) {
18
+           pw_properties_setf(props, PW_KEY_NODE_RATE,
19
+                   "1/%u", q.denom);
20
+           pw_properties_setf(props, PW_KEY_NODE_LATENCY,
21
+                   "%u/%u", q.num, q.denom);
22
+       }
23
+   }
24
 
25
    spa_hook_list_init(&impl->hooks);
26
    this->properties = props;
27
@@ -1860,7 +1870,7 @@
28
    struct spa_data *d;
29
 
30
    if ((buf = pw_filter_dequeue_buffer(port_data)) == NULL)
31
-       return empty;
32
+       return NULL;
33
 
34
    d = &buf->buffer->datas[0];
35
 
36
pipewire-0.3.43.tar.gz/src/pipewire/impl-link.c -> pipewire-0.3.44.tar.gz/src/pipewire/impl-link.c Changed
86
 
1
@@ -451,7 +451,7 @@
2
    return res;
3
 }
4
 
5
-static int select_io(struct pw_impl_link *this)
6
+static void select_io(struct pw_impl_link *this)
7
 {
8
    struct impl *impl = SPA_CONTAINER_OF(this, struct impl, this);
9
    struct spa_io_buffers *io;
10
@@ -461,13 +461,9 @@
11
        io = this->rt.out_mix.io;
12
    if (io == NULL)
13
        io = &impl->io;
14
-   if (io == NULL)
15
-       return -EIO;
16
 
17
    this->io = io;
18
    *this->io = SPA_IO_BUFFERS_INIT;
19
-
20
-   return 0;
21
 }
22
 
23
 static int do_allocation(struct pw_impl_link *this)
24
@@ -1133,7 +1129,7 @@
25
 
26
    if (check_permission(this->context, this->output, this->input, this->properties) < 0) {
27
        pw_impl_link_destroy(this);
28
-   } else {
29
+   } else if (this->global != NULL) {
30
        pw_global_update_permissions(this->global, client, old, new);
31
    }
32
 }
33
@@ -1229,6 +1225,16 @@
34
    spa_hook_list_init(&this->listener_list);
35
 
36
    impl->format_filter = format_filter;
37
+   this->info.format = NULL;
38
+   this->info.props = &this->properties->dict;
39
+
40
+   this->rt.out_mix.peer_id = input->global->id;
41
+   this->rt.in_mix.peer_id = output->global->id;
42
+
43
+   if ((res = pw_impl_port_init_mix(output, &this->rt.out_mix)) < 0)
44
+       goto error_output_mix;
45
+   if ((res = pw_impl_port_init_mix(input, &this->rt.in_mix)) < 0)
46
+       goto error_input_mix;
47
 
48
    pw_impl_port_add_listener(input, &impl->input_port_listener, &input_port_events, impl);
49
    pw_impl_node_add_listener(input_node, &impl->input_node_listener, &input_node_events, impl);
50
@@ -1245,19 +1251,9 @@
51
    spa_list_append(&output->links, &this->output_link);
52
    spa_list_append(&input->links, &this->input_link);
53
 
54
-   this->info.format = NULL;
55
-   this->info.props = &this->properties->dict;
56
-
57
    impl->io = SPA_IO_BUFFERS_INIT;
58
 
59
-   this->rt.out_mix.peer_id = input->global->id;
60
-   this->rt.in_mix.peer_id = output->global->id;
61
-
62
-   pw_impl_port_init_mix(output, &this->rt.out_mix);
63
-   pw_impl_port_init_mix(input, &this->rt.in_mix);
64
-
65
-   if ((res = select_io(this)) < 0)
66
-       goto error_no_io;
67
+   select_io(this);
68
 
69
    if (this->feedback) {
70
        impl->inode = output_node;
71
@@ -1317,8 +1313,12 @@
72
    res = -errno;
73
    pw_log_debug("work queue failed: %m");
74
    goto error_free;
75
-error_no_io:
76
-   pw_log_debug("%p: can't set io %d (%s)", this, res, spa_strerror(res));
77
+error_output_mix:
78
+   pw_log_error("%p: can't get output mix %d (%s)", this, res, spa_strerror(res));
79
+   goto error_free;
80
+error_input_mix:
81
+   pw_log_error("%p: can't get input mix %d (%s)", this, res, spa_strerror(res));
82
+   pw_impl_port_release_mix(output, &this->rt.out_mix);
83
    goto error_free;
84
 error_free:
85
    free(impl);
86
pipewire-0.3.43.tar.gz/src/pipewire/impl-metadata.c -> pipewire-0.3.44.tar.gz/src/pipewire/impl-metadata.c Changed
19
 
1
@@ -523,14 +523,15 @@
2
 int pw_impl_metadata_register(struct pw_impl_metadata *metadata,
3
             struct pw_properties *properties)
4
 {
5
+   struct pw_context *context = metadata->context;
6
    static const char * const keys[] = {
7
+       PW_KEY_OBJECT_SERIAL,
8
        PW_KEY_MODULE_ID,
9
+       PW_KEY_FACTORY_ID,
10
        PW_KEY_METADATA_NAME,
11
        NULL
12
    };
13
 
14
-   struct pw_context *context = metadata->context;
15
-
16
    if (metadata->registered)
17
        goto error_existed;
18
 
19
pipewire-0.3.43.tar.gz/src/pipewire/impl-module.c -> pipewire-0.3.44.tar.gz/src/pipewire/impl-module.c Changed
33
 
1
@@ -171,6 +171,11 @@
2
    const char *state = NULL, *p;
3
    size_t len;
4
    char path_part[PATH_MAX];
5
+   static const char * const keys[] = {
6
+       PW_KEY_OBJECT_SERIAL,
7
+       PW_KEY_MODULE_NAME,
8
+       NULL
9
+   };
10
 
11
    module_dir = getenv("PIPEWIRE_MODULE_DIR");
12
    if (module_dir == NULL) {
13
@@ -234,9 +239,7 @@
14
    this->global = pw_global_new(context,
15
                     PW_TYPE_INTERFACE_Module,
16
                     PW_VERSION_MODULE,
17
-                    pw_properties_new(
18
-                        PW_KEY_MODULE_NAME, name,
19
-                        NULL),
20
+                    NULL,
21
                     global_bind,
22
                     this);
23
 
24
@@ -251,6 +254,8 @@
25
            pw_global_get_serial(this->global));
26
    this->info.props = &this->properties->dict;
27
 
28
+   pw_global_update_keys(this->global, &this->properties->dict, keys);
29
+
30
    pw_impl_module_emit_initialized(this);
31
 
32
    pw_global_add_listener(this->global, &this->global_listener, &global_events, this);
33
pipewire-0.3.43.tar.gz/src/pipewire/impl-node.c -> pipewire-0.3.44.tar.gz/src/pipewire/impl-node.c Changed
48
 
1
@@ -59,6 +59,7 @@
2
    struct spa_list pending_list;
3
 
4
    unsigned int pause_on_idle:1;
5
+   unsigned int suspend_on_idle:1;
6
    unsigned int cache_params:1;
7
    unsigned int pending_play:1;
8
 };
9
@@ -387,6 +388,10 @@
10
        spa_list_for_each(resource, &node->global->resource_list, link)
11
            pw_resource_error(resource, res, error);
12
    }
13
+   if (old == PW_NODE_STATE_RUNNING &&
14
+       state == PW_NODE_STATE_IDLE &&
15
+       impl->suspend_on_idle)
16
+        pw_impl_node_set_state(node, PW_NODE_STATE_SUSPENDED);
17
 }
18
 
19
 static int suspend_node(struct pw_impl_node *this)
20
@@ -867,8 +872,9 @@
21
    }
22
 
23
    impl->pause_on_idle = pw_properties_get_bool(node->properties, PW_KEY_NODE_PAUSE_ON_IDLE, true);
24
+   impl->suspend_on_idle = pw_properties_get_bool(node->properties, PW_KEY_NODE_SUSPEND_ON_IDLE, false);
25
    impl->cache_params =  pw_properties_get_bool(node->properties, PW_KEY_NODE_CACHE_PARAMS, true);
26
-   node->transport_sync = pw_properties_get_bool(node->properties, "node.transport.sync", false);
27
+   node->transport_sync = pw_properties_get_bool(node->properties, PW_KEY_NODE_TRANSPORT_SYNC, false);
28
    driver = pw_properties_get_bool(node->properties, PW_KEY_NODE_DRIVER, false);
29
 
30
    if (node->driver != driver) {
31
@@ -1654,6 +1660,16 @@
32
    if (SPA_UNLIKELY(node->driver && !node->driving))
33
        return 0;
34
 
35
+   if (!node->driver) {
36
+       struct timespec ts;
37
+       struct pw_node_activation *a = node->rt.activation;
38
+       struct spa_system *data_system = node->context->data_system;
39
+
40
+       spa_system_clock_gettime(data_system, CLOCK_MONOTONIC, &ts);
41
+       a->status = PW_NODE_ACTIVATION_AWAKE;
42
+       a->signal_time = a->awake_time = SPA_TIMESPEC_TO_NSEC(&ts);
43
+   }
44
+
45
    if (status & SPA_STATUS_HAVE_DATA) {
46
        spa_list_for_each(p, &node->rt.output_mix, rt.node_link)
47
            spa_node_process(p->mix);
48
pipewire-0.3.43.tar.gz/src/pipewire/impl-port.c -> pipewire-0.3.44.tar.gz/src/pipewire/impl-port.c Changed
96
 
1
@@ -214,16 +214,16 @@
2
    if (port_id == SPA_ID_INVALID)
3
        return -errno;
4
 
5
+   if ((res = spa_node_add_port(port->mix, port->direction, port_id, NULL)) < 0 &&
6
+       res != -ENOTSUP)
7
+       goto error_remove_map;
8
+
9
    mix->port.direction = port->direction;
10
    mix->port.port_id = port_id;
11
-
12
-   spa_list_append(&port->mix_list, &mix->link);
13
-   port->n_mix++;
14
    mix->p = port;
15
 
16
-   spa_node_add_port(port->mix, port->direction, port_id, NULL);
17
-
18
-   res = pw_impl_port_call_init_mix(port, mix);
19
+   if ((res = pw_impl_port_call_init_mix(port, mix)) < 0)
20
+       goto error_remove_port;
21
 
22
    /* set the same format on the mixer as on the port if any */
23
    {
24
@@ -242,11 +242,20 @@
25
        }
26
    }
27
 
28
+   spa_list_append(&port->mix_list, &mix->link);
29
+   port->n_mix++;
30
+
31
    pw_log_debug("%p: init mix n_mix:%d %d.%d io:%p: (%s)", port,
32
            port->n_mix, port->port_id, mix->port.port_id,
33
            mix->io, spa_strerror(res));
34
 
35
    return res;
36
+
37
+error_remove_port:
38
+   spa_node_remove_port(port->mix, port->direction, port_id);
39
+error_remove_map:
40
+   pw_map_remove(&port->mix_port_map, port_id);
41
+   return res;
42
 }
43
 
44
 SPA_EXPORT
45
@@ -261,7 +270,9 @@
46
 
47
    res = pw_impl_port_call_release_mix(port, mix);
48
 
49
-   spa_node_remove_port(port->mix, port->direction, port_id);
50
+   if ((res = spa_node_remove_port(port->mix, port->direction, port_id)) < 0 &&
51
+       res != -ENOTSUP)
52
+       pw_log_warn("can't remove mix port %d: %s", port_id, spa_strerror(res));
53
 
54
    pw_log_debug("%p: release mix %d %d.%d", port,
55
            port->n_mix, port->port_id, mix->port.port_id);
56
@@ -583,8 +594,10 @@
57
    int res;
58
    const char *fallback_lib, *factory_name;
59
    struct spa_handle *handle;
60
-   struct spa_dict_item items[1];
61
+   struct spa_dict_item items[2];
62
+   char quantum_limit[16];
63
    void *iface;
64
+   struct pw_context *context = port->node->context;
65
 
66
    if ((res = spa_format_parse(param, &media_type, &media_subtype)) < 0)
67
        return res;
68
@@ -634,7 +647,11 @@
69
    }
70
 
71
    items[0] = SPA_DICT_ITEM_INIT(SPA_KEY_LIBRARY_NAME, fallback_lib);
72
-   handle = pw_context_load_spa_handle(port->node->context, factory_name,
73
+   spa_scnprintf(quantum_limit, sizeof(quantum_limit), "%u",
74
+           context->settings.clock_quantum_limit);
75
+   items[1] = SPA_DICT_ITEM_INIT("clock.quantum-limit", quantum_limit);
76
+
77
+   handle = pw_context_load_spa_handle(context, factory_name,
78
            &SPA_DICT_INIT_ARRAY(items));
79
    if (handle == NULL)
80
        return -errno;
81
@@ -1070,10 +1087,12 @@
82
    }
83
 
84
    if (port->direction == PW_DIRECTION_INPUT) {
85
-       pw_map_insert_at(&node->input_port_map, port->port_id, NULL);
86
+       if ((res = pw_map_insert_at(&node->input_port_map, port->port_id, NULL)) < 0)
87
+           pw_log_warn("%p: can't remove input port: %s", port, spa_strerror(res));
88
        node->info.n_input_ports--;
89
    } else {
90
-       pw_map_insert_at(&node->output_port_map, port->port_id, NULL);
91
+       if ((res = pw_map_insert_at(&node->output_port_map, port->port_id, NULL)) < 0)
92
+           pw_log_warn("%p: can't remove output port: %s", port, spa_strerror(res));
93
        node->info.n_output_ports--;
94
    }
95
 
96
pipewire-0.3.43.tar.gz/src/pipewire/keys.h -> pipewire-0.3.44.tar.gz/src/pipewire/keys.h Changed
20
 
1
@@ -171,7 +171,9 @@
2
 #define PW_KEY_NODE_WANT_DRIVER        "node.want-driver"  /**< the node wants to be grouped with a driver
3
                                  *  node in order to schedule the graph. */
4
 #define PW_KEY_NODE_PAUSE_ON_IDLE  "node.pause-on-idle"    /**< pause the node when idle */
5
+#define PW_KEY_NODE_SUSPEND_ON_IDLE    "node.suspend-on-idle"  /**< suspend the node when idle */
6
 #define PW_KEY_NODE_CACHE_PARAMS   "node.cache-params" /**< cache the node params */
7
+#define PW_KEY_NODE_TRANSPORT_SYNC "node.transport.sync"   /**< the node handles transport sync */
8
 #define PW_KEY_NODE_DRIVER     "node.driver"       /**< node can drive the graph */
9
 #define PW_KEY_NODE_STREAM     "node.stream"       /**< node is a stream, the server side should
10
                                  *  add a converter */
11
@@ -326,6 +328,8 @@
12
 #define PW_KEY_PRIORITY_MASTER     "priority.master"   /**< deprecated */
13
 #endif /* PW_ENABLE_DEPRECATED */
14
 
15
+#define PW_KEY_TARGET_OBJECT       "target.object"     /**< a target object to link to */
16
+
17
 /** \}
18
  */
19
 
20
pipewire-0.3.43.tar.gz/src/pipewire/private.h -> pipewire-0.3.44.tar.gz/src/pipewire/private.h Changed
26
 
1
@@ -51,7 +51,7 @@
2
 
3
 #define MAX_RATES              16u
4
 #define CLOCK_MIN_QUANTUM          4u
5
-#define CLOCK_MAX_QUANTUM          8192u
6
+#define CLOCK_MAX_QUANTUM          65536u
7
 
8
 struct settings {
9
    uint32_t log_level;
10
@@ -61,12 +61,15 @@
11
    uint32_t clock_quantum;         /* default quantum */
12
    uint32_t clock_min_quantum;     /* min quantum */
13
    uint32_t clock_max_quantum;     /* max quantum */
14
+   uint32_t clock_quantum_limit;       /* quantum limit */
15
    struct spa_rectangle video_size;
16
    struct spa_fraction video_rate;
17
    uint32_t link_max_buffers;
18
    unsigned int mem_warn_mlock:1;
19
    unsigned int mem_allow_mlock:1;
20
    unsigned int clock_power_of_two_quantum:1;
21
+   unsigned int check_quantum:1;
22
+   unsigned int check_rate:1;
23
 #define CLOCK_RATE_UPDATE_MODE_HARD 0
24
 #define CLOCK_RATE_UPDATE_MODE_SOFT 1
25
    int clock_rate_update_mode;
26
pipewire-0.3.43.tar.gz/src/pipewire/settings.c -> pipewire-0.3.44.tar.gz/src/pipewire/settings.c Changed
71
 
1
@@ -43,7 +43,8 @@
2
 #define DEFAULT_CLOCK_RATE         48000u
3
 #define DEFAULT_CLOCK_QUANTUM          1024u
4
 #define DEFAULT_CLOCK_MIN_QUANTUM      32u
5
-#define DEFAULT_CLOCK_MAX_QUANTUM      8192u
6
+#define DEFAULT_CLOCK_MAX_QUANTUM      2048u
7
+#define DEFAULT_CLOCK_QUANTUM_LIMIT        8192u
8
 #define DEFAULT_CLOCK_POWER_OF_TWO_QUANTUM true
9
 #define DEFAULT_VIDEO_WIDTH            640
10
 #define DEFAULT_VIDEO_HEIGHT           480
11
@@ -52,6 +53,8 @@
12
 #define DEFAULT_LINK_MAX_BUFFERS       64u
13
 #define DEFAULT_MEM_WARN_MLOCK         false
14
 #define DEFAULT_MEM_ALLOW_MLOCK            true
15
+#define DEFAULT_CHECK_QUANTUM          false
16
+#define DEFAULT_CHECK_RATE         false
17
 
18
 struct impl {
19
    struct pw_context *context;
20
@@ -184,12 +187,23 @@
21
        recalc = true;
22
    } else if (spa_streq(key, "clock.force-rate")) {
23
        v = value ? atoi(value) : 0;
24
-       s->clock_force_rate = v;
25
-       recalc = true;
26
+       if (v != 0 && s->check_rate &&
27
+           !uint32_array_contains(s->clock_rates, s->n_clock_rates, v)) {
28
+           pw_log_info("invalid %s: %d not in allowed rates", key, v);
29
+       } else {
30
+           s->clock_force_rate = v;
31
+           recalc = true;
32
+       }
33
    } else if (spa_streq(key, "clock.force-quantum")) {
34
        v = value ? atoi(value) : 0;
35
-       s->clock_force_quantum = SPA_MIN(v, 8192u);
36
-       recalc = true;
37
+       if (v != 0 && s->check_quantum &&
38
+           (v < s->clock_min_quantum || v > s->clock_max_quantum)) {
39
+           pw_log_info("invalid %s: %d not in (%d-%d)", key, v,
40
+                   s->clock_min_quantum, s->clock_max_quantum);
41
+       } else {
42
+           s->clock_force_quantum = v;
43
+           recalc = true;
44
+       }
45
    }
46
    if (recalc)
47
        pw_context_recalc_graph(context, "settings changed");
48
@@ -213,6 +227,7 @@
49
    d->clock_quantum = get_default_int(p, "default.clock.quantum", DEFAULT_CLOCK_QUANTUM);
50
    d->clock_min_quantum = get_default_int(p, "default.clock.min-quantum", DEFAULT_CLOCK_MIN_QUANTUM);
51
    d->clock_max_quantum = get_default_int(p, "default.clock.max-quantum", DEFAULT_CLOCK_MAX_QUANTUM);
52
+   d->clock_quantum_limit = get_default_int(p, "default.clock.quantum-limit", DEFAULT_CLOCK_QUANTUM_LIMIT);
53
    d->video_size.width = get_default_int(p, "default.video.width", DEFAULT_VIDEO_WIDTH);
54
    d->video_size.height = get_default_int(p, "default.video.height", DEFAULT_VIDEO_HEIGHT);
55
    d->video_rate.num = get_default_int(p, "default.video.rate.num", DEFAULT_VIDEO_RATE_NUM);
56
@@ -225,8 +240,13 @@
57
    d->mem_warn_mlock = get_default_bool(p, "mem.warn-mlock", DEFAULT_MEM_WARN_MLOCK);
58
    d->mem_allow_mlock = get_default_bool(p, "mem.allow-mlock", DEFAULT_MEM_ALLOW_MLOCK);
59
 
60
-   d->clock_max_quantum = SPA_CLAMP(d->clock_max_quantum,
61
+   d->check_quantum = get_default_bool(p, "settings.check-quantum", DEFAULT_CHECK_QUANTUM);
62
+   d->check_rate = get_default_bool(p, "settings.check-rate", DEFAULT_CHECK_RATE);
63
+
64
+   d->clock_quantum_limit = SPA_CLAMP(d->clock_quantum_limit,
65
            CLOCK_MIN_QUANTUM, CLOCK_MAX_QUANTUM);
66
+   d->clock_max_quantum = SPA_CLAMP(d->clock_max_quantum,
67
+           CLOCK_MIN_QUANTUM, d->clock_quantum_limit);
68
    d->clock_min_quantum = SPA_CLAMP(d->clock_min_quantum,
69
            CLOCK_MIN_QUANTUM, d->clock_max_quantum);
70
    d->clock_quantum = SPA_CLAMP(d->clock_quantum,
71
pipewire-0.3.43.tar.gz/src/pipewire/stream.c -> pipewire-0.3.44.tar.gz/src/pipewire/stream.c Changed
19
 
1
@@ -1358,6 +1358,17 @@
2
    }
3
    if ((str = getenv("PIPEWIRE_LATENCY")) != NULL)
4
        pw_properties_set(props, PW_KEY_NODE_LATENCY, str);
5
+   if ((str = getenv("PIPEWIRE_RATE")) != NULL)
6
+       pw_properties_set(props, PW_KEY_NODE_RATE, str);
7
+   if ((str = getenv("PIPEWIRE_QUANTUM")) != NULL) {
8
+       struct spa_fraction q;
9
+       if (sscanf(str, "%u/%u", &q.num, &q.denom) == 2 && q.denom != 0) {
10
+           pw_properties_setf(props, PW_KEY_NODE_RATE,
11
+                   "1/%u", q.denom);
12
+           pw_properties_setf(props, PW_KEY_NODE_LATENCY,
13
+                   "%u/%u", q.num, q.denom);
14
+       }
15
+   }
16
 
17
    spa_hook_list_init(&impl->hooks);
18
    this->properties = props;
19
pipewire-0.3.43.tar.gz/src/tests/meson.build -> pipewire-0.3.44.tar.gz/src/tests/meson.build Changed
14
 
1
@@ -13,9 +13,9 @@
2
       install : installed_tests_enabled,
3
       install_dir : installed_tests_execdir),
4
     env : [
5
-      'SPA_PLUGIN_DIR=@0@'.format(spa_dep.get_variable(internal: 'plugindir')),
6
-      'PIPEWIRE_CONFIG_DIR=@0@'.format(pipewire_dep.get_variable(internal: 'confdatadir')),
7
-      'PIPEWIRE_MODULE_DIR=@0@'.format(pipewire_dep.get_variable(internal: 'moduledir')),
8
+      'SPA_PLUGIN_DIR=@0@'.format(spa_dep.get_variable('plugindir')),
9
+      'PIPEWIRE_CONFIG_DIR=@0@'.format(pipewire_dep.get_variable('confdatadir')),
10
+      'PIPEWIRE_MODULE_DIR=@0@'.format(pipewire_dep.get_variable('moduledir')),
11
       ])
12
 
13
   if installed_tests_enabled
14
pipewire-0.3.43.tar.gz/src/tools/pw-cat.c -> pipewire-0.3.44.tar.gz/src/tools/pw-cat.c Changed
15
 
1
@@ -1906,9 +1906,10 @@
2
            spa_list_for_each(target, &data.targets, link) {
3
                if (target->type != TARGET_TYPE_SINK)
4
                    continue;
5
-               printf("%s\t%"PRIu32": sink description=\"%s\" prio=%d\n",
6
-                      target == target_default ? "*" : "",
7
-                      target->id, target->desc, target->prio);
8
+               printf("%s\t%"PRIu32": %s description=\"%s\" prio=%d\n",
9
+                   target == target_default ? "*" : "",
10
+                   target->id, data.mode == mode_record ? "monitor" : "sink",
11
+                   target->desc, target->prio);
12
            }
13
            spa_list_for_each(target, &data.targets, link) {
14
                if (target->type != TARGET_TYPE_STREAM)
15
pipewire-0.3.43.tar.gz/src/tools/pw-cli.c -> pipewire-0.3.44.tar.gz/src/tools/pw-cli.c Changed
719
 
1
@@ -32,6 +32,7 @@
2
 #include <alloca.h>
3
 #endif
4
 #include <getopt.h>
5
+#include <fnmatch.h>
6
 #include <readline/readline.h>
7
 #include <readline/history.h>
8
 
9
@@ -41,7 +42,7 @@
10
 #include <spa/utils/string.h>
11
 #include <spa/debug/pod.h>
12
 #include <spa/utils/keys.h>
13
-#include <spa/utils/json.h>
14
+#include <spa/utils/json-pod.h>
15
 #include <spa/pod/builder.h>
16
 
17
 #include <pipewire/impl.h>
18
@@ -53,6 +54,18 @@
19
 static char prompt[64];
20
 
21
 struct remote_data;
22
+struct proxy_data;
23
+
24
+typedef void (*info_func_t) (struct proxy_data *pd);
25
+
26
+struct class {
27
+   const char *type;
28
+   uint32_t version;
29
+   const void *events;
30
+   pw_destroy_t destroy;
31
+   info_func_t info;
32
+   const char *name_key;
33
+};
34
 
35
 struct data {
36
    struct pw_main_loop *loop;
37
@@ -73,6 +86,7 @@
38
    uint32_t permissions;
39
    uint32_t version;
40
    char *type;
41
+   const struct class *class;
42
    struct pw_proxy *proxy;
43
    bool info_pending;
44
    struct pw_properties *properties;
45
@@ -96,19 +110,15 @@
46
    struct pw_map globals;
47
 };
48
 
49
-struct proxy_data;
50
-
51
-typedef void (*info_func_t) (struct proxy_data *pd);
52
 
53
 struct proxy_data {
54
    struct remote_data *rd;
55
    struct global *global;
56
    struct pw_proxy *proxy;
57
-        void *info;
58
-   info_func_t info_func;
59
-        pw_destroy_t destroy;
60
-        struct spa_hook proxy_listener;
61
-        struct spa_hook object_listener;
62
+   void *info;
63
+   const struct class *class;
64
+   struct spa_hook proxy_listener;
65
+   struct spa_hook object_listener;
66
 };
67
 
68
 struct command {
69
@@ -303,6 +313,29 @@
70
    }
71
 }
72
 
73
+static bool global_matches(struct global *g, const char *pattern)
74
+{
75
+   const char *str;
76
+
77
+   if (g->properties == NULL)
78
+       return false;
79
+
80
+   if (strstr(g->type, pattern) != NULL)
81
+       return true;
82
+   if ((str = pw_properties_get(g->properties, PW_KEY_OBJECT_PATH)) != NULL &&
83
+       fnmatch(pattern, str, FNM_EXTMATCH) == 0)
84
+       return true;
85
+   if ((str = pw_properties_get(g->properties, PW_KEY_OBJECT_SERIAL)) != NULL &&
86
+       spa_streq(pattern, str))
87
+       return true;
88
+   if (g->class != NULL && g->class->name_key != NULL &&
89
+       (str = pw_properties_get(g->properties, g->class->name_key)) != NULL &&
90
+       fnmatch(pattern, str, FNM_EXTMATCH) == 0)
91
+       return true;
92
+
93
+   return false;
94
+}
95
+
96
 static int print_global(void *obj, void *data)
97
 {
98
    struct global *global = obj;
99
@@ -311,7 +344,7 @@
100
    if (global == NULL)
101
        return 0;
102
 
103
-   if (filter && !strstr(global->type, filter))
104
+   if (filter && !global_matches(global, filter))
105
        return 0;
106
 
107
    fprintf(stdout, "\tid %d, type %s/%d\n", global->id,
108
@@ -403,6 +436,24 @@
109
    .global_remove = registry_event_global_remove,
110
 };
111
 
112
+static struct global *find_global(struct remote_data *rd, const char *pattern)
113
+{
114
+   uint32_t id;
115
+   union pw_map_item *item;
116
+
117
+   if (spa_atou32(pattern, &id, 0))
118
+       return pw_map_lookup(&rd->globals, id);
119
+
120
+   pw_array_for_each(item, &rd->globals.items) {
121
+       struct global *g = item->data;
122
+       if (pw_map_item_is_free(item) || g == NULL)
123
+           continue;
124
+       if (global_matches(g, pattern))
125
+           return g;
126
+        }
127
+   return NULL;
128
+}
129
+
130
 static void on_core_error(void *_data, uint32_t id, int seq, int res, const char *message)
131
 {
132
    struct remote_data *rd = _data;
133
@@ -1106,14 +1157,14 @@
134
    spa_hook_remove(&pd->proxy_listener);
135
    spa_hook_remove(&pd->object_listener);
136
 
137
-   if (pd->info == NULL)
138
-       return;
139
-
140
    if (pd->global)
141
        pd->global->proxy = NULL;
142
 
143
-   if (pd->destroy)
144
-       pd->destroy(pd->info);
145
+   if (pd->info == NULL)
146
+       return;
147
+
148
+   if (pd->class->destroy)
149
+       pd->class->destroy(pd->info);
150
    pd->info = NULL;
151
 }
152
 
153
@@ -1130,88 +1181,150 @@
154
    return true;
155
 }
156
 
157
+static const struct class core_class = {
158
+   .type = PW_TYPE_INTERFACE_Core,
159
+   .version = PW_VERSION_CORE,
160
+   .events = &core_events,
161
+   .destroy = (pw_destroy_t) pw_core_info_free,
162
+   .info = info_core,
163
+   .name_key = PW_KEY_CORE_NAME,
164
+};
165
+static const struct class module_class = {
166
+   .type = PW_TYPE_INTERFACE_Module,
167
+   .version = PW_VERSION_MODULE,
168
+   .events = &module_events,
169
+   .destroy = (pw_destroy_t) pw_module_info_free,
170
+   .info = info_module,
171
+   .name_key = PW_KEY_MODULE_NAME,
172
+};
173
+
174
+static const struct class factory_class = {
175
+   .type = PW_TYPE_INTERFACE_Factory,
176
+   .version = PW_VERSION_FACTORY,
177
+   .events = &factory_events,
178
+   .destroy = (pw_destroy_t) pw_factory_info_free,
179
+   .info = info_factory,
180
+   .name_key = PW_KEY_FACTORY_NAME,
181
+};
182
+
183
+static const struct class client_class = {
184
+   .type = PW_TYPE_INTERFACE_Client,
185
+   .version = PW_VERSION_CLIENT,
186
+   .events = &client_events,
187
+   .destroy = (pw_destroy_t) pw_client_info_free,
188
+   .info = info_client,
189
+   .name_key = PW_KEY_APP_NAME,
190
+};
191
+static const struct class device_class = {
192
+   .type = PW_TYPE_INTERFACE_Device,
193
+   .version = PW_VERSION_DEVICE,
194
+   .events = &device_events,
195
+   .destroy = (pw_destroy_t) pw_device_info_free,
196
+   .info = info_device,
197
+   .name_key = PW_KEY_DEVICE_NAME,
198
+};
199
+static const struct class node_class = {
200
+   .type = PW_TYPE_INTERFACE_Node,
201
+   .version = PW_VERSION_NODE,
202
+   .events = &node_events,
203
+   .destroy = (pw_destroy_t) pw_node_info_free,
204
+   .info = info_node,
205
+   .name_key = PW_KEY_NODE_NAME,
206
+};
207
+static const struct class port_class = {
208
+   .type = PW_TYPE_INTERFACE_Port,
209
+   .version = PW_VERSION_PORT,
210
+   .events = &port_events,
211
+   .destroy = (pw_destroy_t) pw_port_info_free,
212
+   .info = info_port,
213
+   .name_key = PW_KEY_PORT_NAME,
214
+};
215
+static const struct class link_class = {
216
+   .type = PW_TYPE_INTERFACE_Link,
217
+   .version = PW_VERSION_LINK,
218
+   .events = &link_events,
219
+   .destroy = (pw_destroy_t) pw_link_info_free,
220
+   .info = info_link,
221
+};
222
+static const struct class session_class = {
223
+   .type = PW_TYPE_INTERFACE_Session,
224
+   .version = PW_VERSION_SESSION,
225
+   .events = &session_events,
226
+   .destroy = (pw_destroy_t) session_info_free,
227
+   .info = info_session,
228
+};
229
+static const struct class endpoint_class = {
230
+   .type = PW_TYPE_INTERFACE_Endpoint,
231
+   .version = PW_VERSION_ENDPOINT,
232
+   .events = &endpoint_events,
233
+   .destroy = (pw_destroy_t) endpoint_info_free,
234
+   .info = info_endpoint,
235
+};
236
+static const struct class endpoint_stream_class = {
237
+   .type = PW_TYPE_INTERFACE_EndpointStream,
238
+   .version = PW_VERSION_ENDPOINT_STREAM,
239
+   .events = &endpoint_stream_events,
240
+   .destroy = (pw_destroy_t) endpoint_stream_info_free,
241
+   .info = info_endpoint_stream,
242
+};
243
+static const struct class metadata_class = {
244
+   .type = PW_TYPE_INTERFACE_Metadata,
245
+   .version = PW_VERSION_METADATA,
246
+   .name_key = PW_KEY_METADATA_NAME,
247
+};
248
+
249
+static const struct class *classes[] =
250
+{
251
+   &core_class,
252
+   &module_class,
253
+   &factory_class,
254
+   &client_class,
255
+   &device_class,
256
+   &node_class,
257
+   &port_class,
258
+   &link_class,
259
+   &session_class,
260
+   &endpoint_class,
261
+   &endpoint_stream_class,
262
+   &metadata_class,
263
+};
264
+
265
+static const struct class *find_class(const char *type, uint32_t version)
266
+{
267
+   size_t i;
268
+   for (i = 0; i < SPA_N_ELEMENTS(classes); i++) {
269
+       if (spa_streq(classes[i]->type, type) &&
270
+           classes[i]->version <= version)
271
+           return classes[i];
272
+   }
273
+   return NULL;
274
+}
275
+
276
 static bool bind_global(struct remote_data *rd, struct global *global, char **error)
277
 {
278
-        const void *events;
279
-        uint32_t client_version;
280
-   info_func_t info_func;
281
-        pw_destroy_t destroy;
282
+   const struct class *class;
283
    struct proxy_data *pd;
284
    struct pw_proxy *proxy;
285
 
286
-   if (spa_streq(global->type, PW_TYPE_INTERFACE_Core)) {
287
-       events = &core_events;
288
-       client_version = PW_VERSION_CORE;
289
-       destroy = (pw_destroy_t) pw_core_info_free;
290
-       info_func = info_core;
291
-   } else if (spa_streq(global->type, PW_TYPE_INTERFACE_Module)) {
292
-       events = &module_events;
293
-       client_version = PW_VERSION_MODULE;
294
-       destroy = (pw_destroy_t) pw_module_info_free;
295
-       info_func = info_module;
296
-   } else if (spa_streq(global->type, PW_TYPE_INTERFACE_Device)) {
297
-       events = &device_events;
298
-       client_version = PW_VERSION_DEVICE;
299
-       destroy = (pw_destroy_t) pw_device_info_free;
300
-       info_func = info_device;
301
-   } else if (spa_streq(global->type, PW_TYPE_INTERFACE_Node)) {
302
-       events = &node_events;
303
-       client_version = PW_VERSION_NODE;
304
-       destroy = (pw_destroy_t) pw_node_info_free;
305
-       info_func = info_node;
306
-   } else if (spa_streq(global->type, PW_TYPE_INTERFACE_Port)) {
307
-       events = &port_events;
308
-       client_version = PW_VERSION_PORT;
309
-       destroy = (pw_destroy_t) pw_port_info_free;
310
-       info_func = info_port;
311
-   } else if (spa_streq(global->type, PW_TYPE_INTERFACE_Factory)) {
312
-       events = &factory_events;
313
-       client_version = PW_VERSION_FACTORY;
314
-       destroy = (pw_destroy_t) pw_factory_info_free;
315
-       info_func = info_factory;
316
-   } else if (spa_streq(global->type, PW_TYPE_INTERFACE_Client)) {
317
-       events = &client_events;
318
-       client_version = PW_VERSION_CLIENT;
319
-       destroy = (pw_destroy_t) pw_client_info_free;
320
-       info_func = info_client;
321
-   } else if (spa_streq(global->type, PW_TYPE_INTERFACE_Link)) {
322
-       events = &link_events;
323
-       client_version = PW_VERSION_LINK;
324
-       destroy = (pw_destroy_t) pw_link_info_free;
325
-       info_func = info_link;
326
-   } else if (spa_streq(global->type, PW_TYPE_INTERFACE_Session)) {
327
-       events = &session_events;
328
-       client_version = PW_VERSION_SESSION;
329
-       destroy = (pw_destroy_t) session_info_free;
330
-       info_func = info_session;
331
-   } else if (spa_streq(global->type, PW_TYPE_INTERFACE_Endpoint)) {
332
-       events = &endpoint_events;
333
-       client_version = PW_VERSION_ENDPOINT;
334
-       destroy = (pw_destroy_t) endpoint_info_free;
335
-       info_func = info_endpoint;
336
-   } else if (spa_streq(global->type, PW_TYPE_INTERFACE_EndpointStream)) {
337
-       events = &endpoint_stream_events;
338
-       client_version = PW_VERSION_ENDPOINT_STREAM;
339
-       destroy = (pw_destroy_t) endpoint_stream_info_free;
340
-       info_func = info_endpoint_stream;
341
-   } else {
342
+   class = find_class(global->type, global->version);
343
+   if (class == NULL) {
344
        *error = spa_aprintf("unsupported type %s", global->type);
345
        return false;
346
    }
347
+   global->class = class;
348
 
349
    proxy = pw_registry_bind(rd->registry,
350
                       global->id,
351
                       global->type,
352
-                      client_version,
353
+                      class->version,
354
                       sizeof(struct proxy_data));
355
 
356
    pd = pw_proxy_get_user_data(proxy);
357
    pd->rd = rd;
358
    pd->global = global;
359
    pd->proxy = proxy;
360
-   pd->info_func = info_func;
361
-   pd->destroy = destroy;
362
-   pw_proxy_add_object_listener(proxy, &pd->object_listener, events, pd);
363
+   pd->class = class;
364
+   pw_proxy_add_object_listener(proxy, &pd->object_listener, class->events, pd);
365
    pw_proxy_add_listener(proxy, &pd->proxy_listener, &proxy_events, pd);
366
 
367
    global->proxy = proxy;
368
@@ -1232,8 +1345,8 @@
369
        global->info_pending = true;
370
    } else {
371
        pd = pw_proxy_get_user_data(global->proxy);
372
-       if (pd->info_func)
373
-           pd->info_func(pd);
374
+       if (pd->class->info)
375
+           pd->class->info(pd);
376
    }
377
    return true;
378
 }
379
@@ -1257,7 +1370,6 @@
380
    struct remote_data *rd = data->current;
381
    char *a[1];
382
         int n;
383
-   uint32_t id;
384
    struct global *global;
385
 
386
    n = pw_split_ip(args, WHITESPACE, 1, a);
387
@@ -1269,10 +1381,9 @@
388
        pw_map_for_each(&rd->globals, do_global_info_all, NULL);
389
    }
390
    else {
391
-       id = atoi(a[0]);
392
-       global = pw_map_lookup(&rd->globals, id);
393
+       global = find_global(rd, a[0]);
394
        if (global == NULL) {
395
-           *error = spa_aprintf("%s: unknown global %d", cmd, id);
396
+           *error = spa_aprintf("%s: unknown global '%s'", cmd, a[0]);
397
            return false;
398
        }
399
        return do_global_info(global, error);
400
@@ -1309,7 +1420,7 @@
401
    pd = pw_proxy_get_user_data(proxy);
402
    pd->rd = rd;
403
    pd->proxy = proxy;
404
-   pd->destroy = (pw_destroy_t) pw_device_info_free;
405
+   pd->class = &device_class;
406
    pw_proxy_add_object_listener(proxy, &pd->object_listener, &device_events, pd);
407
    pw_proxy_add_listener(proxy, &pd->proxy_listener, &proxy_events, pd);
408
 
409
@@ -1348,7 +1459,7 @@
410
    pd = pw_proxy_get_user_data(proxy);
411
    pd->rd = rd;
412
    pd->proxy = proxy;
413
-        pd->destroy = (pw_destroy_t) pw_node_info_free;
414
+        pd->class = &node_class;
415
         pw_proxy_add_object_listener(proxy, &pd->object_listener, &node_events, pd);
416
         pw_proxy_add_listener(proxy, &pd->proxy_listener, &proxy_events, pd);
417
 
418
@@ -1363,7 +1474,6 @@
419
    struct remote_data *rd = data->current;
420
    char *a[1];
421
         int n;
422
-   uint32_t id;
423
    struct global *global;
424
 
425
    n = pw_split_ip(args, WHITESPACE, 1, a);
426
@@ -1371,13 +1481,12 @@
427
        *error = spa_aprintf("%s <object-id>", cmd);
428
        return false;
429
    }
430
-   id = atoi(a[0]);
431
-   global = pw_map_lookup(&rd->globals, id);
432
+   global = find_global(rd, a[0]);
433
    if (global == NULL) {
434
-       *error = spa_aprintf("%s: unknown global %d", cmd, id);
435
+       *error = spa_aprintf("%s: unknown global '%s'", cmd, a[0]);
436
        return false;
437
    }
438
-   pw_registry_destroy(rd->registry, id);
439
+   pw_registry_destroy(rd->registry, global->id);
440
 
441
    return true;
442
 }
443
@@ -1423,7 +1532,7 @@
444
    pd = pw_proxy_get_user_data(proxy);
445
    pd->rd = rd;
446
    pd->proxy = proxy;
447
-        pd->destroy = (pw_destroy_t) pw_link_info_free;
448
+        pd->class = &link_class;
449
         pw_proxy_add_object_listener(proxy, &pd->object_listener, &link_events, pd);
450
         pw_proxy_add_listener(proxy, &pd->proxy_listener, &proxy_events, pd);
451
 
452
@@ -1477,26 +1586,12 @@
453
    return false;
454
 }
455
 
456
-static const struct spa_type_info *find_type_info(const struct spa_type_info *info, const char *name)
457
-{
458
-   while (info && info->name) {
459
-                if (spa_streq(info->name, name))
460
-                        return info;
461
-                if (spa_streq(spa_debug_type_short_name(info->name), name))
462
-                        return info;
463
-                if (info->type != 0 && info->type == (uint32_t)atoi(name))
464
-                        return info;
465
-                info++;
466
-        }
467
-        return NULL;
468
-}
469
-
470
 static bool do_enum_params(struct data *data, const char *cmd, char *args, char **error)
471
 {
472
    struct remote_data *rd = data->current;
473
    char *a[2];
474
    int n;
475
-   uint32_t id, param_id;
476
+   uint32_t param_id;
477
    const struct spa_type_info *ti;
478
    struct global *global;
479
 
480
@@ -1506,17 +1601,16 @@
481
        return false;
482
    }
483
 
484
-   id = atoi(a[0]);
485
-   ti = find_type_info(spa_type_param, a[1]);
486
+   ti = spa_debug_type_find_short(spa_type_param, a[1]);
487
    if (ti == NULL) {
488
        *error = spa_aprintf("%s: unknown param type: %s", cmd, a[1]);
489
        return false;
490
    }
491
    param_id = ti->type;
492
 
493
-   global = pw_map_lookup(&rd->globals, id);
494
+   global = find_global(rd, a[0]);
495
    if (global == NULL) {
496
-       *error = spa_aprintf("%s: unknown global %d", cmd, id);
497
+       *error = spa_aprintf("%s: unknown global '%s'", cmd, a[0]);
498
        return false;
499
    }
500
    if (global->proxy == NULL) {
501
@@ -1544,126 +1638,15 @@
502
    return true;
503
 }
504
 
505
-static int json_to_pod(struct spa_pod_builder *b, uint32_t id,
506
-       const struct spa_type_info *info, struct spa_json *iter, const char *value, int len)
507
-{
508
-   const struct spa_type_info *ti;
509
-   char key[256];
510
-   struct spa_pod_frame f[1];
511
-   struct spa_json it[1];
512
-   int l, res;
513
-   const char *v;
514
-   uint32_t type;
515
-
516
-   if (spa_json_is_object(value, len) && info != NULL) {
517
-       if ((ti = spa_debug_type_find(NULL, info->parent)) == NULL)
518
-           return -EINVAL;
519
-
520
-       spa_pod_builder_push_object(b, &f[0], info->parent, id);
521
-
522
-       spa_json_enter(iter, &it[0]);
523
-       while (spa_json_get_string(&it[0], key, sizeof(key)) > 0) {
524
-           const struct spa_type_info *pi;
525
-           if ((l = spa_json_next(&it[0], &v)) <= 0)
526
-               break;
527
-           if ((pi = find_type_info(ti->values, key)) != NULL)
528
-               type = pi->type;
529
-           else if ((type = atoi(key)) == 0)
530
-               continue;
531
-           spa_pod_builder_prop(b, type, 0);
532
-           if ((res = json_to_pod(b, id, pi, &it[0], v, l)) < 0)
533
-               return res;
534
-       }
535
-       spa_pod_builder_pop(b, &f[0]);
536
-   }
537
-   else if (spa_json_is_array(value, len)) {
538
-       if (info == NULL || info->parent == SPA_TYPE_Struct) {
539
-           spa_pod_builder_push_struct(b, &f[0]);
540
-       } else {
541
-           spa_pod_builder_push_array(b, &f[0]);
542
-           info = info->values;
543
-       }
544
-       spa_json_enter(iter, &it[0]);
545
-       while ((l = spa_json_next(&it[0], &v)) > 0)
546
-           if ((res = json_to_pod(b, id, info, &it[0], v, l)) < 0)
547
-               return res;
548
-       spa_pod_builder_pop(b, &f[0]);
549
-   }
550
-   else if (spa_json_is_float(value, len)) {
551
-       float val = 0.0f;
552
-       spa_json_parse_float(value, len, &val);
553
-       switch (info ? info->parent : SPA_TYPE_Struct) {
554
-       case SPA_TYPE_Bool:
555
-           spa_pod_builder_bool(b, val >= 0.5f);
556
-           break;
557
-       case SPA_TYPE_Id:
558
-           spa_pod_builder_id(b, val);
559
-           break;
560
-       case SPA_TYPE_Int:
561
-           spa_pod_builder_int(b, val);
562
-           break;
563
-       case SPA_TYPE_Long:
564
-           spa_pod_builder_long(b, val);
565
-           break;
566
-       case SPA_TYPE_Struct:
567
-           if (spa_json_is_int(value, len))
568
-               spa_pod_builder_int(b, val);
569
-           else
570
-               spa_pod_builder_float(b, val);
571
-           break;
572
-       case SPA_TYPE_Float:
573
-           spa_pod_builder_float(b, val);
574
-           break;
575
-       case SPA_TYPE_Double:
576
-           spa_pod_builder_double(b, val);
577
-           break;
578
-       default:
579
-           spa_pod_builder_none(b);
580
-           break;
581
-       }
582
-   }
583
-   else if (spa_json_is_bool(value, len)) {
584
-       bool val = false;
585
-       spa_json_parse_bool(value, len, &val);
586
-       spa_pod_builder_bool(b, val);
587
-   }
588
-   else if (spa_json_is_null(value, len)) {
589
-       spa_pod_builder_none(b);
590
-   }
591
-   else {
592
-       char *val = alloca(len+1);
593
-       spa_json_parse_stringn(value, len, val, len+1);
594
-       switch (info ? info->parent : SPA_TYPE_Struct) {
595
-       case SPA_TYPE_Id:
596
-           if ((ti = find_type_info(info->values, val)) != NULL)
597
-               type = ti->type;
598
-           else if ((type = atoi(val)) == 0)
599
-               return -EINVAL;
600
-           spa_pod_builder_id(b, type);
601
-           break;
602
-       case SPA_TYPE_Struct:
603
-       case SPA_TYPE_String:
604
-           spa_pod_builder_string(b, val);
605
-           break;
606
-       default:
607
-           spa_pod_builder_none(b);
608
-           break;
609
-       }
610
-   }
611
-   return 0;
612
-}
613
-
614
 static bool do_set_param(struct data *data, const char *cmd, char *args, char **error)
615
 {
616
    struct remote_data *rd = data->current;
617
    char *a[3];
618
-   const char *val;
619
-        int res, n, len;
620
-   uint32_t id, param_id;
621
+   int res, n;
622
+   uint32_t param_id;
623
    struct global *global;
624
-   struct spa_json it[3];
625
    uint8_t buffer[1024];
626
-        struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer));
627
+   struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer));
628
    const struct spa_type_info *ti;
629
    struct spa_pod *pod;
630
 
631
@@ -1673,11 +1656,9 @@
632
        return false;
633
    }
634
 
635
-   id = atoi(a[0]);
636
-
637
-   global = pw_map_lookup(&rd->globals, id);
638
+   global = find_global(rd, a[0]);
639
    if (global == NULL) {
640
-       *error = spa_aprintf("%s: unknown global %d", cmd, id);
641
+       *error = spa_aprintf("%s: unknown global '%s'", cmd, a[0]);
642
        return false;
643
    }
644
    if (global->proxy == NULL) {
645
@@ -1685,19 +1666,12 @@
646
            return false;
647
    }
648
 
649
-   ti = find_type_info(spa_type_param, a[1]);
650
+   ti = spa_debug_type_find_short(spa_type_param, a[1]);
651
    if (ti == NULL) {
652
        *error = spa_aprintf("%s: unknown param type: %s", cmd, a[1]);
653
        return false;
654
    }
655
-   param_id = ti->type;
656
-
657
-   spa_json_init(&it[0], a[2], strlen(a[2]));
658
-   if ((len = spa_json_next(&it[0], &val)) <= 0) {
659
-       *error = spa_aprintf("%s: not a JSON object: %s", cmd, a[2]);
660
-       return false;
661
-   }
662
-   if ((res = json_to_pod(&b, param_id, ti, &it[0], val, len)) < 0) {
663
+   if ((res = spa_json_to_pod(&b, 0, ti, a[2], strlen(a[2]))) < 0) {
664
        *error = spa_aprintf("%s: can't make pod: %s", cmd, spa_strerror(res));
665
        return false;
666
    }
667
@@ -1707,6 +1681,8 @@
668
    }
669
    spa_debug_pod(0, NULL, pod);
670
 
671
+   param_id = ti->type;
672
+
673
    if (spa_streq(global->type, PW_TYPE_INTERFACE_Node))
674
        pw_node_set_param((struct pw_node*)global->proxy,
675
                param_id, 0, pod);
676
@@ -1729,7 +1705,7 @@
677
    struct remote_data *rd = data->current;
678
    char *a[3];
679
    int n;
680
-   uint32_t id, p;
681
+   uint32_t p;
682
    struct global *global;
683
    struct pw_permission permissions[1];
684
 
685
@@ -1739,10 +1715,9 @@
686
        return false;
687
    }
688
 
689
-   id = atoi(a[0]);
690
-   global = pw_map_lookup(&rd->globals, id);
691
+   global = find_global(rd, a[0]);
692
    if (global == NULL) {
693
-       *error = spa_aprintf("%s: unknown global %d", cmd, id);
694
+       *error = spa_aprintf("%s: unknown global '%s'", cmd, a[0]);
695
        return false;
696
    }
697
    if (!spa_streq(global->type, PW_TYPE_INTERFACE_Client)) {
698
@@ -1770,7 +1745,6 @@
699
    struct remote_data *rd = data->current;
700
    char *a[3];
701
         int n;
702
-   uint32_t id;
703
    struct global *global;
704
 
705
    n = pw_split_ip(args, WHITESPACE, 1, a);
706
@@ -1779,10 +1753,9 @@
707
        return false;
708
    }
709
 
710
-   id = atoi(a[0]);
711
-   global = pw_map_lookup(&rd->globals, id);
712
+   global = find_global(rd, a[0]);
713
    if (global == NULL) {
714
-       *error = spa_aprintf("%s: unknown global %d", cmd, id);
715
+       *error = spa_aprintf("%s: unknown global '%s'", cmd, a[0]);
716
        return false;
717
    }
718
    if (!spa_streq(global->type, PW_TYPE_INTERFACE_Client)) {
719
pipewire-0.3.43.tar.gz/src/tools/pw-dump.c -> pipewire-0.3.44.tar.gz/src/tools/pw-dump.c Changed
153
 
1
@@ -30,6 +30,7 @@
2
 #include <getopt.h>
3
 #include <limits.h>
4
 #include <math.h>
5
+#include <fnmatch.h>
6
 
7
 #include <spa/utils/result.h>
8
 #include <spa/utils/string.h>
9
@@ -37,6 +38,7 @@
10
 #include <spa/debug/types.h>
11
 #include <spa/utils/json.h>
12
 #include <spa/utils/ansi.h>
13
+#include <spa/utils/string.h>
14
 
15
 #include <pipewire/pipewire.h>
16
 #include <pipewire/extensions/metadata.h>
17
@@ -65,7 +67,7 @@
18
 
19
    struct spa_list object_list;
20
 
21
-   uint32_t id;
22
+   const char *pattern;
23
 
24
    FILE *out;
25
    int level;
26
@@ -93,6 +95,7 @@
27
    const void *events;
28
    void (*destroy) (struct object *object);
29
    void (*dump) (struct object *object);
30
+   const char *name_key;
31
 };
32
 
33
 struct object {
34
@@ -552,6 +555,7 @@
35
    .type = PW_TYPE_INTERFACE_Core,
36
    .version = PW_VERSION_CORE,
37
    .dump = core_dump,
38
+   .name_key = PW_KEY_CORE_NAME,
39
 };
40
 
41
 /* client */
42
@@ -608,6 +612,7 @@
43
    .events = &client_events,
44
    .destroy = client_destroy,
45
    .dump = client_dump,
46
+   .name_key = PW_KEY_APP_NAME,
47
 };
48
 
49
 /* module */
50
@@ -667,6 +672,7 @@
51
    .events = &module_events,
52
    .destroy = module_destroy,
53
    .dump = module_dump,
54
+   .name_key = PW_KEY_MODULE_NAME,
55
 };
56
 
57
 /* factory */
58
@@ -726,6 +732,7 @@
59
    .events = &factory_events,
60
    .destroy = factory_destroy,
61
    .dump = factory_dump,
62
+   .name_key = PW_KEY_FACTORY_NAME,
63
 };
64
 
65
 /* device */
66
@@ -810,6 +817,7 @@
67
    .events = &device_events,
68
    .destroy = device_destroy,
69
    .dump = device_dump,
70
+   .name_key = PW_KEY_DEVICE_NAME,
71
 };
72
 
73
 /* node */
74
@@ -906,6 +914,7 @@
75
    .events = &node_events,
76
    .destroy = node_destroy,
77
    .dump = node_dump,
78
+   .name_key = PW_KEY_NODE_NAME,
79
 };
80
 
81
 /* port */
82
@@ -991,6 +1000,7 @@
83
    .events = &port_events,
84
    .destroy = port_destroy,
85
    .dump = port_dump,
86
+   .name_key = PW_KEY_PORT_NAME,
87
 };
88
 
89
 /* link */
90
@@ -1206,6 +1216,7 @@
91
    .events = &metadata_events,
92
    .destroy = metadata_destroy,
93
    .dump = metadata_dump,
94
+   .name_key = PW_KEY_METADATA_NAME,
95
 };
96
 
97
 static const struct class *classes[] =
98
@@ -1331,6 +1342,32 @@
99
    .global_remove = registry_event_global_remove,
100
 };
101
 
102
+static bool object_matches(struct object *o, const char *pattern)
103
+{
104
+   uint32_t id;
105
+   const char *str;
106
+
107
+   if (spa_atou32(pattern, &id, 0) && o->id == id)
108
+       return true;
109
+
110
+   if (o->props == NULL)
111
+       return false;
112
+
113
+   if (strstr(o->type, pattern) != NULL)
114
+       return true;
115
+   if ((str = pw_properties_get(o->props, PW_KEY_OBJECT_PATH)) != NULL &&
116
+       fnmatch(pattern, str, FNM_EXTMATCH) == 0)
117
+       return true;
118
+   if ((str = pw_properties_get(o->props, PW_KEY_OBJECT_SERIAL)) != NULL &&
119
+       spa_streq(pattern, str))
120
+       return true;
121
+   if (o->class != NULL && o->class->name_key != NULL &&
122
+       (str = pw_properties_get(o->props, o->class->name_key)) != NULL &&
123
+       fnmatch(pattern, str, FNM_EXTMATCH) == 0)
124
+       return true;
125
+   return false;
126
+}
127
+
128
 static void dump_objects(struct data *d)
129
 {
130
    static const struct flags_info fl[] = {
131
@@ -1345,7 +1382,7 @@
132
 
133
    d->state = STATE_FIRST;
134
    spa_list_for_each(o, &d->object_list, link) {
135
-       if (d->id != SPA_ID_INVALID && d->id != o->id)
136
+       if (d->pattern != NULL && !object_matches(o, d->pattern))
137
            continue;
138
        if (o->changed == 0)
139
            continue;
140
@@ -1493,10 +1530,8 @@
141
        }
142
    }
143
 
144
-   data.id = SPA_ID_INVALID;
145
-   if (optind < argc) {
146
-       spa_atou32(argv[optind++], &data.id, 0);
147
-   }
148
+   if (optind < argc)
149
+       data.pattern = argv[optind++];
150
 
151
    data.loop = pw_main_loop_new(NULL);
152
    if (data.loop == NULL) {
153
pipewire-0.3.43.tar.gz/src/tools/pw-metadata.c -> pipewire-0.3.44.tar.gz/src/tools/pw-metadata.c Changed
11
 
1
@@ -96,7 +96,8 @@
2
    if (!spa_streq(type, PW_TYPE_INTERFACE_Metadata))
3
        return;
4
 
5
-   if ((str = spa_dict_lookup(props, PW_KEY_METADATA_NAME)) != NULL &&
6
+   if (props != NULL &&
7
+       (str = spa_dict_lookup(props, PW_KEY_METADATA_NAME)) != NULL &&
8
        !spa_streq(str, d->opt_name))
9
        return;
10
 
11