Overview

Request 5536 (accepted)

Versionbump

Submit package home:zaitor:...s:Essentials / pipewire-aptx to package Essentials / pipewire-aptx

pipewire-aptx.changes Changed
x
 
1
@@ -1,4 +1,9 @@
2
 -------------------------------------------------------------------
3
+Thu Mar  3 11:50:58 UTC 2022 - Bjørn Lie <zaitor@opensuse.org>
4
+
5
+- Update to version 0.3.48
6
+
7
+-------------------------------------------------------------------
8
 Fri Feb 18 14:59:46 UTC 2022 - Bjørn Lie <zaitor@opensuse.org>
9
 
10
 - Update to version 0.3.47
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.47
6
+Version:        0.3.48
7
 Release:        0
8
 Summary:        PipeWire Bluetooth aptX codec plugin
9
 License:        MIT
10
pipewire-0.3.47.tar.gz/NEWS -> pipewire-0.3.48.tar.gz/NEWS Changed
92
 
1
@@ -1,3 +1,81 @@
2
+# PipeWire 0.3.48 (2022-03-03)
3
+
4
+This is a bugfix release that is API and ABI compatible with previous
5
+0.3.x releases.
6
+
7
+## Highlights
8
+  - Fix IEC958 passthrough again.
9
+  - Fix pulse-server crashes when playing a sample.
10
+  - Support for more a more advanced upmixing algorithm.
11
+  - filter-chain now supports arbitrary many ports.
12
+  - Fix multichannel support in WINE. (with new WirePlumber).
13
+  - Many bugfixes and improvements.
14
+
15
+
16
+## PipeWire
17
+  - The work queue is now created in the context so we can fail early and
18
+    avoid further error checking in various places.
19
+  - Fix a potential use after free with threaded loops.
20
+  - The protocol now has a message footer. This is used to pass around
21
+    global state such as the last registered object serial number. This can
22
+    be used to detect when a client tries to bind to old (but reused)
23
+    object ids. This avoids some races in the session manager but also
24
+    when binding objects.
25
+  - The zero-denormals CPU flag is now not touched anymore unless explicitly
26
+    selected by the user. Denormals are avoided in filter-chain now in
27
+    software. If the zero-denormals are now only configured in the data
28
+    thread. This should fix issues with luajit. (#2160)
29
+  - Configuration parsing will not actually fail on errors.
30
+  - pw-top now correctly clips unicode characters.
31
+  - Many places now use a dynamic POD builder to support arbitrary large
32
+    property sets.
33
+  - pw-stream now support PropInfo parameters so that they can announce
34
+    custom properties.
35
+  - Serial number are now also set on metadata and session-manager objects.
36
+
37
+## SPA
38
+  - audioadapter is now smarter when trying to fixate the format. It will
39
+    use the PortConfig format to fill in any wildcards. This results in
40
+    the least amount of conversions when the stream can handle it. It also
41
+    is part of a fix (also requires a session manager fix) for WINE
42
+    multichannel support. (#876).
43
+  - Fix 5.1 to 2 channels mixing. It was using the volume of the stereo
44
+    pair on all channels.
45
+  - Fix some weird volume issues when a source is capturing and
46
+    channelmixing.
47
+  - Add stereo to 7.1 upmixing.
48
+  - The channelmix parameters can be changed at runtime now.
49
+  - Many improvements to the upmixing algorithms. Rear channels are now
50
+    constructed from the ambient sound and can have delay and phase shift
51
+    applied to them to improve spacialization. The stereo channels can
52
+    be filtered so that the dialog is more concentrated in the center
53
+    channel. (#861)
54
+
55
+## modules
56
+  - Module X11 bell received cleanups and improvements.
57
+  - The module now has a private method to schedule unload later. This
58
+    simplifies cleanup in many modules.
59
+  - module-filter-chain now handles arbitrary many ports and control
60
+    ports. (#2179)
61
+  - Fix a bug in RAOP where it was reading from the wrong port. (#2183)
62
+
63
+## pulse-server
64
+  - Nodes with the DONT_MOVE property should fail with -EINVAL when
65
+    they are moved.
66
+  - Fix a segfault when playing a sample. (#2151)
67
+  - The _FIX flags in pulse-server also now ignore the configured
68
+    sample format, just like pulseaudio does. (#876)
69
+  - Fix IEC958 passthrough again. It got accidentally broken since
70
+    0.3.45 with a fix for another issue. (#1442)
71
+  - Fix module-null-sink device.description. (#2166)
72
+
73
+## Bluetooth
74
+  - Don't try to connect HSP/HFP when no backend is available.
75
+
76
+
77
+Older versions:
78
+
79
+
80
 # PipeWire 0.3.47 (2022-02-18)
81
 
82
 This is a bugfix release that is API and ABI compatible with previous
83
@@ -13,8 +91,6 @@
84
     proxy. This might access invalid memory and cause infinite
85
     loops in older wireplumber.
86
 
87
-Older versions:
88
-
89
 # PipeWire 0.3.46 (2022-02-17)
90
 
91
 This is a bugfix release that is API and ABI compatible with previous
92
pipewire-0.3.47.tar.gz/meson.build -> pipewire-0.3.48.tar.gz/meson.build Changed
60
 
1
@@ -1,5 +1,5 @@
2
 project('pipewire', ['c' ],
3
-  version : '0.3.47',
4
+  version : '0.3.48',
5
   license : [ 'MIT', 'LGPL-2.1-or-later', 'GPL-2.0-only' ],
6
   meson_version : '>= 0.59.0',
7
   default_options : [ 'warning_level=3',
8
@@ -221,18 +221,6 @@
9
   cdata.set(h.get(1), cc.has_header(h.get(0)))
10
 endforeach
11
 
12
-check_functions = [
13
-  ['gettid', '#include <unistd.h>', ['-D_GNU_SOURCE']],
14
-  ['memfd_create', '#include <sys/mman.h>', ['-D_GNU_SOURCE']],
15
-  ['getrandom', '#include <stddef.h>\n#include <sys/random.h>', ['-D_GNU_SOURCE']],
16
-  ['sigabbrev_np', '#include <string.h>', ['-D_GNU_SOURCE']],
17
-]
18
-
19
-foreach f : check_functions
20
-  cdata.set('HAVE_' + f.get(0).to_upper(),
21
-            cc.has_function(f.get(0), prefix: f.get(1), args: f.get(2)))
22
-endforeach
23
-
24
 cdata.set('HAVE_PIDFD_OPEN',
25
           cc.get_define('SYS_pidfd_open', prefix: '#include <sys/syscall.h>') != '')
26
 
27
@@ -292,6 +280,9 @@
28
 summary({'X11 (x11-bell)': x11_dep.found()}, bool_yn: true,
29
   section: 'Misc dependencies')
30
 
31
+xfixes_dep = dependency('xfixes', required : get_option('x11-xfixes'), version: '>= 6')
32
+cdata.set('HAVE_XFIXES_6', xfixes_dep.found())
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
@@ -380,6 +371,22 @@
38
 summary({'lilv (for lv2 plugins)': lilv_lib.found()}, bool_yn: true)
39
 cdata.set('HAVE_LILV', lilv_lib.found())
40
 
41
+check_functions = [
42
+  ['gettid', '#include <unistd.h>', ['-D_GNU_SOURCE'], []],
43
+  ['memfd_create', '#include <sys/mman.h>', ['-D_GNU_SOURCE'], []],
44
+  ['getrandom', '#include <stddef.h>\n#include <sys/random.h>', ['-D_GNU_SOURCE'], []],
45
+  ['sigabbrev_np', '#include <string.h>', ['-D_GNU_SOURCE'], []],
46
+  ['XSetIOErrorExitHandler', '#include <X11/Xlib.h>', [], [x11_dep]],
47
+]
48
+
49
+foreach f : check_functions
50
+  cdata.set('HAVE_' + f.get(0).to_upper(),
51
+            cc.has_function(f.get(0),
52
+                            prefix: f.get(1),
53
+                            args: f.get(2),
54
+                            dependencies: f.get(3)))
55
+endforeach
56
+
57
 installed_tests_metadir = pipewire_datadir / 'installed-tests' / pipewire_name
58
 installed_tests_execdir = pipewire_libexecdir / 'installed-tests' / pipewire_name
59
 installed_tests_enabled = get_option('installed_tests').allowed()
60
pipewire-0.3.47.tar.gz/meson_options.txt -> pipewire-0.3.48.tar.gz/meson_options.txt Changed
12
 
1
@@ -229,6 +229,10 @@
2
        description: 'Enable code that depends on X11',
3
        type: 'feature',
4
        value: 'auto')
5
+option('x11-xfixes',
6
+       description: 'Enable code that depends on XFixes',
7
+       type: 'feature',
8
+       value: 'auto')
9
 option('libcanberra',
10
        description: 'Enable code that depends on libcanberra',
11
        type: 'feature',
12
pipewire-0.3.47.tar.gz/pipewire-jack/src/pipewire-jack.c -> pipewire-0.3.48.tar.gz/pipewire-jack/src/pipewire-jack.c Changed
10
 
1
@@ -5328,7 +5328,7 @@
2
        res = is_def2 - is_def1;
3
    else if ((*o1)->port.priority != (*o2)->port.priority)
4
        res = (*o2)->port.priority - (*o1)->port.priority;
5
-   else if ((res = strcmp((*o1)->port.alias1, (*o2)->port.alias1) == 0)) {
6
+   else if ((res = strcmp((*o1)->port.alias1, (*o2)->port.alias1)) == 0) {
7
        res = (*o1)->port.node_id - (*o2)->port.node_id;
8
        if (res == 0)
9
            res = (*o1)->port.system_id - (*o2)->port.system_id;
10
pipewire-0.3.48.tar.gz/spa/include/spa/pod/dynamic.h Added
83
 
1
@@ -0,0 +1,81 @@
2
+/* Simple Plugin API
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
+#ifndef SPA_POD_DYNAMIC_H
27
+#define SPA_POD_DYNAMIC_H
28
+
29
+#ifdef __cplusplus
30
+extern "C" {
31
+#endif
32
+
33
+#include <spa/pod/builder.h>
34
+
35
+struct spa_pod_dynamic_builder {
36
+   struct spa_pod_builder b;
37
+   void *data;
38
+   uint32_t extend;
39
+   uint32_t _padding;
40
+};
41
+
42
+static int spa_pod_dynamic_builder_overflow(void *data, uint32_t size)
43
+{
44
+   struct spa_pod_dynamic_builder *d = (struct spa_pod_dynamic_builder*)data;
45
+   int32_t old_size = d->b.size;
46
+   int32_t new_size = SPA_ROUND_UP_N(size, d->extend);
47
+   void *old_data = d->b.data;
48
+
49
+   if (old_data == d->data)
50
+       d->b.data = NULL;
51
+   if ((d->b.data = realloc(d->b.data, new_size)) == NULL)
52
+       return -errno;
53
+   if (old_data == d->data && d->b.data != old_data && old_size > 0)
54
+       memcpy(d->b.data, old_data, old_size);
55
+   d->b.size = new_size;
56
+        return 0;
57
+}
58
+
59
+static inline void spa_pod_dynamic_builder_init(struct spa_pod_dynamic_builder *builder,
60
+       void *data, uint32_t size, uint32_t extend)
61
+{
62
+   static const struct spa_pod_builder_callbacks spa_pod_dynamic_builder_callbacks = {
63
+       SPA_VERSION_POD_BUILDER_CALLBACKS,
64
+       .overflow = spa_pod_dynamic_builder_overflow
65
+   };
66
+   builder->b = SPA_POD_BUILDER_INIT(data, size);
67
+   spa_pod_builder_set_callbacks(&builder->b, &spa_pod_dynamic_builder_callbacks, builder);
68
+   builder->extend = extend;
69
+   builder->data = data;
70
+}
71
+
72
+static inline void spa_pod_dynamic_builder_clean(struct spa_pod_dynamic_builder *builder)
73
+{
74
+   if (builder->data != builder->b.data)
75
+       free(builder->b.data);
76
+}
77
+
78
+#ifdef __cplusplus
79
+}  /* extern "C" */
80
+#endif
81
+
82
+#endif /* SPA_POD_DYNAMIC_H */
83
pipewire-0.3.47.tar.gz/spa/plugins/alsa/acp/alsa-mixer.c -> pipewire-0.3.48.tar.gz/spa/plugins/alsa/acp/alsa-mixer.c Changed
21
 
1
@@ -4742,6 +4742,10 @@
2
    int count = 0;
3
 
4
    f = open_memstream(&ptr, &size);
5
+   if (f == NULL) {
6
+            pa_log("failed to open memstream: %m");
7
+            return -1;
8
+   }
9
 
10
         if (p->output_mappings)
11
             PA_IDXSET_FOREACH(m, p->output_mappings, idx) {
12
@@ -4816,6 +4820,8 @@
13
    size_t size;
14
 
15
    f = open_memstream(&ptr, &size);
16
+   if (f == NULL)
17
+       return;
18
 
19
         pa_assert(db_fix->min_step <= db_fix->max_step);
20
         nsteps = db_fix->max_step - db_fix->min_step + 1;
21
pipewire-0.3.47.tar.gz/spa/plugins/audioconvert/audioadapter.c -> pipewire-0.3.48.tar.gz/spa/plugins/audioconvert/audioadapter.c Changed
202
 
1
@@ -36,6 +36,7 @@
2
 #include <spa/buffer/alloc.h>
3
 #include <spa/pod/parser.h>
4
 #include <spa/pod/filter.h>
5
+#include <spa/pod/dynamic.h>
6
 #include <spa/param/param.h>
7
 #include <spa/param/audio/format-utils.h>
8
 #include <spa/param/latency-utils.h>
9
@@ -68,6 +69,7 @@
10
    struct spa_hook follower_listener;
11
    uint32_t follower_flags;
12
    struct spa_audio_info follower_current_format;
13
+   struct spa_audio_info default_format;
14
 
15
    struct spa_handle *hnd_convert;
16
    struct spa_node *convert;
17
@@ -141,8 +143,8 @@
18
                 const struct spa_pod *filter)
19
 {
20
    struct impl *this = object;
21
-   struct spa_pod_builder b = { 0 };
22
    uint8_t buffer[4096];
23
+   struct spa_pod_dynamic_builder b;
24
    struct spa_result_node_params result;
25
    uint32_t count = 0;
26
    int res;
27
@@ -157,7 +159,7 @@
28
 
29
    spa_log_debug(this->log, "%p: %d id:%u", this, seq, id);
30
 
31
-   spa_pod_builder_init(&b, buffer, sizeof(buffer));
32
+   spa_pod_dynamic_builder_init(&b, buffer, sizeof(buffer), 4096);
33
 
34
    switch (id) {
35
    case SPA_PARAM_EnumPortConfig:
36
@@ -165,35 +167,38 @@
37
        res = spa_node_enum_params(this->convert, seq, id, start, num, filter);
38
        return res;
39
    case SPA_PARAM_PropInfo:
40
-       if ((res = follower_enum_params(this,
41
-               id, IDX_PropInfo, &result, filter, &b)) != 1)
42
-           return res;
43
+       res = follower_enum_params(this,
44
+               id, IDX_PropInfo, &result, filter, &b.b);
45
        break;
46
    case SPA_PARAM_Props:
47
-       if ((res = follower_enum_params(this,
48
-               id, IDX_Props, &result, filter, &b)) != 1)
49
-           return res;
50
+       res = follower_enum_params(this,
51
+               id, IDX_Props, &result, filter, &b.b);
52
        break;
53
    case SPA_PARAM_ProcessLatency:
54
-       if ((res = follower_enum_params(this,
55
-               id, IDX_ProcessLatency, &result, filter, &b)) != 1)
56
-           return res;
57
+       res = follower_enum_params(this,
58
+               id, IDX_ProcessLatency, &result, filter, &b.b);
59
        break;
60
    case SPA_PARAM_EnumFormat:
61
    case SPA_PARAM_Format:
62
    case SPA_PARAM_Latency:
63
-       if ((res = spa_node_port_enum_params_sync(this->follower,
64
+       res = spa_node_port_enum_params_sync(this->follower,
65
                this->direction, 0,
66
-               id, &result.next, filter, &result.param, &b)) != 1)
67
-           return res;
68
+               id, &result.next, filter, &result.param, &b.b);
69
        break;
70
    default:
71
        return -ENOENT;
72
    }
73
 
74
-   spa_node_emit_result(&this->hooks, seq, 0, SPA_RESULT_TYPE_NODE_PARAMS, &result);
75
+   if (res == 1) {
76
+       spa_node_emit_result(&this->hooks, seq, 0, SPA_RESULT_TYPE_NODE_PARAMS, &result);
77
+       count++;
78
+   }
79
+   spa_pod_dynamic_builder_clean(&b);
80
 
81
-   if (++count != num)
82
+   if (res != 1)
83
+       return res;
84
+
85
+   if (count != num)
86
        goto next;
87
 
88
    return 0;
89
@@ -522,6 +527,31 @@
90
    return 0;
91
 }
92
 
93
+static int format_audio_raw_parse_opt(const struct spa_pod *format, struct spa_audio_info_raw *info)
94
+{
95
+   struct spa_pod *position = NULL;
96
+   uint32_t media_type, media_subtype;
97
+   int res;
98
+   if ((res = spa_format_parse(format, &media_type, &media_subtype)) < 0)
99
+       return res;
100
+   if (media_type != SPA_MEDIA_TYPE_audio ||
101
+       media_subtype != SPA_MEDIA_SUBTYPE_raw)
102
+       return -ENOTSUP;
103
+
104
+   spa_zero(*info);
105
+   res = spa_pod_parse_object(format,
106
+           SPA_TYPE_OBJECT_Format, NULL,
107
+           SPA_FORMAT_AUDIO_format, SPA_POD_OPT_Id(&info->format),
108
+           SPA_FORMAT_AUDIO_rate, SPA_POD_OPT_Int(&info->rate),
109
+           SPA_FORMAT_AUDIO_channels, SPA_POD_OPT_Int(&info->channels),
110
+           SPA_FORMAT_AUDIO_position, SPA_POD_OPT_Pod(&position));
111
+   if (position == NULL ||
112
+       !spa_pod_copy_array(position, SPA_TYPE_Id, info->position, SPA_AUDIO_MAX_CHANNELS))
113
+       SPA_FLAG_SET(info->flags, SPA_AUDIO_FLAG_UNPOSITIONED);
114
+
115
+   return res;
116
+}
117
+
118
 static int impl_node_set_param(void *object, uint32_t id, uint32_t flags,
119
                   const struct spa_pod *param)
120
 {
121
@@ -569,6 +599,12 @@
122
                SPA_PARAM_PORT_CONFIG_format,       SPA_POD_OPT_Pod(&format)) < 0)
123
            return -EINVAL;
124
 
125
+       if (format) {
126
+           struct spa_audio_info info;
127
+           if (format_audio_raw_parse_opt(format, &info.info.raw) >= 0)
128
+               this->default_format = info;
129
+       }
130
+
131
        switch (mode) {
132
        case SPA_PARAM_PORT_CONFIG_MODE_none:
133
            return -ENOTSUP;
134
@@ -634,10 +670,44 @@
135
    return res;
136
 }
137
 
138
+static struct spa_pod *merge_objects(struct impl *this, struct spa_pod_builder *b, uint32_t id,
139
+           struct spa_pod_object *o1, struct spa_pod_object *o2)
140
+{
141
+   const struct spa_pod_prop *p1, *p2;
142
+   struct spa_pod_frame f;
143
+   struct spa_pod_builder_state state;
144
+   int res = 0;
145
+
146
+   if (o2 == NULL || SPA_POD_TYPE(o1) != SPA_POD_TYPE(o2))
147
+       return (struct spa_pod*)o1;
148
+
149
+   spa_pod_builder_push_object(b, &f, o1->body.type, o1->body.id);
150
+   p2 = NULL;
151
+   SPA_POD_OBJECT_FOREACH(o1, p1) {
152
+       p2 = spa_pod_object_find_prop(o2, p2, p1->key);
153
+       if (p2 != NULL) {
154
+           spa_pod_builder_get_state(b, &state);
155
+           res = spa_pod_filter_prop(b, p1, p2);
156
+           if (res < 0)
157
+                       spa_pod_builder_reset(b, &state);
158
+       }
159
+       if (p2 == NULL || res < 0)
160
+           spa_pod_builder_raw_padded(b, p1, SPA_POD_PROP_SIZE(p1));
161
+   }
162
+   p1 = NULL;
163
+   SPA_POD_OBJECT_FOREACH(o2, p2) {
164
+       p1 = spa_pod_object_find_prop(o1, p1, p2->key);
165
+       if (p1 != NULL)
166
+           continue;
167
+       spa_pod_builder_raw_padded(b, p2, SPA_POD_PROP_SIZE(p2));
168
+   }
169
+   return spa_pod_builder_pop(b, &f);
170
+}
171
+
172
 static int negotiate_format(struct impl *this)
173
 {
174
    uint32_t state;
175
-   struct spa_pod *format;
176
+   struct spa_pod *format, *def;
177
    uint8_t buffer[4096];
178
    struct spa_pod_builder b = { 0 };
179
    int res;
180
@@ -669,7 +739,6 @@
181
            goto done;
182
        }
183
    }
184
-
185
    if (this->convert) {
186
        state = 0;
187
        if ((res = spa_node_port_enum_params_sync(this->convert,
188
@@ -688,6 +757,13 @@
189
        goto done;
190
    }
191
 
192
+   def = spa_format_audio_raw_build(&b,
193
+           SPA_PARAM_Format, &this->default_format.info.raw);
194
+
195
+   format = merge_objects(this, &b, SPA_PARAM_Format,
196
+           (struct spa_pod_object*)format,
197
+           (struct spa_pod_object*)def);
198
+
199
    spa_pod_fixate(format);
200
 
201
    res = configure_format(this, 0, format);
202
pipewire-0.3.47.tar.gz/spa/plugins/audioconvert/channelmix-ops-c.c -> pipewire-0.3.48.tar.gz/spa/plugins/audioconvert/channelmix-ops-c.c Changed
359
 
1
@@ -25,10 +25,10 @@
2
 #include "channelmix-ops.h"
3
 
4
 void
5
-channelmix_copy_c(struct channelmix *mix, uint32_t n_dst, void * SPA_RESTRICT dst[n_dst],
6
-       uint32_t n_src, const void * SPA_RESTRICT src[n_src], uint32_t n_samples)
7
+channelmix_copy_c(struct channelmix *mix, void * SPA_RESTRICT dst[],
8
+       const void * SPA_RESTRICT src[], uint32_t n_samples)
9
 {
10
-   uint32_t i, n;
11
+   uint32_t i, n, n_dst = mix->dst_chan;
12
    float **d = (float **)dst;
13
    const float **s = (const float **)src;
14
 
15
@@ -51,10 +51,10 @@
16
 #define _M(ch)     (1UL << SPA_AUDIO_CHANNEL_ ## ch)
17
 
18
 void
19
-channelmix_f32_n_m_c(struct channelmix *mix, uint32_t n_dst, void * SPA_RESTRICT dst[n_dst],
20
-       uint32_t n_src, const void * SPA_RESTRICT src[n_src], uint32_t n_samples)
21
+channelmix_f32_n_m_c(struct channelmix *mix, void * SPA_RESTRICT dst[],
22
+       const void * SPA_RESTRICT src[], uint32_t n_samples)
23
 {
24
-   uint32_t i, j, n;
25
+   uint32_t i, j, n, n_dst = mix->dst_chan, n_src = mix->src_chan;
26
    float **d = (float **) dst;
27
    const float **s = (const float **) src;
28
 
29
@@ -78,10 +78,8 @@
30
                d[i][n] = sum;
31
            }
32
        }
33
-       for (i = 0; i < n_dst; i++) {
34
-           if (mix->lr4_info[i] > 0)
35
-               lr4_process(&mix->lr4[i], d[i], n_samples);
36
-       }
37
+       for (i = 0; i < n_dst; i++)
38
+           lr4_process(&mix->lr4[i], d[i], d[i], 1.0f, n_samples);
39
    }
40
 }
41
 
42
@@ -89,8 +87,8 @@
43
 #define MASK_STEREO    _M(FL)|_M(FR)|_M(UNKNOWN)
44
 
45
 void
46
-channelmix_f32_1_2_c(struct channelmix *mix, uint32_t n_dst, void * SPA_RESTRICT dst[n_dst],
47
-       uint32_t n_src, const void * SPA_RESTRICT src[n_src], uint32_t n_samples)
48
+channelmix_f32_1_2_c(struct channelmix *mix, void * SPA_RESTRICT dst[],
49
+       const void * SPA_RESTRICT src[], uint32_t n_samples)
50
 {
51
    uint32_t n;
52
    float **d = (float **)dst;
53
@@ -118,8 +116,8 @@
54
 }
55
 
56
 void
57
-channelmix_f32_2_1_c(struct channelmix *mix, uint32_t n_dst, void * SPA_RESTRICT dst[n_dst],
58
-          uint32_t n_src, const void * SPA_RESTRICT src[n_src], uint32_t n_samples)
59
+channelmix_f32_2_1_c(struct channelmix *mix, void * SPA_RESTRICT dst[],
60
+          const void * SPA_RESTRICT src[], uint32_t n_samples)
61
 {
62
    uint32_t n;
63
    float **d = (float **)dst;
64
@@ -140,8 +138,8 @@
65
 }
66
 
67
 void
68
-channelmix_f32_4_1_c(struct channelmix *mix, uint32_t n_dst, void * SPA_RESTRICT dst[n_dst],
69
-          uint32_t n_src, const void * SPA_RESTRICT src[n_src], uint32_t n_samples)
70
+channelmix_f32_4_1_c(struct channelmix *mix, void * SPA_RESTRICT dst[],
71
+          const void * SPA_RESTRICT src[], uint32_t n_samples)
72
 {
73
    uint32_t n;
74
    float **d = (float **)dst;
75
@@ -166,8 +164,8 @@
76
 }
77
 
78
 void
79
-channelmix_f32_3p1_1_c(struct channelmix *mix, uint32_t n_dst, void * SPA_RESTRICT dst[n_dst],
80
-          uint32_t n_src, const void * SPA_RESTRICT src[n_src], uint32_t n_samples)
81
+channelmix_f32_3p1_1_c(struct channelmix *mix, void * SPA_RESTRICT dst[],
82
+          const void * SPA_RESTRICT src[], uint32_t n_samples)
83
 {
84
    uint32_t n;
85
    float **d = (float **)dst;
86
@@ -193,10 +191,10 @@
87
 #define MASK_QUAD  _M(FL)|_M(FR)|_M(RL)|_M(RR)|_M(UNKNOWN)
88
 
89
 void
90
-channelmix_f32_2_4_c(struct channelmix *mix, uint32_t n_dst, void * SPA_RESTRICT dst[n_dst],
91
-          uint32_t n_src, const void * SPA_RESTRICT src[n_src], uint32_t n_samples)
92
+channelmix_f32_2_4_c(struct channelmix *mix, void * SPA_RESTRICT dst[],
93
+          const void * SPA_RESTRICT src[], uint32_t n_samples)
94
 {
95
-   uint32_t i, n;
96
+   uint32_t i, n, n_dst = mix->dst_chan;
97
    float **d = (float **)dst;
98
    const float **s = (const float **)src;
99
    const float v0 = mix->matrix[0][0];
100
@@ -233,10 +231,10 @@
101
 
102
 #define MASK_3_1   _M(FL)|_M(FR)|_M(FC)|_M(LFE)
103
 void
104
-channelmix_f32_2_3p1_c(struct channelmix *mix, uint32_t n_dst, void * SPA_RESTRICT dst[n_dst],
105
-          uint32_t n_src, const void * SPA_RESTRICT src[n_src], uint32_t n_samples)
106
+channelmix_f32_2_3p1_c(struct channelmix *mix, void * SPA_RESTRICT dst[],
107
+          const void * SPA_RESTRICT src[], uint32_t n_samples)
108
 {
109
-   uint32_t i, n;
110
+   uint32_t i, n, n_dst = mix->dst_chan;
111
    float **d = (float **)dst;
112
    const float **s = (const float **)src;
113
    const float v0 = mix->matrix[0][0];
114
@@ -251,33 +249,89 @@
115
    else if (v0 == 1.0f && v1 == 1.0f) {
116
        for (n = 0; n < n_samples; n++) {
117
            float c = s[0][n] + s[1][n];
118
-           d[0][n] = s[0][n];
119
-           d[1][n] = s[1][n];
120
-           d[2][n] = c * v2;
121
-           d[3][n] = c * v3;
122
+           float w = c * mix->widen;
123
+           d[0][n] = s[0][n] - w;
124
+           d[1][n] = s[1][n] - w;
125
+           d[2][n] = c;
126
        }
127
-       if (v3 > 0.0f)
128
-           lr4_process(&mix->lr4[3], d[3], n_samples);
129
+       lr4_process(&mix->lr4[3], d[3], d[2], v3, n_samples);
130
+       lr4_process(&mix->lr4[2], d[2], d[2], v2, n_samples);
131
    }
132
    else {
133
        for (n = 0; n < n_samples; n++) {
134
            float c = s[0][n] + s[1][n];
135
-           d[0][n] = s[0][n] * v0;
136
-           d[1][n] = s[1][n] * v1;
137
-           d[2][n] = c * v2;
138
-           d[3][n] = c * v3;
139
+           float w = c * mix->widen;
140
+           d[0][n] = (s[0][n] - w) * v0;
141
+           d[1][n] = (s[1][n] - w) * v1;
142
+           d[2][n] = c;
143
        }
144
-       if (v3 > 0.0f)
145
-           lr4_process(&mix->lr4[3], d[3], n_samples);
146
+       lr4_process(&mix->lr4[3], d[3], d[2], v3, n_samples);
147
+       lr4_process(&mix->lr4[2], d[2], d[2], v2, n_samples);
148
    }
149
 }
150
 
151
 #define MASK_5_1   _M(FL)|_M(FR)|_M(FC)|_M(LFE)|_M(SL)|_M(SR)|_M(RL)|_M(RR)
152
 void
153
-channelmix_f32_2_5p1_c(struct channelmix *mix, uint32_t n_dst, void * SPA_RESTRICT dst[n_dst],
154
-          uint32_t n_src, const void * SPA_RESTRICT src[n_src], uint32_t n_samples)
155
+channelmix_f32_2_5p1_c(struct channelmix *mix, void * SPA_RESTRICT dst[],
156
+          const void * SPA_RESTRICT src[], uint32_t n_samples)
157
+{
158
+   uint32_t i, n, n_dst = mix->dst_chan;
159
+   float **d = (float **)dst;
160
+   const float **s = (const float **)src;
161
+   const float v0 = mix->matrix[0][0];
162
+   const float v1 = mix->matrix[1][1];
163
+   const float v2 = (mix->matrix[2][0] + mix->matrix[2][1]) * 0.5f;
164
+   const float v3 = (mix->matrix[3][0] + mix->matrix[3][1]) * 0.5f;
165
+   const float v4 = mix->matrix[4][0];
166
+   const float v5 = mix->matrix[5][1];
167
+
168
+   if (SPA_FLAG_IS_SET(mix->flags, CHANNELMIX_FLAG_ZERO)) {
169
+       for (i = 0; i < n_dst; i++)
170
+           memset(d[i], 0, n_samples * sizeof(float));
171
+   }
172
+   else if (v0 == 1.0f && v1 == 1.0f) {
173
+       for (n = 0; n < n_samples; n++) {
174
+           float c = s[0][n] + s[1][n];
175
+           float w = c * mix->widen;
176
+           float m = s[0][n] - s[1][n];
177
+           d[0][n] = s[0][n] - w;
178
+           d[1][n] = s[1][n] - w;
179
+           d[3][n] = c;
180
+           d[5][n] = m;
181
+       }
182
+       lr4_process(&mix->lr4[2], d[2], d[3], v2, n_samples);
183
+       lr4_process(&mix->lr4[3], d[3], d[3], v3, n_samples);
184
+
185
+       delay_convolve_run(mix->buffer[0], &mix->pos[0], BUFFER_SIZE, mix->delay,
186
+               mix->taps, mix->n_taps, d[4], d[5], v4, n_samples);
187
+       delay_convolve_run(mix->buffer[1], &mix->pos[1], BUFFER_SIZE, mix->delay,
188
+               mix->taps, mix->n_taps, d[5], d[5], -v5, n_samples);
189
+   }
190
+   else {
191
+       for (n = 0; n < n_samples; n++) {
192
+           float c = s[0][n] + s[1][n];
193
+           float w = c * mix->widen;
194
+           float m = s[0][n] - s[1][n];
195
+           d[0][n] = (s[0][n] - w) * v0;
196
+           d[1][n] = (s[1][n] - w) * v1;
197
+           d[3][n] = c;
198
+           d[5][n] = m;
199
+       }
200
+       lr4_process(&mix->lr4[2], d[2], d[3], v2, n_samples);
201
+       lr4_process(&mix->lr4[3], d[3], d[3], v3, n_samples);
202
+
203
+       delay_convolve_run(mix->buffer[0], &mix->pos[0], BUFFER_SIZE, mix->delay,
204
+               mix->taps, mix->n_taps, d[4], d[5], v4, n_samples);
205
+       delay_convolve_run(mix->buffer[1], &mix->pos[1], BUFFER_SIZE, mix->delay,
206
+               mix->taps, mix->n_taps, d[5], d[5], -v5, n_samples);
207
+   }
208
+}
209
+
210
+void
211
+channelmix_f32_2_7p1_c(struct channelmix *mix, void * SPA_RESTRICT dst[],
212
+          const void * SPA_RESTRICT src[], uint32_t n_samples)
213
 {
214
-   uint32_t i, n;
215
+   uint32_t i, n, n_dst = mix->dst_chan;
216
    float **d = (float **)dst;
217
    const float **s = (const float **)src;
218
    const float v0 = mix->matrix[0][0];
219
@@ -286,6 +340,8 @@
220
    const float v3 = (mix->matrix[3][0] + mix->matrix[3][1]) * 0.5f;
221
    const float v4 = mix->matrix[4][0];
222
    const float v5 = mix->matrix[5][1];
223
+   const float v6 = mix->matrix[6][0];
224
+   const float v7 = mix->matrix[7][1];
225
 
226
    if (SPA_FLAG_IS_SET(mix->flags, CHANNELMIX_FLAG_ZERO)) {
227
        for (i = 0; i < n_dst; i++)
228
@@ -294,33 +350,49 @@
229
    else if (v0 == 1.0f && v1 == 1.0f && v4 == 1.0f && v5 == 1.0f) {
230
        for (n = 0; n < n_samples; n++) {
231
            float c = s[0][n] + s[1][n];
232
-           d[0][n] = d[4][n] = s[0][n];
233
-           d[1][n] = d[5][n] = s[1][n];
234
-           d[2][n] = c * v2;
235
-           d[3][n] = c * v3;
236
+           float w = c * mix->widen;
237
+           float m = s[0][n] - s[1][n];
238
+           d[0][n] = s[0][n] - w;
239
+           d[1][n] = s[1][n] - w;
240
+           d[3][n] = c;
241
+           d[4][n] = s[0][n];
242
+           d[5][n] = s[1][n];
243
+           d[7][n] = m;
244
        }
245
-       if (v3 > 0.0f)
246
-           lr4_process(&mix->lr4[3], d[3], n_samples);
247
+       lr4_process(&mix->lr4[2], d[2], d[3], v2, n_samples);
248
+       lr4_process(&mix->lr4[3], d[3], d[3], v3, n_samples);
249
+
250
+       delay_convolve_run(mix->buffer[0], &mix->pos[0], BUFFER_SIZE, mix->delay,
251
+               mix->taps, mix->n_taps, d[6], d[7], v6, n_samples);
252
+       delay_convolve_run(mix->buffer[1], &mix->pos[1], BUFFER_SIZE, mix->delay,
253
+               mix->taps, mix->n_taps, d[7], d[7], -v7, n_samples);
254
    }
255
    else {
256
        for (n = 0; n < n_samples; n++) {
257
            float c = s[0][n] + s[1][n];
258
-           d[0][n] = s[0][n] * v0;
259
-           d[1][n] = s[1][n] * v1;
260
-           d[2][n] = c * v2;
261
-           d[3][n] = c * v3;
262
+           float w = c * mix->widen;
263
+           float m = s[0][n] - s[1][n];
264
+           d[0][n] = (s[0][n] - w) * v0;
265
+           d[1][n] = (s[1][n] - w) * v1;
266
+           d[3][n] = c;
267
            d[4][n] = s[0][n] * v4;
268
            d[5][n] = s[1][n] * v5;
269
+           d[7][n] = m;
270
        }
271
-       if (v3 > 0.0f)
272
-           lr4_process(&mix->lr4[3], d[3], n_samples);
273
+       lr4_process(&mix->lr4[2], d[2], d[3], v2, n_samples);
274
+       lr4_process(&mix->lr4[3], d[3], d[3], v3, n_samples);
275
+
276
+       delay_convolve_run(mix->buffer[0], &mix->pos[0], BUFFER_SIZE, mix->delay,
277
+               mix->taps, mix->n_taps, d[6], d[7], v6, n_samples);
278
+       delay_convolve_run(mix->buffer[1], &mix->pos[1], BUFFER_SIZE, mix->delay,
279
+               mix->taps, mix->n_taps, d[7], d[7], -v7, n_samples);
280
    }
281
 }
282
 
283
 /* FL+FR+FC+LFE+SL+SR -> FL+FR */
284
 void
285
-channelmix_f32_5p1_2_c(struct channelmix *mix, uint32_t n_dst, void * SPA_RESTRICT dst[n_dst],
286
-          uint32_t n_src, const void * SPA_RESTRICT src[n_src], uint32_t n_samples)
287
+channelmix_f32_5p1_2_c(struct channelmix *mix, void * SPA_RESTRICT dst[],
288
+          const void * SPA_RESTRICT src[], uint32_t n_samples)
289
 {
290
    uint32_t n;
291
    float **d = (float **) dst;
292
@@ -347,10 +419,10 @@
293
 
294
 /* FL+FR+FC+LFE+SL+SR -> FL+FR+FC+LFE*/
295
 void
296
-channelmix_f32_5p1_3p1_c(struct channelmix *mix, uint32_t n_dst, void * SPA_RESTRICT dst[n_dst],
297
-          uint32_t n_src, const void * SPA_RESTRICT src[n_src], uint32_t n_samples)
298
+channelmix_f32_5p1_3p1_c(struct channelmix *mix, void * SPA_RESTRICT dst[],
299
+          const void * SPA_RESTRICT src[], uint32_t n_samples)
300
 {
301
-   uint32_t i, n;
302
+   uint32_t i, n, n_dst = mix->dst_chan;
303
    float **d = (float **) dst;
304
    const float **s = (const float **) src;
305
    const float v0 = mix->matrix[0][0];
306
@@ -376,10 +448,10 @@
307
 
308
 /* FL+FR+FC+LFE+SL+SR -> FL+FR+RL+RR*/
309
 void
310
-channelmix_f32_5p1_4_c(struct channelmix *mix, uint32_t n_dst, void * SPA_RESTRICT dst[n_dst],
311
-          uint32_t n_src, const void * SPA_RESTRICT src[n_src], uint32_t n_samples)
312
+channelmix_f32_5p1_4_c(struct channelmix *mix, void * SPA_RESTRICT dst[],
313
+          const void * SPA_RESTRICT src[], uint32_t n_samples)
314
 {
315
-   uint32_t i, n;
316
+   uint32_t i, n, n_dst = mix->dst_chan;
317
    float **d = (float **) dst;
318
    const float **s = (const float **) src;
319
    const float clev = mix->matrix[0][2];
320
@@ -408,8 +480,8 @@
321
 
322
 /* FL+FR+FC+LFE+SL+SR+RL+RR -> FL+FR */
323
 void
324
-channelmix_f32_7p1_2_c(struct channelmix *mix, uint32_t n_dst, void * SPA_RESTRICT dst[n_dst],
325
-          uint32_t n_src, const void * SPA_RESTRICT src[n_src], uint32_t n_samples)
326
+channelmix_f32_7p1_2_c(struct channelmix *mix, void * SPA_RESTRICT dst[],
327
+          const void * SPA_RESTRICT src[], uint32_t n_samples)
328
 {
329
    uint32_t n;
330
    float **d = (float **) dst;
331
@@ -438,10 +510,10 @@
332
 
333
 /* FL+FR+FC+LFE+SL+SR+RL+RR -> FL+FR+FC+LFE*/
334
 void
335
-channelmix_f32_7p1_3p1_c(struct channelmix *mix, uint32_t n_dst, void * SPA_RESTRICT dst[n_dst],
336
-          uint32_t n_src, const void * SPA_RESTRICT src[n_src], uint32_t n_samples)
337
+channelmix_f32_7p1_3p1_c(struct channelmix *mix, void * SPA_RESTRICT dst[],
338
+          const void * SPA_RESTRICT src[], uint32_t n_samples)
339
 {
340
-   uint32_t i, n;
341
+   uint32_t i, n, n_dst = mix->dst_chan;
342
    float **d = (float **) dst;
343
    const float **s = (const float **) src;
344
    const float v0 = mix->matrix[0][0];
345
@@ -467,10 +539,10 @@
346
 
347
 /* FL+FR+FC+LFE+SL+SR+RL+RR -> FL+FR+RL+RR*/
348
 void
349
-channelmix_f32_7p1_4_c(struct channelmix *mix, uint32_t n_dst, void * SPA_RESTRICT dst[n_dst],
350
-          uint32_t n_src, const void * SPA_RESTRICT src[n_src], uint32_t n_samples)
351
+channelmix_f32_7p1_4_c(struct channelmix *mix, void * SPA_RESTRICT dst[],
352
+          const void * SPA_RESTRICT src[], uint32_t n_samples)
353
 {
354
-   uint32_t i, n;
355
+   uint32_t i, n, n_dst = mix->dst_chan;
356
    float **d = (float **) dst;
357
    const float **s = (const float **) src;
358
    const float v0 = mix->matrix[0][0];
359
pipewire-0.3.47.tar.gz/spa/plugins/audioconvert/channelmix-ops-sse.c -> pipewire-0.3.48.tar.gz/spa/plugins/audioconvert/channelmix-ops-sse.c Changed
100
 
1
@@ -26,10 +26,10 @@
2
 
3
 #include <xmmintrin.h>
4
 
5
-void channelmix_copy_sse(struct channelmix *mix, uint32_t n_dst, void * SPA_RESTRICT dst[n_dst],
6
-       uint32_t n_src, const void * SPA_RESTRICT src[n_src], uint32_t n_samples)
7
+void channelmix_copy_sse(struct channelmix *mix, void * SPA_RESTRICT dst[],
8
+       const void * SPA_RESTRICT src[], uint32_t n_samples)
9
 {
10
-   uint32_t i, n, unrolled;
11
+   uint32_t i, n, unrolled, n_dst = mix->dst_chan;
12
    float **d = (float **)dst;
13
    const float **s = (const float **)src;
14
 
15
@@ -71,10 +71,10 @@
16
 }
17
 
18
 void
19
-channelmix_f32_2_4_sse(struct channelmix *mix, uint32_t n_dst, void * SPA_RESTRICT dst[n_dst],
20
-       uint32_t n_src, const void * SPA_RESTRICT src[n_src], uint32_t n_samples)
21
+channelmix_f32_2_4_sse(struct channelmix *mix, void * SPA_RESTRICT dst[],
22
+       const void * SPA_RESTRICT src[], uint32_t n_samples)
23
 {
24
-   uint32_t i, n, unrolled;
25
+   uint32_t i, n, unrolled, n_dst = mix->dst_chan;
26
    float **d = (float **)dst;
27
    const float **s = (const float **)src;
28
    const float m00 = mix->matrix[0][0];
29
@@ -139,8 +139,8 @@
30
 
31
 /* FL+FR+FC+LFE+SL+SR -> FL+FR */
32
 void
33
-channelmix_f32_5p1_2_sse(struct channelmix *mix, uint32_t n_dst, void * SPA_RESTRICT dst[n_dst],
34
-       uint32_t n_src, const void * SPA_RESTRICT src[n_src], uint32_t n_samples)
35
+channelmix_f32_5p1_2_sse(struct channelmix *mix, void * SPA_RESTRICT dst[],
36
+       const void * SPA_RESTRICT src[], uint32_t n_samples)
37
 {
38
    uint32_t n, unrolled;
39
    float **d = (float **) dst;
40
@@ -205,13 +205,11 @@
41
            ctr = _mm_add_ps(ctr, _mm_mul_ps(_mm_load_ps(&sLFE[n]), llev));
42
            in = _mm_mul_ps(_mm_load_ps(&sSL[n]), slev0);
43
            in = _mm_add_ps(in, ctr);
44
-           in = _mm_add_ps(in, _mm_load_ps(&sFL[n]));
45
-           in = _mm_mul_ps(in, v0);
46
+           in = _mm_add_ps(in, _mm_mul_ps(_mm_load_ps(&sFL[n]), v0));
47
            _mm_store_ps(&dFL[n], in);
48
            in = _mm_mul_ps(_mm_load_ps(&sSR[n]), slev1);
49
            in = _mm_add_ps(in, ctr);
50
-           in = _mm_add_ps(in, _mm_load_ps(&sFR[n]));
51
-           in = _mm_mul_ps(in, v1);
52
+           in = _mm_add_ps(in, _mm_mul_ps(_mm_load_ps(&sFR[n]), v1));
53
            _mm_store_ps(&dFR[n], in);
54
        }
55
        for(; n < n_samples; n++) {
56
@@ -219,13 +217,11 @@
57
            ctr = _mm_add_ss(ctr, _mm_mul_ss(_mm_load_ss(&sLFE[n]), llev));
58
            in = _mm_mul_ss(_mm_load_ss(&sSL[n]), slev0);
59
            in = _mm_add_ss(in, ctr);
60
-           in = _mm_add_ss(in, _mm_load_ss(&sFL[n]));
61
-           in = _mm_mul_ss(in, v0);
62
+           in = _mm_add_ss(in, _mm_mul_ss(_mm_load_ss(&sFL[n]), v0));
63
            _mm_store_ss(&dFL[n], in);
64
            in = _mm_mul_ss(_mm_load_ss(&sSR[n]), slev1);
65
            in = _mm_add_ss(in, ctr);
66
-           in = _mm_add_ss(in, _mm_load_ss(&sFR[n]));
67
-           in = _mm_mul_ss(in, v1);
68
+           in = _mm_add_ss(in, _mm_mul_ss(_mm_load_ss(&sFR[n]), v1));
69
            _mm_store_ss(&dFR[n], in);
70
        }
71
    }
72
@@ -233,10 +229,10 @@
73
 
74
 /* FL+FR+FC+LFE+SL+SR -> FL+FR+FC+LFE*/
75
 void
76
-channelmix_f32_5p1_3p1_sse(struct channelmix *mix, uint32_t n_dst, void * SPA_RESTRICT dst[n_dst],
77
-       uint32_t n_src, const void * SPA_RESTRICT src[n_src], uint32_t n_samples)
78
+channelmix_f32_5p1_3p1_sse(struct channelmix *mix, void * SPA_RESTRICT dst[],
79
+       const void * SPA_RESTRICT src[], uint32_t n_samples)
80
 {
81
-   uint32_t i, n, unrolled;
82
+   uint32_t i, n, unrolled, n_dst = mix->dst_chan;
83
    float **d = (float **) dst;
84
    const float **s = (const float **) src;
85
    const __m128 v0 = _mm_set1_ps(mix->matrix[0][0]);
86
@@ -311,10 +307,10 @@
87
 
88
 /* FL+FR+FC+LFE+SL+SR -> FL+FR+RL+RR*/
89
 void
90
-channelmix_f32_5p1_4_sse(struct channelmix *mix, uint32_t n_dst, void * SPA_RESTRICT dst[n_dst],
91
-       uint32_t n_src, const void * SPA_RESTRICT src[n_src], uint32_t n_samples)
92
+channelmix_f32_5p1_4_sse(struct channelmix *mix, void * SPA_RESTRICT dst[],
93
+       const void * SPA_RESTRICT src[], uint32_t n_samples)
94
 {
95
-   uint32_t i, n, unrolled;
96
+   uint32_t i, n, unrolled, n_dst = mix->dst_chan;
97
    float **d = (float **) dst;
98
    const float **s = (const float **) src;
99
    const __m128 clev = _mm_set1_ps(mix->matrix[0][2]);
100
pipewire-0.3.47.tar.gz/spa/plugins/audioconvert/channelmix-ops.c -> pipewire-0.3.48.tar.gz/spa/plugins/audioconvert/channelmix-ops.c Changed
90
 
1
@@ -35,6 +35,7 @@
2
 #define VOLUME_NORM 1.0f
3
 
4
 #include "channelmix-ops.h"
5
+#include "hilbert.h"
6
 
7
 #undef SPA_LOG_TOPIC_DEFAULT
8
 #define SPA_LOG_TOPIC_DEFAULT log_topic
9
@@ -51,8 +52,8 @@
10
 #define ANY    ((uint32_t)-1)
11
 #define EQ ((uint32_t)-2)
12
 
13
-typedef void (*channelmix_func_t) (struct channelmix *mix, uint32_t n_dst, void * SPA_RESTRICT dst[n_dst],
14
-           uint32_t n_src, const void * SPA_RESTRICT src[n_src], uint32_t n_samples);
15
+typedef void (*channelmix_func_t) (struct channelmix *mix, void * SPA_RESTRICT dst[],
16
+           const void * SPA_RESTRICT src[], uint32_t n_samples);
17
 
18
 static const struct channelmix_info {
19
    uint32_t src_chan;
20
@@ -84,6 +85,7 @@
21
    { 2, MASK_STEREO, 4, MASK_QUAD, channelmix_f32_2_4_c, 0, "f32_2_4_c" },
22
    { 2, MASK_STEREO, 4, MASK_3_1, channelmix_f32_2_3p1_c, 0, "f32_2_3p1_c" },
23
    { 2, MASK_STEREO, 6, MASK_5_1, channelmix_f32_2_5p1_c, 0, "f32_2_5p1_c" },
24
+   { 2, MASK_STEREO, 8, MASK_7_1, channelmix_f32_2_7p1_c, 0, "f32_2_7p1_c" },
25
 #if defined (HAVE_SSE)
26
    { 6, MASK_5_1, 2, MASK_STEREO, channelmix_f32_5p1_2_sse, SPA_CPU_FLAG_SSE, "f32_5p1_2_sse" },
27
 #endif
28
@@ -214,8 +216,10 @@
29
    keep |= FRONT;
30
    if (mix->lfe_cutoff > 0.0f)
31
        keep |= _MASK(LFE);
32
+   else
33
+       keep &= ~_MASK(LFE);
34
 
35
-   spa_log_debug(mix->log, "unassigned downmix %08" PRIx64, unassigned);
36
+   spa_log_debug(mix->log, "unassigned downmix %08" PRIx64 " %08" PRIx64, unassigned, keep);
37
 
38
    if (unassigned & FRONT){
39
        if ((dst_mask & STEREO) == STEREO){
40
@@ -452,11 +456,13 @@
41
        }
42
        maxsum = SPA_MAX(maxsum, sum);
43
        if (i == _CH(LFE) && mix->lfe_cutoff > 0.0f) {
44
-           spa_log_debug(mix->log, "channel %d is LFE", ic);
45
+           spa_log_debug(mix->log, "channel %d is LFE cutoff:%f", ic, mix->lfe_cutoff);
46
            lr4_set(&mix->lr4[ic], BQ_LOWPASS, mix->lfe_cutoff / mix->freq);
47
-           mix->lr4_info[ic] = 1;
48
+       } else if (i == _CH(FC) && mix->fc_cutoff > 0.0f) {
49
+           spa_log_debug(mix->log, "channel %d is FC cutoff:%f", ic, mix->fc_cutoff);
50
+           lr4_set(&mix->lr4[ic], BQ_LOWPASS, mix->fc_cutoff / mix->freq);
51
        } else {
52
-           mix->lr4_info[ic] = 0;
53
+           mix->lr4[ic].active = false;
54
        }
55
        ic++;
56
    }
57
@@ -467,6 +473,7 @@
58
            for (j = 0; j < jc; j++)
59
                        mix->matrix_orig[i][j] /= maxsum;
60
    }
61
+
62
    return 0;
63
 }
64
 
65
@@ -542,11 +549,22 @@
66
    if (info == NULL)
67
        return -ENOTSUP;
68
 
69
-   spa_log_debug(mix->log, "selected %s", info->name);
70
-
71
    mix->free = impl_channelmix_free;
72
    mix->process = info->process;
73
    mix->set_volume = impl_channelmix_set_volume;
74
    mix->cpu_flags = info->cpu_flags;
75
+   mix->delay = mix->rear_delay * mix->freq / 1000.0f;
76
+
77
+   spa_log_debug(mix->log, "selected %s delay:%d options:%08x", info->name, mix->delay,
78
+           mix->options);
79
+
80
+   if (mix->hilbert_taps > 0) {
81
+       mix->n_taps = SPA_CLAMP(mix->hilbert_taps, 15u, 255u) | 1;
82
+       blackman_window(mix->taps, mix->n_taps);
83
+       hilbert_generate(mix->taps, mix->n_taps);
84
+   } else {
85
+       mix->n_taps = 1;
86
+       mix->taps[0] = 1.0f;
87
+   }
88
    return make_matrix(mix);
89
 }
90
pipewire-0.3.47.tar.gz/spa/plugins/audioconvert/channelmix-ops.h -> pipewire-0.3.48.tar.gz/spa/plugins/audioconvert/channelmix-ops.h Changed
66
 
1
@@ -33,6 +33,7 @@
2
 extern struct spa_log_topic *log_topic;
3
 
4
 #include "crossover.h"
5
+#include "delay.h"
6
 
7
 #define VOLUME_MIN 0.0f
8
 #define VOLUME_NORM 1.0f
9
@@ -45,6 +46,10 @@
10
 #define MASK_5_1   _M(FL)|_M(FR)|_M(FC)|_M(LFE)|_M(SL)|_M(SR)|_M(RL)|_M(RR)
11
 #define MASK_7_1   _M(FL)|_M(FR)|_M(FC)|_M(LFE)|_M(SL)|_M(SR)|_M(RL)|_M(RR)
12
 
13
+#define BUFFER_SIZE 4096
14
+
15
+#define BUFFER_SIZE 4096
16
+#define MAX_TAPS 255
17
 
18
 struct channelmix {
19
    uint32_t src_chan;
20
@@ -69,11 +74,20 @@
21
 
22
    float freq;                 /* sample frequency */
23
    float lfe_cutoff;               /* in Hz, 0 is disabled */
24
-   uint32_t lr4_info[SPA_AUDIO_MAX_CHANNELS];
25
+   float fc_cutoff;                /* in Hz, 0 is disabled */
26
+   float rear_delay;               /* in ms, 0 is disabled */
27
+   float widen;                    /* stereo widen. 0 is disabled */
28
+   uint32_t hilbert_taps;              /* to phase shift, 0 disabled */
29
    struct lr4 lr4[SPA_AUDIO_MAX_CHANNELS];
30
 
31
-   void (*process) (struct channelmix *mix, uint32_t n_dst, void * SPA_RESTRICT dst[n_dst],
32
-           uint32_t n_src, const void * SPA_RESTRICT src[n_src], uint32_t n_samples);
33
+   float buffer[2][BUFFER_SIZE];
34
+   uint32_t pos[2];
35
+   uint32_t delay;
36
+   float taps[MAX_TAPS];
37
+   uint32_t n_taps;
38
+
39
+   void (*process) (struct channelmix *mix, void * SPA_RESTRICT dst[],
40
+           const void * SPA_RESTRICT src[], uint32_t n_samples);
41
    void (*set_volume) (struct channelmix *mix, float volume, bool mute,
42
            uint32_t n_channel_volumes, float *channel_volumes);
43
    void (*free) (struct channelmix *mix);
44
@@ -87,10 +101,9 @@
45
 #define channelmix_set_volume(mix,...) (mix)->set_volume(mix, __VA_ARGS__)
46
 #define channelmix_free(mix)       (mix)->free(mix)
47
 
48
-#define DEFINE_FUNCTION(name,arch)                 \
49
-void channelmix_##name##_##arch(struct channelmix *mix,            \
50
-       uint32_t n_dst, void * SPA_RESTRICT dst[n_dst],     \
51
-       uint32_t n_src, const void * SPA_RESTRICT src[n_src],   \
52
+#define DEFINE_FUNCTION(name,arch)                     \
53
+void channelmix_##name##_##arch(struct channelmix *mix,                \
54
+       void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], \
55
        uint32_t n_samples);
56
 
57
 #define CHANNELMIX_OPS_MAX_ALIGN 16
58
@@ -104,6 +117,7 @@
59
 DEFINE_FUNCTION(f32_2_4, c);
60
 DEFINE_FUNCTION(f32_2_3p1, c);
61
 DEFINE_FUNCTION(f32_2_5p1, c);
62
+DEFINE_FUNCTION(f32_2_7p1, c);
63
 DEFINE_FUNCTION(f32_5p1_2, c);
64
 DEFINE_FUNCTION(f32_5p1_3p1, c);
65
 DEFINE_FUNCTION(f32_5p1_4, c);
66
pipewire-0.3.47.tar.gz/spa/plugins/audioconvert/channelmix.c -> pipewire-0.3.48.tar.gz/spa/plugins/audioconvert/channelmix.c Changed
269
 
1
@@ -145,6 +145,7 @@
2
    struct spa_cpu *cpu;
3
    uint32_t quantum_limit;
4
 
5
+   enum spa_direction direction;
6
    struct spa_io_position *io_position;
7
 
8
    struct spa_hook_list hooks;
9
@@ -360,7 +361,7 @@
10
    if ((res = channelmix_init(&this->mix)) < 0)
11
        return res;
12
 
13
-   remap_volumes(this, src_info);
14
+   remap_volumes(this, this->direction == SPA_DIRECTION_INPUT ? src_info : dst_info);
15
    set_volume(this);
16
 
17
    emit_props_changed(this);
18
@@ -467,13 +468,21 @@
19
        case 8:
20
            param = spa_pod_builder_add_object(&b,
21
                SPA_TYPE_OBJECT_PropInfo, id,
22
+               SPA_PROP_INFO_name, SPA_POD_String("channelmix.disable"),
23
+               SPA_PROP_INFO_description, SPA_POD_String("Disable Channel mixing"),
24
+               SPA_PROP_INFO_type, SPA_POD_CHOICE_Bool(p->disabled),
25
+               SPA_PROP_INFO_params, SPA_POD_Bool(true));
26
+           break;
27
+       case 9:
28
+           param = spa_pod_builder_add_object(&b,
29
+               SPA_TYPE_OBJECT_PropInfo, id,
30
                SPA_PROP_INFO_name, SPA_POD_String("channelmix.normalize"),
31
                SPA_PROP_INFO_description, SPA_POD_String("Normalize Volumes"),
32
                SPA_PROP_INFO_type, SPA_POD_CHOICE_Bool(
33
                    SPA_FLAG_IS_SET(this->mix.options, CHANNELMIX_OPTION_NORMALIZE)),
34
                SPA_PROP_INFO_params, SPA_POD_Bool(true));
35
            break;
36
-       case 9:
37
+       case 10:
38
            param = spa_pod_builder_add_object(&b,
39
                SPA_TYPE_OBJECT_PropInfo, id,
40
                SPA_PROP_INFO_name, SPA_POD_String("channelmix.mix-lfe"),
41
@@ -482,7 +491,7 @@
42
                    SPA_FLAG_IS_SET(this->mix.options, CHANNELMIX_OPTION_MIX_LFE)),
43
                SPA_PROP_INFO_params, SPA_POD_Bool(true));
44
            break;
45
-       case 10:
46
+       case 11:
47
            param = spa_pod_builder_add_object(&b,
48
                SPA_TYPE_OBJECT_PropInfo, id,
49
                SPA_PROP_INFO_name, SPA_POD_String("channelmix.upmix"),
50
@@ -491,21 +500,49 @@
51
                    SPA_FLAG_IS_SET(this->mix.options, CHANNELMIX_OPTION_UPMIX)),
52
                SPA_PROP_INFO_params, SPA_POD_Bool(true));
53
            break;
54
-       case 11:
55
+       case 12:
56
            param = spa_pod_builder_add_object(&b,
57
                SPA_TYPE_OBJECT_PropInfo, id,
58
                SPA_PROP_INFO_name, SPA_POD_String("channelmix.lfe-cutoff"),
59
-               SPA_PROP_INFO_description, SPA_POD_String("LFE cutoff frequency"),
60
+               SPA_PROP_INFO_description, SPA_POD_String("LFE cutoff frequency (Hz)"),
61
                SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Float(
62
                    this->mix.lfe_cutoff, 0.0, 1000.0),
63
                SPA_PROP_INFO_params, SPA_POD_Bool(true));
64
            break;
65
-       case 12:
66
+       case 13:
67
            param = spa_pod_builder_add_object(&b,
68
                SPA_TYPE_OBJECT_PropInfo, id,
69
-               SPA_PROP_INFO_name, SPA_POD_String("channelmix.disable"),
70
-               SPA_PROP_INFO_description, SPA_POD_String("Disable Channel mixing"),
71
-               SPA_PROP_INFO_type, SPA_POD_CHOICE_Bool(p->disabled),
72
+               SPA_PROP_INFO_name, SPA_POD_String("channelmix.fc-cutoff"),
73
+               SPA_PROP_INFO_description, SPA_POD_String("FC cutoff frequency (Hz)"),
74
+               SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Float(
75
+                   this->mix.fc_cutoff, 0.0, 48000.0),
76
+               SPA_PROP_INFO_params, SPA_POD_Bool(true));
77
+           break;
78
+       case 14:
79
+           param = spa_pod_builder_add_object(&b,
80
+               SPA_TYPE_OBJECT_PropInfo, id,
81
+               SPA_PROP_INFO_name, SPA_POD_String("channelmix.rear-delay"),
82
+               SPA_PROP_INFO_description, SPA_POD_String("Rear channels delay (ms)"),
83
+               SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Float(
84
+                   this->mix.rear_delay, 0.0, 1000.0),
85
+               SPA_PROP_INFO_params, SPA_POD_Bool(true));
86
+           break;
87
+       case 15:
88
+           param = spa_pod_builder_add_object(&b,
89
+               SPA_TYPE_OBJECT_PropInfo, id,
90
+               SPA_PROP_INFO_name, SPA_POD_String("channelmix.stereo-widen"),
91
+               SPA_PROP_INFO_description, SPA_POD_String("Stereo widen"),
92
+               SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Float(
93
+                   this->mix.widen, 0.0, 1.0),
94
+               SPA_PROP_INFO_params, SPA_POD_Bool(true));
95
+           break;
96
+       case 16:
97
+           param = spa_pod_builder_add_object(&b,
98
+               SPA_TYPE_OBJECT_PropInfo, id,
99
+               SPA_PROP_INFO_name, SPA_POD_String("channelmix.hilbert-taps"),
100
+               SPA_PROP_INFO_description, SPA_POD_String("Taps for phase shift of rear"),
101
+               SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Int(
102
+                   this->mix.hilbert_taps, 0, MAX_TAPS),
103
                SPA_PROP_INFO_params, SPA_POD_Bool(true));
104
            break;
105
        default:
106
@@ -546,6 +583,8 @@
107
                0);
108
            spa_pod_builder_prop(&b, SPA_PROP_params, 0);
109
            spa_pod_builder_push_struct(&b, &f[1]);
110
+           spa_pod_builder_string(&b, "channelmix.disable");
111
+           spa_pod_builder_bool(&b, this->props.disabled);
112
            spa_pod_builder_string(&b, "channelmix.normalize");
113
            spa_pod_builder_bool(&b, SPA_FLAG_IS_SET(this->mix.options,
114
                        CHANNELMIX_OPTION_NORMALIZE));
115
@@ -557,8 +596,14 @@
116
                        CHANNELMIX_OPTION_UPMIX));
117
            spa_pod_builder_string(&b, "channelmix.lfe-cutoff");
118
            spa_pod_builder_float(&b, this->mix.lfe_cutoff);
119
-           spa_pod_builder_string(&b, "channelmix.disable");
120
-           spa_pod_builder_bool(&b, this->props.disabled);
121
+           spa_pod_builder_string(&b, "channelmix.fc-cutoff");
122
+           spa_pod_builder_float(&b, this->mix.fc_cutoff);
123
+           spa_pod_builder_string(&b, "channelmix.rear-delay");
124
+           spa_pod_builder_float(&b, this->mix.rear_delay);
125
+           spa_pod_builder_string(&b, "channelmix.stereo-widen");
126
+           spa_pod_builder_float(&b, this->mix.widen);
127
+           spa_pod_builder_string(&b, "channelmix.hilbert-taps");
128
+           spa_pod_builder_int(&b, this->mix.hilbert_taps);
129
            spa_pod_builder_pop(&b, &f[1]);
130
            param = spa_pod_builder_pop(&b, &f[0]);
131
            break;
132
@@ -584,23 +629,34 @@
133
 
134
 static int channelmix_set_param(struct impl *this, const char *k, const char *s)
135
 {
136
-   if (spa_streq(k, "channelmix.normalize"))
137
+   if (spa_streq(k, "channelmix.disable"))
138
+       this->props.disabled = spa_atob(s);
139
+   else if (spa_streq(k, "channelmix.normalize"))
140
        SPA_FLAG_UPDATE(this->mix.options, CHANNELMIX_OPTION_NORMALIZE, spa_atob(s));
141
    else if (spa_streq(k, "channelmix.mix-lfe"))
142
        SPA_FLAG_UPDATE(this->mix.options, CHANNELMIX_OPTION_MIX_LFE, spa_atob(s));
143
    else if (spa_streq(k, "channelmix.upmix"))
144
        SPA_FLAG_UPDATE(this->mix.options, CHANNELMIX_OPTION_UPMIX, spa_atob(s));
145
    else if (spa_streq(k, "channelmix.lfe-cutoff"))
146
-       this->mix.lfe_cutoff = atoi(s);
147
-   else if (spa_streq(k, "channelmix.disable"))
148
-       this->props.disabled = spa_atob(s);
149
-   return 0;
150
+       spa_atof(s, &this->mix.lfe_cutoff);
151
+   else if (spa_streq(k, "channelmix.fc-cutoff"))
152
+       spa_atof(s, &this->mix.fc_cutoff);
153
+   else if (spa_streq(k, "channelmix.rear-delay"))
154
+       spa_atof(s, &this->mix.rear_delay);
155
+   else if (spa_streq(k, "channelmix.stereo-widen"))
156
+       spa_atof(s, &this->mix.widen);
157
+   else if (spa_streq(k, "channelmix.hilbert-taps"))
158
+       spa_atou32(s, &this->mix.hilbert_taps, 0);
159
+   else
160
+       return 0;
161
+   return 1;
162
 }
163
 
164
 static int parse_prop_params(struct impl *this, struct spa_pod *params)
165
 {
166
    struct spa_pod_parser prs;
167
    struct spa_pod_frame f;
168
+   int changed = 0;
169
 
170
    spa_pod_parser_pod(&prs, params);
171
    if (spa_pod_parser_push_struct(&prs, &f) < 0)
172
@@ -633,9 +689,11 @@
173
            continue;
174
 
175
        spa_log_info(this->log, "key:'%s' val:'%s'", name, value);
176
-       channelmix_set_param(this, name, value);
177
+       changed += channelmix_set_param(this, name, value);
178
    }
179
-   return 0;
180
+   if (changed)
181
+       channelmix_init(&this->mix);
182
+   return changed;
183
 }
184
 
185
 static int apply_props(struct impl *this, const struct spa_pod *param)
186
@@ -714,7 +772,7 @@
187
        }
188
    }
189
    if (changed) {
190
-       struct port *port = GET_IN_PORT(this, 0);
191
+       struct port *port = GET_PORT(this, this->direction, 0);
192
        if (have_soft_volume)
193
            p->have_soft_volume = true;
194
        else if (have_channel_volume)
195
@@ -1292,8 +1350,7 @@
196
 }
197
 
198
 static int channelmix_process_control(struct impl *this, struct port *ctrlport,
199
-                     uint32_t n_dst, void * SPA_RESTRICT dst[n_dst],
200
-                     uint32_t n_src, const void * SPA_RESTRICT src[n_src],
201
+                     void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
202
                      uint32_t n_samples)
203
 {
204
    struct spa_pod_control *c, *prev = NULL;
205
@@ -1336,10 +1393,10 @@
206
        spa_log_trace_fp(this->log, "%p: process %d %d", this,
207
                c->offset, chunk);
208
 
209
-       channelmix_process(&this->mix, n_dst, dst, n_src, src, chunk);
210
-       for (i = 0; i < n_src; i++)
211
+       channelmix_process(&this->mix, dst, src, chunk);
212
+       for (i = 0; i < this->mix.src_chan; i++)
213
            s[i] += chunk;
214
-       for (i = 0; i < n_dst; i++)
215
+       for (i = 0; i < this->mix.dst_chan; i++)
216
            d[i] += chunk;
217
 
218
        avail_samples -= chunk;
219
@@ -1352,7 +1409,7 @@
220
     * remaining samples */
221
    spa_log_trace_fp(this->log, "%p: remain %d", this, avail_samples);
222
    if (avail_samples > 0)
223
-       channelmix_process(&this->mix, n_dst, dst, n_src, src, avail_samples);
224
+       channelmix_process(&this->mix, dst, src, avail_samples);
225
 
226
    return 1;
227
 }
228
@@ -1444,14 +1501,14 @@
229
        if (!is_passthrough) {
230
            if (ctrlport->ctrl != NULL) {
231
                /* if return value is 1, the sequence has been processed */
232
-               if (channelmix_process_control(this, ctrlport, n_dst_datas, dst_datas,
233
-                       n_src_datas, src_datas, n_samples) == 1) {
234
+               if (channelmix_process_control(this, ctrlport, dst_datas,
235
+                       src_datas, n_samples) == 1) {
236
                    ctrlio->status = SPA_STATUS_OK;
237
                    ctrlport->ctrl = NULL;
238
                }
239
            } else {
240
-               channelmix_process(&this->mix, n_dst_datas, dst_datas,
241
-                       n_src_datas, src_datas, n_samples);
242
+               channelmix_process(&this->mix, dst_datas,
243
+                       src_datas, n_samples);
244
            }
245
        }
246
    }
247
@@ -1571,6 +1628,8 @@
248
    props_reset(&this->props);
249
 
250
    this->mix.options = CHANNELMIX_OPTION_NORMALIZE;
251
+   this->mix.log = this->log;
252
+   this->mix.rear_delay = 12.0f;
253
 
254
    for (i = 0; info && i < info->n_items; i++) {
255
        const char *k = info->items[i].key;
256
@@ -1579,6 +1638,12 @@
257
            this->props.n_channels = parse_position(this->props.channel_map, s, strlen(s));
258
        else if (spa_streq(k, "clock.quantum-limit"))
259
            spa_atou32(s, &this->quantum_limit, 0);
260
+       else if (spa_streq(k, "factory.mode")) {
261
+           if (spa_streq(s, "merge"))
262
+               this->direction = SPA_DIRECTION_OUTPUT;
263
+           else
264
+               this->direction = SPA_DIRECTION_INPUT;
265
+       }
266
        else
267
            channelmix_set_param(this, k, s);
268
 
269
pipewire-0.3.47.tar.gz/spa/plugins/audioconvert/crossover.c -> pipewire-0.3.48.tar.gz/spa/plugins/audioconvert/crossover.c Changed
71
 
1
@@ -5,6 +5,9 @@
2
 
3
 #include "config.h"
4
 
5
+#include <float.h>
6
+#include <string.h>
7
+
8
 #include "crossover.h"
9
 
10
 void lr4_set(struct lr4 *lr4, enum biquad_type type, float freq)
11
@@ -16,9 +19,10 @@
12
    lr4->y2 = 0;
13
    lr4->z1 = 0;
14
    lr4->z2 = 0;
15
+   lr4->active = true;
16
 }
17
 
18
-void lr4_process(struct lr4 *lr4, float *data, int samples)
19
+void lr4_process(struct lr4 *lr4, float *dst, const float *src, const float vol, int samples)
20
 {
21
    float lx1 = lr4->x1;
22
    float lx2 = lr4->x2;
23
@@ -31,11 +35,22 @@
24
    float lb2 = lr4->bq.b2;
25
    float la1 = lr4->bq.a1;
26
    float la2 = lr4->bq.a2;
27
-
28
    int i;
29
+
30
+   if (vol == 0.0f) {
31
+       memset(dst, 0, samples * sizeof(float));
32
+       return;
33
+   } else if (!lr4->active) {
34
+       if (src != dst || vol != 1.0f) {
35
+           for (i = 0; i < samples; i++)
36
+               dst[i] = src[i] * vol;
37
+       }
38
+       return;
39
+   }
40
+
41
    for (i = 0; i < samples; i++) {
42
        float x, y, z;
43
-       x = data[i];
44
+       x = src[i];
45
        y = lb0*x + lb1*lx1 + lb2*lx2 - la1*ly1 - la2*ly2;
46
        z = lb0*y + lb1*ly1 + lb2*ly2 - la1*lz1 - la2*lz2;
47
        lx2 = lx1;
48
@@ -44,13 +59,14 @@
49
        ly1 = y;
50
        lz2 = lz1;
51
        lz1 = z;
52
-       data[i] = z;
53
+       dst[i] = z * vol;
54
    }
55
-
56
-   lr4->x1 = lx1;
57
-   lr4->x2 = lx2;
58
-   lr4->y1 = ly1;
59
-   lr4->y2 = ly2;
60
-   lr4->z1 = lz1;
61
-   lr4->z2 = lz2;
62
+#define F(x) (-FLT_MIN < (x) && (x) < FLT_MIN ? 0.0f : (x))
63
+   lr4->x1 = F(lx1);
64
+   lr4->x2 = F(lx2);
65
+   lr4->y1 = F(ly1);
66
+   lr4->y2 = F(ly2);
67
+   lr4->z1 = F(lz1);
68
+   lr4->z2 = F(lz2);
69
+#undef F
70
 }
71
pipewire-0.3.47.tar.gz/spa/plugins/audioconvert/crossover.h -> pipewire-0.3.48.tar.gz/spa/plugins/audioconvert/crossover.h Changed
23
 
1
@@ -6,6 +6,8 @@
2
 #ifndef CROSSOVER_H_
3
 #define CROSSOVER_H_
4
 
5
+#include <stdbool.h>
6
+
7
 #include "biquad.h"
8
 /* An LR4 filter is two biquads with the same parameters connected in series:
9
  *
10
@@ -19,10 +21,11 @@
11
    float x1, x2;
12
    float y1, y2;
13
    float z1, z2;
14
+   bool active;
15
 };
16
 
17
 void lr4_set(struct lr4 *lr4, enum biquad_type type, float freq);
18
 
19
-void lr4_process(struct lr4 *lr4, float *data, int samples);
20
+void lr4_process(struct lr4 *lr4, float *dst, const float *src, const float vol, int samples);
21
 
22
 #endif /* CROSSOVER_H_ */
23
pipewire-0.3.48.tar.gz/spa/plugins/audioconvert/delay.h Added
74
 
1
@@ -0,0 +1,72 @@
2
+/* Spa
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 DELAY_H
27
+#define DELAY_H
28
+
29
+#ifdef __cplusplus
30
+extern "C" {
31
+#endif
32
+
33
+static inline void delay_run(float *buffer, uint32_t *pos,
34
+       uint32_t n_buffer, uint32_t delay,
35
+       float *dst, const float *src, const float vol, uint32_t n_samples)
36
+{
37
+   uint32_t i;
38
+   uint32_t p = *pos;
39
+
40
+   for (i = 0; i < n_samples; i++) {
41
+       buffer[p] = src[i];
42
+       dst[i] = buffer[(p - delay) & (n_buffer-1)] * vol;
43
+       p = (p + 1) & (n_buffer-1);
44
+   }
45
+   *pos = p;
46
+}
47
+
48
+static inline void delay_convolve_run(float *buffer, uint32_t *pos,
49
+       uint32_t n_buffer, uint32_t delay,
50
+       const float *taps, uint32_t n_taps,
51
+       float *dst, const float *src, const float vol, uint32_t n_samples)
52
+{
53
+   uint32_t i, j;
54
+   uint32_t p = *pos;
55
+
56
+   for (i = 0; i < n_samples; i++) {
57
+       float sum = 0.0f;
58
+
59
+       buffer[p] = src[i];
60
+       for (j = 0; j < n_taps; j++)
61
+           sum += (taps[j] * buffer[((p - delay) - j) & (n_buffer-1)]);
62
+       dst[i] = sum * vol;
63
+
64
+       p = (p + 1) & (n_buffer-1);
65
+   }
66
+   *pos = p;
67
+}
68
+
69
+#ifdef __cplusplus
70
+}
71
+#endif
72
+
73
+#endif /* DELAY_H */
74
pipewire-0.3.48.tar.gz/spa/plugins/audioconvert/hilbert.h Added
71
 
1
@@ -0,0 +1,69 @@
2
+/* Hilbert function
3
+ *
4
+ * Copyright © 2021 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 HILBERT_H
27
+#define HILBERT_H
28
+
29
+#ifdef __cplusplus
30
+extern "C" {
31
+#endif
32
+
33
+#include <errno.h>
34
+#include <stddef.h>
35
+#include <math.h>
36
+
37
+static inline void blackman_window(float *taps, int n_taps)
38
+{
39
+   int n;
40
+   for (n = 0; n < n_taps; n++) {
41
+       float w = 2 * M_PI * n / (n_taps-1);
42
+       taps[n] = 0.3635819 - 0.4891775 * cos(w)
43
+           + 0.1365995 * cos(2 * w) - 0.0106411 * cos(3 * w);
44
+   }
45
+}
46
+
47
+static inline int hilbert_generate(float *taps, int n_taps)
48
+{
49
+   int i;
50
+
51
+   if ((n_taps & 1) == 0)
52
+       return -EINVAL;
53
+
54
+   for (i = 0; i < n_taps; i++) {
55
+       int k = -(n_taps / 2) + i;
56
+       if (k & 1) {
57
+           float pk = M_PI * k;
58
+           taps[i] *= (1.0f - cosf(pk)) / pk;
59
+       } else {
60
+           taps[i] = 0.0f;
61
+       }
62
+   }
63
+   return 0;
64
+}
65
+
66
+#ifdef __cplusplus
67
+} /* extern "C" */
68
+#endif
69
+
70
+#endif /* HILBERT_H */
71
pipewire-0.3.47.tar.gz/spa/plugins/audioconvert/merger.c -> pipewire-0.3.48.tar.gz/spa/plugins/audioconvert/merger.c Changed
23
 
1
@@ -386,10 +386,13 @@
2
 
3
    case SPA_PARAM_Props:
4
    {
5
+#if 0
6
        struct props *p = &this->props;
7
        struct spa_pod_frame f[2];
8
+#endif
9
 
10
        switch (result.index) {
11
+#if 0
12
        case 0:
13
            spa_pod_builder_push_object(&b, &f[0],
14
                                 SPA_TYPE_OBJECT_Props, id);
15
@@ -422,6 +425,7 @@
16
            spa_pod_builder_pop(&b, &f[1]);
17
            param = spa_pod_builder_pop(&b, &f[0]);
18
            break;
19
+#endif
20
        default:
21
            return 0;
22
        }
23
pipewire-0.3.47.tar.gz/spa/plugins/bluez5/bluez5-dbus.c -> pipewire-0.3.48.tar.gz/spa/plugins/bluez5/bluez5-dbus.c Changed
22
 
1
@@ -1469,9 +1469,17 @@
2
                dbus_message_iter_get_basic(&iter, &uuid);
3
 
4
                profile = spa_bt_profile_from_uuid(uuid);
5
-               if (profile && (device->profiles & profile) == 0) {
6
-                   spa_log_debug(monitor->log, "device %p: add UUID=%s", device, uuid);
7
-                   device->profiles |= profile;
8
+
9
+               /* Only add A2DP profiles if HSP/HFP backed is none.
10
+                * This allows BT device to connect instantly instead of waiting for
11
+                * profile timeout, because all available profiles are connected.
12
+                */
13
+               if (monitor->backend_selection != BACKEND_NONE || (monitor->backend_selection == BACKEND_NONE &&
14
+                       profile & (SPA_BT_PROFILE_A2DP_SINK | SPA_BT_PROFILE_A2DP_SOURCE))) {
15
+                   if (profile && (device->profiles & profile) == 0) {
16
+                       spa_log_debug(monitor->log, "device %p: add UUID=%s", device, uuid);
17
+                       device->profiles |= profile;
18
+                   }
19
                }
20
                dbus_message_iter_next(&iter);
21
            }
22
pipewire-0.3.47.tar.gz/spa/plugins/support/loop.c -> pipewire-0.3.48.tar.gz/spa/plugins/support/loop.c Changed
66
 
1
@@ -75,6 +75,7 @@
2
         struct spa_system *system;
3
 
4
    struct spa_list source_list;
5
+   struct spa_list destroy_list;
6
    struct spa_hook_list hooks_list;
7
 
8
    int poll_fd;
9
@@ -325,6 +326,14 @@
10
        impl->thread = 0;
11
 }
12
 
13
+static inline void process_destroy(struct impl *impl)
14
+{
15
+   struct source_impl *source, *tmp;
16
+   spa_list_for_each_safe(source, tmp, &impl->destroy_list, link)
17
+       free(source);
18
+   spa_list_init(&impl->destroy_list);
19
+}
20
+
21
 static int loop_iterate(void *object, int timeout)
22
 {
23
    struct impl *impl = object;
24
@@ -354,11 +363,14 @@
25
    }
26
    for (i = 0; i < nfds; i++) {
27
        struct spa_source *s = ep[i].data;
28
-       if (SPA_LIKELY(s && s->rmask)) {
29
+       if (SPA_LIKELY(s && s->rmask && s->loop)) {
30
            s->priv = NULL;
31
            s->func(s);
32
        }
33
    }
34
+   if (SPA_UNLIKELY(!spa_list_is_empty(&impl->destroy_list)))
35
+       process_destroy(impl);
36
+
37
    return nfds;
38
 }
39
 
40
@@ -712,7 +724,7 @@
41
        spa_system_close(impl->impl->system, source->fd);
42
        source->fd = -1;
43
    }
44
-   free(source);
45
+   spa_list_insert(&impl->impl->destroy_list, &impl->link);
46
 }
47
 
48
 static const struct spa_loop_methods impl_loop = {
49
@@ -783,6 +795,8 @@
50
    spa_list_consume(source, &impl->source_list, link)
51
        loop_destroy_source(impl, &source->source);
52
 
53
+   process_destroy(impl);
54
+
55
    spa_system_close(impl->system, impl->ack_fd);
56
    spa_system_close(impl->system, impl->poll_fd);
57
 
58
@@ -844,6 +858,7 @@
59
    impl->poll_fd = res;
60
 
61
    spa_list_init(&impl->source_list);
62
+   spa_list_init(&impl->destroy_list);
63
    spa_hook_list_init(&impl->hooks_list);
64
 
65
    impl->buffer_data = SPA_PTR_ALIGN(impl->buffer_mem, MAX_ALIGN, uint8_t);
66
pipewire-0.3.47.tar.gz/src/daemon/client-rt.conf.in -> pipewire-0.3.48.tar.gz/src/daemon/client-rt.conf.in Changed
10
 
1
@@ -85,4 +85,8 @@
2
     #channelmix.mix-lfe    = true
3
     #channelmix.upmix      = false
4
     #channelmix.lfe-cutoff = 0
5
+    #channelmix.fc-cutoff  = 0
6
+    #channelmix.rear-delay = 12.0
7
+    #channelmix.stereo-widen = 0.0
8
+    #channelmix.hilbert-taps = 0
9
 }
10
pipewire-0.3.47.tar.gz/src/daemon/client.conf.in -> pipewire-0.3.48.tar.gz/src/daemon/client.conf.in Changed
10
 
1
@@ -75,4 +75,8 @@
2
     #channelmix.mix-lfe    = false
3
     #channelmix.upmix      = false
4
     #channelmix.lfe-cutoff = 0
5
+    #channelmix.fc-cutoff  = 0
6
+    #channelmix.rear-delay = 12.0
7
+    #channelmix.stereo-widen = 0.0
8
+    #channelmix.hilbert-taps = 0
9
 }
10
pipewire-0.3.47.tar.gz/src/daemon/filter-chain/demonic.conf -> pipewire-0.3.48.tar.gz/src/daemon/filter-chain/demonic.conf Changed
23
 
1
@@ -46,8 +46,7 @@
2
             #audio.format    = F32
3
             #audio.rate      = 48000
4
             audio.channels   = 2
5
-            #audio.position  = [ FL FR ]
6
-            node.name        = "filter-chain-demonic"
7
+            audio.position   = [ FL FR ]
8
             node.description = "Demonic example"
9
             media.name       = "Demonic example"
10
             filter.graph = {
11
@@ -89,9 +88,11 @@
12
                 outputs = [ "rev2:Out L" ]
13
             }
14
             capture.props = {
15
+                node.name        = "effect_input.filter-chain-demonic"
16
                 #media.class = Audio/Sink
17
             }
18
             playback.props = {
19
+                node.name        = "effect_output.filter-chain-demonic"
20
                 #media.class = Audio/Source
21
             }
22
         }
23
pipewire-0.3.47.tar.gz/src/daemon/filter-chain/duplicate-FL.conf -> pipewire-0.3.48.tar.gz/src/daemon/filter-chain/duplicate-FL.conf Changed
22
 
1
@@ -6,7 +6,6 @@
2
 context.modules = [
3
     { name = libpipewire-module-filter-chain
4
         args = {
5
-            node.name        = "remap-FL-to-FL-FR"
6
             node.description = "Remap example"
7
             media.name       = "Remap example"
8
             filter.graph = {
9
@@ -37,10 +36,12 @@
10
                 outputs = [ "copyOL:Out" "copyOR:Out" ]
11
             }
12
             capture.props = {
13
+                node.name        = "remap_input.remap-FL-to-FL-FR"
14
                 audio.position  = [ FL ]
15
                 stream.dont-remix = true
16
             }
17
             playback.props = {
18
+                node.name        = "remap_output.remap-FL-to-FL-FR"
19
                 audio.position  = [ FL FR ]
20
             }
21
         }
22
pipewire-0.3.47.tar.gz/src/daemon/filter-chain/sink-dolby-surround.conf -> pipewire-0.3.48.tar.gz/src/daemon/filter-chain/sink-dolby-surround.conf Changed
23
 
1
@@ -26,7 +26,6 @@
2
 
3
     { name = libpipewire-module-filter-chain
4
         args = {
5
-            node.name        = "effect_output.dolby_surround"
6
             node.description = "Dolby Surround Sink"
7
             media.name       = "Dolby Surround Sink"
8
             filter.graph = {
9
@@ -51,11 +50,13 @@
10
                 outputs = [ "enc:Lt" "enc:Rt" ]
11
             }
12
             capture.props = {
13
+                node.name      = "effect_input.dolby_surround"
14
                 media.class    = Audio/Sink
15
                 audio.channels = 6
16
                 audio.position = [ FL FR FC LFE SL SR ]
17
             }
18
             playback.props = {
19
+                node.name      = "effect_output.dolby_surround"
20
                 node.passive   = true
21
                 audio.channels = 2
22
                 audio.position = [ FL FR ]
23
pipewire-0.3.47.tar.gz/src/daemon/filter-chain/sink-eq6.conf -> pipewire-0.3.48.tar.gz/src/daemon/filter-chain/sink-eq6.conf Changed
21
 
1
@@ -26,7 +26,6 @@
2
 
3
     { name = libpipewire-module-filter-chain
4
         args = {
5
-            node.name        = "effect_output.eq6"
6
             node.description = "Equalizer Sink"
7
             media.name       = "Equalizer Sink"
8
             filter.graph = {
9
@@ -77,9 +76,11 @@
10
                 ]
11
             }
12
             capture.props = {
13
+                node.name   = "effect_input.eq6"
14
                 media.class = Audio/Sink
15
             }
16
             playback.props = {
17
+                node.name   = "effect_output.eq6"
18
                 node.passive = true
19
             }
20
         }
21
pipewire-0.3.47.tar.gz/src/daemon/filter-chain/sink-matrix-spatialiser.conf -> pipewire-0.3.48.tar.gz/src/daemon/filter-chain/sink-matrix-spatialiser.conf Changed
31
 
1
@@ -27,7 +27,6 @@
2
 
3
     { name = libpipewire-module-filter-chain
4
         args = {
5
-            node.name        = "effect_output.matrix_spatialiser"
6
             node.description = "Matrix Spatialiser"
7
             media.name       = "Matrix Spatialiser"
8
             filter.graph = {
9
@@ -45,16 +44,15 @@
10
                 inputs  = [ "matrix:Input L" "matrix:Input R" ]
11
                 outputs = [ "matrix:Output L" "matrix:Output R" ]
12
             }
13
+            audio.channels = 2
14
+            audio.position = [ FL FR ]
15
             capture.props = {
16
+                node.name      = "effect_input.matrix_spatialiser"
17
                 media.class    = Audio/Sink
18
-                audio.channels = 2
19
-                audio.position = [ FL FR ]
20
             }
21
             playback.props = {
22
-                #media.class   = Audio/Source
23
-                #node.passive  = true
24
-                audio.channels = 2
25
-                audio.position = [ FL FR ]
26
+                node.name      = "effect_output.matrix_spatialiser"
27
+                node.passive   = true
28
             }
29
         }
30
     }
31
pipewire-0.3.47.tar.gz/src/daemon/filter-chain/sink-virtual-surround-5.1-kemar.conf -> pipewire-0.3.48.tar.gz/src/daemon/filter-chain/sink-virtual-surround-5.1-kemar.conf Changed
23
 
1
@@ -26,7 +26,6 @@
2
 
3
     { name = libpipewire-module-filter-chain
4
         args = {
5
-            node.name        = "effect_output.virtual-surround-5.1-kemar"
6
             node.description = "Virtual Surround Sink"
7
             media.name       = "Virtual Surround Sink"
8
             filter.graph = {
9
@@ -182,11 +181,13 @@
10
 
11
             }
12
             capture.props = {
13
+                node.name      = "effect_input.virtual-surround-5.1-kemar"
14
                 media.class    = Audio/Sink
15
                 audio.channels = 6
16
                 audio.position = [ FL FR FC LFE SL SR]
17
             }
18
             playback.props = {
19
+                node.name      = "effect_output.virtual-surround-5.1-kemar"
20
                 node.passive   = true
21
                 audio.channels = 2
22
                 audio.position = [ FL FR ]
23
pipewire-0.3.47.tar.gz/src/daemon/filter-chain/sink-virtual-surround-7.1-hesuvi.conf -> pipewire-0.3.48.tar.gz/src/daemon/filter-chain/sink-virtual-surround-7.1-hesuvi.conf Changed
23
 
1
@@ -26,7 +26,6 @@
2
 
3
     { name = libpipewire-module-filter-chain
4
         args = {
5
-            node.name        = "effect_output.virtual-surround-7.1-hesuvi"
6
             node.description = "Virtual Surround Sink"
7
             media.name       = "Virtual Surround Sink"
8
             filter.graph = {
9
@@ -106,11 +105,13 @@
10
                 outputs = [ "mixL:Out" "mixR:Out" ]
11
             }
12
             capture.props = {
13
+                node.name      = "effect_input.virtual-surround-7.1-hesuvi"
14
                 media.class    = Audio/Sink
15
                 audio.channels = 8
16
                 audio.position = [ FL FR FC LFE RL RR SL SR ]
17
             }
18
             playback.props = {
19
+                node.name      = "effect_output.virtual-surround-7.1-hesuvi"
20
                 node.passive   = true
21
                 audio.channels = 2
22
                 audio.position = [ FL FR ]
23
pipewire-0.3.47.tar.gz/src/daemon/filter-chain/source-rnnoise.conf -> pipewire-0.3.48.tar.gz/src/daemon/filter-chain/source-rnnoise.conf Changed
23
 
1
@@ -26,7 +26,6 @@
2
 
3
     { name = libpipewire-module-filter-chain
4
         args = {
5
-            node.name        = "effect_input.rnnoise"
6
             node.description = "Noise Canceling source"
7
             media.name       = "Noise Canceling source"
8
             filter.graph = {
9
@@ -42,10 +41,13 @@
10
                     }
11
                 ]
12
             }
13
+            audio.position = [ FL FR ]
14
             capture.props = {
15
+                node.name = "effect_input.rnnoise"
16
                 node.passive = true
17
             }
18
             playback.props = {
19
+                node.name = "effect_output.rnnoise"
20
                 media.class = Audio/Source
21
             }
22
         }
23
pipewire-0.3.47.tar.gz/src/daemon/minimal.conf.in -> pipewire-0.3.48.tar.gz/src/daemon/minimal.conf.in Changed
75
 
1
@@ -20,7 +20,7 @@
2
     #mem.mlock-all                         = false
3
     #clock.power-of-two-quantum            = true
4
     #log.level                             = 2
5
-    #cpu.zero.denormals                    = true
6
+    #cpu.zero.denormals                    = false
7
 
8
     core.daemon = true              # listening for socket connections
9
     core.name   = pipewire-0        # core name and socket name
10
@@ -206,6 +206,10 @@
11
             #channelmix.mix-lfe     = false
12
             #channelmix.upmix       = false
13
             #channelmix.lfe-cutoff  = 0
14
+            #channelmix.fc-cutoff  = 0
15
+            #channelmix.rear-delay  = 12.0
16
+            #channelmix.stereo-widen = 0.0
17
+            #channelmix.hilbert-taps = 0
18
             channelmix.disable     = true
19
             #node.param.Props      = {
20
             #    params = [
21
@@ -261,6 +265,10 @@
22
             #channelmix.mix-lfe    = false
23
             #channelmix.upmix      = false
24
             #channelmix.lfe-cutoff = 0
25
+            #channelmix.fc-cutoff  = 0
26
+            #channelmix.rear-delay = 12.0
27
+            #channelmix.stereo-widen = 0.0
28
+            #channelmix.hilbert-taps = 0
29
             channelmix.disable     = true
30
             #node.param.Props      = {
31
             #    params = [
32
@@ -286,6 +294,42 @@
33
             #}
34
         }
35
     }
36
+    # This creates a new Source node. It will have input ports
37
+    # that you can link, to provide audio for this source.
38
+    #{ factory = adapter
39
+    #    args = {
40
+    #        factory.name     = support.null-audio-sink
41
+    #        node.name        = "my-mic"
42
+    #        node.description = "Microphone"
43
+    #        media.class      = "Audio/Source/Virtual"
44
+    #        audio.position   = "FL,FR"
45
+    #        adapter.auto-port-config = {
46
+    #            mode = dsp
47
+    #            monitor = true
48
+    #            position = preserve   # unknown, aux, preserve
49
+    #        }
50
+    #    }
51
+    #}
52
+    # This creates a new link between the source and the virtual
53
+    # source ports.
54
+    #{ factory = link-factory
55
+    #    args = {
56
+    #        link.output.node = system
57
+    #        link.output.port = capture_1
58
+    #        link.input.node  = my-mic
59
+    #        link.input.port  = input_FL
60
+    #        link.passive     = true
61
+    #    }
62
+    #}
63
+    #{ factory = link-factory
64
+    #    args = {
65
+    #        link.output.node = system
66
+    #        link.output.port = capture_2
67
+    #        link.input.node  = my-mic
68
+    #        link.input.port  = input_FR
69
+    #        link.passive     = true
70
+    #    }
71
+    #}
72
 ]
73
 
74
 context.exec = [
75
pipewire-0.3.47.tar.gz/src/daemon/pipewire-pulse.conf.in -> pipewire-0.3.48.tar.gz/src/daemon/pipewire-pulse.conf.in Changed
12
 
1
@@ -85,6 +85,10 @@
2
     #channelmix.mix-lfe    = false
3
     #channelmix.upmix      = false
4
     #channelmix.lfe-cutoff = 0
5
+    #channelmix.fc-cutoff  = 0
6
+    #channelmix.rear-delay = 12.0
7
+    #channelmix.stereo-widen = 0.0
8
+    #channelmix.hilbert-taps = 0
9
 }
10
 
11
 # client/stream specific properties
12
pipewire-0.3.47.tar.gz/src/daemon/pipewire.conf.in -> pipewire-0.3.48.tar.gz/src/daemon/pipewire.conf.in Changed
10
 
1
@@ -20,7 +20,7 @@
2
     #mem.mlock-all                         = false
3
     #clock.power-of-two-quantum            = true
4
     #log.level                             = 2
5
-    #cpu.zero.denormals                    = true
6
+    #cpu.zero.denormals                    = false
7
 
8
     core.daemon = true              # listening for socket connections
9
     core.name   = pipewire-0        # core name and socket name
10
pipewire-0.3.47.tar.gz/src/modules/meson.build -> pipewire-0.3.48.tar.gz/src/modules/meson.build Changed
18
 
1
@@ -197,6 +197,7 @@
2
     'module-protocol-native/portal-screencast.c',
3
     'module-protocol-native/protocol-native.c',
4
     'module-protocol-native/v0/protocol-native.c',
5
+    'module-protocol-native/protocol-footer.c',
6
     'module-protocol-native/connection.c' ],
7
   include_directories : [configinc],
8
   install : true,
9
@@ -489,7 +490,7 @@
10
   install : true,
11
   install_dir : modules_install_dir,
12
   install_rpath: modules_install_dir,
13
-  dependencies : [mathlib, dl_lib, rt_lib, pipewire_dep, x11_dep, canberra_dep],
14
+  dependencies : [mathlib, dl_lib, rt_lib, pipewire_dep, x11_dep, xfixes_dep, canberra_dep],
15
 )
16
 endif
17
 summary({'x11-bell': build_module_x11_bell}, bool_yn: true, section: 'Optional Modules')
18
pipewire-0.3.47.tar.gz/src/modules/module-client-device/protocol-native.c -> pipewire-0.3.48.tar.gz/src/modules/module-client-device/protocol-native.c Changed
10
 
1
@@ -32,7 +32,7 @@
2
 
3
 #include <pipewire/extensions/protocol-native.h>
4
 
5
-#define MAX_DICT   256
6
+#define MAX_DICT   1024
7
 #define MAX_PARAM_INFO 128
8
 
9
 static inline void push_item(struct spa_pod_builder *b, const struct spa_dict_item *item)
10
pipewire-0.3.47.tar.gz/src/modules/module-client-node/client-node.c -> pipewire-0.3.48.tar.gz/src/modules/module-client-node/client-node.c Changed
73
 
1
@@ -33,6 +33,7 @@
2
 #include <spa/node/node.h>
3
 #include <spa/node/utils.h>
4
 #include <spa/pod/filter.h>
5
+#include <spa/pod/dynamic.h>
6
 #include <spa/pod/parser.h>
7
 #include <spa/debug/types.h>
8
 
9
@@ -293,7 +294,7 @@
10
 {
11
    struct node *this = object;
12
    uint8_t buffer[1024];
13
-   struct spa_pod_builder b = { 0 };
14
+   struct spa_pod_dynamic_builder b;
15
    struct spa_result_node_params result;
16
    uint32_t count = 0;
17
    bool found = false;
18
@@ -321,14 +322,15 @@
19
        if (result.index < start)
20
            continue;
21
 
22
-       spa_pod_builder_init(&b, buffer, sizeof(buffer));
23
-       if (spa_pod_filter(&b, &result.param, param, filter) != 0)
24
-           continue;
25
-
26
-       pw_log_debug("%p: %d param %u", this, seq, result.index);
27
-       spa_node_emit_result(&this->hooks, seq, 0, SPA_RESULT_TYPE_NODE_PARAMS, &result);
28
+       spa_pod_dynamic_builder_init(&b, buffer, sizeof(buffer), 4096);
29
+       if (spa_pod_filter(&b.b, &result.param, param, filter) == 0) {
30
+           pw_log_debug("%p: %d param %u", this, seq, result.index);
31
+           spa_node_emit_result(&this->hooks, seq, 0, SPA_RESULT_TYPE_NODE_PARAMS, &result);
32
+           count++;
33
+       }
34
+       spa_pod_dynamic_builder_clean(&b);
35
 
36
-       if (++count == num)
37
+       if (count == num)
38
            break;
39
    }
40
    return found ? 0 : -ENOENT;
41
@@ -563,7 +565,7 @@
42
    struct node *this = object;
43
    struct port *port;
44
    uint8_t buffer[1024];
45
-   struct spa_pod_builder b = { 0 };
46
+   struct spa_pod_dynamic_builder b;
47
    struct spa_result_node_params result;
48
    uint32_t count = 0;
49
    bool found = false;
50
@@ -597,14 +599,15 @@
51
        if (result.index < start)
52
            continue;
53
 
54
-       spa_pod_builder_init(&b, buffer, sizeof(buffer));
55
-       if (spa_pod_filter(&b, &result.param, param, filter) < 0)
56
-           continue;
57
-
58
-       pw_log_debug("%p: %d param %u", this, seq, result.index);
59
-       spa_node_emit_result(&this->hooks, seq, 0, SPA_RESULT_TYPE_NODE_PARAMS, &result);
60
+       spa_pod_dynamic_builder_init(&b, buffer, sizeof(buffer), 4096);
61
+       if (spa_pod_filter(&b.b, &result.param, param, filter) == 0) {
62
+           pw_log_debug("%p: %d param %u", this, seq, result.index);
63
+           spa_node_emit_result(&this->hooks, seq, 0, SPA_RESULT_TYPE_NODE_PARAMS, &result);
64
+           count++;
65
+       }
66
+       spa_pod_dynamic_builder_clean(&b);
67
 
68
-       if (++count == num)
69
+       if (count == num)
70
            break;
71
    }
72
    return found ? 0 : -ENOENT;
73
pipewire-0.3.47.tar.gz/src/modules/module-client-node/protocol-native.c -> pipewire-0.3.48.tar.gz/src/modules/module-client-node/protocol-native.c Changed
12
 
1
@@ -33,8 +33,8 @@
2
 #include <pipewire/extensions/protocol-native.h>
3
 #include <pipewire/extensions/client-node.h>
4
 
5
-#define MAX_DICT   256
6
-#define MAX_PARAMS 128
7
+#define MAX_DICT   1024
8
+#define MAX_PARAMS 4096
9
 #define MAX_PARAM_INFO 128
10
 #define MAX_BUFFERS    64
11
 #define MAX_METAS  16u
12
pipewire-0.3.47.tar.gz/src/modules/module-client-node/remote-node.c -> pipewire-0.3.48.tar.gz/src/modules/module-client-node/remote-node.c Changed
79
 
1
@@ -31,6 +31,7 @@
2
 #include <sys/mman.h>
3
 
4
 #include <spa/pod/parser.h>
5
+#include <spa/pod/dynamic.h>
6
 #include <spa/node/utils.h>
7
 #include <spa/utils/result.h>
8
 #include <spa/debug/types.h>
9
@@ -301,7 +302,7 @@
10
    if (change_mask & PW_CLIENT_NODE_UPDATE_PARAMS) {
11
        uint32_t i, idx, id;
12
        uint8_t buf[4096];
13
-       struct spa_pod_builder b = { 0 };
14
+       struct spa_pod_dynamic_builder b;
15
 
16
        for (i = 0; i < node->info.n_params; i++) {
17
            struct spa_pod *param;
18
@@ -311,14 +312,17 @@
19
                continue;
20
 
21
            for (idx = 0;;) {
22
-               spa_pod_builder_init(&b, buf, sizeof(buf));
23
-                           if (spa_node_enum_params_sync(node->node,
24
-                           id, &idx,
25
-                           NULL, &param, &b) != 1)
26
-                                   break;
27
+               spa_pod_dynamic_builder_init(&b, buf, sizeof(buf), 4096);
28
 
29
-               params = realloc(params, sizeof(struct spa_pod *) * (n_params + 1));
30
-               params[n_params++] = spa_pod_copy(param);
31
+                           res = spa_node_enum_params_sync(node->node,
32
+                           id, &idx, NULL, &param, &b.b);
33
+               if (res == 1) {
34
+                   params = realloc(params, sizeof(struct spa_pod *) * (n_params + 1));
35
+                   params[n_params++] = spa_pod_copy(param);
36
+               }
37
+               spa_pod_dynamic_builder_clean(&b);
38
+               if (res != 1)
39
+                                   break;
40
            }
41
                 }
42
    }
43
@@ -356,7 +360,7 @@
44
    if (change_mask & PW_CLIENT_NODE_PORT_UPDATE_PARAMS) {
45
        uint32_t i, idx, id;
46
        uint8_t buf[4096];
47
-       struct spa_pod_builder b = { 0 };
48
+       struct spa_pod_dynamic_builder b;
49
 
50
        for (i = 0; i < port->info.n_params; i++) {
51
            struct spa_pod *param;
52
@@ -366,15 +370,20 @@
53
                continue;
54
 
55
            for (idx = 0;;) {
56
-               spa_pod_builder_init(&b, buf, sizeof(buf));
57
-                           if (spa_node_port_enum_params_sync(port->node->node,
58
+               spa_pod_dynamic_builder_init(&b, buf, sizeof(buf), 4096);
59
+
60
+                           res = spa_node_port_enum_params_sync(port->node->node,
61
                            port->direction, port->port_id,
62
-                           id, &idx,
63
-                           NULL, &param, &b) != 1)
64
+                           id, &idx, NULL, &param, &b.b);
65
+               if (res == 1) {
66
+                   params = realloc(params, sizeof(struct spa_pod *) * (n_params + 1));
67
+                   params[n_params++] = spa_pod_copy(param);
68
+               }
69
+               spa_pod_dynamic_builder_clean(&b);
70
+
71
+               if (res != 1)
72
                                    break;
73
 
74
-               params = realloc(params, sizeof(struct spa_pod *) * (n_params + 1));
75
-               params[n_params++] = spa_pod_copy(param);
76
            }
77
                 }
78
    }
79
pipewire-0.3.47.tar.gz/src/modules/module-echo-cancel.c -> pipewire-0.3.48.tar.gz/src/modules/module-echo-cancel.c Changed
108
 
1
@@ -151,7 +151,6 @@
2
    struct pw_context *context;
3
 
4
    struct pw_impl_module *module;
5
-   struct pw_work_queue *work;
6
    struct spa_hook module_listener;
7
 
8
    uint32_t id;
9
@@ -194,7 +193,6 @@
10
    unsigned int sink_ready:1;
11
 
12
    unsigned int do_disconnect:1;
13
-   unsigned int unloading:1;
14
 
15
    uint32_t max_buffer_size;
16
    uint32_t buffer_delay;
17
@@ -203,19 +201,6 @@
18
    struct spa_plugin_loader *loader;
19
 };
20
 
21
-static void do_unload_module(void *obj, void *data, int res, uint32_t id)
22
-{
23
-   struct impl *impl = data;
24
-   pw_impl_module_destroy(impl->module);
25
-}
26
-static void unload_module(struct impl *impl)
27
-{
28
-   if (!impl->unloading) {
29
-       impl->unloading = true;
30
-       pw_work_queue_add(impl->work, impl, 0, do_unload_module, impl);
31
-   }
32
-}
33
-
34
 static void process(struct impl *impl)
35
 {
36
    struct pw_buffer *cout;
37
@@ -774,7 +759,7 @@
38
            id, seq, res, spa_strerror(res), message);
39
 
40
    if (id == PW_ID_CORE && res == -EPIPE)
41
-       unload_module(impl);
42
+       pw_impl_module_schedule_destroy(impl->module);
43
 }
44
 
45
 static const struct pw_core_events core_events = {
46
@@ -787,7 +772,7 @@
47
    struct impl *impl = d;
48
    spa_hook_remove(&impl->core_listener);
49
    impl->core = NULL;
50
-   unload_module(impl);
51
+   pw_impl_module_schedule_destroy(impl->module);
52
 }
53
 
54
 static const struct pw_proxy_events core_proxy_events = {
55
@@ -812,9 +797,6 @@
56
    pw_properties_free(impl->source_props);
57
    pw_properties_free(impl->sink_props);
58
 
59
-   if (impl->work)
60
-       pw_work_queue_cancel(impl->work, impl, SPA_ID_INVALID);
61
-
62
    for (i = 0; i < impl->info.channels; i++) {
63
        if (impl->rec_buffer[i])
64
            free(impl->rec_buffer[i]);
65
@@ -830,7 +812,6 @@
66
 static void module_destroy(void *data)
67
 {
68
    struct impl *impl = data;
69
-   impl->unloading = true;
70
    spa_hook_remove(&impl->module_listener);
71
    impl_destroy(impl);
72
 }
73
@@ -931,12 +912,6 @@
74
    impl->id = id;
75
    impl->module = module;
76
    impl->context = context;
77
-   impl->work = pw_context_get_work_queue(context);
78
-   if (impl->work == NULL) {
79
-       res = -errno;
80
-       pw_log_error( "can't create work queue: %m");
81
-       goto error;
82
-   }
83
 
84
    if (pw_properties_get(props, PW_KEY_NODE_GROUP) == NULL)
85
        pw_properties_setf(props, PW_KEY_NODE_GROUP, "echo-cancel-%u", id);
86
@@ -1020,14 +995,16 @@
87
    else
88
        aec_props = pw_properties_new(NULL, NULL);
89
 
90
-   if (spa_audio_aec_init(impl->aec, &aec_props->dict, &impl->info)) {
91
-       pw_log_error("codec plugin %s create failed", impl->aec->name);
92
-       res = -ENOENT;
93
-       goto error;
94
-   }
95
+   res = spa_audio_aec_init(impl->aec, &aec_props->dict, &impl->info);
96
 
97
    pw_properties_free(aec_props);
98
 
99
+   if (res < 0) {
100
+       pw_log_error("codec plugin %s create failed: %s", impl->aec->name,
101
+               spa_strerror(res));
102
+       goto error;
103
+   }
104
+
105
    if (impl->aec->latency) {
106
        unsigned int num, denom, req_num, req_denom;
107
        unsigned int factor = 0;
108
pipewire-0.3.47.tar.gz/src/modules/module-example-sink.c -> pipewire-0.3.48.tar.gz/src/modules/module-example-sink.c Changed
13
 
1
@@ -399,11 +399,6 @@
2
    impl->module = module;
3
    impl->context = context;
4
    impl->work = pw_context_get_work_queue(context);
5
-   if (impl->work == NULL) {
6
-       res = -errno;
7
-       pw_log_error( "can't get work queue: %m");
8
-       goto error;
9
-   }
10
 
11
    if (pw_properties_get(props, PW_KEY_NODE_GROUP) == NULL)
12
        pw_properties_set(props, PW_KEY_NODE_GROUP, "pipewire.dummy");
13
pipewire-0.3.47.tar.gz/src/modules/module-example-source.c -> pipewire-0.3.48.tar.gz/src/modules/module-example-source.c Changed
13
 
1
@@ -419,11 +419,6 @@
2
    impl->module = module;
3
    impl->context = context;
4
    impl->work = pw_context_get_work_queue(context);
5
-   if (impl->work == NULL) {
6
-       res = -errno;
7
-       pw_log_error( "can't get work queue: %m");
8
-       goto error;
9
-   }
10
 
11
    if (pw_properties_get(props, PW_KEY_NODE_GROUP) == NULL)
12
        pw_properties_set(props, PW_KEY_NODE_GROUP, "pipewire.dummy");
13
pipewire-0.3.47.tar.gz/src/modules/module-filter-chain.c -> pipewire-0.3.48.tar.gz/src/modules/module-filter-chain.c Changed
460
 
1
@@ -39,6 +39,7 @@
2
 #include <spa/utils/string.h>
3
 #include <spa/utils/json.h>
4
 #include <spa/param/profiler.h>
5
+#include <spa/pod/dynamic.h>
6
 #include <spa/debug/pod.h>
7
 
8
 #include <pipewire/utils.h>
9
@@ -107,8 +108,6 @@
10
 #include <pipewire/pipewire.h>
11
 
12
 #define MAX_HNDL 64
13
-#define MAX_PORTS 64
14
-#define MAX_CONTROLS 256
15
 #define MAX_SAMPLES 8192
16
 
17
 static float silence_data[MAX_SAMPLES];
18
@@ -136,11 +135,11 @@
19
    uint32_t n_output;
20
    uint32_t n_control;
21
    uint32_t n_notify;
22
-   unsigned long input[MAX_PORTS];
23
-   unsigned long output[MAX_PORTS];
24
-   unsigned long control[MAX_PORTS];
25
-   unsigned long notify[MAX_PORTS];
26
-   float default_control[MAX_PORTS];
27
+   unsigned long *input;
28
+   unsigned long *output;
29
+   unsigned long *control;
30
+   unsigned long *notify;
31
+   float *default_control;
32
 };
33
 
34
 struct port {
35
@@ -167,10 +166,10 @@
36
    char name[256];
37
    char *config;
38
 
39
-   struct port input_port[MAX_PORTS];
40
-   struct port output_port[MAX_PORTS];
41
-   struct port control_port[MAX_PORTS];
42
-   struct port notify_port[MAX_PORTS];
43
+   struct port *input_port;
44
+   struct port *output_port;
45
+   struct port *control_port;
46
+   struct port *notify_port;
47
 
48
    uint32_t n_hndl;
49
    void *hndl[MAX_HNDL];
50
@@ -207,23 +206,22 @@
51
    struct spa_list link_list;
52
 
53
    uint32_t n_input;
54
-   struct graph_port input[MAX_PORTS];
55
+   struct graph_port *input;
56
 
57
    uint32_t n_output;
58
-   struct graph_port output[MAX_PORTS];
59
+   struct graph_port *output;
60
 
61
    uint32_t n_hndl;
62
-   struct graph_hndl hndl[MAX_HNDL];
63
+   struct graph_hndl *hndl;
64
 
65
    uint32_t n_control;
66
-   struct port *control_port[MAX_CONTROLS];
67
+   struct port **control_port;
68
 };
69
 
70
 struct impl {
71
    struct pw_context *context;
72
 
73
    struct pw_impl_module *module;
74
-   struct pw_work_queue *work;
75
 
76
    struct spa_hook module_listener;
77
 
78
@@ -244,26 +242,12 @@
79
    struct spa_audio_info_raw playback_info;
80
 
81
    unsigned int do_disconnect:1;
82
-   unsigned int unloading:1;
83
 
84
    long unsigned rate;
85
 
86
    struct graph graph;
87
 };
88
 
89
-static void do_unload_module(void *obj, void *data, int res, uint32_t id)
90
-{
91
-   struct impl *impl = data;
92
-   pw_impl_module_destroy(impl->module);
93
-}
94
-static void unload_module(struct impl *impl)
95
-{
96
-   if (!impl->unloading) {
97
-       impl->unloading = true;
98
-       pw_work_queue_add(impl->work, impl, 0, do_unload_module, impl);
99
-   }
100
-}
101
-
102
 static void capture_destroy(void *d)
103
 {
104
    struct impl *impl = d;
105
@@ -628,26 +612,13 @@
106
    .param_changed = param_changed
107
 };
108
 
109
-static int builder_overflow(void *data, uint32_t size)
110
-{
111
-   struct spa_pod_builder *b = data;
112
-   b->size = SPA_ROUND_UP_N(size, 4096);
113
-   if ((b->data = realloc(b->data, b->size)) == NULL)
114
-       return -errno;
115
-        return 0;
116
-}
117
-
118
-static const struct spa_pod_builder_callbacks builder_callbacks = {
119
-   SPA_VERSION_POD_BUILDER_CALLBACKS,
120
-   .overflow = builder_overflow
121
-};
122
-
123
 static int setup_streams(struct impl *impl)
124
 {
125
    int res;
126
    uint32_t i, n_params;
127
-   const struct spa_pod *params[256];
128
-   struct spa_pod_builder b;
129
+   uint32_t offsets[512];
130
+   const struct spa_pod *params[512];
131
+   struct spa_pod_dynamic_builder b;
132
    struct graph *graph = &impl->graph;
133
 
134
    impl->capture = pw_stream_new(impl->core,
135
@@ -671,16 +642,22 @@
136
            &out_stream_events, impl);
137
 
138
    n_params = 0;
139
-   spa_pod_builder_init(&b, NULL, 0);
140
-   spa_pod_builder_set_callbacks(&b, &builder_callbacks, &b);
141
+   spa_pod_dynamic_builder_init(&b, NULL, 0, 4096);
142
 
143
-   params[n_params++] = spa_format_audio_raw_build(&b,
144
+   offsets[n_params++] = b.b.state.offset;
145
+   spa_format_audio_raw_build(&b.b,
146
            SPA_PARAM_EnumFormat, &impl->capture_info);
147
 
148
-   for (i = 0; i < graph->n_control; i++)
149
-       params[n_params++] = get_prop_info(graph, &b, i);
150
+   for (i = 0; i < graph->n_control; i++) {
151
+       offsets[n_params++] = b.b.state.offset;
152
+       get_prop_info(graph, &b.b, i);
153
+   }
154
 
155
-   params[n_params++] = get_props_param(graph, &b);
156
+   offsets[n_params++] = b.b.state.offset;
157
+   get_props_param(graph, &b.b);
158
+
159
+   for (i = 0; i < n_params; i++)
160
+       params[i] = spa_pod_builder_deref(&b.b, offsets[i]);
161
 
162
    res = pw_stream_connect(impl->capture,
163
            PW_DIRECTION_INPUT,
164
@@ -689,14 +666,14 @@
165
            PW_STREAM_FLAG_MAP_BUFFERS |
166
            PW_STREAM_FLAG_RT_PROCESS,
167
            params, n_params);
168
-   free(b.data);
169
+
170
+   spa_pod_dynamic_builder_clean(&b);
171
    if (res < 0)
172
        return res;
173
 
174
    n_params = 0;
175
-   spa_pod_builder_init(&b, NULL, 0);
176
-   spa_pod_builder_set_callbacks(&b, &builder_callbacks, &b);
177
-   params[n_params++] = spa_format_audio_raw_build(&b,
178
+   spa_pod_dynamic_builder_init(&b, NULL, 0, 4096);
179
+   params[n_params++] = spa_format_audio_raw_build(&b.b,
180
            SPA_PARAM_EnumFormat, &impl->playback_info);
181
 
182
    res = pw_stream_connect(impl->playback,
183
@@ -707,7 +684,7 @@
184
            PW_STREAM_FLAG_RT_PROCESS  |
185
            PW_STREAM_FLAG_TRIGGER,
186
            params, n_params);
187
-   free(b.data);
188
+   spa_pod_dynamic_builder_clean(&b);
189
 
190
    if (res < 0)
191
        return res;
192
@@ -741,7 +718,6 @@
193
 {
194
    struct fc_plugin *pl = NULL;
195
    struct plugin *hndl;
196
-   int res = 0;
197
    const struct spa_support *support;
198
    uint32_t n_support;
199
 
200
@@ -765,6 +741,11 @@
201
        pl = load_lv2_plugin(support, n_support, path, NULL);
202
    }
203
 #endif
204
+   else {
205
+       pl = NULL;
206
+       errno = EINVAL;
207
+   }
208
+
209
    if (pl == NULL)
210
        goto exit;
211
 
212
@@ -784,9 +765,7 @@
213
    spa_list_append(&impl->plugin_list, &hndl->link);
214
 
215
    return hndl;
216
-
217
 exit:
218
-   errno = -res;
219
    return NULL;
220
 }
221
 
222
@@ -797,6 +776,11 @@
223
 
224
    spa_list_remove(&desc->link);
225
    plugin_unref(desc->plugin);
226
+   free(desc->input);
227
+   free(desc->output);
228
+   free(desc->control);
229
+   free(desc->default_control);
230
+   free(desc->notify);
231
    free(desc);
232
 }
233
 
234
@@ -806,7 +790,7 @@
235
    struct plugin *hndl;
236
    struct descriptor *desc;
237
    const struct fc_descriptor *d;
238
-   uint32_t i;
239
+   uint32_t i, n_input, n_output, n_control, n_notify;
240
    unsigned long p;
241
    int res;
242
 
243
@@ -832,6 +816,7 @@
244
    desc = calloc(1, sizeof(*desc));
245
    desc->ref = 1;
246
    desc->plugin = hndl;
247
+   spa_list_init(&desc->link);
248
 
249
    if ((d = hndl->plugin->make_desc(hndl->plugin, label)) == NULL) {
250
        pw_log_error("cannot find label %s", label);
251
@@ -841,6 +826,27 @@
252
    desc->desc = d;
253
    snprintf(desc->label, sizeof(desc->label), "%s", label);
254
 
255
+   n_input = n_output = n_control = n_notify = 0;
256
+   for (p = 0; p < d->n_ports; p++) {
257
+       struct fc_port *fp = &d->ports[p];
258
+       if (FC_IS_PORT_AUDIO(fp->flags)) {
259
+           if (FC_IS_PORT_INPUT(fp->flags))
260
+               n_input++;
261
+           else if (FC_IS_PORT_OUTPUT(fp->flags))
262
+               n_output++;
263
+       } else if (FC_IS_PORT_CONTROL(fp->flags)) {
264
+           if (FC_IS_PORT_INPUT(fp->flags))
265
+               n_control++;
266
+           else if (FC_IS_PORT_OUTPUT(fp->flags))
267
+               n_notify++;
268
+       }
269
+   }
270
+   desc->input = calloc(n_input, sizeof(unsigned long));
271
+   desc->output = calloc(n_output, sizeof(unsigned long));
272
+   desc->control = calloc(n_control, sizeof(unsigned long));
273
+   desc->default_control = calloc(n_control, sizeof(float));
274
+   desc->notify = calloc(n_notify, sizeof(unsigned long));
275
+
276
    for (p = 0; p < d->n_ports; p++) {
277
        struct fc_port *fp = &d->ports[p];
278
 
279
@@ -884,9 +890,7 @@
280
    return desc;
281
 
282
 exit:
283
-   if (hndl != NULL)
284
-       plugin_unref(hndl);
285
-   free(desc);
286
+   descriptor_unref(desc);
287
    errno = -res;
288
    return NULL;
289
 }
290
@@ -1095,6 +1099,11 @@
291
    node->desc = desc;
292
    snprintf(node->name, sizeof(node->name), "%s", name);
293
 
294
+   node->input_port = calloc(desc->n_input, sizeof(struct port));
295
+   node->output_port = calloc(desc->n_output, sizeof(struct port));
296
+   node->control_port = calloc(desc->n_control, sizeof(struct port));
297
+   node->notify_port = calloc(desc->n_notify, sizeof(struct port));
298
+
299
    for (i = 0; i < desc->n_input; i++) {
300
        struct port *port = &node->input_port[i];
301
        port->node = node;
302
@@ -1154,6 +1163,10 @@
303
        d->cleanup(node->hndl[i]);
304
    }
305
    descriptor_unref(node->desc);
306
+   free(node->input_port);
307
+   free(node->output_port);
308
+   free(node->control_port);
309
+   free(node->notify_port);
310
    free(node);
311
 }
312
 
313
@@ -1221,16 +1234,13 @@
314
    struct port *port;
315
    struct graph_port *gp;
316
    struct graph_hndl *gh;
317
-   uint32_t i, j, n_input, n_output, n_hndl = 0;
318
+   uint32_t i, j, n_nodes, n_input, n_output, n_control, n_hndl = 0;
319
    int res;
320
    unsigned long p;
321
    struct descriptor *desc;
322
    const struct fc_descriptor *d;
323
    char v[256];
324
 
325
-   graph->n_input = 0;
326
-   graph->n_output = 0;
327
-
328
    first = spa_list_first(&graph->node_list, struct node, link);
329
    last = spa_list_last(&graph->node_list, struct node, link);
330
 
331
@@ -1272,11 +1282,16 @@
332
        res = -EINVAL;
333
        goto error;
334
    }
335
+   if (n_hndl > MAX_HNDL) {
336
+       pw_log_error("too many channels");
337
+       res = -EINVAL;
338
+       goto error;
339
+   }
340
    pw_log_info("using %d instances %d %d", n_hndl, n_input, n_output);
341
 
342
-   /* now go over all nodes and create instances. We can also link
343
-    * the control and notify ports already */
344
-   graph->n_control = 0;
345
+   /* now go over all nodes and create instances. */
346
+   n_control = 0;
347
+   n_nodes = 0;
348
    spa_list_for_each(node, &graph->node_list, link) {
349
        float *sd = silence_data, *dd = discard_data;
350
 
351
@@ -1313,11 +1328,8 @@
352
            if (d->activate)
353
                d->activate(node->hndl[i]);
354
        }
355
-       /* collect all control ports on the graph */
356
-       for (j = 0; j < desc->n_control; j++) {
357
-           graph->control_port[graph->n_control] = &node->control_port[j];
358
-           graph->n_control++;
359
-       }
360
+       n_control += desc->n_control;
361
+       n_nodes++;
362
    }
363
    pw_log_info("suggested rate:%lu capture:%d playback:%d", impl->rate,
364
            impl->capture_info.rate, impl->playback_info.rate);
365
@@ -1327,6 +1339,11 @@
366
    if (impl->playback_info.rate == 0)
367
        impl->playback_info.rate = impl->rate;
368
 
369
+   graph->n_input = 0;
370
+   graph->input = calloc(n_input * n_hndl, sizeof(struct graph_port));
371
+   graph->n_output = 0;
372
+   graph->output = calloc(n_output * n_hndl, sizeof(struct graph_port));
373
+
374
    /* now collect all input and output ports for all the handles. */
375
    for (i = 0; i < n_hndl; i++) {
376
        if (inputs == NULL) {
377
@@ -1429,6 +1446,9 @@
378
 
379
    /* order all nodes based on dependencies */
380
    graph->n_hndl = 0;
381
+   graph->hndl = calloc(n_nodes * n_hndl, sizeof(struct graph_hndl));
382
+   graph->n_control = 0;
383
+   graph->control_port = calloc(n_control, sizeof(struct port *));
384
    while (true) {
385
        if ((node = find_next_node(graph)) == NULL)
386
            break;
387
@@ -1447,6 +1467,12 @@
388
 
389
        for (i = 0; i < desc->n_output; i++)
390
            setup_output_port(graph, &node->output_port[i]);
391
+
392
+       /* collect all control ports on the graph */
393
+       for (i = 0; i < desc->n_control; i++) {
394
+           graph->control_port[graph->n_control] = &node->control_port[i];
395
+           graph->n_control++;
396
+       }
397
    }
398
    return 0;
399
 
400
@@ -1539,6 +1565,10 @@
401
        link_free(link);
402
    spa_list_consume(node, &graph->node_list, link)
403
        node_free(node);
404
+   free(graph->input);
405
+   free(graph->output);
406
+   free(graph->hndl);
407
+   free(graph->control_port);
408
 }
409
 
410
 static void core_error(void *data, uint32_t id, int seq, int res, const char *message)
411
@@ -1549,7 +1579,7 @@
412
            id, seq, res, spa_strerror(res), message);
413
 
414
    if (id == PW_ID_CORE && res == -EPIPE)
415
-       unload_module(impl);
416
+       pw_impl_module_schedule_destroy(impl->module);
417
 }
418
 
419
 static const struct pw_core_events core_events = {
420
@@ -1562,7 +1592,7 @@
421
    struct impl *impl = d;
422
    spa_hook_remove(&impl->core_listener);
423
    impl->core = NULL;
424
-   unload_module(impl);
425
+   pw_impl_module_schedule_destroy(impl->module);
426
 }
427
 
428
 static const struct pw_proxy_events core_proxy_events = {
429
@@ -1579,8 +1609,6 @@
430
        pw_core_disconnect(impl->core);
431
    pw_properties_free(impl->capture_props);
432
    pw_properties_free(impl->playback_props);
433
-   if (impl->work)
434
-       pw_work_queue_cancel(impl->work, impl, SPA_ID_INVALID);
435
    graph_free(&impl->graph);
436
    free(impl);
437
 }
438
@@ -1588,7 +1616,6 @@
439
 static void module_destroy(void *data)
440
 {
441
    struct impl *impl = data;
442
-   impl->unloading = true;
443
    spa_hook_remove(&impl->module_listener);
444
    impl_destroy(impl);
445
 }
446
@@ -1688,12 +1715,7 @@
447
 
448
    impl->module = module;
449
    impl->context = context;
450
-   impl->work = pw_context_get_work_queue(context);
451
-   if (impl->work == NULL) {
452
-       res = -errno;
453
-       pw_log_error( "can't create work queue: %m");
454
-       goto error;
455
-   }
456
+
457
    impl->rate = 48000;
458
    impl->graph.impl = impl;
459
    spa_list_init(&impl->plugin_list);
460
pipewire-0.3.47.tar.gz/src/modules/module-filter-chain/builtin_plugin.c -> pipewire-0.3.48.tar.gz/src/modules/module-filter-chain/builtin_plugin.c Changed
26
 
1
@@ -24,6 +24,7 @@
2
 
3
 #include "config.h"
4
 
5
+#include <float.h>
6
 #include <math.h>
7
 #ifdef HAVE_SNDFILE
8
 #include <sndfile.h>
9
@@ -303,10 +304,12 @@
10
        y2 = y1;
11
        y1 = y;
12
    }
13
-   bq->x1 = x1;
14
-   bq->x2 = x2;
15
-   bq->y1 = y1;
16
-   bq->y2 = y2;
17
+#define F(x) (-FLT_MIN < (x) && (x) < FLT_MIN ? 0.0f : (x))
18
+   bq->x1 = F(x1);
19
+   bq->x2 = F(x2);
20
+   bq->y1 = F(y1);
21
+   bq->y2 = F(y2);
22
+#undef F
23
 }
24
 
25
 /** bq_lowpass */
26
pipewire-0.3.47.tar.gz/src/modules/module-link-factory.c -> pipewire-0.3.48.tar.gz/src/modules/module-link-factory.c Changed
22
 
1
@@ -510,7 +510,6 @@
2
    struct pw_context *context = pw_impl_module_get_context(module);
3
    struct pw_impl_factory *factory;
4
    struct factory_data *data;
5
-   int res;
6
 
7
    PW_LOG_TOPIC_INIT(mod_topic);
8
 
9
@@ -530,12 +529,6 @@
10
    data->module = module;
11
    data->context = context;
12
    data->work = pw_context_get_work_queue(context);
13
-   if (data->work == NULL) {
14
-       res = -errno;
15
-       pw_log_error( "can't get work queue: %m");
16
-       pw_impl_factory_destroy(factory);
17
-       return res;
18
-   }
19
 
20
    spa_list_init(&data->link_list);
21
 
22
pipewire-0.3.47.tar.gz/src/modules/module-loopback.c -> pipewire-0.3.48.tar.gz/src/modules/module-loopback.c Changed
79
 
1
@@ -81,7 +81,6 @@
2
    struct pw_context *context;
3
 
4
    struct pw_impl_module *module;
5
-   struct pw_work_queue *work;
6
 
7
    struct spa_hook module_listener;
8
 
9
@@ -100,22 +99,8 @@
10
    struct spa_audio_info_raw playback_info;
11
 
12
    unsigned int do_disconnect:1;
13
-   unsigned int unloading:1;
14
 };
15
 
16
-static void do_unload_module(void *obj, void *data, int res, uint32_t id)
17
-{
18
-   struct impl *impl = data;
19
-   pw_impl_module_destroy(impl->module);
20
-}
21
-static void unload_module(struct impl *impl)
22
-{
23
-   if (!impl->unloading) {
24
-       impl->unloading = true;
25
-       pw_work_queue_add(impl->work, impl, 0, do_unload_module, impl);
26
-   }
27
-}
28
-
29
 static void capture_destroy(void *d)
30
 {
31
    struct impl *impl = d;
32
@@ -312,7 +297,7 @@
33
            id, seq, res, spa_strerror(res), message);
34
 
35
    if (id == PW_ID_CORE && res == -EPIPE)
36
-       unload_module(impl);
37
+       pw_impl_module_schedule_destroy(impl->module);
38
 }
39
 
40
 static const struct pw_core_events core_events = {
41
@@ -325,7 +310,7 @@
42
    struct impl *impl = d;
43
    spa_hook_remove(&impl->core_listener);
44
    impl->core = NULL;
45
-   unload_module(impl);
46
+   pw_impl_module_schedule_destroy(impl->module);
47
 }
48
 
49
 static const struct pw_proxy_events core_proxy_events = {
50
@@ -342,15 +327,12 @@
51
        pw_core_disconnect(impl->core);
52
    pw_properties_free(impl->capture_props);
53
    pw_properties_free(impl->playback_props);
54
-   if (impl->work)
55
-       pw_work_queue_cancel(impl->work, impl, SPA_ID_INVALID);
56
    free(impl);
57
 }
58
 
59
 static void module_destroy(void *data)
60
 {
61
    struct impl *impl = data;
62
-   impl->unloading = true;
63
    spa_hook_remove(&impl->module_listener);
64
    impl_destroy(impl);
65
 }
66
@@ -447,12 +429,6 @@
67
 
68
    impl->module = module;
69
    impl->context = context;
70
-   impl->work = pw_context_get_work_queue(context);
71
-   if (impl->work == NULL) {
72
-       res = -errno;
73
-       pw_log_error( "can't get work queue: %m");
74
-       goto error;
75
-   }
76
 
77
    if (pw_properties_get(props, PW_KEY_NODE_GROUP) == NULL)
78
        pw_properties_setf(props, PW_KEY_NODE_GROUP, "loopback-%u", id);
79
pipewire-0.3.47.tar.gz/src/modules/module-metadata/metadata.c -> pipewire-0.3.48.tar.gz/src/modules/module-metadata/metadata.c Changed
28
 
1
@@ -259,6 +259,15 @@
2
           struct pw_properties *properties)
3
 {
4
    struct impl *impl;
5
+   char serial_str[32];
6
+   struct spa_dict_item items[1] = {
7
+       SPA_DICT_ITEM_INIT(PW_KEY_OBJECT_SERIAL, serial_str),
8
+   };
9
+   struct spa_dict extra_props = SPA_DICT_INIT_ARRAY(items);
10
+   static const char * const keys[] = {
11
+       PW_KEY_OBJECT_SERIAL,
12
+       NULL
13
+   };
14
 
15
    if (properties == NULL)
16
        properties = pw_properties_new(NULL, NULL);
17
@@ -285,6 +294,10 @@
18
    impl->resource = resource;
19
    impl->metadata = (struct pw_metadata*)resource;
20
 
21
+   spa_scnprintf(serial_str, sizeof(serial_str), "%"PRIu64,
22
+           pw_global_get_serial(impl->global));
23
+   pw_global_update_keys(impl->global, &extra_props, keys);
24
+
25
    pw_context_add_listener(context, &impl->context_listener,
26
            &context_events, impl);
27
 
28
pipewire-0.3.47.tar.gz/src/modules/module-protocol-native.c -> pipewire-0.3.48.tar.gz/src/modules/module-protocol-native.c Changed
141
 
1
@@ -57,6 +57,7 @@
2
 
3
 #include "modules/module-protocol-native/connection.h"
4
 #include "modules/module-protocol-native/defs.h"
5
+#include "modules/module-protocol-native/protocol-footer.h"
6
 
7
 
8
 #define NAME "protocol-native"
9
@@ -115,6 +116,8 @@
10
 
11
    int ref;
12
 
13
+   struct footer_core_global_state footer_state;
14
+
15
    unsigned int connected:1;
16
    unsigned int disconnecting:1;
17
    unsigned int need_flush:1;
18
@@ -151,6 +154,8 @@
19
    struct pw_protocol_native_connection *connection;
20
    struct spa_hook conn_listener;
21
 
22
+   struct footer_client_global_state footer_state;
23
+
24
    unsigned int busy:1;
25
    unsigned int need_flush:1;
26
 
27
@@ -164,7 +169,7 @@
28
              "%s: id:%d op:%d size:%d seq:%d", prefix,
29
              msg->id, msg->opcode, msg->size, msg->seq);
30
 
31
-   if ((pod = spa_pod_from_data(msg->data, msg->size, 0, msg->size)) != NULL)
32
+   if ((pod = get_first_pod_from_data(msg->data, msg->size, 0)) != NULL)
33
        spa_debug_pod(0, NULL, pod);
34
    else
35
        hex = true;
36
@@ -172,6 +177,49 @@
37
        spa_debug_mem(0, msg->data, msg->size);
38
 }
39
 
40
+static void pre_demarshal(struct pw_protocol_native_connection *conn,
41
+       const struct pw_protocol_native_message *msg,
42
+       void *object, const struct footer_demarshal *opcodes, size_t n_opcodes)
43
+{
44
+   struct spa_pod *footer = NULL;
45
+   struct spa_pod_parser parser;
46
+   struct spa_pod_frame f[2];
47
+   uint32_t opcode;
48
+   int ret;
49
+
50
+   footer = pw_protocol_native_connection_get_footer(conn, msg);
51
+   if (footer == NULL)
52
+       return;   /* No valid footer. Ignore silently. */
53
+
54
+   /*
55
+    * Version 3 footer
56
+    *
57
+    * spa_pod Struct { [Id opcode, Struct { ... }]* }
58
+    */
59
+
60
+   spa_pod_parser_pod(&parser, footer);
61
+   if (spa_pod_parser_push_struct(&parser, &f[0]) < 0) {
62
+       pw_log_error("malformed message footer");
63
+       return;
64
+   }
65
+
66
+   while (1) {
67
+       if (spa_pod_parser_get_id(&parser, &opcode) < 0)
68
+           break;
69
+       if (spa_pod_parser_push_struct(&parser, &f[1]) < 0)
70
+           break;
71
+       if (opcode < n_opcodes) {
72
+           if ((ret = opcodes[opcode].demarshal(object, &parser)) < 0)
73
+               pw_log_error("failed processing message footer (opcode %u): %d (%s)",
74
+                       opcode, ret, spa_strerror(ret));
75
+       } else {
76
+           /* Ignore (don't log errors), in case we need to extend this later. */
77
+           pw_log_debug("unknown message footer opcode %u", opcode);
78
+       }
79
+       spa_pod_parser_pop(&parser, &f[1]);
80
+   }
81
+}
82
+
83
 static int
84
 process_messages(struct client_data *data)
85
 {
86
@@ -213,6 +261,9 @@
87
        if (debug_messages)
88
            debug_msg("<<<<<< in", msg, false);
89
 
90
+       pre_demarshal(conn, msg, client, footer_client_demarshal,
91
+               SPA_N_ELEMENTS(footer_client_demarshal));
92
+
93
        resource = pw_impl_client_find_resource(client, msg->id);
94
        if (resource == NULL) {
95
            pw_resource_errorf(client->core_resource,
96
@@ -767,6 +818,9 @@
97
        if (debug_messages)
98
            debug_msg("<<<<<< in", msg, false);
99
 
100
+       pre_demarshal(conn, msg, this, footer_core_demarshal,
101
+               SPA_N_ELEMENTS(footer_core_demarshal));
102
+
103
        proxy = pw_core_find_proxy(this, msg->id);
104
        if (proxy == NULL || proxy->zombie) {
105
            if (proxy == NULL)
106
@@ -1225,11 +1279,25 @@
107
    return pw_protocol_native_connection_get_fd(impl->connection, index);
108
 }
109
 
110
+static void assert_single_pod(struct spa_pod_builder *builder)
111
+{
112
+   /*
113
+    * Check the invariant that the message we just marshaled
114
+    * consists of at most one POD.
115
+    */
116
+   struct spa_pod *pod = builder->data;
117
+   spa_assert(builder->data == NULL ||
118
+           builder->state.offset < sizeof(struct spa_pod) ||
119
+           builder->state.offset == SPA_POD_SIZE(pod));
120
+}
121
+
122
 static int impl_ext_end_proxy(struct pw_proxy *proxy,
123
                   struct spa_pod_builder *builder)
124
 {
125
    struct pw_core *core = proxy->core;
126
    struct client *impl = SPA_CONTAINER_OF(core->conn, struct client, this);
127
+   assert_single_pod(builder);
128
+   marshal_core_footers(&impl->footer_state, core, builder);
129
    return core->send_seq = pw_protocol_native_connection_end(impl->connection, builder);
130
 }
131
 
132
@@ -1257,6 +1325,8 @@
133
 {
134
    struct client_data *data = resource->client->user_data;
135
    struct pw_impl_client *client = resource->client;
136
+   assert_single_pod(builder);
137
+   marshal_client_footers(&data->footer_state, client, builder);
138
    return client->send_seq = pw_protocol_native_connection_end(data->connection, builder);
139
 }
140
 static const struct pw_protocol_native_ext protocol_ext_impl = {
141
pipewire-0.3.47.tar.gz/src/modules/module-protocol-native/connection.c -> pipewire-0.3.48.tar.gz/src/modules/module-protocol-native/connection.c Changed
48
 
1
@@ -45,6 +45,7 @@
2
 #include <spa/debug/pod.h>
3
 
4
 #include "connection.h"
5
+#include "defs.h"
6
 
7
 #define MAX_BUFFER_SIZE (1024 * 32)
8
 #define MAX_FDS 1024u
9
@@ -598,6 +599,38 @@
10
    return 1;
11
 }
12
 
13
+/** Get footer data from the tail of the current packet.
14
+ *
15
+ * \param conn the connection
16
+ * \param msg current message
17
+ * \return footer POD, or NULL if no valid footer present
18
+ *
19
+ * \memberof pw_protocol_native_connection
20
+ */
21
+struct spa_pod *pw_protocol_native_connection_get_footer(struct pw_protocol_native_connection *conn,
22
+       const struct pw_protocol_native_message *msg)
23
+{
24
+   struct impl *impl = SPA_CONTAINER_OF(conn, struct impl, this);
25
+   struct spa_pod *pod;
26
+
27
+   if (impl->version != 3)
28
+       return NULL;
29
+
30
+   /*
31
+    * Protocol version 3 footer: a single SPA POD
32
+    */
33
+
34
+   /* Footer immediately follows the message POD, if it is present */
35
+   if ((pod = get_first_pod_from_data(msg->data, msg->size, 0)) == NULL)
36
+       return NULL;
37
+   pod = get_first_pod_from_data(msg->data, msg->size, SPA_POD_SIZE(pod));
38
+   if (pod == NULL)
39
+       return NULL;
40
+   pw_log_trace("connection %p: recv message footer, size:%zu",
41
+           conn, (size_t)SPA_POD_SIZE(pod));
42
+   return pod;
43
+}
44
+
45
 static inline void *begin_write(struct pw_protocol_native_connection *conn, uint32_t size)
46
 {
47
    struct impl *impl = SPA_CONTAINER_OF(conn, struct impl, this);
48
pipewire-0.3.47.tar.gz/src/modules/module-protocol-native/connection.h -> pipewire-0.3.48.tar.gz/src/modules/module-protocol-native/connection.h Changed
11
 
1
@@ -102,6 +102,9 @@
2
 void pw_protocol_native_connection_enter(struct pw_protocol_native_connection *conn);
3
 void pw_protocol_native_connection_leave(struct pw_protocol_native_connection *conn);
4
 
5
+struct spa_pod *pw_protocol_native_connection_get_footer(struct pw_protocol_native_connection *conn,
6
+       const struct pw_protocol_native_message *msg);
7
+
8
 #ifdef __cplusplus
9
 }  /* extern "C" */
10
 #endif
11
pipewire-0.3.47.tar.gz/src/modules/module-protocol-native/defs.h -> pipewire-0.3.48.tar.gz/src/modules/module-protocol-native/defs.h Changed
16
 
1
@@ -30,3 +30,14 @@
2
                        const struct spa_dict *props,
3
                        void (*done_callback) (void *data, int res),
4
                        void *data);
5
+
6
+static inline void *get_first_pod_from_data(void *data, size_t maxsize, off_t offset)
7
+{
8
+   void *pod;
9
+   if (offset + sizeof(struct spa_pod) > maxsize)
10
+       return NULL;
11
+   pod = SPA_PTROFF(data, offset, void);
12
+   if (offset + SPA_POD_SIZE(pod) > maxsize)
13
+       return NULL;
14
+   return pod;
15
+}
16
pipewire-0.3.48.tar.gz/src/modules/module-protocol-native/protocol-footer.c Added
154
 
1
@@ -0,0 +1,152 @@
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 <stdio.h>
27
+#include <errno.h>
28
+
29
+#include <spa/pod/builder.h>
30
+#include <spa/pod/parser.h>
31
+#include <spa/utils/result.h>
32
+
33
+#include <pipewire/private.h>
34
+
35
+#include "connection.h"
36
+#include "protocol-footer.h"
37
+#include "defs.h"
38
+
39
+PW_LOG_TOPIC_EXTERN(mod_topic);
40
+#define PW_LOG_TOPIC_DEFAULT mod_topic
41
+
42
+struct footer_builder {
43
+   struct spa_pod_builder *builder;
44
+   struct spa_pod_frame outer;
45
+   struct spa_pod_frame inner;
46
+   unsigned int started:1;
47
+};
48
+
49
+#define FOOTER_BUILDER_INIT(builder) (struct footer_builder) { builder }
50
+
51
+static void start_footer_entry(struct footer_builder *fb, uint32_t opcode)
52
+{
53
+   if (!fb->started) {
54
+       spa_pod_builder_push_struct(fb->builder, &fb->outer);
55
+       fb->started = true;
56
+   }
57
+
58
+   spa_pod_builder_id(fb->builder, opcode);
59
+   spa_pod_builder_push_struct(fb->builder, &fb->inner);
60
+}
61
+
62
+static void end_footer_entry(struct footer_builder *fb)
63
+{
64
+   spa_pod_builder_pop(fb->builder, &fb->inner);
65
+}
66
+
67
+static void end_footer(struct footer_builder *fb)
68
+{
69
+   if (!fb->started)
70
+       return;
71
+
72
+   spa_pod_builder_pop(fb->builder, &fb->outer);
73
+}
74
+
75
+void marshal_core_footers(struct footer_core_global_state *state, struct pw_core *core,
76
+       struct spa_pod_builder *builder)
77
+{
78
+   struct footer_builder fb = FOOTER_BUILDER_INIT(builder);
79
+
80
+   if (core->recv_generation != state->last_recv_generation) {
81
+       state->last_recv_generation = core->recv_generation;
82
+
83
+       pw_log_trace("core %p: send client registry generation:%"PRIu64,
84
+               core, core->recv_generation);
85
+
86
+       start_footer_entry(&fb, FOOTER_CLIENT_OPCODE_GENERATION);
87
+       spa_pod_builder_long(fb.builder, core->recv_generation);
88
+       end_footer_entry(&fb);
89
+   }
90
+
91
+   end_footer(&fb);
92
+}
93
+
94
+void marshal_client_footers(struct footer_client_global_state *state, struct pw_impl_client *client,
95
+       struct spa_pod_builder *builder)
96
+{
97
+   struct footer_builder fb = FOOTER_BUILDER_INIT(builder);
98
+
99
+   if (client->context->generation != client->sent_generation) {
100
+       client->sent_generation = client->context->generation;
101
+
102
+       pw_log_trace("impl-client %p: send server registry generation:%"PRIu64,
103
+               client, client->context->generation);
104
+
105
+       start_footer_entry(&fb, FOOTER_CORE_OPCODE_GENERATION);
106
+       spa_pod_builder_long(fb.builder, client->context->generation);
107
+       end_footer_entry(&fb);
108
+   }
109
+
110
+   end_footer(&fb);
111
+}
112
+
113
+int demarshal_core_generation(void *object, struct spa_pod_parser *parser)
114
+{
115
+   struct pw_core *core = object;
116
+   int64_t generation;
117
+
118
+   if (spa_pod_parser_get_long(parser, &generation) < 0)
119
+       return -EINVAL;
120
+
121
+   core->recv_generation = SPA_MAX(core->recv_generation,
122
+           (uint64_t)generation);
123
+
124
+   pw_log_trace("core %p: recv server registry generation:%"PRIu64,
125
+           core, generation);
126
+
127
+   return 0;
128
+}
129
+
130
+int demarshal_client_generation(void *object, struct spa_pod_parser *parser)
131
+{
132
+   struct pw_impl_client *client = object;
133
+   int64_t generation;
134
+
135
+   if (spa_pod_parser_get_long(parser, &generation) < 0)
136
+       return -EINVAL;
137
+
138
+   client->recv_generation = SPA_MAX(client->recv_generation,
139
+           (uint64_t)generation);
140
+
141
+   pw_log_trace("impl-client %p: recv client registry generation:%"PRIu64,
142
+           client, generation);
143
+
144
+   return 0;
145
+}
146
+
147
+const struct footer_demarshal footer_core_demarshal[FOOTER_CORE_OPCODE_LAST] = {
148
+   [FOOTER_CORE_OPCODE_GENERATION] = (struct footer_demarshal){ .demarshal = demarshal_core_generation },
149
+};
150
+
151
+const struct footer_demarshal footer_client_demarshal[FOOTER_CLIENT_OPCODE_LAST] = {
152
+   [FOOTER_CLIENT_OPCODE_GENERATION] = (struct footer_demarshal){ .demarshal = demarshal_client_generation },
153
+};
154
pipewire-0.3.48.tar.gz/src/modules/module-protocol-native/protocol-footer.h Added
61
 
1
@@ -0,0 +1,59 @@
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
+/*
27
+ * Protocol footer.
28
+ *
29
+ * For passing around general state data that is not associated with
30
+ * messages sent to objects.
31
+ */
32
+
33
+enum {
34
+   FOOTER_CORE_OPCODE_GENERATION = 0,
35
+   FOOTER_CORE_OPCODE_LAST
36
+};
37
+
38
+enum {
39
+   FOOTER_CLIENT_OPCODE_GENERATION = 0,
40
+   FOOTER_CLIENT_OPCODE_LAST
41
+};
42
+
43
+struct footer_core_global_state {
44
+   uint64_t last_recv_generation;
45
+};
46
+
47
+struct footer_client_global_state {
48
+};
49
+
50
+struct footer_demarshal {
51
+   int (*demarshal)(void *object, struct spa_pod_parser *parser);
52
+};
53
+
54
+extern const struct footer_demarshal footer_core_demarshal[FOOTER_CORE_OPCODE_LAST];
55
+extern const struct footer_demarshal footer_client_demarshal[FOOTER_CLIENT_OPCODE_LAST];
56
+
57
+void marshal_core_footers(struct footer_core_global_state *state, struct pw_core *core,
58
+       struct spa_pod_builder *builder);
59
+void marshal_client_footers(struct footer_client_global_state *state, struct pw_impl_client *client,
60
+       struct spa_pod_builder *builder);
61
pipewire-0.3.47.tar.gz/src/modules/module-protocol-native/protocol-native.c -> pipewire-0.3.48.tar.gz/src/modules/module-protocol-native/protocol-native.c Changed
13
 
1
@@ -34,9 +34,9 @@
2
 
3
 #include "connection.h"
4
 
5
-#define MAX_DICT   256
6
+#define MAX_DICT   1024
7
 #define MAX_PARAM_INFO 128
8
-#define MAX_PERMISSIONS    1024
9
+#define MAX_PERMISSIONS    4096
10
 
11
 PW_LOG_TOPIC_EXTERN(mod_topic);
12
 #define PW_LOG_TOPIC_DEFAULT mod_topic
13
pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/collect.c -> pipewire-0.3.48.tar.gz/src/modules/module-protocol-pulse/collect.c Changed
17
 
1
@@ -279,13 +279,13 @@
2
        {
3
            struct spa_pod *copy = spa_pod_copy(p->param);
4
            spa_pod_fixate(copy);
5
-           format_parse_param(copy, &dev_info->ss, &dev_info->map,
6
+           format_parse_param(copy, true, &dev_info->ss, &dev_info->map,
7
                    &defs->sample_spec, &defs->channel_map);
8
            free(copy);
9
            break;
10
        }
11
        case SPA_PARAM_Format:
12
-           format_parse_param(p->param, &dev_info->ss, &dev_info->map,
13
+           format_parse_param(p->param, true, &dev_info->ss, &dev_info->map,
14
                    NULL, NULL);
15
            break;
16
 
17
pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/defs.h -> pipewire-0.3.48.tar.gz/src/modules/module-protocol-pulse/defs.h Changed
8
 
1
@@ -260,5 +260,6 @@
2
 #define METADATA_CONFIG_DEFAULT_SINK    "default.configured.audio.sink"
3
 #define METADATA_CONFIG_DEFAULT_SOURCE  "default.configured.audio.source"
4
 #define METADATA_TARGET_NODE            "target.node"
5
+#define METADATA_TARGET_OBJECT          "target.object"
6
 
7
 #endif /* PULSE_SERVER_DEFS_H */
8
pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/extensions/ext-stream-restore.c -> pipewire-0.3.48.tar.gz/src/modules/module-protocol-pulse/extensions/ext-stream-restore.c Changed
12
 
1
@@ -252,7 +252,9 @@
2
        if (name == NULL || name[0] == '\0')
3
            return -EPROTO;
4
 
5
-       f = open_memstream(&ptr, &size);
6
+       if ((f = open_memstream(&ptr, &size)) == NULL)
7
+           return -errno;
8
+
9
        fprintf(f, "{");
10
        fprintf(f, " \"mute\": %s", mute ? "true" : "false");
11
        if (vol.channels > 0) {
12
pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/format.c -> pipewire-0.3.48.tar.gz/src/modules/module-protocol-pulse/format.c Changed
40
 
1
@@ -443,7 +443,8 @@
2
    return res;
3
 }
4
 
5
-int format_parse_param(const struct spa_pod *param, struct sample_spec *ss, struct channel_map *map,
6
+int format_parse_param(const struct spa_pod *param, bool collect,
7
+       struct sample_spec *ss, struct channel_map *map,
8
        const struct sample_spec *def_ss, const struct channel_map *def_map)
9
 {
10
    struct spa_audio_info info = { 0 };
11
@@ -471,11 +472,17 @@
12
    {
13
        struct spa_audio_info_iec958 iec;
14
 
15
+       if (collect)
16
+           break;
17
+
18
        if (spa_format_audio_iec958_parse(param, &iec) < 0)
19
            return -ENOTSUP;
20
 
21
        info.info.raw.format = SPA_AUDIO_FORMAT_S16;
22
        info.info.raw.rate = iec.rate;
23
+       info.info.raw.channels = 2;
24
+       info.info.raw.position[0] = SPA_AUDIO_CHANNEL_FL;
25
+       info.info.raw.position[1] = SPA_AUDIO_CHANNEL_FR;
26
        break;
27
    }
28
    default:
29
@@ -612,7 +619,9 @@
30
        size_t size;
31
        FILE *f;
32
 
33
-       f = open_memstream(&ptr, &size);
34
+       if ((f = open_memstream(&ptr, &size)) == NULL)
35
+           return -errno;
36
+
37
        fprintf(f, "[");
38
        for (i = 1; i < n_values; i++)
39
            fprintf(f, "%s %d", i == 1 ? "" : ",", values[i]);
40
pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/format.h -> pipewire-0.3.48.tar.gz/src/modules/module-protocol-pulse/format.h Changed
10
 
1
@@ -205,7 +205,7 @@
2
 void channel_map_parse(const char *str, struct channel_map *map);
3
 bool channel_map_valid(const struct channel_map *map);
4
 
5
-int format_parse_param(const struct spa_pod *param, struct sample_spec *ss,
6
+int format_parse_param(const struct spa_pod *param, bool collect, struct sample_spec *ss,
7
        struct channel_map *map, const struct sample_spec *def_ss,
8
        const struct channel_map *def_map);
9
 
10
pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/message-handler.c -> pipewire-0.3.48.tar.gz/src/modules/module-protocol-pulse/message-handler.c Changed
19
 
1
@@ -65,7 +65,7 @@
2
 
3
        r = open_memstream(response, &size);
4
        if (r == NULL)
5
-           return -ENOMEM;
6
+           return -errno;
7
 
8
        fputc('[', r);
9
        for (i = 0; i < n_codecs; ++i) {
10
@@ -100,7 +100,7 @@
11
 
12
        r = open_memstream(response, &size);
13
        if (r == NULL)
14
-           return -ENOMEM;
15
+           return -errno;
16
 
17
        fputc('[', r);
18
        spa_list_for_each(o, &m->object_list, link) {
19
pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/modules/module-always-sink.c -> pipewire-0.3.48.tar.gz/src/modules/module-protocol-pulse/modules/module-always-sink.c Changed
12
 
1
@@ -59,7 +59,9 @@
2
    const char *str;
3
    size_t size;
4
 
5
-   f = open_memstream(&args, &size);
6
+   if ((f = open_memstream(&args, &size)) == NULL)
7
+       return -errno;
8
+
9
    fprintf(f, "{");
10
    if ((str = pw_properties_get(module->props, "sink_name")) != NULL)
11
        fprintf(f, " sink.name = \"%s\"", str);
12
pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/modules/module-echo-cancel.c -> pipewire-0.3.48.tar.gz/src/modules/module-protocol-pulse/modules/module-echo-cancel.c Changed
12
 
1
@@ -72,7 +72,9 @@
2
    char *args;
3
    size_t size;
4
 
5
-   f = open_memstream(&args, &size);
6
+   if ((f = open_memstream(&args, &size)) == NULL)
7
+       return -errno;
8
+
9
    fprintf(f, "{");
10
    /* Can't just serialise this dict because the "null" method gets
11
     * interpreted as a JSON null */
12
pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/modules/module-ladspa-sink.c -> pipewire-0.3.48.tar.gz/src/modules/module-protocol-pulse/modules/module-ladspa-sink.c Changed
12
 
1
@@ -78,7 +78,9 @@
2
    pw_properties_setf(data->capture_props, "pulse.module.id", "%u", module->index);
3
    pw_properties_setf(data->playback_props, "pulse.module.id", "%u", module->index);
4
 
5
-   f = open_memstream(&args, &size);
6
+   if ((f = open_memstream(&args, &size)) == NULL)
7
+       return -errno;
8
+
9
    fprintf(f, "{");
10
    pw_properties_serialize_dict(f, &module->props->dict, 0);
11
    fprintf(f, " filter.graph = {");
12
pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/modules/module-ladspa-source.c -> pipewire-0.3.48.tar.gz/src/modules/module-protocol-pulse/modules/module-ladspa-source.c Changed
12
 
1
@@ -78,7 +78,9 @@
2
    pw_properties_setf(data->capture_props, "pulse.module.id", "%u", module->index);
3
    pw_properties_setf(data->playback_props, "pulse.module.id", "%u", module->index);
4
 
5
-   f = open_memstream(&args, &size);
6
+   if ((f = open_memstream(&args, &size)) == NULL)
7
+       return -errno;
8
+
9
    fprintf(f, "{");
10
    pw_properties_serialize_dict(f, &module->props->dict, 0);
11
    fprintf(f, " filter.graph = {");
12
pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/modules/module-loopback.c -> pipewire-0.3.48.tar.gz/src/modules/module-protocol-pulse/modules/module-loopback.c Changed
12
 
1
@@ -75,7 +75,9 @@
2
    pw_properties_setf(data->capture_props, "pulse.module.id", "%u", module->index);
3
    pw_properties_setf(data->playback_props, "pulse.module.id", "%u", module->index);
4
 
5
-   f = open_memstream(&args, &size);
6
+   if ((f = open_memstream(&args, &size)) == NULL)
7
+       return -errno;
8
+
9
    fprintf(f, "{");
10
    if (data->info.channels != 0) {
11
        fprintf(f, " audio.channels = %u", data->info.channels);
12
pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/modules/module-null-sink.c -> pipewire-0.3.48.tar.gz/src/modules/module-protocol-pulse/modules/module-null-sink.c Changed
13
 
1
@@ -219,10 +219,7 @@
2
    if (pw_properties_get(props, PW_KEY_MEDIA_CLASS) == NULL)
3
        pw_properties_set(props, PW_KEY_MEDIA_CLASS, "Audio/Sink");
4
 
5
-   if ((str = pw_properties_get(props, "device.description")) != NULL) {
6
-       pw_properties_set(props, PW_KEY_NODE_DESCRIPTION, str);
7
-       pw_properties_set(props, "device.description", NULL);
8
-   } else {
9
+   if ((str = pw_properties_get(props, PW_KEY_NODE_DESCRIPTION)) == NULL) {
10
        const char *name, *class;
11
 
12
        name = pw_properties_get(props, PW_KEY_NODE_NAME);
13
pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/modules/module-remap-sink.c -> pipewire-0.3.48.tar.gz/src/modules/module-protocol-pulse/modules/module-remap-sink.c Changed
12
 
1
@@ -72,7 +72,9 @@
2
    pw_properties_setf(data->capture_props, "pulse.module.id", "%u", module->index);
3
    pw_properties_setf(data->playback_props, "pulse.module.id", "%u", module->index);
4
 
5
-   f = open_memstream(&args, &size);
6
+   if ((f = open_memstream(&args, &size)) == NULL)
7
+       return -errno;
8
+
9
    fprintf(f, "{");
10
    pw_properties_serialize_dict(f, &module->props->dict, 0);
11
    fprintf(f, " capture.props = {");
12
pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/modules/module-remap-source.c -> pipewire-0.3.48.tar.gz/src/modules/module-protocol-pulse/modules/module-remap-source.c Changed
12
 
1
@@ -72,7 +72,9 @@
2
    pw_properties_setf(data->capture_props, "pulse.module.id", "%u", module->index);
3
    pw_properties_setf(data->playback_props, "pulse.module.id", "%u", module->index);
4
 
5
-   f = open_memstream(&args, &size);
6
+   if ((f = open_memstream(&args, &size)) == NULL)
7
+       return -errno;
8
+
9
    fprintf(f, "{");
10
    pw_properties_serialize_dict(f, &module->props->dict, 0);
11
    fprintf(f, " capture.props = { ");
12
pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/modules/module-roc-sink.c -> pipewire-0.3.48.tar.gz/src/modules/module-protocol-pulse/modules/module-roc-sink.c Changed
12
 
1
@@ -73,7 +73,9 @@
2
    pw_properties_setf(data->sink_props, "pulse.module.id",
3
            "%u", module->index);
4
 
5
-   f = open_memstream(&args, &size);
6
+   if ((f = open_memstream(&args, &size)) == NULL)
7
+       return -errno;
8
+
9
    fprintf(f, "{");
10
    pw_properties_serialize_dict(f, &data->roc_props->dict, 0);
11
    fprintf(f, " } sink.props = {");
12
pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/modules/module-roc-source.c -> pipewire-0.3.48.tar.gz/src/modules/module-protocol-pulse/modules/module-roc-source.c Changed
12
 
1
@@ -73,7 +73,9 @@
2
    pw_properties_setf(data->source_props, "pulse.module.id",
3
            "%u", module->index);
4
 
5
-   f = open_memstream(&args, &size);
6
+   if ((f = open_memstream(&args, &size)) == NULL)
7
+       return -errno;
8
+
9
    fprintf(f, "{");
10
    pw_properties_serialize_dict(f, &data->roc_props->dict, 0);
11
    fprintf(f, " } source.props = {");
12
pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/modules/module-simple-protocol-tcp.c -> pipewire-0.3.48.tar.gz/src/modules/module-protocol-pulse/modules/module-simple-protocol-tcp.c Changed
12
 
1
@@ -68,7 +68,9 @@
2
    uint32_t i;
3
    FILE *f;
4
 
5
-   f = open_memstream(&args, &size);
6
+   if ((f = open_memstream(&args, &size)) == NULL)
7
+       return -errno;
8
+
9
    fprintf(f, "{");
10
    if (data->info.rate != 0)
11
        fprintf(f, " \"audio.rate\": %u,", data->info.rate);
12
pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/modules/module-tunnel-sink.c -> pipewire-0.3.48.tar.gz/src/modules/module-protocol-pulse/modules/module-tunnel-sink.c Changed
12
 
1
@@ -76,7 +76,9 @@
2
    pw_properties_setf(data->stream_props, "pulse.module.id",
3
            "%u", module->index);
4
 
5
-   f = open_memstream(&args, &size);
6
+   if ((f = open_memstream(&args, &size)) == NULL)
7
+       return -errno;
8
+
9
    fprintf(f, "{");
10
    pw_properties_serialize_dict(f, &module->props->dict, 0);
11
    fprintf(f, " pulse.server.address = \"%s\" ", server);
12
pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/modules/module-tunnel-source.c -> pipewire-0.3.48.tar.gz/src/modules/module-protocol-pulse/modules/module-tunnel-source.c Changed
12
 
1
@@ -76,7 +76,9 @@
2
 
3
    server = pw_properties_get(module->props, "server");
4
 
5
-   f = open_memstream(&args, &size);
6
+   if ((f = open_memstream(&args, &size)) == NULL)
7
+       return -errno;
8
+
9
    fprintf(f, "{");
10
    pw_properties_serialize_dict(f, &module->props->dict, 0);
11
    fprintf(f, " pulse.server.address = \"%s\" ", server);
12
pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/modules/module-x11-bell.c -> pipewire-0.3.48.tar.gz/src/modules/module-protocol-pulse/modules/module-x11-bell.c Changed
12
 
1
@@ -59,7 +59,9 @@
2
    const char *str;
3
    size_t size;
4
 
5
-   f = open_memstream(&args, &size);
6
+   if ((f = open_memstream(&args, &size)) == NULL)
7
+       return -errno;
8
+
9
    fprintf(f, "{");
10
    if ((str = pw_properties_get(module->props, "sink")) != NULL)
11
        fprintf(f, " sink.name = \"%s\"", str);
12
pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/operation.c -> pipewire-0.3.48.tar.gz/src/modules/module-protocol-pulse/operation.c Changed
30
 
1
@@ -66,15 +66,27 @@
2
    free(o);
3
 }
4
 
5
+struct operation *operation_find(struct client *client, uint32_t tag)
6
+{
7
+   struct operation *o;
8
+   spa_list_for_each(o, &client->operations, link) {
9
+       if (o->tag == tag)
10
+           return o;
11
+   }
12
+   return NULL;
13
+}
14
+
15
 void operation_complete(struct operation *o)
16
 {
17
    struct client *client = o->client;
18
 
19
    pw_log_info("[%s]: tag:%u complete", client->name, o->tag);
20
 
21
+   spa_list_remove(&o->link);
22
+
23
    if (o->callback)
24
        o->callback(o->data, client, o->tag);
25
    else
26
        reply_simple_ack(client, o->tag);
27
-   operation_free(o);
28
+   free(o);
29
 }
30
pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/operation.h -> pipewire-0.3.48.tar.gz/src/modules/module-protocol-pulse/operation.h Changed
9
 
1
@@ -43,6 +43,7 @@
2
 int operation_new_cb(struct client *client, uint32_t tag,
3
        void (*callback) (void *data, struct client *client, uint32_t tag),
4
        void *data);
5
+struct operation *operation_find(struct client *client, uint32_t tag);
6
 void operation_free(struct operation *o);
7
 void operation_complete(struct operation *o);
8
 
9
pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/pending-sample.c -> pipewire-0.3.48.tar.gz/src/modules/module-protocol-pulse/pending-sample.c Changed
24
 
1
@@ -29,6 +29,7 @@
2
 #include "client.h"
3
 #include "internal.h"
4
 #include "log.h"
5
+#include "operation.h"
6
 #include "pending-sample.h"
7
 #include "sample-play.h"
8
 
9
@@ -36,10 +37,14 @@
10
 {
11
    struct client * const client = ps->client;
12
    struct impl * const impl = client->impl;
13
+   struct operation *o;
14
 
15
    spa_list_remove(&ps->link);
16
    spa_hook_remove(&ps->listener);
17
    pw_work_queue_cancel(impl->work_queue, ps, SPA_ID_INVALID);
18
 
19
+   if ((o = operation_find(client, ps->tag)) != NULL)
20
+       operation_free(o);
21
+
22
    sample_play_destroy(ps->play);
23
 }
24
pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/pending-sample.h -> pipewire-0.3.48.tar.gz/src/modules/module-protocol-pulse/pending-sample.h Changed
10
 
1
@@ -39,6 +39,8 @@
2
    struct sample_play *play;
3
    struct spa_hook listener;
4
    uint32_t tag;
5
+   unsigned ready:1;
6
+   unsigned done:1;
7
 };
8
 
9
 void pending_sample_free(struct pending_sample *ps);
10
pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/pulse-server.c -> pipewire-0.3.48.tar.gz/src/modules/module-protocol-pulse/pulse-server.c Changed
221
 
1
@@ -192,8 +192,11 @@
2
        reply_set_client_name(client, client->connect_tag);
3
        client->connect_tag = SPA_ID_INVALID;
4
    }
5
+
6
+   client->ref++;
7
    spa_list_consume(o, &client->operations, link)
8
        operation_complete(o);
9
+   client_unref(client);
10
 }
11
 
12
 static struct stream *find_stream(struct client *client, uint32_t index)
13
@@ -445,8 +448,8 @@
14
 {
15
    struct spa_fraction lat;
16
    uint64_t lat_usec;
17
-   struct spa_dict_item items[5];
18
-   char latency[32];
19
+   struct spa_dict_item items[6];
20
+   char latency[32], rate[32];
21
    char attr_maxlength[32];
22
    char attr_tlength[32];
23
    char attr_prebuf[32];
24
@@ -463,17 +466,19 @@
25
    lat_usec = lat.num * SPA_USEC_PER_SEC / lat.denom;
26
 
27
    snprintf(latency, sizeof(latency), "%u/%u", lat.num, lat.denom);
28
+   snprintf(rate, sizeof(rate), "1/%u", lat.denom);
29
    snprintf(attr_maxlength, sizeof(attr_maxlength), "%u", s->attr.maxlength);
30
    snprintf(attr_tlength, sizeof(attr_tlength), "%u", s->attr.tlength);
31
    snprintf(attr_prebuf, sizeof(attr_prebuf), "%u", s->attr.prebuf);
32
    snprintf(attr_minreq, sizeof(attr_minreq), "%u", s->attr.minreq);
33
 
34
    items[0] = SPA_DICT_ITEM_INIT(PW_KEY_NODE_LATENCY, latency);
35
-   items[1] = SPA_DICT_ITEM_INIT("pulse.attr.maxlength", attr_maxlength);
36
-   items[2] = SPA_DICT_ITEM_INIT("pulse.attr.tlength", attr_tlength);
37
-   items[3] = SPA_DICT_ITEM_INIT("pulse.attr.prebuf", attr_prebuf);
38
-   items[4] = SPA_DICT_ITEM_INIT("pulse.attr.minreq", attr_minreq);
39
-   pw_stream_update_properties(s->stream, &SPA_DICT_INIT(items, 5));
40
+   items[1] = SPA_DICT_ITEM_INIT(PW_KEY_NODE_RATE, rate);
41
+   items[2] = SPA_DICT_ITEM_INIT("pulse.attr.maxlength", attr_maxlength);
42
+   items[3] = SPA_DICT_ITEM_INIT("pulse.attr.tlength", attr_tlength);
43
+   items[4] = SPA_DICT_ITEM_INIT("pulse.attr.prebuf", attr_prebuf);
44
+   items[5] = SPA_DICT_ITEM_INIT("pulse.attr.minreq", attr_minreq);
45
+   pw_stream_update_properties(s->stream, &SPA_DICT_INIT(items, 6));
46
 
47
    if (s->attr.prebuf > 0)
48
        s->in_prebuf = true;
49
@@ -594,8 +599,8 @@
50
 
51
 static uint64_t set_record_buffer_attr(struct stream *s, struct buffer_attr *attr)
52
 {
53
-   struct spa_dict_item items[3];
54
-   char latency[32];
55
+   struct spa_dict_item items[4];
56
+   char latency[32], rate[32];
57
    char attr_maxlength[32];
58
    char attr_fragsize[32];
59
    struct spa_fraction lat;
60
@@ -610,14 +615,16 @@
61
    lat_usec = lat.num * SPA_USEC_PER_SEC / lat.denom;
62
 
63
    snprintf(latency, sizeof(latency), "%u/%u", lat.num, lat.denom);
64
+   snprintf(rate, sizeof(rate), "1/%u", lat.denom);
65
 
66
    snprintf(attr_maxlength, sizeof(attr_maxlength), "%u", s->attr.maxlength);
67
    snprintf(attr_fragsize, sizeof(attr_fragsize), "%u", s->attr.fragsize);
68
 
69
    items[0] = SPA_DICT_ITEM_INIT(PW_KEY_NODE_LATENCY, latency);
70
-   items[1] = SPA_DICT_ITEM_INIT("pulse.attr.maxlength", attr_maxlength);
71
-   items[2] = SPA_DICT_ITEM_INIT("pulse.attr.fragsize", attr_fragsize);
72
-   pw_stream_update_properties(s->stream, &SPA_DICT_INIT(items, 3));
73
+   items[1] = SPA_DICT_ITEM_INIT(PW_KEY_NODE_RATE, rate);
74
+   items[2] = SPA_DICT_ITEM_INIT("pulse.attr.maxlength", attr_maxlength);
75
+   items[3] = SPA_DICT_ITEM_INIT("pulse.attr.fragsize", attr_fragsize);
76
+   pw_stream_update_properties(s->stream, &SPA_DICT_INIT(items, 4));
77
 
78
    return lat_usec;
79
 }
80
@@ -999,8 +1006,10 @@
81
            stream->killed = true;
82
        destroy_stream = true;
83
        break;
84
-   case PW_STREAM_STATE_CONNECTING:
85
    case PW_STREAM_STATE_PAUSED:
86
+       stream->id = pw_stream_get_node_id(stream->stream);
87
+       break;
88
+   case PW_STREAM_STATE_CONNECTING:
89
    case PW_STREAM_STATE_STREAMING:
90
        break;
91
    }
92
@@ -1055,7 +1064,7 @@
93
    if (id != SPA_PARAM_Format || param == NULL)
94
        return;
95
 
96
-   if ((res = format_parse_param(param, &stream->ss, &stream->map, NULL, NULL)) < 0) {
97
+   if ((res = format_parse_param(param, false, &stream->ss, &stream->map, NULL, NULL)) < 0) {
98
        pw_stream_set_error(stream->stream, res, "format not supported");
99
        return;
100
    }
101
@@ -1073,7 +1082,6 @@
102
 
103
    if (stream->create_tag != SPA_ID_INVALID) {
104
        struct pw_manager_object *peer;
105
-       stream->id = pw_stream_get_node_id(stream->stream);
106
 
107
        if (stream->volume_set) {
108
            pw_stream_set_control(stream->stream,
109
@@ -1556,7 +1564,7 @@
110
                n_valid_formats++;
111
            }
112
        }
113
-       if (n_params < MAX_FORMATS &&
114
+       else if (n_params < MAX_FORMATS &&
115
            (params[n_params] = format_build_param(&b,
116
                SPA_PARAM_EnumFormat, &ss,
117
                ss.channels > 0 ? &map : NULL)) != NULL) {
118
@@ -2324,6 +2332,13 @@
119
    return o;
120
 }
121
 
122
+static void sample_play_finish(struct pending_sample *ps)
123
+{
124
+   struct client *client = ps->client;
125
+   pending_sample_free(ps);
126
+   client_unref(client);
127
+}
128
+
129
 static void sample_play_ready_reply(void *data, struct client *client, uint32_t tag)
130
 {
131
    struct pending_sample *ps = data;
132
@@ -2333,6 +2348,8 @@
133
    pw_log_info("[%s] PLAY_SAMPLE tag:%u index:%u",
134
            client->name, ps->tag, index);
135
 
136
+   ps->ready = true;
137
+
138
    reply = reply_new(client, ps->tag);
139
    if (client->version >= 13)
140
        message_put(reply,
141
@@ -2340,6 +2357,9 @@
142
            TAG_INVALID);
143
 
144
    client_queue_message(client, reply);
145
+
146
+   if (ps->done)
147
+       sample_play_finish(ps);
148
 }
149
 
150
 static void sample_play_ready(void *data, uint32_t id)
151
@@ -2352,10 +2372,9 @@
152
 static void on_sample_done(void *obj, void *data, int res, uint32_t id)
153
 {
154
    struct pending_sample *ps = obj;
155
-   struct client *client = ps->client;
156
-
157
-   pending_sample_free(ps);
158
-   client_unref(client);
159
+   ps->done = true;
160
+   if (ps->ready)
161
+       sample_play_finish(ps);
162
 }
163
 
164
 static void sample_play_done(void *data, int res)
165
@@ -4609,7 +4628,9 @@
166
    struct pw_manager_object *o, *dev, *dev_default;
167
    uint32_t index, index_device;
168
    int target_id;
169
+   int64_t target_serial;
170
    const char *name_device;
171
+   struct pw_node_info *info;
172
    struct selector sel;
173
    int res;
174
    bool sink = command == COMMAND_MOVE_SINK_INPUT;
175
@@ -4636,6 +4657,12 @@
176
    if (o == NULL)
177
        return -ENOENT;
178
 
179
+   info = o->info;
180
+   if (info == NULL || info->props == NULL)
181
+       return -EINVAL;
182
+   if (spa_atob(spa_dict_lookup(info->props, PW_KEY_NODE_DONT_RECONNECT)))
183
+       return -EINVAL;
184
+
185
    if ((dev = find_device(client, index_device, name_device, sink, NULL)) == NULL)
186
        return -ENOENT;
187
 
188
@@ -4647,8 +4674,10 @@
189
         * forgetting target.node. Follow that behavior here.
190
         */
191
        target_id = -1;
192
+       target_serial = -1;
193
    } else {
194
        target_id = dev->id;
195
+       target_serial = dev->serial;
196
    }
197
 
198
    if ((res = pw_manager_set_metadata(manager, client->metadata_default,
199
@@ -4657,6 +4686,12 @@
200
            SPA_TYPE_INFO_BASE"Id", "%d", target_id)) < 0)
201
        return res;
202
 
203
+   if ((res = pw_manager_set_metadata(manager, client->metadata_default,
204
+           o->id,
205
+           METADATA_TARGET_OBJECT,
206
+           SPA_TYPE_INFO_BASE"Id", "%"PRIi64, target_serial)) < 0)
207
+       return res;
208
+
209
    return reply_simple_ack(client, tag);
210
 }
211
 
212
@@ -5330,8 +5365,6 @@
213
    impl->props = props;
214
 
215
    impl->work_queue = pw_context_get_work_queue(context);
216
-   if (impl->work_queue == NULL)
217
-       goto error_free;
218
 
219
    spa_list_init(&impl->servers);
220
    impl->rate_limit.interval = 2 * SPA_NSEC_PER_SEC;
221
pipewire-0.3.47.tar.gz/src/modules/module-protocol-simple.c -> pipewire-0.3.48.tar.gz/src/modules/module-protocol-simple.c Changed
12
 
1
@@ -848,10 +848,6 @@
2
    pw_impl_module_update_properties(module, &SPA_DICT_INIT_ARRAY(module_props));
3
 
4
    impl->work_queue = pw_context_get_work_queue(context);
5
-   if (impl->work_queue == NULL) {
6
-       res = -errno;
7
-       goto error_free;
8
-   }
9
 
10
    if ((res = parse_params(impl)) < 0)
11
        goto error_free;
12
pipewire-0.3.47.tar.gz/src/modules/module-pulse-tunnel.c -> pipewire-0.3.48.tar.gz/src/modules/module-pulse-tunnel.c Changed
98
 
1
@@ -48,6 +48,7 @@
2
 
3
 #include <pipewire/impl.h>
4
 #include <pipewire/i18n.h>
5
+#include <pipewire/private.h>
6
 
7
 #include <pulse/pulseaudio.h>
8
 #include "module-protocol-pulse/format.h"
9
@@ -95,7 +96,6 @@
10
    struct pw_properties *props;
11
 
12
    struct pw_impl_module *module;
13
-   struct pw_work_queue *work;
14
 
15
    struct spa_hook module_listener;
16
 
17
@@ -121,23 +121,8 @@
18
    pa_stream *pa_stream;
19
 
20
    unsigned int do_disconnect:1;
21
-   unsigned int unloading:1;
22
 };
23
 
24
-static void do_unload_module(void *obj, void *data, int res, uint32_t id)
25
-{
26
-   struct impl *impl = data;
27
-   pw_impl_module_destroy(impl->module);
28
-}
29
-
30
-static void unload_module(struct impl *impl)
31
-{
32
-   if (!impl->unloading) {
33
-       impl->unloading = true;
34
-       pw_work_queue_add(impl->work, impl, 0, do_unload_module, impl);
35
-   }
36
-}
37
-
38
 static void cork_stream(struct impl *impl, bool cork)
39
 {
40
    pa_operation *operation;
41
@@ -174,7 +159,7 @@
42
    switch (state) {
43
    case PW_STREAM_STATE_ERROR:
44
    case PW_STREAM_STATE_UNCONNECTED:
45
-       unload_module(impl);
46
+       pw_impl_module_schedule_destroy(impl->module);
47
        break;
48
    case PW_STREAM_STATE_PAUSED:
49
        cork_stream(impl, true);
50
@@ -613,7 +598,7 @@
51
            id, seq, res, spa_strerror(res), message);
52
 
53
    if (id == PW_ID_CORE && res == -EPIPE)
54
-       unload_module(impl);
55
+       pw_impl_module_schedule_destroy(impl->module);
56
 }
57
 
58
 static const struct pw_core_events core_events = {
59
@@ -626,7 +611,7 @@
60
    struct impl *impl = d;
61
    spa_hook_remove(&impl->core_listener);
62
    impl->core = NULL;
63
-   unload_module(impl);
64
+   pw_impl_module_schedule_destroy(impl->module);
65
 }
66
 
67
 static const struct pw_proxy_events core_proxy_events = {
68
@@ -655,8 +640,6 @@
69
    pw_properties_free(impl->stream_props);
70
    pw_properties_free(impl->props);
71
 
72
-   if (impl->work)
73
-       pw_work_queue_cancel(impl->work, impl, SPA_ID_INVALID);
74
    free(impl->buffer);
75
    free(impl);
76
 }
77
@@ -664,7 +647,6 @@
78
 static void module_destroy(void *data)
79
 {
80
    struct impl *impl = data;
81
-   impl->unloading = true;
82
    spa_hook_remove(&impl->module_listener);
83
    impl_destroy(impl);
84
 }
85
@@ -779,12 +761,6 @@
86
 
87
    impl->module = module;
88
    impl->context = context;
89
-   impl->work = pw_context_get_work_queue(context);
90
-   if (impl->work == NULL) {
91
-       res = -errno;
92
-       pw_log_error( "can't get work queue: %m");
93
-       goto error;
94
-   }
95
 
96
    spa_ringbuffer_init(&impl->ring);
97
    impl->buffer = calloc(1, RINGBUFFER_SIZE);
98
pipewire-0.3.47.tar.gz/src/modules/module-raop-discover.c -> pipewire-0.3.48.tar.gz/src/modules/module-raop-discover.c Changed
90
 
1
@@ -71,7 +71,6 @@
2
 
3
    struct pw_impl_module *module;
4
    struct spa_hook module_listener;
5
-   struct pw_work_queue *work;
6
 
7
    struct pw_properties *properties;
8
 
9
@@ -80,8 +79,6 @@
10
    AvahiServiceBrowser *sink_browser;
11
 
12
    struct spa_list tunnel_list;
13
-
14
-   unsigned int unloading:1;
15
 };
16
 
17
 struct tunnel_info {
18
@@ -103,20 +100,6 @@
19
 
20
 static int start_client(struct impl *impl);
21
 
22
-static void do_unload_module(void *obj, void *data, int res, uint32_t id)
23
-{
24
-   struct impl *impl = data;
25
-   pw_impl_module_destroy(impl->module);
26
-}
27
-
28
-static void unload_module(struct impl *impl)
29
-{
30
-   if (!impl->unloading) {
31
-       impl->unloading = true;
32
-       pw_work_queue_add(impl->work, impl, 0, do_unload_module, impl);
33
-   }
34
-}
35
-
36
 static struct tunnel *make_tunnel(struct impl *impl, const struct tunnel_info *info)
37
 {
38
    struct tunnel *t;
39
@@ -168,8 +151,6 @@
40
    if (impl->avahi_poll)
41
        pw_avahi_poll_free(impl->avahi_poll);
42
    pw_properties_free(impl->properties);
43
-   if (impl->work)
44
-       pw_work_queue_cancel(impl->work, impl, SPA_ID_INVALID);
45
    free(impl);
46
 }
47
 
48
@@ -340,7 +321,11 @@
49
    }
50
 
51
 
52
-   f = open_memstream(&args, &size);
53
+   if ((f = open_memstream(&args, &size)) == NULL) {
54
+       pw_log_error("Can't open memstream: %m");
55
+       goto done;
56
+   }
57
+
58
    fprintf(f, "{");
59
    pw_properties_serialize_dict(f, &props->dict, 0);
60
    fprintf(f, " stream.props = {");
61
@@ -465,7 +450,7 @@
62
    }
63
    return;
64
 error:
65
-   unload_module(impl);
66
+   pw_impl_module_schedule_destroy(impl->module);
67
 }
68
 
69
 static int start_client(struct impl *impl)
70
@@ -476,7 +461,7 @@
71
                    client_callback, impl,
72
                    &res)) == NULL) {
73
        pw_log_error("can't create client: %s", avahi_strerror(res));
74
-       unload_module(impl);
75
+       pw_impl_module_schedule_destroy(impl->module);
76
        return -EIO;
77
    }
78
    return 0;
79
@@ -521,10 +506,6 @@
80
    impl->context = context;
81
    impl->properties = props;
82
 
83
-   impl->work = pw_context_get_work_queue(context);
84
-   if (impl->work == NULL)
85
-       goto error_errno;
86
-
87
    pw_impl_module_add_listener(module, &impl->module_listener, &module_events, impl);
88
 
89
    pw_impl_module_update_properties(module, &SPA_DICT_INIT_ARRAY(module_props));
90
pipewire-0.3.47.tar.gz/src/modules/module-raop-sink.c -> pipewire-0.3.48.tar.gz/src/modules/module-raop-sink.c Changed
126
 
1
@@ -58,6 +58,7 @@
2
 
3
 #include <pipewire/impl.h>
4
 #include <pipewire/i18n.h>
5
+#include <pipewire/private.h>
6
 
7
 #include "module-raop/rtsp-client.h"
8
 
9
@@ -134,7 +135,6 @@
10
 
11
    struct pw_impl_module *module;
12
    struct pw_loop *loop;
13
-   struct pw_work_queue *work;
14
 
15
    struct spa_hook module_listener;
16
 
17
@@ -160,7 +160,6 @@
18
    char *password;
19
 
20
    unsigned int do_disconnect:1;
21
-   unsigned int unloading:1;
22
 
23
    uint8_t key[AES_CHUNK_SIZE]; /* Key for aes-cbc */
24
    uint8_t iv[AES_CHUNK_SIZE];  /* Initialization vector for cbc */
25
@@ -196,20 +195,6 @@
26
    uint32_t filled;
27
 };
28
 
29
-static void do_unload_module(void *obj, void *data, int res, uint32_t id)
30
-{
31
-   struct impl *impl = data;
32
-   pw_impl_module_destroy(impl->module);
33
-}
34
-
35
-static void unload_module(struct impl *impl)
36
-{
37
-   if (!impl->unloading) {
38
-       impl->unloading = true;
39
-       pw_work_queue_add(impl->work, impl, 0, do_unload_module, impl);
40
-   }
41
-}
42
-
43
 static void stream_destroy(void *d)
44
 {
45
    struct impl *impl = d;
46
@@ -599,6 +584,10 @@
47
 
48
        received = ntp_now(CLOCK_MONOTONIC);
49
        bytes = read(impl->timing_fd, packet, sizeof(packet));
50
+       if (bytes < 0) {
51
+           pw_log_debug("error reading timing packet: %m");
52
+           return;
53
+       }
54
        if (bytes != sizeof(packet)) {
55
            pw_log_warn("discarding short (%zd < %zd) timing packet",
56
                    bytes, sizeof(bytes));
57
@@ -624,7 +613,11 @@
58
        uint32_t hdr;
59
        uint16_t seq, num;
60
 
61
-       bytes = read(impl->timing_fd, packet, sizeof(packet));
62
+       bytes = read(impl->control_fd, packet, sizeof(packet));
63
+       if (bytes < 0) {
64
+           pw_log_debug("error reading control packet: %m");
65
+           return;
66
+       }
67
        if (bytes != sizeof(packet)) {
68
            pw_log_warn("discarding short (%zd < %zd) control packet",
69
                    bytes, sizeof(bytes));
70
@@ -1260,7 +1253,7 @@
71
    switch (state) {
72
    case PW_STREAM_STATE_ERROR:
73
    case PW_STREAM_STATE_UNCONNECTED:
74
-       unload_module(impl);
75
+       pw_impl_module_schedule_destroy(impl->module);
76
        break;
77
    case PW_STREAM_STATE_PAUSED:
78
        rtsp_do_flush(impl);
79
@@ -1394,7 +1387,7 @@
80
            id, seq, res, spa_strerror(res), message);
81
 
82
    if (id == PW_ID_CORE && res == -EPIPE)
83
-       unload_module(impl);
84
+       pw_impl_module_schedule_destroy(impl->module);
85
 }
86
 
87
 static const struct pw_core_events core_events = {
88
@@ -1407,7 +1400,7 @@
89
    struct impl *impl = d;
90
    spa_hook_remove(&impl->core_listener);
91
    impl->core = NULL;
92
-   unload_module(impl);
93
+   pw_impl_module_schedule_destroy(impl->module);
94
 }
95
 
96
 static const struct pw_proxy_events core_proxy_events = {
97
@@ -1428,15 +1421,12 @@
98
    pw_properties_free(impl->stream_props);
99
    pw_properties_free(impl->props);
100
    free(impl->password);
101
-   if (impl->work)
102
-       pw_work_queue_cancel(impl->work, impl, SPA_ID_INVALID);
103
    free(impl);
104
 }
105
 
106
 static void module_destroy(void *data)
107
 {
108
    struct impl *impl = data;
109
-   impl->unloading = true;
110
    spa_hook_remove(&impl->module_listener);
111
    impl_destroy(impl);
112
 }
113
@@ -1587,12 +1577,6 @@
114
    impl->module = module;
115
    impl->context = context;
116
    impl->loop = pw_context_get_main_loop(context);
117
-   impl->work = pw_context_get_work_queue(context);
118
-   if (impl->work == NULL) {
119
-       res = -errno;
120
-       pw_log_error( "can't get work queue: %m");
121
-       goto error;
122
-   }
123
 
124
    if (pw_properties_get(props, PW_KEY_NODE_GROUP) == NULL)
125
        pw_properties_set(props, PW_KEY_NODE_GROUP, "pipewire.dummy");
126
pipewire-0.3.47.tar.gz/src/modules/module-raop/rtsp-client.c -> pipewire-0.3.48.tar.gz/src/modules/module-raop/rtsp-client.c Changed
11
 
1
@@ -478,7 +478,8 @@
2
    struct message *msg;
3
    int cseq;
4
 
5
-   f = open_memstream((char**)&msg, &len);
6
+   if ((f = open_memstream((char**)&msg, &len)) == NULL)
7
+       return -errno;
8
 
9
    fseek(f, sizeof(*msg), SEEK_SET);
10
 
11
pipewire-0.3.47.tar.gz/src/modules/module-roc-sink.c -> pipewire-0.3.48.tar.gz/src/modules/module-roc-sink.c Changed
95
 
1
@@ -96,7 +96,6 @@
2
 
3
 struct module_roc_sink_data {
4
    struct pw_impl_module *module;
5
-   struct pw_work_queue *work;
6
    struct spa_hook module_listener;
7
    struct pw_properties *props;
8
    struct pw_context *module_context;
9
@@ -110,7 +109,6 @@
10
    struct pw_properties *capture_props;
11
 
12
    unsigned int do_disconnect:1;
13
-   unsigned int unloading:1;
14
 
15
    roc_address local_addr;
16
    roc_address remote_source_addr;
17
@@ -124,20 +122,6 @@
18
    int remote_repair_port;
19
 };
20
 
21
-static void do_unload_module(void *obj, void *d, int res, uint32_t id)
22
-{
23
-   struct module_roc_sink_data *data = d;
24
-   pw_impl_module_destroy(data->module);
25
-}
26
-
27
-static void unload_module(struct module_roc_sink_data *data)
28
-{
29
-   if (!data->unloading) {
30
-       data->unloading = true;
31
-       pw_work_queue_add(data->work, data, 0, do_unload_module, data);
32
-   }
33
-}
34
-
35
 static void stream_destroy(void *d)
36
 {
37
    struct module_roc_sink_data *data = d;
38
@@ -189,7 +173,7 @@
39
            id, seq, res, spa_strerror(res), message);
40
 
41
    if (id == PW_ID_CORE && res == -EPIPE)
42
-       unload_module(data);
43
+       pw_impl_module_schedule_destroy(data->module);
44
 }
45
 
46
 static const struct pw_core_events core_events = {
47
@@ -205,7 +189,7 @@
48
    switch (state) {
49
    case PW_STREAM_STATE_UNCONNECTED:
50
        pw_log_info("stream disconnected, unloading");
51
-       unload_module(data);
52
+       pw_impl_module_schedule_destroy(data->module);
53
        break;
54
    case PW_STREAM_STATE_ERROR:
55
        pw_log_error("stream error: %s", error);
56
@@ -227,7 +211,7 @@
57
    struct module_roc_sink_data *data = d;
58
    spa_hook_remove(&data->core_listener);
59
    data->core = NULL;
60
-   unload_module(data);
61
+   pw_impl_module_schedule_destroy(data->module);
62
 }
63
 
64
 static const struct pw_proxy_events core_proxy_events = {
65
@@ -244,8 +228,6 @@
66
    pw_properties_free(data->capture_props);
67
    pw_properties_free(data->props);
68
 
69
-   if (data->work)
70
-       pw_work_queue_cancel(data->work, data, SPA_ID_INVALID);
71
    if (data->sender)
72
        roc_sender_close(data->sender);
73
    if (data->context)
74
@@ -259,7 +241,6 @@
75
 static void module_destroy(void *d)
76
 {
77
    struct module_roc_sink_data *data = d;
78
-   data->unloading = true;
79
    spa_hook_remove(&data->module_listener);
80
    impl_destroy(data);
81
 }
82
@@ -416,12 +397,6 @@
83
 
84
    data->module = module;
85
    data->module_context = context;
86
-   data->work = pw_context_get_work_queue(context);
87
-   if (data->work == NULL) {
88
-       res = -errno;
89
-       pw_log_error( "can't get work queue: %m");
90
-       goto out;
91
-   }
92
 
93
    if ((str = pw_properties_get(props, "sink.name")) != NULL) {
94
        pw_properties_set(capture_props, PW_KEY_NODE_NAME, str);
95
pipewire-0.3.47.tar.gz/src/modules/module-roc-source.c -> pipewire-0.3.48.tar.gz/src/modules/module-roc-source.c Changed
104
 
1
@@ -100,7 +100,6 @@
2
 
3
 struct module_roc_source_data {
4
    struct pw_impl_module *module;
5
-   struct pw_work_queue *work;
6
    struct spa_hook module_listener;
7
    struct pw_properties *props;
8
    struct pw_context *module_context;
9
@@ -114,7 +113,6 @@
10
    struct pw_properties *playback_props;
11
 
12
    unsigned int do_disconnect:1;
13
-   unsigned int unloading:1;
14
 
15
    roc_address local_addr;
16
    roc_address local_source_addr;
17
@@ -129,20 +127,6 @@
18
    int sess_latency_msec;
19
 };
20
 
21
-static void do_unload_module(void *obj, void *d, int res, uint32_t id)
22
-{
23
-   struct module_roc_source_data *data = d;
24
-   pw_impl_module_destroy(data->module);
25
-}
26
-
27
-static void unload_module(struct module_roc_source_data *data)
28
-{
29
-   if (!data->unloading) {
30
-       data->unloading = true;
31
-       pw_work_queue_add(data->work, data, 0, do_unload_module, data);
32
-   }
33
-}
34
-
35
 static void stream_destroy(void *d)
36
 {
37
    struct module_roc_source_data *data = d;
38
@@ -202,7 +186,7 @@
39
    if (roc_receiver_read(impl->receiver, &frame) != 0) {
40
        /* Handle EOF and error */
41
        pw_log_error("Failed to read from roc source");
42
-       unload_module(data);
43
+       pw_impl_module_schedule_destroy(impl->module);
44
        return;
45
    }
46
 
47
@@ -219,7 +203,7 @@
48
            id, seq, res, spa_strerror(res), message);
49
 
50
    if (id == PW_ID_CORE && res == -EPIPE)
51
-       unload_module(data);
52
+       pw_impl_module_schedule_destroy(data->module);
53
 }
54
 
55
 static const struct pw_core_events core_events = {
56
@@ -235,7 +219,7 @@
57
    switch (state) {
58
    case PW_STREAM_STATE_UNCONNECTED:
59
        pw_log_info("stream disconnected, unloading");
60
-       unload_module(data);
61
+       pw_impl_module_schedule_destroy(data->module);
62
        break;
63
    case PW_STREAM_STATE_ERROR:
64
        pw_log_error("stream error: %s", error);
65
@@ -257,7 +241,7 @@
66
    struct module_roc_source_data *data = d;
67
    spa_hook_remove(&data->core_listener);
68
    data->core = NULL;
69
-   unload_module(data);
70
+   pw_impl_module_schedule_destroy(data->module);
71
 }
72
 
73
 static const struct pw_proxy_events core_proxy_events = {
74
@@ -274,8 +258,6 @@
75
    pw_properties_free(data->playback_props);
76
    pw_properties_free(data->props);
77
 
78
-   if (data->work)
79
-       pw_work_queue_cancel(data->work, data, SPA_ID_INVALID);
80
    if (data->receiver)
81
        roc_receiver_close(data->receiver);
82
    if (data->context)
83
@@ -289,7 +271,6 @@
84
 static void module_destroy(void *d)
85
 {
86
    struct module_roc_source_data *data = d;
87
-   data->unloading = true;
88
    spa_hook_remove(&data->module_listener);
89
    impl_destroy(data);
90
 }
91
@@ -461,12 +442,6 @@
92
 
93
    data->module = module;
94
    data->module_context = context;
95
-   data->work = pw_context_get_work_queue(context);
96
-   if (data->work == NULL) {
97
-       res = -errno;
98
-       pw_log_error( "can't get work queue: %m");
99
-       goto out;
100
-   }
101
 
102
    if ((str = pw_properties_get(props, "source.name")) != NULL) {
103
        pw_properties_set(playback_props, PW_KEY_NODE_NAME, str);
104
pipewire-0.3.47.tar.gz/src/modules/module-session-manager/endpoint-link.c -> pipewire-0.3.48.tar.gz/src/modules/module-session-manager/endpoint-link.c Changed
28
 
1
@@ -389,6 +389,15 @@
2
              struct pw_properties *properties)
3
 {
4
    struct impl *impl;
5
+   char serial_str[32];
6
+   struct spa_dict_item items[1] = {
7
+       SPA_DICT_ITEM_INIT(PW_KEY_OBJECT_SERIAL, serial_str),
8
+   };
9
+   struct spa_dict extra_props = SPA_DICT_INIT_ARRAY(items);
10
+   static const char * const keys[] = {
11
+       PW_KEY_OBJECT_SERIAL,
12
+       NULL
13
+   };
14
 
15
    impl = calloc(1, sizeof(*impl));
16
    if (impl == NULL) {
17
@@ -407,6 +416,10 @@
18
    }
19
    impl->resource = resource;
20
 
21
+   spa_scnprintf(serial_str, sizeof(serial_str), "%"PRIu64,
22
+           pw_global_get_serial(impl->global));
23
+   pw_global_update_keys(impl->global, &extra_props, keys);
24
+
25
    spa_list_init(&impl->cached_params);
26
 
27
    /* handle destroy events */
28
pipewire-0.3.47.tar.gz/src/modules/module-session-manager/endpoint-stream.c -> pipewire-0.3.48.tar.gz/src/modules/module-session-manager/endpoint-stream.c Changed
28
 
1
@@ -380,6 +380,15 @@
2
              struct pw_properties *properties)
3
 {
4
    struct impl *impl;
5
+   char serial_str[32];
6
+   struct spa_dict_item items[1] = {
7
+       SPA_DICT_ITEM_INIT(PW_KEY_OBJECT_SERIAL, serial_str),
8
+   };
9
+   struct spa_dict extra_props = SPA_DICT_INIT_ARRAY(items);
10
+   static const char * const keys[] = {
11
+       PW_KEY_OBJECT_SERIAL,
12
+       NULL
13
+   };
14
 
15
    impl = calloc(1, sizeof(*impl));
16
    if (impl == NULL) {
17
@@ -398,6 +407,10 @@
18
    }
19
    impl->resource = resource;
20
 
21
+   spa_scnprintf(serial_str, sizeof(serial_str), "%"PRIu64,
22
+           pw_global_get_serial(impl->global));
23
+   pw_global_update_keys(impl->global, &extra_props, keys);
24
+
25
    spa_list_init(&impl->cached_params);
26
 
27
    /* handle destroy events */
28
pipewire-0.3.47.tar.gz/src/modules/module-session-manager/endpoint.c -> pipewire-0.3.48.tar.gz/src/modules/module-session-manager/endpoint.c Changed
28
 
1
@@ -389,6 +389,15 @@
2
              struct pw_properties *properties)
3
 {
4
    struct impl *impl;
5
+   char serial_str[32];
6
+   struct spa_dict_item items[1] = {
7
+       SPA_DICT_ITEM_INIT(PW_KEY_OBJECT_SERIAL, serial_str),
8
+   };
9
+   struct spa_dict extra_props = SPA_DICT_INIT_ARRAY(items);
10
+   static const char * const keys[] = {
11
+       PW_KEY_OBJECT_SERIAL,
12
+       NULL
13
+   };
14
 
15
    impl = calloc(1, sizeof(*impl));
16
    if (impl == NULL) {
17
@@ -407,6 +416,10 @@
18
    }
19
    impl->resource = resource;
20
 
21
+   spa_scnprintf(serial_str, sizeof(serial_str), "%"PRIu64,
22
+           pw_global_get_serial(impl->global));
23
+   pw_global_update_keys(impl->global, &extra_props, keys);
24
+
25
    spa_list_init(&impl->cached_params);
26
 
27
    /* handle destroy events */
28
pipewire-0.3.47.tar.gz/src/modules/module-session-manager/protocol-native.c -> pipewire-0.3.48.tar.gz/src/modules/module-session-manager/protocol-native.c Changed
12
 
1
@@ -32,8 +32,8 @@
2
 #include <pipewire/extensions/session-manager.h>
3
 #include <pipewire/extensions/protocol-native.h>
4
 
5
-#define MAX_DICT   256
6
-#define MAX_PARAMS 128
7
+#define MAX_DICT   1024
8
+#define MAX_PARAMS 4096
9
 #define MAX_PARAM_INFO 128
10
 
11
 static void push_dict(struct spa_pod_builder *b, const struct spa_dict *dict)
12
pipewire-0.3.47.tar.gz/src/modules/module-session-manager/session.c -> pipewire-0.3.48.tar.gz/src/modules/module-session-manager/session.c Changed
28
 
1
@@ -378,6 +378,15 @@
2
              struct pw_properties *properties)
3
 {
4
    struct impl *impl;
5
+   char serial_str[32];
6
+   struct spa_dict_item items[1] = {
7
+       SPA_DICT_ITEM_INIT(PW_KEY_OBJECT_SERIAL, serial_str),
8
+   };
9
+   struct spa_dict extra_props = SPA_DICT_INIT_ARRAY(items);
10
+   static const char * const keys[] = {
11
+       PW_KEY_OBJECT_SERIAL,
12
+       NULL
13
+   };
14
 
15
    impl = calloc(1, sizeof(*impl));
16
    if (impl == NULL) {
17
@@ -396,6 +405,10 @@
18
    }
19
    impl->resource = resource;
20
 
21
+   spa_scnprintf(serial_str, sizeof(serial_str), "%"PRIu64,
22
+           pw_global_get_serial(impl->global));
23
+   pw_global_update_keys(impl->global, &extra_props, keys);
24
+
25
    spa_list_init(&impl->cached_params);
26
 
27
    /* handle destroy events */
28
pipewire-0.3.47.tar.gz/src/modules/module-x11-bell.c -> pipewire-0.3.48.tar.gz/src/modules/module-x11-bell.c Changed
297
 
1
@@ -38,10 +38,15 @@
2
 #include <X11/Xlib-xcb.h>
3
 #include <X11/XKBlib.h>
4
 
5
+#ifdef HAVE_XFIXES_6
6
+#include <X11/extensions/Xfixes.h>
7
+#endif
8
+
9
 #include <canberra.h>
10
 
11
-#include "pipewire/pipewire.h"
12
-#include "pipewire/impl.h"
13
+#include <pipewire/pipewire.h>
14
+#include <pipewire/impl.h>
15
+#include <pipewire/private.h>
16
 
17
 /** \page page_module_x11_bell PipeWire Module: X11 Bell
18
  *
19
@@ -81,21 +86,30 @@
20
 struct impl {
21
    struct pw_context *context;
22
    struct pw_thread_loop *thread_loop;
23
+   struct pw_loop *thread_loop_loop;
24
    struct pw_loop *loop;
25
    struct spa_source *source;
26
 
27
    struct pw_properties *properties;
28
 
29
+   struct pw_impl_module *module;
30
    struct spa_hook module_listener;
31
 
32
    Display *display;
33
-   int xkb_event_base;
34
 };
35
 
36
-static int play_sample(struct impl *impl, const char *sample)
37
+static int play_sample(struct impl *impl)
38
 {
39
-   int res;
40
+   const char *sample = NULL;
41
    ca_context *ca;
42
+   int res;
43
+
44
+   if (impl->properties)
45
+       sample = pw_properties_get(impl->properties, "sample.name");
46
+   if (sample == NULL)
47
+       sample = "bell-window-system";
48
+
49
+   pw_log_debug("play sample %s", sample);
50
 
51
    if ((res = ca_context_create(&ca)) < 0) {
52
        pw_log_error("canberra context create error: %s", ca_strerror(res));
53
@@ -113,6 +127,8 @@
54
            CA_PROP_CANBERRA_CACHE_CONTROL, "permanent",
55
            NULL)) < 0) {
56
        pw_log_warn("can't play sample (%s): %s", sample, ca_strerror(res));
57
+       res = -EIO;
58
+       goto exit_destroy;
59
    }
60
 
61
 exit_destroy:
62
@@ -120,11 +136,17 @@
63
 exit:
64
    return res;
65
 }
66
+
67
+static int do_play_sample(struct spa_loop *loop, bool async, uint32_t seq, const void *data, size_t size, void *user_data)
68
+{
69
+   play_sample(user_data);
70
+   return 0;
71
+}
72
+
73
 static void display_io(void *data, int fd, uint32_t mask)
74
 {
75
    struct impl *impl = data;
76
    XEvent e;
77
-   const char *sample = NULL;
78
 
79
    while (XPending(impl->display)) {
80
        XNextEvent(impl->display, &e);
81
@@ -132,60 +154,64 @@
82
        if (((XkbEvent*) &e)->any.xkb_type != XkbBellNotify)
83
            continue;
84
 
85
-       if (impl->properties)
86
-           sample = pw_properties_get(impl->properties, "sample.name");
87
-       if (sample == NULL)
88
-           sample = "bell-window-system";
89
-
90
-       pw_log_debug("play sample %s", sample);
91
-       play_sample(impl, sample);
92
+       pw_loop_invoke(impl->thread_loop_loop, do_play_sample, 0, NULL, 0, false, impl);
93
    }
94
 }
95
 
96
-static void x11_close(struct impl *impl)
97
+#ifdef HAVE_XSETIOERROREXITHANDLER
98
+static void x11_io_error_exit_handler(Display *display, void *data)
99
 {
100
-   if (impl->source) {
101
-       pw_loop_destroy_source(impl->loop, impl->source);
102
-       impl->source = NULL;
103
-   }
104
-   if (impl->display) {
105
-       XCloseDisplay(impl->display);
106
-       impl->display = NULL;
107
-   }
108
+   struct impl *impl = data;
109
+
110
+   spa_assert(display == impl->display);
111
+
112
+   pw_log_warn("X11 display (%s) has encountered a fatal I/O error", DisplayString(display));
113
+
114
+   pw_loop_destroy_source(impl->loop, impl->source);
115
+   impl->source = NULL;
116
+
117
+   pw_impl_module_schedule_destroy(impl->module);
118
 }
119
+#endif
120
 
121
 static int x11_connect(struct impl *impl, const char *name)
122
 {
123
-   int res, major, minor;
124
+   int major, minor;
125
    unsigned int auto_ctrls, auto_values;
126
 
127
    if (!(impl->display = XOpenDisplay(name))) {
128
-       pw_log_warn("XOpenDisplay() failed");
129
-       res = -EIO;
130
-       goto error;
131
+       pw_log_error("XOpenDisplay() failed");
132
+       return -EIO;
133
    }
134
 
135
    impl->source = pw_loop_add_io(impl->loop,
136
            ConnectionNumber(impl->display),
137
            SPA_IO_IN, false, display_io, impl);
138
+   if (!impl->source)
139
+       return -errno;
140
+
141
+#ifdef HAVE_XSETIOERROREXITHANDLER
142
+   XSetIOErrorExitHandler(impl->display, x11_io_error_exit_handler, impl);
143
+#endif
144
+
145
+#ifdef HAVE_XFIXES_6
146
+   XFixesSetClientDisconnectMode(impl->display, XFixesClientDisconnectFlagTerminate);
147
+#endif
148
 
149
    major = XkbMajorVersion;
150
    minor = XkbMinorVersion;
151
 
152
    if (!XkbLibraryVersion(&major, &minor)) {
153
-       pw_log_warn("XkbLibraryVersion() failed");
154
-       res = -EIO;
155
-       goto error;
156
+       pw_log_error("XkbLibraryVersion() failed");
157
+       return -EIO;
158
    }
159
 
160
    major = XkbMajorVersion;
161
    minor = XkbMinorVersion;
162
 
163
-   if (!XkbQueryExtension(impl->display, NULL, &impl->xkb_event_base,
164
-               NULL, &major, &minor)) {
165
-       res = -EIO;
166
-       pw_log_warn("XkbQueryExtension() failed");
167
-       goto error;
168
+   if (!XkbQueryExtension(impl->display, NULL, NULL, NULL, &major, &minor)) {
169
+       pw_log_error("XkbQueryExtension() failed");
170
+       return -EIO;
171
    }
172
 
173
    XkbSelectEvents(impl->display, XkbUseCoreKbd, XkbBellNotifyMask, XkbBellNotifyMask);
174
@@ -193,28 +219,24 @@
175
    XkbSetAutoResetControls(impl->display, XkbAudibleBellMask, &auto_ctrls, &auto_values);
176
    XkbChangeEnabledControls(impl->display, XkbUseCoreKbd, XkbAudibleBellMask, 0);
177
 
178
-   res = 0;
179
-error:
180
-   if (res < 0)
181
-       x11_close(impl);
182
-   return res;
183
+   return 0;
184
 }
185
 
186
 static void module_destroy(void *data)
187
 {
188
    struct impl *impl = data;
189
 
190
-   spa_hook_remove(&impl->module_listener);
191
+   if (impl->module)
192
+       spa_hook_remove(&impl->module_listener);
193
 
194
-   if (impl->thread_loop)
195
-       pw_thread_loop_lock(impl->thread_loop);
196
+   if (impl->source)
197
+       pw_loop_destroy_source(impl->loop, impl->source);
198
 
199
-   x11_close(impl);
200
+   if (impl->display)
201
+       XCloseDisplay(impl->display);
202
 
203
-   if (impl->thread_loop) {
204
-       pw_thread_loop_unlock(impl->thread_loop);
205
+   if (impl->thread_loop)
206
        pw_thread_loop_destroy(impl->thread_loop);
207
-   }
208
 
209
    pw_properties_free(impl->properties);
210
 
211
@@ -252,15 +274,18 @@
212
    pw_log_debug("module %p: new", impl);
213
 
214
    impl->context = context;
215
+   impl->loop = pw_context_get_main_loop(context);
216
+
217
    impl->thread_loop = pw_thread_loop_new("X11 Bell", NULL);
218
    if (impl->thread_loop == NULL) {
219
        res = -errno;
220
        pw_log_error("can't create thread loop: %m");
221
        goto error;
222
    }
223
-   impl->loop = pw_thread_loop_get_loop(impl->thread_loop);
224
+   impl->thread_loop_loop = pw_thread_loop_get_loop(impl->thread_loop);
225
    impl->properties = args ? pw_properties_new_string(args) : NULL;
226
 
227
+   impl->module = module;
228
    pw_impl_module_add_listener(module, &impl->module_listener, &module_events, impl);
229
    pw_impl_module_update_properties(module, &SPA_DICT_INIT_ARRAY(module_x11_bell_info));
230
 
231
@@ -279,9 +304,9 @@
232
     * to pipewire eventually and will then block the mainloop. */
233
    pw_thread_loop_start(impl->thread_loop);
234
 
235
-   pw_thread_loop_lock(impl->thread_loop);
236
-   x11_connect(impl, name);
237
-   pw_thread_loop_unlock(impl->thread_loop);
238
+   res = x11_connect(impl, name);
239
+   if (res < 0)
240
+       goto error;
241
 
242
    return 0;
243
 error:
244
@@ -289,3 +314,52 @@
245
    return res;
246
 
247
 }
248
+
249
+static int x11_error_handler(Display *display, XErrorEvent *error)
250
+{
251
+   pw_log_warn("X11 error handler called on display %s with error %d",
252
+           DisplayString(display), error->error_code);
253
+   return 0;
254
+}
255
+
256
+static int x11_io_error_handler(Display *display)
257
+{
258
+   pw_log_warn("X11 I/O error handler called on display %s", DisplayString(display));
259
+   return 0;
260
+}
261
+
262
+__attribute__((constructor))
263
+static void set_x11_handlers(void)
264
+{
265
+   {
266
+       XErrorHandler prev = XSetErrorHandler(NULL);
267
+       XErrorHandler def = XSetErrorHandler(x11_error_handler);
268
+
269
+       if (prev != def)
270
+           XSetErrorHandler(prev);
271
+   }
272
+
273
+   {
274
+       XIOErrorHandler prev = XSetIOErrorHandler(NULL);
275
+       XIOErrorHandler def = XSetIOErrorHandler(x11_io_error_handler);
276
+
277
+       if (prev != def)
278
+           XSetIOErrorHandler(prev);
279
+   }
280
+}
281
+
282
+__attribute__((destructor))
283
+static void restore_x11_handlers(void)
284
+{
285
+   {
286
+       XErrorHandler prev = XSetErrorHandler(NULL);
287
+       if (prev != x11_error_handler)
288
+           XSetErrorHandler(prev);
289
+   }
290
+
291
+   {
292
+       XIOErrorHandler prev = XSetIOErrorHandler(NULL);
293
+       if (prev != x11_io_error_handler)
294
+           XSetIOErrorHandler(prev);
295
+   }
296
+}
297
pipewire-0.3.47.tar.gz/src/modules/module-zeroconf-discover.c -> pipewire-0.3.48.tar.gz/src/modules/module-zeroconf-discover.c Changed
90
 
1
@@ -73,7 +73,6 @@
2
 
3
    struct pw_impl_module *module;
4
    struct spa_hook module_listener;
5
-   struct pw_work_queue *work;
6
 
7
    struct pw_properties *properties;
8
 
9
@@ -83,8 +82,6 @@
10
    AvahiServiceBrowser *source_browser;
11
 
12
    struct spa_list tunnel_list;
13
-
14
-   unsigned int unloading:1;
15
 };
16
 
17
 struct tunnel_info {
18
@@ -106,20 +103,6 @@
19
 
20
 static int start_client(struct impl *impl);
21
 
22
-static void do_unload_module(void *obj, void *data, int res, uint32_t id)
23
-{
24
-   struct impl *impl = data;
25
-   pw_impl_module_destroy(impl->module);
26
-}
27
-
28
-static void unload_module(struct impl *impl)
29
-{
30
-   if (!impl->unloading) {
31
-       impl->unloading = true;
32
-       pw_work_queue_add(impl->work, impl, 0, do_unload_module, impl);
33
-   }
34
-}
35
-
36
 static struct tunnel *make_tunnel(struct impl *impl, const struct tunnel_info *info)
37
 {
38
    struct tunnel *t;
39
@@ -173,8 +156,6 @@
40
    if (impl->avahi_poll)
41
        pw_avahi_poll_free(impl->avahi_poll);
42
    pw_properties_free(impl->properties);
43
-   if (impl->work)
44
-       pw_work_queue_cancel(impl->work, impl, SPA_ID_INVALID);
45
    free(impl);
46
 }
47
 
48
@@ -348,7 +329,11 @@
49
                _("%s on %s"), desc, fqdn);
50
    }
51
 
52
-   f = open_memstream(&args, &size);
53
+   if ((f = open_memstream(&args, &size)) == NULL) {
54
+       pw_log_error("Can't open memstream: %m");
55
+       goto done;
56
+   }
57
+
58
    fprintf(f, "{");
59
    pw_properties_serialize_dict(f, &props->dict, 0);
60
    fprintf(f, " stream.props = {");
61
@@ -483,7 +468,7 @@
62
    }
63
    return;
64
 error:
65
-   unload_module(impl);
66
+   pw_impl_module_schedule_destroy(impl->module);
67
 }
68
 
69
 static int start_client(struct impl *impl)
70
@@ -494,7 +479,7 @@
71
                    client_callback, impl,
72
                    &res)) == NULL) {
73
        pw_log_error("can't create client: %s", avahi_strerror(res));
74
-       unload_module(impl);
75
+       pw_impl_module_schedule_destroy(impl->module);
76
        return -EIO;
77
    }
78
    return 0;
79
@@ -539,10 +524,6 @@
80
    impl->context = context;
81
    impl->properties = props;
82
 
83
-   impl->work = pw_context_get_work_queue(context);
84
-   if (impl->work == NULL)
85
-       goto error_errno;
86
-
87
    pw_impl_module_add_listener(module, &impl->module_listener, &module_events, impl);
88
 
89
    pw_impl_module_update_properties(module, &SPA_DICT_INIT_ARRAY(module_props));
90
pipewire-0.3.47.tar.gz/src/pipewire/conf.c -> pipewire-0.3.48.tar.gz/src/pipewire/conf.c Changed
45
 
1
@@ -863,23 +863,24 @@
2
        struct pw_properties *conf, const char *section)
3
 {
4
    struct data data = { .context = context };
5
+   int res;
6
 
7
    if (spa_streq(section, "context.spa-libs"))
8
-       pw_context_conf_section_for_each(context, section,
9
+       res = pw_context_conf_section_for_each(context, section,
10
                parse_spa_libs, &data);
11
    else if (spa_streq(section, "context.modules"))
12
-       pw_context_conf_section_for_each(context, section,
13
+       res = pw_context_conf_section_for_each(context, section,
14
                parse_modules, &data);
15
    else if (spa_streq(section, "context.objects"))
16
-       pw_context_conf_section_for_each(context, section,
17
+       res = pw_context_conf_section_for_each(context, section,
18
                parse_objects, &data);
19
    else if (spa_streq(section, "context.exec"))
20
-       pw_context_conf_section_for_each(context, section,
21
+       res = pw_context_conf_section_for_each(context, section,
22
                parse_exec, &data);
23
    else
24
-       data.count = -EINVAL;
25
+       res = -EINVAL;
26
 
27
-   return data.count;
28
+   return res == 0 ? data.count : res;
29
 }
30
 
31
 static int update_props(void *user_data, const char *location, const char *key,
32
@@ -895,9 +896,10 @@
33
        const char *section, struct pw_properties *props)
34
 {
35
    struct data data = { .context = context, .props = props };
36
-   pw_context_conf_section_for_each(context, section,
37
+   int res;
38
+   res = pw_context_conf_section_for_each(context, section,
39
                update_props, &data);
40
-   return data.count;
41
+   return res == 0 ? data.count : res;
42
 }
43
 
44
 struct match {
45
pipewire-0.3.47.tar.gz/src/pipewire/context.c -> pipewire-0.3.48.tar.gz/src/pipewire/context.c Changed
66
 
1
@@ -178,6 +178,22 @@
2
        impl);
3
 }
4
 
5
+static int do_data_loop_setup(struct spa_loop *loop, bool async, uint32_t seq,
6
+       const void *data, size_t size, void *user_data)
7
+{
8
+   struct pw_context *this = user_data;
9
+   const char *str;
10
+   struct spa_cpu *cpu;
11
+
12
+   cpu = spa_support_find(this->support, this->n_support, SPA_TYPE_INTERFACE_CPU);
13
+
14
+   if ((str = pw_properties_get(this->properties, SPA_KEY_CPU_ZERO_DENORMALS)) != NULL &&
15
+       cpu != NULL) {
16
+       pw_log_info("setting zero denormals: %s", str);
17
+       spa_cpu_zero_denormals(cpu, spa_atob(str));
18
+   }
19
+   return 0;
20
+}
21
 
22
 /** Create a new context object
23
  *
24
@@ -290,9 +306,6 @@
25
        if (pw_properties_get(properties, PW_KEY_CPU_MAX_ALIGN) == NULL)
26
            pw_properties_setf(properties, PW_KEY_CPU_MAX_ALIGN,
27
                "%u", spa_cpu_get_max_align(cpu));
28
-       if ((str = pw_properties_get(properties, SPA_KEY_CPU_ZERO_DENORMALS)) == NULL)
29
-           str = "true";
30
-       spa_cpu_zero_denormals(cpu, spa_atob(str));
31
    }
32
 
33
    if (getenv("PIPEWIRE_DEBUG") == NULL &&
34
@@ -330,6 +343,12 @@
35
    this->data_system = this->data_loop->system;
36
    this->main_loop = main_loop;
37
 
38
+   this->work_queue = pw_work_queue_new(this->main_loop);
39
+   if (this->work_queue == NULL) {
40
+       res = -errno;
41
+       goto error_free;
42
+   }
43
+
44
    init_plugin_loader(impl);
45
 
46
    this->support[n_support++] = SPA_SUPPORT_INIT(SPA_TYPE_INTERFACE_System, this->main_loop->system);
47
@@ -389,6 +408,9 @@
48
    if ((res = pw_data_loop_start(this->data_loop_impl)) < 0)
49
        goto error_free;
50
 
51
+   pw_data_loop_invoke(this->data_loop_impl,
52
+           do_data_loop_setup, 0, NULL, 0, false, this);
53
+
54
    context_set_freewheel(this, false);
55
 
56
    pw_settings_expose(this);
57
@@ -520,8 +542,6 @@
58
 SPA_EXPORT
59
 struct pw_work_queue *pw_context_get_work_queue(struct pw_context *context)
60
 {
61
-   if (context->work_queue == NULL)
62
-       context->work_queue = pw_work_queue_new(context->main_loop);
63
    return context->work_queue;
64
 }
65
 
66
pipewire-0.3.47.tar.gz/src/pipewire/filter.c -> pipewire-0.3.48.tar.gz/src/pipewire/filter.c Changed
70
 
1
@@ -35,6 +35,7 @@
2
 #include <spa/utils/ringbuffer.h>
3
 #include <spa/utils/string.h>
4
 #include <spa/pod/filter.h>
5
+#include <spa/pod/dynamic.h>
6
 #include <spa/debug/format.h>
7
 #include <spa/debug/types.h>
8
 #include <spa/debug/pod.h>
9
@@ -146,9 +147,10 @@
10
    uint32_t change_mask_all;
11
    struct spa_node_info info;
12
    struct spa_list param_list;
13
-#define IDX_Props      0
14
-#define IDX_ProcessLatency 1
15
-#define N_NODE_PARAMS      2
16
+#define IDX_PropInfo       0
17
+#define IDX_Props      1
18
+#define IDX_ProcessLatency 2
19
+#define N_NODE_PARAMS      3
20
    struct spa_param_info params[N_NODE_PARAMS];
21
 
22
    struct spa_process_latency_info process_latency;
23
@@ -173,6 +175,8 @@
24
 static int get_param_index(uint32_t id)
25
 {
26
    switch (id) {
27
+   case SPA_PARAM_PropInfo:
28
+       return IDX_PropInfo;
29
    case SPA_PARAM_Props:
30
        return IDX_Props;
31
    case SPA_PARAM_ProcessLatency:
32
@@ -398,7 +402,7 @@
33
 {
34
    struct spa_result_node_params result;
35
    uint8_t buffer[1024];
36
-   struct spa_pod_builder b = { 0 };
37
+   struct spa_pod_dynamic_builder b;
38
    uint32_t count = 0;
39
    struct param *p;
40
    bool found = false;
41
@@ -425,13 +429,14 @@
42
 
43
        found = true;
44
 
45
-       spa_pod_builder_init(&b, buffer, sizeof(buffer));
46
-       if (spa_pod_filter(&b, &result.param, param, filter) != 0)
47
-           continue;
48
-
49
-       spa_node_emit_result(&d->hooks, seq, 0, SPA_RESULT_TYPE_NODE_PARAMS, &result);
50
+       spa_pod_dynamic_builder_init(&b, buffer, sizeof(buffer), 4096);
51
+       if (spa_pod_filter(&b.b, &result.param, param, filter) == 0) {
52
+           spa_node_emit_result(&d->hooks, seq, 0, SPA_RESULT_TYPE_NODE_PARAMS, &result);
53
+           count++;
54
+       }
55
+       spa_pod_dynamic_builder_clean(&b);
56
 
57
-       if (++count == num)
58
+       if (count == num)
59
            break;
60
    }
61
    return found ? 0 : -ENOENT;
62
@@ -1493,6 +1498,7 @@
63
    impl->info.max_output_ports = UINT32_MAX;
64
    impl->info.flags = impl->process_rt ? SPA_NODE_FLAG_RT : 0;
65
    impl->info.props = &filter->properties->dict;
66
+   impl->params[IDX_PropInfo] = SPA_PARAM_INFO(SPA_PARAM_PropInfo, 0);
67
    impl->params[IDX_Props] = SPA_PARAM_INFO(SPA_PARAM_Props, SPA_PARAM_INFO_WRITE);
68
    impl->params[IDX_ProcessLatency] = SPA_PARAM_INFO(SPA_PARAM_ProcessLatency, 0);
69
    impl->info.params = impl->params;
70
pipewire-0.3.47.tar.gz/src/pipewire/global.c -> pipewire-0.3.48.tar.gz/src/pipewire/global.c Changed
60
 
1
@@ -139,6 +139,7 @@
2
 {
3
    struct pw_resource *registry;
4
    struct pw_context *context = global->context;
5
+   struct pw_impl_client *client;
6
 
7
    if (global->registered)
8
        return -EEXIST;
9
@@ -146,10 +147,12 @@
10
    spa_list_append(&context->global_list, &global->link);
11
    global->registered = true;
12
 
13
+   global->generation = ++context->generation;
14
+
15
    spa_list_for_each(registry, &context->registry_resource_list, link) {
16
        uint32_t permissions = pw_global_get_permissions(global, registry->client);
17
-       pw_log_debug("registry %p: global %d %08x serial:%"PRIu64,
18
-               registry, global->id, permissions, global->serial);
19
+       pw_log_debug("registry %p: global %d %08x serial:%"PRIu64" generation:%"PRIu64,
20
+               registry, global->id, permissions, global->serial, global->generation);
21
        if (PW_PERM_IS_R(permissions))
22
            pw_registry_resource_global(registry,
23
                            global->id,
24
@@ -159,6 +162,25 @@
25
                            &global->properties->dict);
26
    }
27
 
28
+   /* Ensure a message is sent also to clients without registries, to force
29
+    * generation number update. */
30
+   spa_list_for_each(client, &context->client_list, link) {
31
+       uint32_t permissions;
32
+
33
+       if (client->sent_generation >= context->generation)
34
+           continue;
35
+       if (!client->core_resource)
36
+           continue;
37
+
38
+       permissions = pw_global_get_permissions(global, client);
39
+       if (PW_PERM_IS_R(permissions)) {
40
+           pw_log_debug("impl-client %p: (no registry) global %d %08x serial:%"PRIu64
41
+                   " generation:%"PRIu64, client, global->id, permissions, global->serial,
42
+                   global->generation);
43
+           pw_core_resource_done(client->core_resource, global->id, 0);
44
+       }
45
+   }
46
+
47
    pw_log_debug("%p: registered %u", global, global->id);
48
    pw_context_emit_global_added(context, global);
49
 
50
@@ -352,8 +374,7 @@
51
        }
52
        else if (do_show) {
53
            pw_log_debug("client %p: resource %p show global %d serial:%"PRIu64,
54
-                   client, resource, global->id,
55
-                   global->serial);
56
+                   client, resource, global->id, global->serial);
57
            pw_registry_resource_global(resource,
58
                            global->id,
59
                            new_permissions,
60
pipewire-0.3.47.tar.gz/src/pipewire/impl-client.c -> pipewire-0.3.48.tar.gz/src/pipewire/impl-client.c Changed
30
 
1
@@ -228,6 +228,18 @@
2
    pw_global_update_keys(client->global, client->info.props, keys);
3
    pw_global_register(client->global);
4
 
5
+#ifdef OLD_MEDIA_SESSION_WORKAROUND
6
+   /*
7
+    * XXX: temporary workaround for pipewire-media-session, see #2159
8
+    */
9
+   if (spa_streq(spa_dict_lookup(client->info.props, PW_KEY_APP_NAME),
10
+                   "pipewire-media-session")) {
11
+       client->recv_generation = UINT64_MAX;
12
+       pw_log_info("impl-client %p: enable old pipewire-media-session workaround",
13
+               client);
14
+   }
15
+#endif
16
+
17
    return 0;
18
 }
19
 
20
@@ -737,6 +749,9 @@
21
    if ((global = pw_context_find_global(context, global_id)) == NULL)
22
        return -ENOENT;
23
 
24
+   if (client->recv_generation != 0 && global->generation > client->recv_generation)
25
+       return -ESTALE;
26
+
27
    perms = pw_global_get_permissions(global, client);
28
    if ((perms & permissions) != permissions)
29
        return -EPERM;
30
pipewire-0.3.47.tar.gz/src/pipewire/impl-core.c -> pipewire-0.3.48.tar.gz/src/pipewire/impl-core.c Changed
48
 
1
@@ -64,6 +64,9 @@
2
    if (!PW_PERM_IS_R(permissions))
3
        goto error_no_id;
4
 
5
+   if (resource->client->recv_generation != 0 && global->generation > resource->client->recv_generation)
6
+       goto error_stale_id;
7
+
8
    if (!spa_streq(global->type, type))
9
        goto error_wrong_interface;
10
 
11
@@ -75,6 +78,12 @@
12
 
13
    return NULL;
14
 
15
+error_stale_id:
16
+   pw_log_debug("registry %p: not binding stale global "
17
+           "id %u to %u, generation:%"PRIu64" recv-generation:%"PRIu64,
18
+           resource, id, new_id, global->generation, resource->client->recv_generation);
19
+   pw_resource_errorf_id(resource, new_id, -ESTALE, "no global %u any more", id);
20
+   goto error_exit_clean;
21
 error_no_id:
22
    pw_log_debug("registry %p: no global with id %u to bind to %u", resource, id, new_id);
23
    pw_resource_errorf_id(resource, new_id, -ENOENT, "no global %u", id);
24
@@ -110,6 +119,9 @@
25
    if (!PW_PERM_IS_R(permissions))
26
        goto error_no_id;
27
 
28
+   if (resource->client->recv_generation != 0 && global->generation > resource->client->recv_generation)
29
+       goto error_stale_id;
30
+
31
    if (id == PW_ID_CORE || !PW_PERM_IS_X(permissions))
32
        goto error_not_allowed;
33
 
34
@@ -118,6 +130,13 @@
35
    pw_global_destroy(global);
36
    return 0;
37
 
38
+error_stale_id:
39
+   pw_log_debug("registry %p: not destroying stale global "
40
+           "id %u, generation:%"PRIu64" recv-generation:%"PRIu64,
41
+           resource, id, global->generation, resource->client->recv_generation);
42
+   pw_resource_errorf(resource, -ESTALE, "no global %u any more", id);
43
+   res = -ESTALE;
44
+   goto error_exit;
45
 error_no_id:
46
    pw_log_debug("registry %p: no global with id %u to destroy", resource, id);
47
    pw_resource_errorf(resource, -ENOENT, "no global %u", id);
48
pipewire-0.3.47.tar.gz/src/pipewire/impl-device.c -> pipewire-0.3.48.tar.gz/src/pipewire/impl-device.c Changed
41
 
1
@@ -27,6 +27,7 @@
2
 #include <spa/debug/types.h>
3
 #include <spa/monitor/utils.h>
4
 #include <spa/pod/filter.h>
5
+#include <spa/pod/dynamic.h>
6
 #include <spa/utils/string.h>
7
 
8
 #include "pipewire/impl.h"
9
@@ -324,7 +325,7 @@
10
    if (pi->user == 1) {
11
        struct pw_param *p;
12
        uint8_t buffer[4096];
13
-       struct spa_pod_builder b = { 0 };
14
+       struct spa_pod_dynamic_builder b;
15
            struct spa_result_device_params result;
16
        uint32_t count = 0;
17
 
18
@@ -339,14 +340,15 @@
19
            if (result.index < index)
20
                continue;
21
 
22
-           spa_pod_builder_init(&b, buffer, sizeof(buffer));
23
-           if (spa_pod_filter(&b, &result.param, p->param, filter) != 0)
24
-               continue;
25
-
26
-           pw_log_debug("%p: %d param %u", device, seq, result.index);
27
-           result_device_params(&user_data, seq, 0, SPA_RESULT_TYPE_DEVICE_PARAMS, &result);
28
+           spa_pod_dynamic_builder_init(&b, buffer, sizeof(buffer), 4096);
29
+           if (spa_pod_filter(&b.b, &result.param, p->param, filter) == 0) {
30
+               pw_log_debug("%p: %d param %u", device, seq, result.index);
31
+               result_device_params(&user_data, seq, 0, SPA_RESULT_TYPE_DEVICE_PARAMS, &result);
32
+               count++;
33
+           }
34
+           spa_pod_dynamic_builder_clean(&b);
35
 
36
-           if (++count == max)
37
+           if (count == max)
38
                break;
39
        }
40
        res = 0;
41
pipewire-0.3.47.tar.gz/src/pipewire/impl-link.c -> pipewire-0.3.48.tar.gz/src/pipewire/impl-link.c Changed
21
 
1
@@ -1209,8 +1209,6 @@
2
                 this->user_data = SPA_PTROFF(impl, sizeof(struct impl), void);
3
 
4
    impl->work = pw_context_get_work_queue(context);
5
-   if (impl->work == NULL)
6
-       goto error_work_queue;
7
 
8
    this->context = context;
9
    this->properties = properties;
10
@@ -1309,10 +1307,6 @@
11
    res = -errno;
12
    pw_log_debug("alloc failed: %m");
13
    goto error_exit;
14
-error_work_queue:
15
-   res = -errno;
16
-   pw_log_debug("work queue failed: %m");
17
-   goto error_free;
18
 error_output_mix:
19
    pw_log_error("%p: can't get output mix %d (%s)", this, res, spa_strerror(res));
20
    goto error_free;
21
pipewire-0.3.47.tar.gz/src/pipewire/impl-module.c -> pipewire-0.3.48.tar.gz/src/pipewire/impl-module.c Changed
49
 
1
@@ -44,6 +44,7 @@
2
 struct impl {
3
    struct pw_impl_module this;
4
    void *hnd;
5
+   uint32_t destroy_work_id;
6
 };
7
 
8
 #define pw_module_resource_info(r,...) pw_resource_call(r,struct pw_module_events,info,0,__VA_ARGS__)
9
@@ -220,6 +221,7 @@
10
        goto error_no_mem;
11
 
12
    impl->hnd = hnd;
13
+   impl->destroy_work_id = SPA_ID_INVALID;
14
    hnd = NULL;
15
 
16
    this = &impl->this;
17
@@ -336,6 +338,10 @@
18
 
19
    spa_hook_list_clean(&module->listener_list);
20
 
21
+   if (impl->destroy_work_id != SPA_ID_INVALID)
22
+       pw_work_queue_cancel(pw_context_get_work_queue(module->context),
23
+                    module, SPA_ID_INVALID);
24
+
25
    if (!pw_in_valgrind() && dlclose(impl->hnd) != 0)
26
        pw_log_warn("%p: dlclose failed: %s", module, dlerror());
27
    free(impl);
28
@@ -398,3 +404,20 @@
29
 {
30
    spa_hook_list_append(&module->listener_list, listener, events, data);
31
 }
32
+
33
+static void do_destroy_module(void *obj, void *data, int res, uint32_t id)
34
+{
35
+   pw_impl_module_destroy(obj);
36
+}
37
+
38
+SPA_EXPORT
39
+void pw_impl_module_schedule_destroy(struct pw_impl_module *module)
40
+{
41
+   struct impl *impl = SPA_CONTAINER_OF(module, struct impl, this);
42
+
43
+   if (impl->destroy_work_id != SPA_ID_INVALID)
44
+       return;
45
+
46
+   impl->destroy_work_id = pw_work_queue_add(pw_context_get_work_queue(module->context),
47
+                         module, 0, do_destroy_module, NULL);
48
+}
49
pipewire-0.3.47.tar.gz/src/pipewire/impl-node.c -> pipewire-0.3.48.tar.gz/src/pipewire/impl-node.c Changed
52
 
1
@@ -32,6 +32,7 @@
2
 #include <spa/support/system.h>
3
 #include <spa/pod/parser.h>
4
 #include <spa/pod/filter.h>
5
+#include <spa/pod/dynamic.h>
6
 #include <spa/node/utils.h>
7
 #include <spa/debug/types.h>
8
 #include <spa/utils/string.h>
9
@@ -1236,10 +1237,6 @@
10
    }
11
 
12
    impl->work = pw_context_get_work_queue(this->context);
13
-   if (impl->work == NULL) {
14
-       res = -errno;
15
-       goto error_clean;
16
-   }
17
    impl->pending_id = SPA_ID_INVALID;
18
 
19
    this->data_loop = context->data_loop;
20
@@ -1971,7 +1968,7 @@
21
    if (pi->user == 1) {
22
        struct pw_param *p;
23
        uint8_t buffer[4096];
24
-       struct spa_pod_builder b = { 0 };
25
+       struct spa_pod_dynamic_builder b;
26
            struct spa_result_node_params result;
27
        uint32_t count = 0;
28
 
29
@@ -1986,14 +1983,16 @@
30
            if (result.index < index)
31
                continue;
32
 
33
-           spa_pod_builder_init(&b, buffer, sizeof(buffer));
34
-           if (spa_pod_filter(&b, &result.param, p->param, filter) != 0)
35
-               continue;
36
+           spa_pod_dynamic_builder_init(&b, buffer, sizeof(buffer), 4096);
37
 
38
-           pw_log_debug("%p: %d param %u", node, seq, result.index);
39
-           result_node_params(&user_data, seq, 0, SPA_RESULT_TYPE_NODE_PARAMS, &result);
40
+           if (spa_pod_filter(&b.b, &result.param, p->param, filter) == 0)  {
41
+               pw_log_debug("%p: %d param %u", node, seq, result.index);
42
+               result_node_params(&user_data, seq, 0, SPA_RESULT_TYPE_NODE_PARAMS, &result);
43
+               count++;
44
+           }
45
+           spa_pod_dynamic_builder_clean(&b);
46
 
47
-           if (++count == max)
48
+           if (count == max)
49
                break;
50
        }
51
        res = 0;
52
pipewire-0.3.47.tar.gz/src/pipewire/impl-port.c -> pipewire-0.3.48.tar.gz/src/pipewire/impl-port.c Changed
64
 
1
@@ -34,6 +34,7 @@
2
 #include <spa/utils/string.h>
3
 #include <spa/debug/types.h>
4
 #include <spa/pod/filter.h>
5
+#include <spa/pod/dynamic.h>
6
 
7
 #include "pipewire/impl.h"
8
 #include "pipewire/private.h"
9
@@ -229,17 +230,19 @@
10
    {
11
        uint32_t idx = 0;
12
        uint8_t buffer[1024];
13
-       struct spa_pod_builder b;
14
+       struct spa_pod_dynamic_builder b;
15
        struct spa_pod *param;
16
 
17
-       spa_pod_builder_init(&b, buffer, sizeof(buffer));
18
+       spa_pod_dynamic_builder_init(&b, buffer, sizeof(buffer), 4096);
19
+
20
        if (spa_node_port_enum_params_sync(port->mix,
21
                pw_direction_reverse(port->direction), 0,
22
-               SPA_PARAM_Format, &idx, NULL, &param, &b) == 1) {
23
+               SPA_PARAM_Format, &idx, NULL, &param, &b.b) == 1) {
24
            spa_node_port_set_param(port->mix,
25
                port->direction, port_id,
26
                SPA_PARAM_Format, 0, param);
27
        }
28
+       spa_pod_dynamic_builder_clean(&b);
29
    }
30
 
31
    spa_list_append(&port->mix_list, &mix->link);
32
@@ -1216,7 +1219,7 @@
33
    if (pi->user == 1) {
34
        struct pw_param *p;
35
        uint8_t buffer[1024];
36
-       struct spa_pod_builder b = { 0 };
37
+       struct spa_pod_dynamic_builder b;
38
            struct spa_result_node_params result;
39
        uint32_t count = 0;
40
 
41
@@ -1231,14 +1234,16 @@
42
            if (result.index < index)
43
                continue;
44
 
45
-           spa_pod_builder_init(&b, buffer, sizeof(buffer));
46
-           if (spa_pod_filter(&b, &result.param, p->param, filter) != 0)
47
-               continue;
48
+           spa_pod_dynamic_builder_init(&b, buffer, sizeof(buffer), 4096);
49
 
50
-           pw_log_debug("%p: %d param %u", port, seq, result.index);
51
-           result_port_params(&user_data, seq, 0, SPA_RESULT_TYPE_NODE_PARAMS, &result);
52
+           if (spa_pod_filter(&b.b, &result.param, p->param, filter) >= 0) {
53
+               pw_log_debug("%p: %d param %u", port, seq, result.index);
54
+               result_port_params(&user_data, seq, 0, SPA_RESULT_TYPE_NODE_PARAMS, &result);
55
+               count++;
56
+           }
57
+           spa_pod_dynamic_builder_clean(&b);
58
 
59
-           if (++count == max)
60
+           if (count == max)
61
                break;
62
        }
63
        res = 0;
64
pipewire-0.3.47.tar.gz/src/pipewire/meson.build -> pipewire-0.3.48.tar.gz/src/pipewire/meson.build Changed
9
 
1
@@ -91,6 +91,7 @@
2
 install_headers(pipewire_headers, subdir : pipewire_headers_dir)
3
 
4
 libpipewire_c_args = [
5
+  '-DOLD_MEDIA_SESSION_WORKAROUND=1'
6
 ]
7
 
8
 if build_machine.system() != 'freebsd'
9
pipewire-0.3.47.tar.gz/src/pipewire/private.h -> pipewire-0.3.48.tar.gz/src/pipewire/private.h Changed
43
 
1
@@ -299,6 +299,8 @@
2
    struct pw_protocol *protocol;   /**< protocol in use */
3
    int recv_seq;           /**< last received sequence number */
4
    int send_seq;           /**< last sender sequence number */
5
+   uint64_t recv_generation;   /**< last received registry generation */
6
+   uint64_t sent_generation;   /**< last sent registry generation */
7
 
8
    void *user_data;        /**< extra user data */
9
 
10
@@ -334,6 +336,7 @@
11
    pw_global_bind_func_t func; /**< bind function */
12
    void *object;           /**< object associated with the interface */
13
    uint64_t serial;        /**< increasing serial number */
14
+   uint64_t generation;        /**< registry generation number */
15
 
16
    struct spa_list resource_list;  /**< The list of resources of this global */
17
 
18
@@ -430,6 +433,7 @@
19
 
20
    uint64_t stamp;
21
    uint64_t serial;
22
+   uint64_t generation;            /**< registry generation number */
23
    struct pw_map globals;          /**< map of globals */
24
 
25
    struct spa_list core_impl_list;     /**< list of core_imp */
26
@@ -1001,6 +1005,7 @@
27
    struct pw_protocol_client *conn;    /**< the protocol client connection */
28
    int recv_seq;               /**< last received sequence number */
29
    int send_seq;               /**< last protocol result code */
30
+   uint64_t recv_generation;       /**< last received registry generation */
31
 
32
    unsigned int removed:1;
33
    unsigned int destroyed:1;
34
@@ -1279,6 +1284,8 @@
35
 int pw_settings_expose(struct pw_context *context);
36
 void pw_settings_clean(struct pw_context *context);
37
 
38
+void pw_impl_module_schedule_destroy(struct pw_impl_module *module);
39
+
40
 /** \endcond */
41
 
42
 #ifdef __cplusplus
43
pipewire-0.3.47.tar.gz/src/pipewire/stream.c -> pipewire-0.3.48.tar.gz/src/pipewire/stream.c Changed
68
 
1
@@ -34,6 +34,7 @@
2
 #include <spa/node/utils.h>
3
 #include <spa/utils/ringbuffer.h>
4
 #include <spa/pod/filter.h>
5
+#include <spa/pod/dynamic.h>
6
 #include <spa/debug/format.h>
7
 #include <spa/debug/types.h>
8
 #include <spa/debug/pod.h>
9
@@ -135,8 +136,9 @@
10
 
11
    uint32_t change_mask_all;
12
    struct spa_node_info info;
13
-#define IDX_Props  0
14
-#define N_NODE_PARAMS  1
15
+#define IDX_PropInfo   0
16
+#define IDX_Props  1
17
+#define N_NODE_PARAMS  2
18
    struct spa_param_info params[N_NODE_PARAMS];
19
 
20
    uint32_t media_type;
21
@@ -173,6 +175,8 @@
22
 static int get_param_index(uint32_t id)
23
 {
24
    switch (id) {
25
+   case SPA_PARAM_PropInfo:
26
+       return IDX_PropInfo;
27
    case SPA_PARAM_Props:
28
        return IDX_Props;
29
    default:
30
@@ -483,7 +487,7 @@
31
    struct stream *d = object;
32
    struct spa_result_node_params result;
33
    uint8_t buffer[1024];
34
-   struct spa_pod_builder b = { 0 };
35
+   struct spa_pod_dynamic_builder b;
36
    uint32_t count = 0;
37
    struct param *p;
38
    bool found = false;
39
@@ -510,13 +514,14 @@
40
 
41
        found = true;
42
 
43
-       spa_pod_builder_init(&b, buffer, sizeof(buffer));
44
-       if (spa_pod_filter(&b, &result.param, param, filter) != 0)
45
-           continue;
46
-
47
-       spa_node_emit_result(&d->hooks, seq, 0, SPA_RESULT_TYPE_NODE_PARAMS, &result);
48
+       spa_pod_dynamic_builder_init(&b, buffer, sizeof(buffer), 4096);
49
+       if (spa_pod_filter(&b.b, &result.param, param, filter) == 0) {
50
+           spa_node_emit_result(&d->hooks, seq, 0, SPA_RESULT_TYPE_NODE_PARAMS, &result);
51
+           count++;
52
+       }
53
+       spa_pod_dynamic_builder_clean(&b);
54
 
55
-       if (++count == num)
56
+       if (count == num)
57
            break;
58
    }
59
    return found ? 0 : -ENOENT;
60
@@ -1724,6 +1729,7 @@
61
    if (!impl->process_rt)
62
        impl->info.flags |= SPA_NODE_FLAG_ASYNC;
63
    impl->info.props = &stream->properties->dict;
64
+   impl->params[IDX_PropInfo] = SPA_PARAM_INFO(SPA_PARAM_PropInfo, 0);
65
    impl->params[IDX_Props] = SPA_PARAM_INFO(SPA_PARAM_Props, SPA_PARAM_INFO_WRITE);
66
    impl->info.params = impl->params;
67
    impl->info.n_params = N_NODE_PARAMS;
68
pipewire-0.3.47.tar.gz/src/tools/pw-cli.c -> pipewire-0.3.48.tar.gz/src/tools/pw-cli.c Changed
10
 
1
@@ -40,7 +40,7 @@
2
 #define FNM_EXTMATCH 0
3
 #endif
4
 
5
-#define spa_debug(fmt,...) printf(fmt, ## __VA_ARGS__)
6
+#define spa_debug(fmt,...) printf(fmt"\n", ## __VA_ARGS__)
7
 
8
 #include <spa/utils/result.h>
9
 #include <spa/utils/string.h>
10
pipewire-0.3.47.tar.gz/src/tools/pw-loopback.c -> pipewire-0.3.48.tar.gz/src/tools/pw-loopback.c Changed
14
 
1
@@ -202,7 +202,11 @@
2
    }
3
 
4
 
5
-        f = open_memstream(&args, &size);
6
+        if ((f = open_memstream(&args, &size)) == NULL) {
7
+       fprintf(stderr, "can't open memstream: %m\n");
8
+       goto exit;
9
+   }
10
+
11
    fprintf(f, "{");
12
 
13
    if (opt_remote != NULL)
14
pipewire-0.3.47.tar.gz/src/tools/pw-top.c -> pipewire-0.3.48.tar.gz/src/tools/pw-top.c Changed
64
 
1
@@ -241,9 +241,8 @@
2
    return buf;
3
 }
4
 
5
-static void print_node(struct data *d, struct driver *i, struct node *n)
6
+static void print_node(struct data *d, struct driver *i, struct node *n, int y)
7
 {
8
-   char line[1024];
9
    char buf1[64];
10
    char buf2[64];
11
    char buf3[64];
12
@@ -264,7 +263,7 @@
13
    waiting = (n->measurement.awake - n->measurement.signal) / 1000000000.f,
14
    busy = (n->measurement.finish - n->measurement.awake) / 1000000000.f,
15
 
16
-   snprintf(line, sizeof(line), "%s %4.1u %6.1u %6.1u %s %s %s %s  %3.1u  %s%s",
17
+   mvwprintw(d->win, y, 0, "%s %4.1u %6.1u %6.1u %s %s %s %s  %3.1u  %s%s",
18
            n->measurement.status != 3 ? "!" : " ",
19
            n->id,
20
            frac.num, frac.denom,
21
@@ -275,13 +274,12 @@
22
            i->xrun_count + n->errors,
23
            n->driver == n ? "" : " + ",
24
            n->name);
25
-
26
-   wprintw(d->win, "%.*s\n", COLS-1, line);
27
 }
28
 
29
 static void do_refresh(struct data *d)
30
 {
31
    struct node *n, *t, *f;
32
+   int y = 1;
33
 
34
    wclear(d->win);
35
    wattron(d->win, A_REVERSE);
36
@@ -293,15 +291,25 @@
37
        if (n->driver != n)
38
            continue;
39
 
40
-       print_node(d, &n->info, n);
41
+       print_node(d, &n->info, n, y++);
42
+       if(y > LINES)
43
+           break;
44
 
45
        spa_list_for_each(f, &d->node_list, link) {
46
            if (f->driver != n || f == n)
47
                continue;
48
 
49
-           print_node(d, &n->info, f);
50
+           print_node(d, &n->info, f, y++);
51
+           if(y > LINES)
52
+               break;
53
+
54
        }
55
    }
56
+
57
+   // Clear from last line to the end of the window to hide text wrapping from the last node
58
+   wmove(d->win, y, 0);
59
+   wclrtobot(d->win);
60
+
61
    wrefresh(d->win);
62
 }
63
 
64
pipewire-0.3.47.tar.gz/test/test-loop.c -> pipewire-0.3.48.tar.gz/test/test-loop.c Changed
47
 
1
@@ -227,11 +227,45 @@
2
    return PWTEST_PASS;
3
 }
4
 
5
+PWTEST(thread_loop_destroy_between_poll_and_lock)
6
+{
7
+   pw_init(NULL, NULL);
8
+
9
+   struct pw_thread_loop *thread_loop = pw_thread_loop_new("uaf", NULL);
10
+   pwtest_ptr_notnull(thread_loop);
11
+
12
+   struct pw_loop *loop = pw_thread_loop_get_loop(thread_loop);
13
+   pwtest_ptr_notnull(loop);
14
+
15
+   int evfd = eventfd(0, 0);
16
+   pwtest_errno_ok(evfd);
17
+
18
+   struct spa_source *source = pw_loop_add_io(loop, evfd, SPA_IO_IN, true, NULL, NULL);
19
+   pwtest_ptr_notnull(source);
20
+
21
+   pw_thread_loop_start(thread_loop);
22
+
23
+   pw_thread_loop_lock(thread_loop);
24
+   {
25
+       write(evfd, &(uint64_t){1}, sizeof(uint64_t));
26
+       sleep(1);
27
+       pw_loop_destroy_source(loop, source);
28
+   }
29
+   pw_thread_loop_unlock(thread_loop);
30
+
31
+   pw_thread_loop_destroy(thread_loop);
32
+
33
+   pw_deinit();
34
+
35
+   return PWTEST_PASS;
36
+}
37
+
38
 PWTEST_SUITE(support)
39
 {
40
    pwtest_add(pwtest_loop_destroy2, PWTEST_NOARG);
41
    pwtest_add(pwtest_loop_recurse1, PWTEST_NOARG);
42
    pwtest_add(pwtest_loop_recurse2, PWTEST_NOARG);
43
+   pwtest_add(thread_loop_destroy_between_poll_and_lock, PWTEST_NOARG);
44
 
45
    return PWTEST_PASS;
46
 }
47
Refresh

No build results available

Refresh

No rpmlint results available

Request History
Bjørn Lie's avatar

zaitor created request about 3 years ago

Versionbump


Bjørn Lie's avatar

zaitor accepted request about 3 years ago

xin