Changes of Revision 43

pipewire-aptx.changes Changed
x
 
1
@@ -1,4 +1,9 @@
2
 -------------------------------------------------------------------
3
+Mon Aug 19 20:39:19 UTC 2024 - Bjørn Lie <zaitor@opensuse.org>
4
+
5
+- Update to version 1.2.2
6
+
7
+-------------------------------------------------------------------
8
 Sun Jun 30 17:34:39 UTC 2024 - Bjørn Lie <zaitor@opensuse.org>
9
 
10
 - Update to version 1.2.0
11
pipewire-aptx.spec Changed
16
 
1
@@ -7,12 +7,12 @@
2
 %define soversion 0_2
3
 
4
 Name:           pipewire-aptx
5
-Version:        1.2.0
6
+Version:        1.2.2
7
 Release:        0
8
 Summary:        PipeWire Bluetooth aptX codec plugin
9
 License:        MIT
10
 URL:            https://gitlab.freedesktop.org/pipewire/pipewire
11
-Source:         %{url}/-/archive/%{version}/pipewire-%{version}.tar.gz
12
+Source:         %{url}/-/archive/%{version}/pipewire-%{version}.tar.bz2
13
 
14
 BuildRequires:  c++_compiler
15
 BuildRequires:  c_compiler
16
pipewire-1.2.0.tar.gz/NEWS -> pipewire-1.2.2.tar.bz2/NEWS Changed
108
 
1
@@ -1,3 +1,96 @@
2
+# PipeWire 1.2.2 (2024-07-31)
3
+
4
+This is a bugfix release that is API and ABI compatible with the
5
+previous 1.2.x and 1.0.x releases.
6
+
7
+## Highlights
8
+  - Fix some more fallout of the async nodes rewrite. Fixes some
9
+    crackling, xruns and possibly also some crashes in some cases.
10
+  - Fix freewheeling timeouts in case of xruns. This fixes ardour export.
11
+  - Fix event mixdown in JACK. Fixes qsynth and possibly other apps.
12
+  - Some more small fixes and improvements.
13
+
14
+
15
+## PipeWire
16
+  - Add a new SPA_IO_CLOCK_FLAG_XRUN_RECOVER flag when the process function
17
+    is called because of xrun recovery.
18
+  - Properly stop nodes in all cases, this avoids spurious xruns and
19
+    scheduling errors. (#4122)
20
+  - Make sure async nodes receive an async link in all cases. Do the
21
+    processing of source output ports slightly differently to make sure we
22
+    don't cause latency for sources. (#4138) (#4133)
23
+  - Fix some races when negotiating and starting nodes. (#4094)
24
+  - Actually include the config.h header to use malloc_trim() to reduce
25
+    memory usage in pulse-server.
26
+
27
+## Modules
28
+  - Avoid unloading some modules on stream errors because it is possible to
29
+    recover from the error. (#4121)
30
+  - Fix a (harmless) warning in module-rtp because of comparing samples and
31
+    time. (#4095)
32
+
33
+## SPA
34
+  - Let the freewheel driver detect xrun recovery and handle the timeouts
35
+    correctly. This fixes an issue with ardour export.
36
+  - Remove the HDMI/AC3 profiles. they turn out to fail on some hardware
37
+    with no way to detect this.
38
+  - Signal the eventfd when the loop is full to make sure the other thread
39
+    is woken up to process the queue.
40
+
41
+## JACK
42
+  - Don't check timestamps when mixing down events. The timestamps are only
43
+    checked when writing new events with the public API. This fixes an
44
+    issue where qsynth would not receive midi events anymore.
45
+  - Fix the jack_get_time() function, it was returning nano instead of micro
46
+    seconds.
47
+
48
+Older versions:
49
+
50
+
51
+# PipeWire 1.2.1 (2024-07-12)
52
+
53
+This is a bugfix release that is API and ABI compatible with previous
54
+the previous 1.2.0 release and the 1.0.x releases.
55
+
56
+## Highlights
57
+  - Fix a regression in the node activation counters that would break audio
58
+    when using KODI.
59
+  - Fix a regression in ardour export because of mishandling of sync groups.
60
+  - Fix a regression in KDE screen preview because of the new async
61
+    scheduling.
62
+  - Fix a regression in context.exec argument parsing that would break some
63
+    existing scripts.
64
+  - More small bug fixes and improvements.
65
+
66
+
67
+## PipeWire
68
+  - Fix a regression in the node activation counters that would break audio
69
+    when using KODI. (#4087)
70
+  - Fix a regression in ardour export because of mishandling of sync groups.
71
+    (#4083)
72
+  - Fix a regression in KDE screen preview because of the new async
73
+    scheduling. Disable async for driver nodes. (#4092)
74
+  - Slightly improve node shutdown to cause less xruns.
75
+  - Fix a regression in context.exec argument parsing that would break some
76
+    existing scripts.
77
+  - Support custom thread create functions.
78
+
79
+## Modules
80
+  - Improve snapcast address parsing. (#4093)
81
+
82
+## SPA
83
+  - Fix multiple %f parsing in ACP for the new plug+a52 profiles.
84
+  - Improve v4l2 param generation. Improve recovery when framesize or rates
85
+    are unknown, support vivid. (#4063)
86
+
87
+## JACK
88
+  - Use the custom thread create function to correctly let module-rt kit
89
+    manage threads so that we don't end up with priorities on the wrong
90
+    threads. (#4099)
91
+
92
+## GStreamer
93
+  - Fix a crash when destroying a stream.
94
+
95
 # PipeWire 1.2.0 (2024-06-27)
96
 
97
 This is the 1.2 release that is API and ABI compatible with previous
98
@@ -69,9 +162,6 @@
99
 ## Bluetooth
100
   - Improvements to BAP broadcast code parsing.
101
 
102
-Older versions:
103
-
104
-
105
 # PipeWire 1.1.83 (2024-06-17)
106
 
107
 This is the third and hopefully the last 1.2 release candidate that is
108
pipewire-1.2.0.tar.gz/meson.build -> pipewire-1.2.2.tar.bz2/meson.build Changed
21
 
1
@@ -1,5 +1,5 @@
2
 project('pipewire', 'c' ,
3
-  version : '1.2.0',
4
+  version : '1.2.2',
5
   license :  'MIT', 'LGPL-2.1-or-later', 'GPL-2.0-only' ,
6
   meson_version : '>= 0.61.1',
7
   default_options :  'warning_level=3',
8
@@ -345,9 +345,9 @@
9
 flatpak_support = glib2_dep.found()
10
 cdata.set('HAVE_GLIB2', flatpak_support)
11
 
12
-gio_dep = dependency('gio-2.0', version : '>= 2.26.0', required : get_option('gsettings'))
13
-summary({'GIO (GSettings)': gio_dep.found()}, bool_yn: true, section: 'Misc dependencies')
14
-if not gio_dep.found() and get_option('gsettings-pulse-schema').enabled()
15
+gsettings_gio_dep = dependency('gio-2.0', version : '>= 2.26.0', required : get_option('gsettings'))
16
+summary({'GIO (GSettings)': gsettings_gio_dep.found()}, bool_yn: true, section: 'Misc dependencies')
17
+if not gsettings_gio_dep.found() and get_option('gsettings-pulse-schema').enabled()
18
   error('`gsettings-pulse-schema` is enabled but `gio` was not found.')
19
 endif
20
 
21
pipewire-1.2.0.tar.gz/pipewire-jack/src/pipewire-jack.c -> pipewire-1.2.2.tar.bz2/pipewire-jack/src/pipewire-jack.c Changed
201
 
1
@@ -1444,12 +1444,41 @@
2
    }
3
 }
4
 
5
+static inline jack_midi_data_t* midi_event_reserve(void *port_buffer,
6
+                        jack_nframes_t  time, size_t data_size)
7
+{
8
+   struct midi_buffer *mb = port_buffer;
9
+   uint8_t *res = NULL;
10
+
11
+   /* Check if data_size is >0 and there is enough space in the buffer for the event. */
12
+   if (SPA_UNLIKELY(data_size <= 0)) {
13
+       pw_log_warn("midi %p: data_size:%zd", port_buffer, data_size);
14
+   } else if (SPA_UNLIKELY(jack_midi_max_event_size (port_buffer) < data_size)) {
15
+       pw_log_warn("midi %p: event too large: data_size:%zd", port_buffer, data_size);
16
+   } else {
17
+       struct midi_event *events = SPA_PTROFF(mb, sizeof(*mb), struct midi_event);
18
+       struct midi_event *ev = &eventsmb->event_count;
19
+
20
+       ev->time = time;
21
+       ev->size = data_size;
22
+       if (SPA_LIKELY(data_size <= MIDI_INLINE_MAX)) {
23
+           res = ev->inline_data;
24
+       } else {
25
+           mb->write_pos += data_size;
26
+           ev->byte_offset = mb->buffer_size - 1 - mb->write_pos;
27
+           res = SPA_PTROFF(mb, ev->byte_offset, uint8_t);
28
+       }
29
+       mb->event_count += 1;
30
+   }
31
+   return res;
32
+}
33
+
34
 static inline int midi_event_write(void *port_buffer,
35
                       jack_nframes_t time,
36
                       const jack_midi_data_t *data,
37
                       size_t data_size, bool fix)
38
 {
39
-   jack_midi_data_t *retbuf = jack_midi_event_reserve (port_buffer, time, data_size);
40
+   jack_midi_data_t *retbuf = midi_event_reserve (port_buffer, time, data_size);
41
         if (SPA_UNLIKELY(retbuf == NULL))
42
                 return -ENOBUFS;
43
    memcpy (retbuf, data, data_size);
44
@@ -3182,31 +3211,27 @@
45
            void *(*start)(void*), void *arg)
46
 {
47
    struct client *c = (struct client *) object;
48
-   struct spa_thread *thr;
49
-   int res = 0;
50
+   struct spa_dict_item *items;
51
+   struct spa_dict copy;
52
+   char creator_ptr64;
53
 
54
    pw_log_info("create thread");
55
    if (globals.creator != NULL) {
56
-       pthread_t pt;
57
-       pthread_attr_t *attr = NULL, attributes;
58
+       uint32_t i, n_items = props ? props->n_items : 0;
59
 
60
-       attr = pw_thread_fill_attr(props, &attributes);
61
+       items = alloca((n_items) + 1 * sizeof(*items));
62
 
63
-       res = -globals.creator(&pt, attr, start, arg);
64
-       if (attr)
65
-           pthread_attr_destroy(attr);
66
-       if (res != 0)
67
-           goto error;
68
-       thr = (struct spa_thread*)pt;
69
-   } else {
70
-       thr = spa_thread_utils_create(c->context.old_thread_utils, props, start, arg);
71
-   }
72
-   return thr;
73
-error:
74
-   pw_log_warn("create RT thread failed: %s", strerror(res));
75
-   errno = -res;
76
-   return NULL;
77
+       for (i = 0; i < n_items; i++)
78
+           itemsi = props->itemsi;
79
 
80
+       snprintf(creator_ptr, sizeof(creator_ptr), "pointer:%p", globals.creator);
81
+       itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_THREAD_CREATOR,
82
+               creator_ptr);
83
+
84
+       copy = SPA_DICT_INIT(items, n_items);
85
+       props = &copy;
86
+   }
87
+   return spa_thread_utils_create(c->context.old_thread_utils, props, start, arg);
88
 }
89
 
90
 static int impl_join(void *object,
91
@@ -5557,7 +5582,7 @@
92
        ptr = p->get_buffer(p, frames);
93
    }
94
 done:
95
-   pw_log_trace_fp("%p: port:%p buffer:%p frames:%d", c, p, ptr, frames);
96
+   pw_log_warn("%p: port:%p buffer:%p frames:%d", c, p, ptr, frames);
97
    return ptr;
98
 }
99
 
100
@@ -6746,7 +6771,7 @@
101
 {
102
    struct timespec ts;
103
    clock_gettime(CLOCK_MONOTONIC, &ts);
104
-   return SPA_TIMESPEC_TO_NSEC(&ts);
105
+   return SPA_TIMESPEC_TO_USEC(&ts);
106
 }
107
 
108
 SPA_EXPORT
109
@@ -7358,55 +7383,45 @@
110
         }
111
 }
112
 
113
-SPA_EXPORT
114
-jack_midi_data_t* jack_midi_event_reserve(void *port_buffer,
115
-                        jack_nframes_t  time,
116
-                        size_t data_size)
117
+static inline int midi_buffer_check(void *port_buffer, jack_nframes_t  time)
118
 {
119
    struct midi_buffer *mb = port_buffer;
120
    struct midi_event *events;
121
 
122
    if (SPA_UNLIKELY(mb == NULL)) {
123
        pw_log_warn("port buffer is NULL");
124
-       return NULL;
125
+       return -EINVAL;
126
    }
127
    if (SPA_UNLIKELY(mb->magic != MIDI_BUFFER_MAGIC)) {
128
        pw_log_warn("port buffer is invalid");
129
-       return NULL;
130
+       return -EINVAL;
131
    }
132
    if (SPA_UNLIKELY(time >= mb->nframes)) {
133
        pw_log_warn("midi %p: time:%d frames:%d", port_buffer, time, mb->nframes);
134
-       goto failed;
135
+       return -EINVAL;
136
    }
137
    events = SPA_PTROFF(mb, sizeof(*mb), struct midi_event);
138
    if (SPA_UNLIKELY(mb->event_count > 0 && time < eventsmb->event_count - 1.time)) {
139
        pw_log_warn("midi %p: time:%d ev:%d", port_buffer, time, mb->event_count);
140
-       goto failed;
141
+       return -EINVAL;
142
    }
143
+   return 0;
144
+}
145
 
146
-   /* Check if data_size is >0 and there is enough space in the buffer for the event. */
147
-   if (SPA_UNLIKELY(data_size <= 0)) {
148
-       pw_log_warn("midi %p: data_size:%zd", port_buffer, data_size);
149
-       goto failed; // return NULL?
150
-   } else if (SPA_UNLIKELY(jack_midi_max_event_size (port_buffer) < data_size)) {
151
-       pw_log_warn("midi %p: event too large: data_size:%zd", port_buffer, data_size);
152
+SPA_EXPORT
153
+jack_midi_data_t* jack_midi_event_reserve(void *port_buffer,
154
+                        jack_nframes_t  time,
155
+                        size_t data_size)
156
+{
157
+   struct midi_buffer *mb = port_buffer;
158
+   jack_midi_data_t *res;
159
+
160
+   if (midi_buffer_check(port_buffer, time) < 0)
161
        goto failed;
162
-   } else {
163
-       struct midi_event *ev = &eventsmb->event_count;
164
-       uint8_t *res;
165
 
166
-       ev->time = time;
167
-       ev->size = data_size;
168
-       if (SPA_LIKELY(data_size <= MIDI_INLINE_MAX)) {
169
-           res = ev->inline_data;
170
-       } else {
171
-           mb->write_pos += data_size;
172
-           ev->byte_offset = mb->buffer_size - 1 - mb->write_pos;
173
-           res = SPA_PTROFF(mb, ev->byte_offset, uint8_t);
174
-       }
175
-       mb->event_count += 1;
176
+   res = midi_event_reserve(port_buffer, time, data_size);
177
+   if (res != NULL)
178
        return res;
179
-   }
180
 failed:
181
    mb->lost_events++;
182
    return NULL;
183
@@ -7418,7 +7433,17 @@
184
                       const jack_midi_data_t *data,
185
                       size_t data_size)
186
 {
187
-   return midi_event_write(port_buffer, time, data, data_size, false);
188
+   jack_midi_data_t *ptr;
189
+   int res;
190
+
191
+   if ((res = midi_buffer_check(port_buffer, time)) < 0)
192
+       return res;
193
+
194
+   if ((ptr = midi_event_reserve(port_buffer, time, data_size)) == NULL)
195
+       return -ENOBUFS;
196
+
197
+   memcpy (ptr, data, data_size);
198
+   return 0;
199
 }
200
 
201
pipewire-1.2.0.tar.gz/spa/include/spa/node/io.h -> pipewire-1.2.2.tar.bz2/spa/include/spa/node/io.h Changed
11
 
1
@@ -125,7 +125,8 @@
2
  * \ref spa_io_position.clock.id in \ref SPA_IO_Position are the same.
3
  */
4
 struct spa_io_clock {
5
-#define SPA_IO_CLOCK_FLAG_FREEWHEEL (1u<<0)
6
+#define SPA_IO_CLOCK_FLAG_FREEWHEEL    (1u<<0) /* graph is freewheeling */
7
+#define SPA_IO_CLOCK_FLAG_XRUN_RECOVER (1u<<1) /* recovering from xrun */
8
    uint32_t flags;         /**< Clock flags */
9
    uint32_t id;            /**< Unique clock id, set by host application */
10
    char name64;            /**< Clock name prefixed with API, set by node when it receives
11
pipewire-1.2.0.tar.gz/spa/include/spa/support/thread.h -> pipewire-1.2.2.tar.bz2/spa/include/spa/support/thread.h Changed
9
 
1
@@ -118,6 +118,7 @@
2
 #define SPA_KEY_THREAD_NAME        "thread.name"       /* the thread name */
3
 #define SPA_KEY_THREAD_STACK_SIZE  "thread.stack-size" /* the stack size of the thread */
4
 #define SPA_KEY_THREAD_AFFINITY        "thread.affinity"   /* array of CPUs for this thread */
5
+#define SPA_KEY_THREAD_CREATOR     "thread.creator"    /* platform specific thread creator function */
6
 
7
 /**
8
  * \}
9
pipewire-1.2.0.tar.gz/spa/include/spa/utils/cleanup.h -> pipewire-1.2.2.tar.bz2/spa/include/spa/utils/cleanup.h Changed
49
 
1
@@ -31,6 +31,7 @@
2
 
3
 /* ========================================================================== */
4
 
5
+#include <errno.h>
6
 #include <unistd.h>
7
 
8
 #define spa_steal_fd(fd) spa_exchange((fd), -1)
9
@@ -53,7 +54,9 @@
10
 typedef __typeof__(type) _spa_auto_cleanup_type_ ## name; \
11
 static inline void _spa_auto_cleanup_func_ ## name (__typeof__(type) *thing) \
12
 { \
13
+   int _save_errno = errno; \
14
    __VA_ARGS__ \
15
+   errno = _save_errno; \
16
 }
17
 
18
 #define spa_auto(name) \
19
@@ -64,7 +67,9 @@
20
 typedef __typeof__(type) * _spa_autoptr_cleanup_type_ ## name; \
21
 static inline void _spa_autoptr_cleanup_func_ ## name (__typeof__(type) **thing) \
22
 { \
23
+   int _save_errno = errno; \
24
    __VA_ARGS__ \
25
+   errno = _save_errno; \
26
 }
27
 
28
 #define spa_autoptr(name) \
29
@@ -77,7 +82,9 @@
30
 
31
 static inline void _spa_autofree_cleanup_func(void *p)
32
 {
33
+   int save_errno = errno;
34
    free(*(void **) p);
35
+   errno = save_errno;
36
 }
37
 #define spa_autofree spa_cleanup(_spa_autofree_cleanup_func)
38
 
39
@@ -85,7 +92,9 @@
40
 
41
 static inline void _spa_autoclose_cleanup_func(int *fd)
42
 {
43
+   int save_errno = errno;
44
    spa_clear_fd(*fd);
45
+   errno = save_errno;
46
 }
47
 #define spa_autoclose spa_cleanup(_spa_autoclose_cleanup_func)
48
 
49
pipewire-1.2.0.tar.gz/spa/meson.build -> pipewire-1.2.2.tar.bz2/spa/meson.build Changed
17
 
1
@@ -47,12 +47,12 @@
2
   summary({'ALSA': alsa_dep.found()}, bool_yn: true, section: 'Backend')
3
 
4
   bluez_dep = dependency('bluez', version : '>= 4.101', required: get_option('bluez5'))
5
-  gio_dep = dependency('gio-2.0', required : get_option('bluez5'))
6
-  gio_unix_dep = dependency('gio-unix-2.0', required : get_option('bluez5'))
7
+  bluez_gio_dep = dependency('gio-2.0', required : get_option('bluez5'))
8
+  bluez_gio_unix_dep = dependency('gio-unix-2.0', required : get_option('bluez5'))
9
   bluez_glib2_dep = dependency('glib-2.0', required : get_option('bluez5'))
10
   sbc_dep = dependency('sbc', required: get_option('bluez5'))
11
   summary({'SBC': sbc_dep.found()}, bool_yn: true, section: 'Bluetooth audio codecs')
12
-  bluez5_deps =  mathlib, dbus_dep, sbc_dep, bluez_dep, bluez_glib2_dep, gio_dep, gio_unix_dep 
13
+  bluez5_deps =  mathlib, dbus_dep, sbc_dep, bluez_dep, bluez_glib2_dep, bluez_gio_dep, bluez_gio_unix_dep 
14
   bluez_deps_found = get_option('bluez5').allowed()
15
   foreach dep: bluez5_deps
16
       if get_option('bluez5').enabled() and not dep.found()
17
pipewire-1.2.0.tar.gz/spa/plugins/alsa/alsa-acp-device.c -> pipewire-1.2.2.tar.bz2/spa/plugins/alsa/alsa-acp-device.c Changed
57
 
1
@@ -126,6 +126,29 @@
2
    return 0;
3
 }
4
 
5
+static int replace_string(const char *str, const char *val, const char *rep,
6
+       char *buf, size_t size)
7
+{
8
+   struct spa_strbuf s;
9
+   const char *p;
10
+   size_t len = strlen(val);
11
+
12
+   spa_assert(len > 0);
13
+   spa_strbuf_init(&s, buf, size);
14
+
15
+   while (1) {
16
+       p = strstr(str, val);
17
+       if (!p)
18
+           break;
19
+
20
+       spa_strbuf_append(&s, "%.*s%s", (int)SPA_PTRDIFF(p, str), str, rep);
21
+       str = p + len;
22
+   }
23
+
24
+   spa_strbuf_append(&s, "%s", str);
25
+   return 0;
26
+}
27
+
28
 static int emit_node(struct impl *this, struct acp_device *dev)
29
 {
30
    struct spa_dict_item *items;
31
@@ -136,7 +159,7 @@
32
    char positionsSPA_AUDIO_MAX_CHANNELS * 12;
33
    struct spa_device_object_info info;
34
    struct acp_card *card = this->card;
35
-   const char *stream, *devstr, *card_id;
36
+   const char *stream, *card_id;
37
 
38
    info = SPA_DEVICE_OBJECT_INFO_INIT();
39
    info.type = SPA_TYPE_INTERFACE_Node;
40
@@ -158,15 +181,7 @@
41
    card_id = acp_dict_lookup(&card->props, "alsa.id");
42
    snprintf(card_name, sizeof(card_name), "%s", card_id ? card_id : card_index);
43
 
44
-   devstr = dev->device_strings0;
45
-   p = strstr(devstr, "%f");
46
-   if (p) {
47
-       snprintf(device_name, sizeof(device_name), "%.*s%d%s",
48
-               (int)SPA_PTRDIFF(p, devstr), devstr,
49
-               card->index, p+2);
50
-   } else {
51
-       snprintf(device_name, sizeof(device_name), "%s", devstr);
52
-   }
53
+   replace_string(dev->device_strings0, "%f", card_index, device_name, sizeof(device_name));
54
 
55
    snprintf(path, sizeof(path), "alsa:acp:%s:%d:%s", card_name, dev->index, stream);
56
    itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_OBJECT_PATH, path);
57
pipewire-1.2.0.tar.gz/spa/plugins/alsa/alsa-pcm.c -> pipewire-1.2.2.tar.bz2/spa/plugins/alsa/alsa-pcm.c Changed
12
 
1
@@ -2245,7 +2245,9 @@
2
 
3
    state->max_delay = state->buffer_frames / 2;
4
    if (spa_strstartswith(state->props.device, "a52") ||
5
-       spa_strstartswith(state->props.device, "dca"))
6
+           spa_strstartswith(state->props.device, "dca") ||
7
+           (spa_strstartswith(state->props.device, "plug:") &&
8
+                   strstr(state->props.device, "a52:")))
9
        state->min_delay = SPA_MIN(2048u, state->buffer_frames);
10
    else
11
        state->min_delay = 0;
12
pipewire-1.2.0.tar.gz/spa/plugins/alsa/mixer/profile-sets/default.conf -> pipewire-1.2.2.tar.bz2/spa/plugins/alsa/mixer/profile-sets/default.conf Changed
166
 
1
@@ -237,14 +237,6 @@
2
 priority = 6
3
 direction = output
4
 
5
-Mapping hdmi-ac3-surround
6
-description = Digital Surround 5.1 (HDMI/AC3)
7
-device-strings = plug:{SLAVE="a52:%f,'hw:%f,3'"}
8
-paths-output = hdmi-output-0
9
-channel-map = front-left,front-right,rear-left,rear-right,front-center,lfe
10
-priority = 6
11
-direction = output
12
-
13
 Mapping hdmi-stereo-extra1
14
 description = Digital Stereo (HDMI 2)
15
 device-strings = hdmi:%f,1
16
@@ -277,14 +269,6 @@
17
 priority = 6
18
 direction = output
19
 
20
-Mapping hdmi-ac3-surround-extra1
21
-description = Digital Surround 5.1 (HDMI 2/AC3)
22
-device-strings = plug:{SLAVE="a52:%f,'hw:%f,7'"}
23
-paths-output = hdmi-output-1
24
-channel-map = front-left,front-right,rear-left,rear-right,front-center,lfe
25
-priority = 6
26
-direction = output
27
-
28
 Mapping hdmi-stereo-extra2
29
 description = Digital Stereo (HDMI 3)
30
 device-strings = hdmi:%f,2
31
@@ -317,14 +301,6 @@
32
 priority = 6
33
 direction = output
34
 
35
-Mapping hdmi-ac3-surround-extra2
36
-description = Digital Surround 5.1 (HDMI 3/AC3)
37
-device-strings = plug:{SLAVE="a52:%f,'hw:%f,8'"}
38
-paths-output = hdmi-output-2
39
-channel-map = front-left,front-right,rear-left,rear-right,front-center,lfe
40
-priority = 6
41
-direction = output
42
-
43
 Mapping hdmi-stereo-extra3
44
 description = Digital Stereo (HDMI 4)
45
 device-strings = hdmi:%f,3
46
@@ -357,14 +333,6 @@
47
 priority = 6
48
 direction = output
49
 
50
-Mapping hdmi-ac3-surround-extra3
51
-description = Digital Surround 5.1 (HDMI 4/AC3)
52
-device-strings = plug:{SLAVE="a52:%f,'hw:%f,9'"}
53
-paths-output = hdmi-output-3
54
-channel-map = front-left,front-right,rear-left,rear-right,front-center,lfe
55
-priority = 6
56
-direction = output
57
-
58
 Mapping hdmi-stereo-extra4
59
 description = Digital Stereo (HDMI 5)
60
 device-strings = hdmi:%f,4
61
@@ -397,14 +365,6 @@
62
 priority = 6
63
 direction = output
64
 
65
-Mapping hdmi-ac3-surround-extra4
66
-description = Digital Surround 5.1 (HDMI 5/AC3)
67
-device-strings = plug:{SLAVE="a52:%f,'hw:%f,10'"}
68
-paths-output = hdmi-output-4
69
-channel-map = front-left,front-right,rear-left,rear-right,front-center,lfe
70
-priority = 6
71
-direction = output
72
-
73
 Mapping hdmi-stereo-extra5
74
 description = Digital Stereo (HDMI 6)
75
 device-strings = hdmi:%f,5
76
@@ -437,14 +397,6 @@
77
 priority = 6
78
 direction = output
79
 
80
-Mapping hdmi-ac3-surround-extra5
81
-description = Digital Surround 5.1 (HDMI 6/AC3)
82
-device-strings = plug:{SLAVE="a52:%f,'hw:%f,11'"}
83
-paths-output = hdmi-output-5
84
-channel-map = front-left,front-right,rear-left,rear-right,front-center,lfe
85
-priority = 6
86
-direction = output
87
-
88
 Mapping hdmi-stereo-extra6
89
 description = Digital Stereo (HDMI 7)
90
 device-strings = hdmi:%f,6
91
@@ -477,14 +429,6 @@
92
 priority = 6
93
 direction = output
94
 
95
-Mapping hdmi-ac3-surround-extra6
96
-description = Digital Surround 5.1 (HDMI 7/AC3)
97
-device-strings = plug:{SLAVE="a52:%f,'hw:%f,12'"}
98
-paths-output = hdmi-output-6
99
-channel-map = front-left,front-right,rear-left,rear-right,front-center,lfe
100
-priority = 6
101
-direction = output
102
-
103
 Mapping hdmi-stereo-extra7
104
 description = Digital Stereo (HDMI 8)
105
 device-strings = hdmi:%f,7
106
@@ -517,14 +461,6 @@
107
 priority = 6
108
 direction = output
109
 
110
-Mapping hdmi-ac3-surround-extra7
111
-description = Digital Surround 5.1 (HDMI 8/AC3)
112
-device-strings = plug:{SLAVE="a52:%f,'hw:%f,13'"}
113
-paths-output = hdmi-output-7
114
-channel-map = front-left,front-right,rear-left,rear-right,front-center,lfe
115
-priority = 6
116
-direction = output
117
-
118
 Mapping hdmi-stereo-extra8
119
 description = Digital Stereo (HDMI 9)
120
 device-strings = hdmi:%f,8
121
@@ -557,14 +493,6 @@
122
 priority = 6
123
 direction = output
124
 
125
-Mapping hdmi-ac3-surround-extra8
126
-description = Digital Surround 5.1 (HDMI 9/AC3)
127
-device-strings = plug:{SLAVE="a52:%f,'hw:%f,14'"}
128
-paths-output = hdmi-output-8
129
-channel-map = front-left,front-right,rear-left,rear-right,front-center,lfe
130
-priority = 6
131
-direction = output
132
-
133
 Mapping hdmi-stereo-extra9
134
 description = Digital Stereo (HDMI 10)
135
 device-strings = hdmi:%f,9
136
@@ -597,14 +525,6 @@
137
 priority = 6
138
 direction = output
139
 
140
-Mapping hdmi-ac3-surround-extra9
141
-description = Digital Surround 5.1 (HDMI 10/AC3)
142
-device-strings = plug:{SLAVE="a52:%f,'hw:%f,15'"}
143
-paths-output = hdmi-output-9
144
-channel-map = front-left,front-right,rear-left,rear-right,front-center,lfe
145
-priority = 6
146
-direction = output
147
-
148
 Mapping hdmi-stereo-extra10
149
 description = Digital Stereo (HDMI 11)
150
 device-strings = hdmi:%f,10
151
@@ -637,14 +557,6 @@
152
 priority = 6
153
 direction = output
154
 
155
-Mapping hdmi-ac3-surround-extra10
156
-description = Digital Surround 5.1 (HDMI 11/AC3)
157
-device-strings = plug:{SLAVE="a52:%f,'hw:%f,16'"}
158
-paths-output = hdmi-output-10
159
-channel-map = front-left,front-right,rear-left,rear-right,front-center,lfe
160
-priority = 6
161
-direction = output
162
-
163
 Mapping multichannel-output
164
 device-strings = hw:%f
165
 channel-map = left,right,rear-left,rear-right
166
pipewire-1.2.0.tar.gz/spa/plugins/audioconvert/audioadapter.c -> pipewire-1.2.2.tar.bz2/spa/plugins/audioconvert/audioadapter.c Changed
70
 
1
@@ -268,23 +268,31 @@
2
            res, spa_strerror(res));
3
    }
4
 
5
+   return 0;
6
+}
7
+
8
+static int activate_io(struct impl *this, bool active)
9
+{
10
+   int res;
11
+   struct spa_io_buffers *data = active ? &this->io_buffers : NULL;
12
+   uint32_t size = active ? sizeof(this->io_buffers) : 0;
13
+
14
    if (this->follower == this->target)
15
        return 0;
16
 
17
-   this->io_buffers = SPA_IO_BUFFERS_INIT;
18
+   if (active)
19
+       this->io_buffers = SPA_IO_BUFFERS_INIT;
20
 
21
    if ((res = spa_node_port_set_io(this->follower,
22
            this->direction, 0,
23
-           SPA_IO_Buffers,
24
-           &this->io_buffers, sizeof(this->io_buffers))) < 0) {
25
+           SPA_IO_Buffers, data, size)) < 0) {
26
        spa_log_warn(this->log, "%p: set Buffers on follower failed %d %s", this,
27
            res, spa_strerror(res));
28
        return res;
29
    }
30
    else if ((res = spa_node_port_set_io(this->convert,
31
            SPA_DIRECTION_REVERSE(this->direction), 0,
32
-           SPA_IO_Buffers,
33
-           &this->io_buffers, sizeof(this->io_buffers))) < 0) {
34
+           SPA_IO_Buffers, data, size)) < 0) {
35
        spa_log_warn(this->log, "%p: set Buffers on convert failed %d %s", this,
36
            res, spa_strerror(res));
37
        return res;
38
@@ -484,6 +492,8 @@
39
               this->buffers, this->n_buffers)) < 0)
40
        return res;
41
 
42
+   activate_io(this, true);
43
+
44
    return 0;
45
 }
46
 
47
@@ -499,12 +509,20 @@
48
    uint8_t buffer4096;
49
    int res;
50
 
51
+   spa_log_debug(this->log, "%p: configure format:", this);
52
+
53
    if (format == NULL && !this->have_format)
54
        return 0;
55
 
56
-   spa_log_debug(this->log, "%p: configure format:", this);
57
-   if (format)
58
+
59
+   if (format == NULL) {
60
+       if (!this->have_format)
61
+           return 0;
62
+       activate_io(this, false);
63
+   }
64
+   else {
65
        spa_debug_log_format(this->log, SPA_LOG_LEVEL_DEBUG, 0, NULL, format);
66
+   }
67
 
68
    if ((res = spa_node_port_set_param(this->follower,
69
                       this->direction, 0,
70
pipewire-1.2.0.tar.gz/spa/plugins/audioconvert/audioconvert.c -> pipewire-1.2.2.tar.bz2/spa/plugins/audioconvert/audioconvert.c Changed
61
 
1
@@ -193,6 +193,7 @@
2
 
3
    struct spa_log *log;
4
    struct spa_cpu *cpu;
5
+   struct spa_loop *data_loop;
6
 
7
    uint32_t cpu_flags;
8
    uint32_t max_align;
9
@@ -2448,7 +2449,7 @@
10
 
11
    port = GET_PORT(this, direction, port_id);
12
 
13
-   spa_log_debug(this->log, "%p: set format", this);
14
+   spa_log_debug(this->log, "%p: %d:%d set format", this, direction, port_id);
15
 
16
    if (format == NULL) {
17
        port->have_format = false;
18
@@ -2677,6 +2678,20 @@
19
    return 0;
20
 }
21
 
22
+struct io_data {
23
+   struct port *port;
24
+   void *data;
25
+   size_t size;
26
+};
27
+
28
+static int do_set_port_io(struct spa_loop *loop, bool async, uint32_t seq,
29
+       const void *data, size_t size, void *user_data)
30
+{
31
+   const struct io_data *d = user_data;
32
+   d->port->io = d->data;
33
+   return 0;
34
+}
35
+
36
 static int
37
 impl_node_port_set_io(void *object,
38
              enum spa_direction direction, uint32_t port_id,
39
@@ -2696,7 +2711,12 @@
40
 
41
    switch (id) {
42
    case SPA_IO_Buffers:
43
-       port->io = data;
44
+       if (this->data_loop) {
45
+           struct io_data d = { .port = port, .data = data, .size = size };
46
+           spa_loop_invoke(this->data_loop, do_set_port_io, 0, NULL, 0, true, &d);
47
+       }
48
+       else
49
+           port->io = data;
50
        break;
51
    case SPA_IO_RateMatch:
52
        this->io_rate_match = data;
53
@@ -3432,6 +3452,7 @@
54
 
55
    this = (struct impl *) handle;
56
 
57
+   this->data_loop = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_DataLoop);
58
    this->log = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_Log);
59
    spa_log_topic_init(this->log, &log_topic);
60
 
61
pipewire-1.2.0.tar.gz/spa/plugins/bluez5/backend-native.c -> pipewire-1.2.2.tar.bz2/spa/plugins/bluez5/backend-native.c Changed
11
 
1
@@ -1388,7 +1388,8 @@
2
 
3
        if (!handler(rfcomm, token)) {
4
            spa_log_debug(backend->log, "RFCOMM received unsupported event: %s", token);
5
-           rfcomm_send_error(rfcomm, CMEE_OPERATION_NOT_SUPPORTED);
6
+           if (ag)
7
+               rfcomm_send_error(rfcomm, CMEE_OPERATION_NOT_SUPPORTED);
8
        }
9
    }
10
 }
11
pipewire-1.2.0.tar.gz/spa/plugins/bluez5/bluez5-dbus.c -> pipewire-1.2.2.tar.bz2/spa/plugins/bluez5/bluez5-dbus.c Changed
11
 
1
@@ -5310,7 +5310,8 @@
2
    int options = 0;
3
    int skip = 0;
4
    int sync_cte_type = 0;
5
-   int sync_factor = 1;
6
+   /* sync_factor should be >=2 to avoid invalid extended advertising interval value */
7
+   int sync_factor = 2;
8
    int sync_timeout = 2000;
9
    int timeout = 2000;
10
 
11
pipewire-1.2.0.tar.gz/spa/plugins/support/loop.c -> pipewire-1.2.2.tar.bz2/spa/plugins/support/loop.c Changed
34
 
1
@@ -212,9 +212,12 @@
2
         * read index before we call the function because then the item
3
         * might get overwritten. */
4
        func = spa_steal_ptr(item->func);
5
-       if (func)
6
+       if (func) {
7
+           pthread_mutex_unlock(&impl->queue_lock);
8
            item->res = func(&impl->loop, true, item->seq, item->data,
9
                item->size, item->user_data);
10
+           pthread_mutex_lock(&impl->queue_lock);
11
+       }
12
 
13
        /* if this function did a recursive invoke, it now flushed the
14
         * ringbuffer and we can exit */
15
@@ -338,6 +341,7 @@
16
        spa_log_warn(impl->log, "%p: queue full %d, need %zd (%d suppressed)",
17
                queue, avail, need, suppressed);
18
    }
19
+   loop_signal_event(impl, impl->wakeup);
20
    if (impl->retry_timeout == 0)
21
        return -EPIPE;
22
    usleep(impl->retry_timeout);
23
@@ -884,8 +888,9 @@
24
    if (SPA_LIKELY(value)) {
25
        its.it_value = *value;
26
    } else if (interval) {
27
+       // timer initially fires after one interval
28
        its.it_value = *interval;
29
-       absolute = true;
30
+       absolute = false;
31
    }
32
    if (SPA_UNLIKELY(interval))
33
        its.it_interval = *interval;
34
pipewire-1.2.0.tar.gz/spa/plugins/support/node-driver.c -> pipewire-1.2.2.tar.bz2/spa/plugins/support/node-driver.c Changed
20
 
1
@@ -33,7 +33,7 @@
2
 #define SPA_LOG_TOPIC_DEFAULT &log_topic
3
 
4
 #define DEFAULT_FREEWHEEL  false
5
-#define DEFAULT_FREEWHEEL_WAIT 10
6
+#define DEFAULT_FREEWHEEL_WAIT 5
7
 #define DEFAULT_CLOCK_PREFIX   "clock.system"
8
 #define DEFAULT_CLOCK_ID   CLOCK_MONOTONIC
9
 #define DEFAULT_RESYNC_MS  10
10
@@ -524,7 +524,8 @@
11
    spa_return_val_if_fail(this != NULL, -EINVAL);
12
    spa_log_trace(this->log, "process %d", this->props.freewheel);
13
 
14
-   if (this->props.freewheel) {
15
+   if (this->props.freewheel &&
16
+       !SPA_FLAG_IS_SET(this->position->clock.flags, SPA_IO_CLOCK_FLAG_XRUN_RECOVER)) {
17
        this->next_time = gettime_nsec(this, this->timer_clockid);
18
        set_timeout(this, this->next_time);
19
    }
20
pipewire-1.2.0.tar.gz/spa/plugins/v4l2/v4l2-source.c -> pipewire-1.2.2.tar.bz2/spa/plugins/v4l2/v4l2-source.c Changed
201
 
1
@@ -243,7 +243,8 @@
2
 {
3
    struct impl *this = object;
4
    struct spa_pod *param;
5
-   struct spa_pod_builder b = { 0 };
6
+   spa_auto(spa_pod_dynamic_builder) b = { 0 };
7
+   struct spa_pod_builder_state state;
8
    uint8_t buffer1024;
9
    struct spa_result_node_params result;
10
    uint32_t count = 0;
11
@@ -252,12 +253,15 @@
12
    spa_return_val_if_fail(this != NULL, -EINVAL);
13
    spa_return_val_if_fail(num != 0, -EINVAL);
14
 
15
+   spa_pod_dynamic_builder_init(&b, buffer, sizeof(buffer), 4096);
16
+   spa_pod_builder_get_state(&b.b, &state);
17
+
18
    result.id = id;
19
    result.next = start;
20
       next:
21
    result.index = result.next++;
22
 
23
-   spa_pod_builder_init(&b, buffer, sizeof(buffer));
24
+   spa_pod_builder_reset(&b.b, &state);
25
 
26
    switch (id) {
27
    case SPA_PARAM_PropInfo:
28
@@ -266,21 +270,21 @@
29
 
30
        switch (result.index) {
31
        case 0:
32
-           param = spa_pod_builder_add_object(&b,
33
+           param = spa_pod_builder_add_object(&b.b,
34
                SPA_TYPE_OBJECT_PropInfo, id,
35
                SPA_PROP_INFO_id,   SPA_POD_Id(SPA_PROP_device),
36
                SPA_PROP_INFO_description, SPA_POD_String("The V4L2 device"),
37
                SPA_PROP_INFO_type, SPA_POD_String(p->device));
38
            break;
39
        case 1:
40
-           param = spa_pod_builder_add_object(&b,
41
+           param = spa_pod_builder_add_object(&b.b,
42
                SPA_TYPE_OBJECT_PropInfo, id,
43
                SPA_PROP_INFO_id,   SPA_POD_Id(SPA_PROP_deviceName),
44
                SPA_PROP_INFO_description, SPA_POD_String("The V4L2 device name"),
45
                SPA_PROP_INFO_type, SPA_POD_String(p->device_name));
46
            break;
47
        case 2:
48
-           param = spa_pod_builder_add_object(&b,
49
+           param = spa_pod_builder_add_object(&b.b,
50
                SPA_TYPE_OBJECT_PropInfo, id,
51
                SPA_PROP_INFO_id,   SPA_POD_Id(SPA_PROP_deviceFd),
52
                SPA_PROP_INFO_description, SPA_POD_String("The V4L2 fd"),
53
@@ -305,8 +309,8 @@
54
 
55
        switch (result.index) {
56
        case 0:
57
-           spa_pod_builder_push_object(&b, &f, SPA_TYPE_OBJECT_Props, id);
58
-           spa_pod_builder_add(&b,
59
+           spa_pod_builder_push_object(&b.b, &f, SPA_TYPE_OBJECT_Props, id);
60
+           spa_pod_builder_add(&b.b,
61
                SPA_PROP_device,     SPA_POD_String(p->device),
62
                SPA_PROP_deviceName, SPA_POD_String(p->device_name),
63
                SPA_PROP_deviceFd,   SPA_POD_Int(p->device_fd),
64
@@ -314,20 +318,20 @@
65
            for (i = 0; i < port->n_controls; i++) {
66
                struct control *c = &port->controlsi;
67
 
68
-               spa_pod_builder_prop(&b, c->id, 0);
69
+               spa_pod_builder_prop(&b.b, c->id, 0);
70
                switch (c->type) {
71
                case SPA_TYPE_Int:
72
-                   spa_pod_builder_int(&b, c->value);
73
+                   spa_pod_builder_int(&b.b, c->value);
74
                    break;
75
                case SPA_TYPE_Bool:
76
-                   spa_pod_builder_bool(&b, c->value);
77
+                   spa_pod_builder_bool(&b.b, c->value);
78
                    break;
79
                default:
80
-                   spa_pod_builder_int(&b, c->value);
81
+                   spa_pod_builder_int(&b.b, c->value);
82
                    break;
83
                }
84
            }
85
-           param = spa_pod_builder_pop(&b, &f);
86
+           param = spa_pod_builder_pop(&b.b, &f);
87
            break;
88
        default:
89
            return 0;
90
@@ -338,14 +342,14 @@
91
        return spa_v4l2_enum_format(this, seq, start, num, filter);
92
    case SPA_PARAM_Format:
93
        if((res = port_get_format(GET_OUT_PORT(this, 0),
94
-                       result.index, filter, &param, &b)) <= 0)
95
+                       result.index, filter, &param, &b.b)) <= 0)
96
            return res;
97
        break;
98
    default:
99
        return -ENOENT;
100
    }
101
 
102
-   if (spa_pod_filter(&b, &result.param, param, filter) < 0)
103
+   if (spa_pod_filter(&b.b, &result.param, param, filter) < 0)
104
        goto next;
105
 
106
    spa_node_emit_result(&this->hooks, seq, 0, SPA_RESULT_TYPE_NODE_PARAMS, &result);
107
@@ -535,7 +539,8 @@
108
    struct impl *this = object;
109
    struct port *port;
110
    struct spa_pod *param;
111
-   struct spa_pod_builder b = { 0 };
112
+   spa_auto(spa_pod_dynamic_builder) b = { 0 };
113
+   struct spa_pod_builder_state state;
114
    uint8_t buffer1024;
115
    struct spa_result_node_params result;
116
    uint32_t count = 0;
117
@@ -545,6 +550,9 @@
118
    spa_return_val_if_fail(num != 0, -EINVAL);
119
    spa_return_val_if_fail(CHECK_PORT(this, direction, port_id), -EINVAL);
120
 
121
+   spa_pod_dynamic_builder_init(&b, buffer, sizeof(buffer), 4096);
122
+   spa_pod_builder_get_state(&b.b, &state);
123
+
124
    port = GET_PORT(this, direction, port_id);
125
 
126
    result.id = id;
127
@@ -552,7 +560,7 @@
128
      next:
129
    result.index = result.next++;
130
 
131
-   spa_pod_builder_init(&b, buffer, sizeof(buffer));
132
+   spa_pod_builder_reset(&b.b, &state);
133
 
134
    switch (id) {
135
    case SPA_PARAM_PropInfo:
136
@@ -562,7 +570,7 @@
137
        return spa_v4l2_enum_format(this, seq, start, num, filter);
138
 
139
    case SPA_PARAM_Format:
140
-       if((res = port_get_format(port, result.index, filter, &param, &b)) <= 0)
141
+       if((res = port_get_format(port, result.index, filter, &param, &b.b)) <= 0)
142
            return res;
143
        break;
144
    case SPA_PARAM_Buffers:
145
@@ -571,7 +579,7 @@
146
        if (result.index > 0)
147
            return 0;
148
 
149
-       param = spa_pod_builder_add_object(&b,
150
+       param = spa_pod_builder_add_object(&b.b,
151
            SPA_TYPE_OBJECT_ParamBuffers, id,
152
            SPA_PARAM_BUFFERS_buffers, SPA_POD_CHOICE_RANGE_Int(4, 1, MAX_BUFFERS),
153
            SPA_PARAM_BUFFERS_blocks,  SPA_POD_Int(1),
154
@@ -582,13 +590,13 @@
155
    case SPA_PARAM_Meta:
156
        switch (result.index) {
157
        case 0:
158
-           param = spa_pod_builder_add_object(&b,
159
+           param = spa_pod_builder_add_object(&b.b,
160
                SPA_TYPE_OBJECT_ParamMeta, id,
161
                SPA_PARAM_META_type, SPA_POD_Id(SPA_META_Header),
162
                SPA_PARAM_META_size, SPA_POD_Int(sizeof(struct spa_meta_header)));
163
            break;
164
        case 1:
165
-           param = spa_pod_builder_add_object(&b,
166
+           param = spa_pod_builder_add_object(&b.b,
167
                SPA_TYPE_OBJECT_ParamMeta, id,
168
                SPA_PARAM_META_type, SPA_POD_Id(SPA_META_VideoTransform),
169
                SPA_PARAM_META_size, SPA_POD_Int(sizeof(struct spa_meta_videotransform)));
170
@@ -600,19 +608,19 @@
171
    case SPA_PARAM_IO:
172
        switch (result.index) {
173
        case 0:
174
-           param = spa_pod_builder_add_object(&b,
175
+           param = spa_pod_builder_add_object(&b.b,
176
                SPA_TYPE_OBJECT_ParamIO, id,
177
                SPA_PARAM_IO_id,   SPA_POD_Id(SPA_IO_Buffers),
178
                SPA_PARAM_IO_size, SPA_POD_Int(sizeof(struct spa_io_buffers)));
179
            break;
180
        case 1:
181
-           param = spa_pod_builder_add_object(&b,
182
+           param = spa_pod_builder_add_object(&b.b,
183
                SPA_TYPE_OBJECT_ParamIO, id,
184
                SPA_PARAM_IO_id,   SPA_POD_Id(SPA_IO_Clock),
185
                SPA_PARAM_IO_size, SPA_POD_Int(sizeof(struct spa_io_clock)));
186
            break;
187
        case 2:
188
-           param = spa_pod_builder_add_object(&b,
189
+           param = spa_pod_builder_add_object(&b.b,
190
                SPA_TYPE_OBJECT_ParamIO, id,
191
                SPA_PARAM_IO_id,   SPA_POD_Id(SPA_IO_Control),
192
                SPA_PARAM_IO_size, SPA_POD_Int(sizeof(struct spa_io_sequence)));
193
@@ -624,7 +632,7 @@
194
    case SPA_PARAM_Latency:
195
        switch (result.index) {
196
        case 0: case 1:
197
-           param = spa_latency_build(&b, id, &this->latencyresult.index);
198
+           param = spa_latency_build(&b.b, id, &this->latencyresult.index);
199
            break;
200
        default:
201
pipewire-1.2.0.tar.gz/spa/plugins/v4l2/v4l2-utils.c -> pipewire-1.2.2.tar.bz2/spa/plugins/v4l2/v4l2-utils.c Changed
201
 
1
@@ -11,6 +11,8 @@
2
 #include <sys/mman.h>
3
 #include <poll.h>
4
 
5
+#include <spa/pod/dynamic.h>
6
+#include <spa/utils/cleanup.h>
7
 #include <spa/utils/result.h>
8
 
9
 static int xioctl(int fd, int request, void *arg)
10
@@ -505,7 +507,8 @@
11
    uint32_t filter_media_type, filter_media_subtype;
12
    struct spa_v4l2_device *dev = &port->dev;
13
    uint8_t buffer1024;
14
-   struct spa_pod_builder b = { 0 };
15
+   spa_auto(spa_pod_dynamic_builder) b = { 0 };
16
+   struct spa_pod_builder_state state;
17
    struct spa_pod_frame f2;
18
    struct spa_result_node_params result;
19
    uint32_t count = 0;
20
@@ -513,6 +516,9 @@
21
    if ((res = spa_v4l2_open(dev, this->props.device)) < 0)
22
        return res;
23
 
24
+   spa_pod_dynamic_builder_init(&b, buffer, sizeof(buffer), 4096);
25
+   spa_pod_builder_get_state(&b.b, &state);
26
+
27
    result.id = SPA_PARAM_EnumFormat;
28
    result.next = start;
29
 
30
@@ -630,14 +636,31 @@
31
        }
32
          do_frmsize:
33
        if ((res = xioctl(dev->fd, VIDIOC_ENUM_FRAMESIZES, &port->frmsize)) < 0) {
34
-           if (errno == EINVAL || errno == ENOTTY)
35
+           if (errno == ENOTTY)
36
                goto next_fmtdesc;
37
+           if (errno == EINVAL) {
38
+               if (port->frmsize.index == 0) {
39
+                   port->frmsize.type = V4L2_FRMSIZE_TYPE_CONTINUOUS;
40
+                   port->frmsize.stepwise.min_width = 16;
41
+                   port->frmsize.stepwise.min_height = 16;
42
+                   port->frmsize.stepwise.max_width = 16384;
43
+                   port->frmsize.stepwise.max_height = 16384;
44
+                   port->frmsize.stepwise.step_width = 16;
45
+                   port->frmsize.stepwise.step_height = 16;
46
+                   port->fmtdesc.index++;
47
+                   port->next_fmtdesc = true;
48
+                   goto do_frmsize_filter;
49
+               }
50
+               else
51
+                   goto next_fmtdesc;
52
+           }
53
 
54
            res = -errno;
55
            spa_log_error(this->log, "'%s' VIDIOC_ENUM_FRAMESIZES: %m",
56
                    this->props.device);
57
            goto exit;
58
        }
59
+do_frmsize_filter:
60
        if (filter) {
61
            static const struct spa_rectangle step = {1, 1};
62
 
63
@@ -695,34 +718,35 @@
64
        }
65
    }
66
 
67
-   spa_pod_builder_init(&b, buffer, sizeof(buffer));
68
-   spa_pod_builder_push_object(&b, &f0, SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat);
69
-   spa_pod_builder_add(&b,
70
+   spa_pod_builder_reset(&b.b, &state);
71
+   spa_pod_builder_push_object(&b.b, &f0, SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat);
72
+   spa_pod_builder_add(&b.b,
73
            SPA_FORMAT_mediaType,    SPA_POD_Id(info->media_type),
74
            SPA_FORMAT_mediaSubtype, SPA_POD_Id(info->media_subtype),
75
            0);
76
 
77
    if (info->media_subtype == SPA_MEDIA_SUBTYPE_raw) {
78
-       spa_pod_builder_prop(&b, SPA_FORMAT_VIDEO_format, 0);
79
-       spa_pod_builder_id(&b, info->format);
80
+       spa_pod_builder_prop(&b.b, SPA_FORMAT_VIDEO_format, 0);
81
+       spa_pod_builder_id(&b.b, info->format);
82
    }
83
-   spa_pod_builder_prop(&b, SPA_FORMAT_VIDEO_size, 0);
84
+
85
+   spa_pod_builder_prop(&b.b, SPA_FORMAT_VIDEO_size, 0);
86
    if (port->frmsize.type == V4L2_FRMSIZE_TYPE_DISCRETE) {
87
-       spa_pod_builder_rectangle(&b,
88
+       spa_pod_builder_rectangle(&b.b,
89
                port->frmsize.discrete.width,
90
                port->frmsize.discrete.height);
91
    } else if (port->frmsize.type == V4L2_FRMSIZE_TYPE_CONTINUOUS ||
92
           port->frmsize.type == V4L2_FRMSIZE_TYPE_STEPWISE) {
93
-       spa_pod_builder_push_choice(&b, &f1, SPA_CHOICE_None, 0);
94
-       choice = (struct spa_pod_choice*)spa_pod_builder_frame(&b, &f1);
95
+       spa_pod_builder_push_choice(&b.b, &f1, SPA_CHOICE_None, 0);
96
+       choice = (struct spa_pod_choice*)spa_pod_builder_frame(&b.b, &f1);
97
 
98
-       spa_pod_builder_rectangle(&b,
99
+       spa_pod_builder_rectangle(&b.b,
100
                port->frmsize.stepwise.min_width,
101
                port->frmsize.stepwise.min_height);
102
-       spa_pod_builder_rectangle(&b,
103
+       spa_pod_builder_rectangle(&b.b,
104
                port->frmsize.stepwise.min_width,
105
                port->frmsize.stepwise.min_height);
106
-       spa_pod_builder_rectangle(&b,
107
+       spa_pod_builder_rectangle(&b.b,
108
                port->frmsize.stepwise.max_width,
109
                port->frmsize.stepwise.max_height);
110
 
111
@@ -730,35 +754,43 @@
112
            choice->body.type = SPA_CHOICE_Range;
113
        } else {
114
            choice->body.type = SPA_CHOICE_Step;
115
-           spa_pod_builder_rectangle(&b,
116
+           spa_pod_builder_rectangle(&b.b,
117
                    port->frmsize.stepwise.max_width,
118
                    port->frmsize.stepwise.max_height);
119
        }
120
-       spa_pod_builder_pop(&b, &f1);
121
+       spa_pod_builder_pop(&b.b, &f1);
122
    }
123
 
124
-   spa_pod_builder_prop(&b, SPA_FORMAT_VIDEO_framerate, 0);
125
+   spa_pod_builder_prop(&b.b, SPA_FORMAT_VIDEO_framerate, 0);
126
 
127
    n_fractions = 0;
128
 
129
-   spa_pod_builder_push_choice(&b, &f1, SPA_CHOICE_None, 0);
130
-   choice = (struct spa_pod_choice*)spa_pod_builder_frame(&b, &f1);
131
+   spa_pod_builder_push_choice(&b.b, &f1, SPA_CHOICE_None, 0);
132
+   choice = (struct spa_pod_choice*)spa_pod_builder_frame(&b.b, &f1);
133
    port->frmival.index = 0;
134
 
135
    while (true) {
136
        if ((res = xioctl(dev->fd, VIDIOC_ENUM_FRAMEINTERVALS, &port->frmival)) < 0) {
137
            res = -errno;
138
+           port->frmsize.index++;
139
+           port->next_frmsize = true;
140
            if (errno == EINVAL || errno == ENOTTY) {
141
-               port->frmsize.index++;
142
-               port->next_frmsize = true;
143
-               if (port->frmival.index == 0)
144
-                   goto next_frmsize;
145
-               break;
146
+               if (port->frmival.index == 0) {
147
+                   port->frmival.type = V4L2_FRMIVAL_TYPE_CONTINUOUS;
148
+                   port->frmival.stepwise.min.denominator = 1;
149
+                   port->frmival.stepwise.min.numerator = 1;
150
+                   port->frmival.stepwise.max.denominator = 120;
151
+                   port->frmival.stepwise.max.numerator = 1;
152
+                   goto do_frminterval_filter;
153
+               }
154
+               else
155
+                   break;
156
            }
157
            spa_log_error(this->log, "'%s' VIDIOC_ENUM_FRAMEINTERVALS: %m",
158
                    this->props.device);
159
            goto exit;
160
        }
161
+do_frminterval_filter:
162
        if (filter) {
163
            static const struct spa_fraction step = {1, 1};
164
 
165
@@ -810,10 +842,10 @@
166
        if (port->frmival.type == V4L2_FRMIVAL_TYPE_DISCRETE) {
167
            choice->body.type = SPA_CHOICE_Enum;
168
            if (n_fractions == 0)
169
-               spa_pod_builder_fraction(&b,
170
+               spa_pod_builder_fraction(&b.b,
171
                             port->frmival.discrete.denominator,
172
                             port->frmival.discrete.numerator);
173
-           spa_pod_builder_fraction(&b,
174
+           spa_pod_builder_fraction(&b.b,
175
                         port->frmival.discrete.denominator,
176
                         port->frmival.discrete.numerator);
177
            port->frmival.index++;
178
@@ -821,11 +853,11 @@
179
        } else if (port->frmival.type == V4L2_FRMIVAL_TYPE_CONTINUOUS ||
180
               port->frmival.type == V4L2_FRMIVAL_TYPE_STEPWISE) {
181
            if (n_fractions == 0)
182
-               spa_pod_builder_fraction(&b, 25, 1);
183
-           spa_pod_builder_fraction(&b,
184
+               spa_pod_builder_fraction(&b.b, 25, 1);
185
+           spa_pod_builder_fraction(&b.b,
186
                         port->frmival.stepwise.min.denominator,
187
                         port->frmival.stepwise.min.numerator);
188
-           spa_pod_builder_fraction(&b,
189
+           spa_pod_builder_fraction(&b.b,
190
                         port->frmival.stepwise.max.denominator,
191
                         port->frmival.stepwise.max.numerator);
192
 
193
@@ -834,7 +866,7 @@
194
                n_fractions += 2;
195
            } else {
196
                choice->body.type = SPA_CHOICE_Step;
197
-               spa_pod_builder_fraction(&b,
198
+               spa_pod_builder_fraction(&b.b,
199
                             port->frmival.stepwise.step.denominator,
200
                             port->frmival.stepwise.step.numerator);
201
pipewire-1.2.0.tar.gz/src/gst/gstpipewiresrc.c -> pipewire-1.2.2.tar.bz2/src/gst/gstpipewiresrc.c Changed
64
 
1
@@ -435,6 +435,8 @@
2
   src->autoconnect = DEFAULT_AUTOCONNECT;
3
   src->min_latency = 0;
4
   src->max_latency = GST_CLOCK_TIME_NONE;
5
+
6
+  src->transform_value = UINT32_MAX;
7
 }
8
 
9
 static gboolean
10
@@ -538,7 +540,7 @@
11
   GstPipeWirePoolData *data;
12
   struct spa_meta_header *h;
13
   struct spa_meta_region *crop;
14
-  struct spa_meta_videotransform *videotransform;
15
+  enum spa_meta_videotransform_value transform_value;
16
   struct pw_time time;
17
   guint i;
18
 
19
@@ -613,24 +615,22 @@
20
     }
21
   }
22
 
23
-  videotransform = data->videotransform;
24
-  if (videotransform) {
25
-    if (pwsrc->transform_value != videotransform->transform) {
26
-      GstEvent *tag_event;
27
-      const char* tag_string;
28
+  transform_value = data->videotransform ? data->videotransform->transform :
29
+                                           SPA_META_TRANSFORMATION_None;
30
+  if (transform_value != pwsrc->transform_value) {
31
+    GstEvent *tag_event;
32
+    const char* tag_string;
33
 
34
-      tag_string =
35
-          spa_transform_value_to_gst_image_orientation(videotransform->transform);
36
+    tag_string = spa_transform_value_to_gst_image_orientation(transform_value);
37
 
38
-      GST_LOG_OBJECT (pwsrc, "got new videotransform: %u / %s",
39
-          videotransform->transform, tag_string);
40
+    GST_LOG_OBJECT (pwsrc, "got new videotransform: %u / %s",
41
+        transform_value, tag_string);
42
 
43
-      tag_event = gst_event_new_tag(gst_tag_list_new(GST_TAG_IMAGE_ORIENTATION,
44
-          tag_string, NULL));
45
-      gst_pad_push_event (GST_BASE_SRC_PAD (pwsrc), tag_event);
46
+    tag_event = gst_event_new_tag(gst_tag_list_new(GST_TAG_IMAGE_ORIENTATION,
47
+        tag_string, NULL));
48
+    gst_pad_push_event (GST_BASE_SRC_PAD (pwsrc), tag_event);
49
 
50
-      pwsrc->transform_value = videotransform->transform;
51
-    }
52
+    pwsrc->transform_value = transform_value;
53
   }
54
 
55
   if (pwsrc->is_video) {
56
@@ -1391,6 +1391,7 @@
57
   pwsrc->eos = false;
58
   gst_buffer_replace (&pwsrc->last_buffer, NULL);
59
   gst_caps_replace(&pwsrc->caps, NULL);
60
+  pwsrc->transform_value = UINT32_MAX;
61
   pw_thread_loop_unlock (pwsrc->stream->core->loop);
62
 
63
   return TRUE;
64
pipewire-1.2.0.tar.gz/src/gst/gstpipewirestream.c -> pipewire-1.2.2.tar.bz2/src/gst/gstpipewirestream.c Changed
15
 
1
@@ -158,7 +158,12 @@
2
 
3
   /* destroy the pw stream */
4
   pw_thread_loop_lock (self->core->loop);
5
-  g_clear_pointer (&self->pwstream, pw_stream_destroy);
6
+  if (self->pwstream) {
7
+     /* Do not use g_clear_pointer() here as pw_stream_destroy() may chain up to
8
+      * code requiring the pointer to still be around */
9
+     pw_stream_destroy (self->pwstream);
10
+     self->pwstream = NULL;
11
+  }
12
   pw_thread_loop_unlock (self->core->loop);
13
 
14
   /* release the core */
15
pipewire-1.2.0.tar.gz/src/modules/meson.build -> pipewire-1.2.2.tar.bz2/src/modules/meson.build Changed
15
 
1
@@ -433,11 +433,11 @@
2
   cdata.set('HAVE_AVAHI', true)
3
 endif
4
 
5
-if gio_dep.found()
6
+if gsettings_gio_dep.found()
7
   pipewire_module_protocol_pulse_sources += 
8
     'module-protocol-pulse/modules/module-gsettings.c',
9
   
10
-  pipewire_module_protocol_pulse_deps += gio_dep
11
+  pipewire_module_protocol_pulse_deps += gsettings_gio_dep
12
   cdata.set('HAVE_GIO', true)
13
   if get_option('gsettings-pulse-schema').enabled()
14
     install_data('module-protocol-pulse/modules/org.freedesktop.pulseaudio.gschema.xml',
15
pipewire-1.2.0.tar.gz/src/modules/module-ffado-driver.c -> pipewire-1.2.2.tar.bz2/src/modules/module-ffado-driver.c Changed
12
 
1
@@ -548,8 +548,8 @@
2
    struct impl *impl = s->impl;
3
    switch (state) {
4
    case PW_FILTER_STATE_ERROR:
5
-       pw_log_error("filter state %d error: %s", state, error);
6
-       SPA_FALLTHROUGH;
7
+       pw_log_warn("filter state %d error: %s", state, error);
8
+       break;
9
    case PW_FILTER_STATE_UNCONNECTED:
10
        pw_impl_module_schedule_destroy(impl->module);
11
        break;
12
pipewire-1.2.0.tar.gz/src/modules/module-jack-tunnel.c -> pipewire-1.2.2.tar.bz2/src/modules/module-jack-tunnel.c Changed
15
 
1
@@ -306,10 +306,12 @@
2
    struct stream *s = d;
3
    struct impl *impl = s->impl;
4
    switch (state) {
5
-   case PW_FILTER_STATE_ERROR:
6
    case PW_FILTER_STATE_UNCONNECTED:
7
        pw_impl_module_schedule_destroy(impl->module);
8
        break;
9
+   case PW_FILTER_STATE_ERROR:
10
+       pw_log_warn("stream %p: error: %s", s, error);
11
+       break;
12
    case PW_FILTER_STATE_PAUSED:
13
        s->running = false;
14
        break;
15
pipewire-1.2.0.tar.gz/src/modules/module-jack-tunnel/weakjack.h -> pipewire-1.2.2.tar.bz2/src/modules/module-jack-tunnel/weakjack.h Changed
10
 
1
@@ -101,7 +101,7 @@
2
 
3
    hnd = dlopen(path, RTLD_NOW);
4
    if (hnd == NULL)
5
-       return -errno;
6
+       return -ENOENT;
7
 
8
    pw_log_info("opened libjack: %s", path);
9
 
10
pipewire-1.2.0.tar.gz/src/modules/module-netjack2-driver.c -> pipewire-1.2.2.tar.bz2/src/modules/module-netjack2-driver.c Changed
10
 
1
@@ -274,6 +274,8 @@
2
    struct impl *impl = s->impl;
3
    switch (state) {
4
    case PW_FILTER_STATE_ERROR:
5
+       pw_log_warn("stream %p: error: %s", s, error);
6
+       break;
7
    case PW_FILTER_STATE_UNCONNECTED:
8
        pw_impl_module_schedule_destroy(impl->module);
9
        break;
10
pipewire-1.2.0.tar.gz/src/modules/module-netjack2-manager.c -> pipewire-1.2.2.tar.bz2/src/modules/module-netjack2-manager.c Changed
10
 
1
@@ -297,6 +297,8 @@
2
    struct impl *impl = s->impl;
3
    switch (state) {
4
    case PW_FILTER_STATE_ERROR:
5
+       pw_log_warn("stream %p: error: %s", s, error);
6
+       break;
7
    case PW_FILTER_STATE_UNCONNECTED:
8
        pw_impl_module_schedule_destroy(impl->module);
9
        break;
10
pipewire-1.2.0.tar.gz/src/modules/module-protocol-simple.c -> pipewire-1.2.2.tar.bz2/src/modules/module-protocol-simple.c Changed
131
 
1
@@ -56,6 +56,8 @@
2
  *               sink for each connected client.
3
  *  - `playback`: boolean if playback is enabled. This will create a playback or
4
  *               source stream for each connected client.
5
+ *  - `local.ifname = <str>`: interface name to use
6
+ *  - `local.ifaddress = <str>`: interface address to use
7
  *  - `server.address = `: an array of server addresses to listen on as
8
  *                            tcp:(<ip>:)<port>.
9
  *  - `capture.props`: optional properties for the capture stream
10
@@ -208,6 +210,8 @@
11
    struct pw_properties *capture_props;
12
    struct pw_properties *playback_props;
13
 
14
+   char *ifname;
15
+   char *ifaddress;
16
    bool capture;
17
    bool playback;
18
 
19
@@ -654,47 +658,16 @@
20
    return;
21
 }
22
 
23
-static uint16_t parse_port(const char *str, uint16_t def)
24
-{
25
-   uint32_t val;
26
-   if (spa_atou32(str, &val, 0) && val <= 65535u)
27
-       return val;
28
-   return def;
29
-}
30
-
31
-static int make_tcp_socket(struct server *server, const char *name)
32
+static int make_tcp_socket(struct server *server, const char *name, const char *ifname,
33
+       const char *ifaddress)
34
 {
35
    struct sockaddr_storage addr;
36
    int res, fd, on;
37
-   uint16_t port;
38
-   char *br = NULL, *col, *n;
39
    socklen_t len = 0;
40
 
41
-   n = strdupa(name);
42
-
43
-   col = strrchr(n, ':');
44
-   if (n0 == '') {
45
-       br = strchr(n, '');
46
-       if (br == NULL)
47
-           return -EINVAL;
48
-       n++;
49
-       *br = 0;
50
-   } else {
51
-   }
52
-   if (br && col && col < br)
53
-       col = NULL;
54
-
55
-   if (col) {
56
-       *col = '\0';
57
-       port = parse_port(col+1, DEFAULT_PORT);
58
-   } else {
59
-       port = parse_port(n, DEFAULT_PORT);
60
-       n = strdupa("0.0.0.0");
61
-   }
62
-
63
-   if ((res = pw_net_parse_address(n, port, &addr, &len)) < 0) {
64
-       pw_log_error("%p: can't parse address:%s port:%d: %s", server,
65
-               n, port, spa_strerror(res));
66
+   if ((res = pw_net_parse_address_port(name, ifaddress, DEFAULT_PORT, &addr, &len)) < 0) {
67
+       pw_log_error("%p: can't parse address %s: %s", server,
68
+               name, spa_strerror(res));
69
        goto error;
70
    }
71
 
72
@@ -703,7 +676,13 @@
73
        pw_log_error("%p: socket() failed: %m", server);
74
        goto error;
75
    }
76
-
77
+#ifdef SO_BINDTODEVICE
78
+   if (ifname && setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, ifname, strlen(ifname)) < 0) {
79
+       res = -errno;
80
+       pw_log_error("%p: setsockopt(SO_BINDTODEVICE) failed: %m", server);
81
+       goto error;
82
+   }
83
+#endif
84
    on = 1;
85
    if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const void *) &on, sizeof(on)) < 0)
86
        pw_log_warn("%p: setsockopt(): %m", server);
87
@@ -764,7 +743,7 @@
88
    spa_list_append(&impl->server_list, &server->link);
89
 
90
    if (spa_strstartswith(address, "tcp:")) {
91
-       fd = make_tcp_socket(server, address+4);
92
+       fd = make_tcp_socket(server, address+4, impl->ifname, impl->ifaddress);
93
    } else {
94
        pw_log_error("address %s does not start with tcp:", address);
95
        fd = -EINVAL;
96
@@ -799,6 +778,8 @@
97
    pw_properties_free(impl->capture_props);
98
    pw_properties_free(impl->playback_props);
99
    pw_properties_free(impl->props);
100
+   free(impl->ifname);
101
+   free(impl->ifaddress);
102
    free(impl);
103
 }
104
 
105
@@ -976,6 +957,11 @@
106
        pw_properties_setf(impl->playback_props, PW_KEY_NODE_RATE,
107
                "1/%u", impl->playback_info.rate);
108
 
109
+   str = pw_properties_get(impl->props, "local.ifname");
110
+   impl->ifname = str ? strdup(str) : NULL;
111
+   str = pw_properties_get(impl->props, "local.ifaddress");
112
+   impl->ifaddress = str ? strdup(str) : NULL;
113
+
114
    if ((str = pw_properties_get(impl->props, "server.address")) == NULL)
115
        str = DEFAULT_SERVER;
116
 
117
@@ -1056,9 +1042,10 @@
118
        uint16_t port = 0;
119
        bool ipv4;
120
 
121
-       if (pw_net_get_ip(&s->addr, ip, sizeof(ip), &ipv4, &port) >= 0)
122
-           fprintf(f, " \"%s%s%s:%d\"", ipv4 ? "" : "",
123
-                   ip, ipv4 ? "" : "", port);
124
+       if (pw_net_get_ip(&s->addr, ip, sizeof(ip), &ipv4, &port) < 0)
125
+           continue;
126
+
127
+       fprintf(f, " \"%s%s%s:%d\"", ipv4 ? "" : "", ip, ipv4 ? "" : "", port);
128
    }
129
    fprintf(f, " ");
130
    fclose(f);
131
pipewire-1.2.0.tar.gz/src/modules/module-raop-sink.c -> pipewire-1.2.2.tar.bz2/src/modules/module-raop-sink.c Changed
23
 
1
@@ -23,7 +23,6 @@
2
 #endif
3
 #include <openssl/rand.h>
4
 #include <openssl/rsa.h>
5
-#include <openssl/engine.h>
6
 #include <openssl/aes.h>
7
 #include <openssl/md5.h>
8
 #include <openssl/evp.h>
9
@@ -1643,10 +1642,10 @@
10
                impl->volume = volume;
11
 
12
                rtsp_send_volume(impl);
13
+               spa_pod_builder_prop(&b, SPA_PROP_softVolumes, 0);
14
+               spa_pod_builder_array(&b, sizeof(float), SPA_TYPE_Float,
15
+                       n_vols, soft_vols);
16
            }
17
-           spa_pod_builder_prop(&b, SPA_PROP_softVolumes, 0);
18
-           spa_pod_builder_array(&b, sizeof(float), SPA_TYPE_Float,
19
-                   n_vols, soft_vols);
20
            spa_pod_builder_raw_padded(&b, prop, SPA_POD_PROP_SIZE(prop));
21
            break;
22
        }
23
pipewire-1.2.0.tar.gz/src/modules/module-rtp/stream.c -> pipewire-1.2.2.tar.bz2/src/modules/module-rtp/stream.c Changed
31
 
1
@@ -452,7 +452,7 @@
2
    min_samples = msec_to_samples(impl, min_ptime);
3
    max_samples = msec_to_samples(impl, max_ptime);
4
 
5
-   float ptime = 0;
6
+   float ptime = 0.0f;
7
    if ((str = pw_properties_get(props, "rtp.ptime")) != NULL)
8
        if (!spa_atof(str, &ptime))
9
            ptime = 0.0f;
10
@@ -502,14 +502,16 @@
11
    impl->target_buffer = msec_to_samples(impl, latency_msec);
12
    impl->max_error = msec_to_samples(impl, ERROR_MSEC);
13
 
14
-   if (impl->target_buffer < ptime) {
15
-       pw_log_warn("sess.latency.msec cannot be lower than rtp.ptime");
16
+   if (impl->target_buffer < impl->psamples) {
17
+       pw_log_warn("sess.latency.msec %f cannot be lower than rtp.ptime %f",
18
+               latency_msec, ptime);
19
        impl->target_buffer = impl->psamples;
20
    }
21
 
22
    /* We're not expecting odd ptimes, so this modulo should be 0 */
23
-   if (fmodf(impl->target_buffer, ptime) != 0) {
24
-       pw_log_warn("sess.latency.msec should be an integer multiple of rtp.ptime");
25
+   if (fmodf(impl->target_buffer, impl->psamples) != 0) {
26
+       pw_log_warn("sess.latency.msec %f should be an integer multiple of rtp.ptime %f",
27
+               latency_msec, ptime);
28
        impl->target_buffer = (uint32_t)((impl->target_buffer / ptime) * impl->psamples);
29
    }
30
 
31
pipewire-1.2.0.tar.gz/src/modules/module-snapcast-discover.c -> pipewire-1.2.2.tar.bz2/src/modules/module-snapcast-discover.c Changed
113
 
1
@@ -35,6 +35,8 @@
2
 #include "module-protocol-pulse/format.h"
3
 #include "module-zeroconf-discover/avahi-poll.h"
4
 
5
+#include "network-utils.h"
6
+
7
 /** \page page_module_snapcast_discover Snapcast Discover
8
  *
9
  * Automatically creates a Snapcast sink device based on zeroconf
10
@@ -67,7 +69,7 @@
11
  *
12
  *\code{.unparsed}
13
  * context.modules = 
14
- * {   name = libpipewire-snapcast-discover
15
+ * {   name = libpipewire-module-snapcast-discover
16
  *     args = {
17
  *         stream.rules = 
18
  *             {   matches = 
19
@@ -147,6 +149,7 @@
20
    AvahiServiceBrowser *sink_browser;
21
 
22
    struct spa_list tunnel_list;
23
+   uint32_t id;
24
 };
25
 
26
 struct tunnel_info {
27
@@ -285,6 +288,7 @@
28
    int res;
29
    socklen_t len;
30
    char *str;
31
+   struct impl *impl = t->impl;
32
 
33
    len = sizeof(res);
34
    if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &res, &len) < 0) {
35
@@ -297,22 +301,23 @@
36
    t->connecting = false;
37
    pw_log_info("connected");
38
 
39
-   str = "{\"id\":8,\"jsonrpc\": \"2.0\",\"method\":\"Server.GetRPCVersion\"}\r\n";
40
+   str = spa_aprintf("{\"id\":%u,\"jsonrpc\": \"2.0\",\"method\":\"Server.GetRPCVersion\"}\r\n",
41
+           impl->id++);
42
    res = write(t->source->fd, str, strlen(str));
43
    pw_log_info("wrote %s: %d", str, res);
44
+   free(str);
45
 
46
-   str = spa_aprintf("{\"id\":4,\"jsonrpc\":\"2.0\",\"method\":\"Stream.RemoveStream\","
47
-           "\"params\":{\"id\":\"%s\"}}\r\n", t->stream_name);
48
+   str = spa_aprintf("{\"id\":%u,\"jsonrpc\":\"2.0\",\"method\":\"Stream.RemoveStream\","
49
+           "\"params\":{\"id\":\"%s\"}}\r\n", impl->id++, t->stream_name);
50
    res = write(t->source->fd, str, strlen(str));
51
    pw_log_info("wrote %s: %d", str, res);
52
    free(str);
53
 
54
-   str = spa_aprintf("{\"id\":4,\"jsonrpc\":\"2.0\",\"method\":\"Stream.AddStream\""
55
+   str = spa_aprintf("{\"id\":%u,\"jsonrpc\":\"2.0\",\"method\":\"Stream.AddStream\""
56
        ",\"params\":{\"streamUri\":\"tcp://%s?name=%s&mode=client&"
57
-       "sampleformat=%d:%d:%d&codec=pcm&chunk_ms=20\"}}\r\n",
58
+       "sampleformat=%d:%d:%d&codec=pcm&chunk_ms=20\"}}\r\n", impl->id++,
59
        t->server_address, t->stream_name, t->audio_info.rate,
60
        get_bps(t->audio_info.format), t->audio_info.channels);
61
-
62
    res = write(t->source->fd, str, strlen(str));
63
    pw_log_info("wrote %s: %d", str, res);
64
    free(str);
65
@@ -327,7 +332,6 @@
66
 
67
    while (true) {
68
        res = read(t->source->fd, buffer, sizeof(buffer));
69
-       pw_log_info("%d", res);
70
        if (res == 0)
71
            return -EPIPE;
72
        if (res < 0) {
73
@@ -340,7 +344,7 @@
74
        }
75
    }
76
 
77
-   pw_log_info("%s", buffer);
78
+   pw_log_info("received: %s", buffer);
79
    return 0;
80
 }
81
 
82
@@ -465,9 +469,9 @@
83
    while (spa_json_get_string(&it1, v, sizeof(v)) > 0) {
84
        t->server_address = strdup(v);
85
        snapcast_connect(t);
86
-       break;
87
+       return 0;
88
    }
89
-   return 0;
90
+   return -ENOENT;
91
 }
92
 
93
 static inline uint32_t format_from_name(const char *name, size_t len)
94
@@ -688,6 +692,7 @@
95
    ifreq.ifr_ifindex = interface;
96
    ioctl(fd, SIOCGIFNAME, &ifreq, sizeof(ifreq));
97
    pw_properties_setf(props, "snapcast.ifname", "%s", ifreq.ifr_name);
98
+   pw_properties_setf(props, "local.ifname", "%s", ifreq.ifr_name);
99
 
100
    struct ifaddrs *if_addr, *ifp;
101
    if (getifaddrs(&if_addr) < 0)
102
@@ -711,6 +716,10 @@
103
                    family == AF_INET ? "" : "",
104
                    hbuf,
105
                    family == AF_INET ? "" : "");
106
+           pw_properties_setf(props, "local.ifaddress", "%s%s%s",
107
+                   family == AF_INET ? "" : "",
108
+                   hbuf,
109
+                   family == AF_INET ? "" : "");
110
        } else {
111
            pw_log_warn("error: %m %d %s", res, gai_strerror(res));
112
        }
113
pipewire-1.2.0.tar.gz/src/modules/network-utils.h -> pipewire-1.2.2.tar.bz2/src/modules/network-utils.h Changed
64
 
1
@@ -38,6 +38,44 @@
2
    return 0;
3
 }
4
 
5
+static inline uint16_t pw_net_parse_port(const char *str, uint16_t def)
6
+{
7
+   uint32_t val;
8
+   if (spa_atou32(str, &val, 0) && val <= 65535u)
9
+       return val;
10
+   return def;
11
+}
12
+
13
+static inline int pw_net_parse_address_port(const char *address,
14
+       const char *default_address, uint16_t default_port,
15
+       struct sockaddr_storage *addr, socklen_t *len)
16
+{
17
+   uint16_t port;
18
+   char *br = NULL, *col, *n;
19
+
20
+   n = strdupa(address);
21
+
22
+   col = strrchr(n, ':');
23
+   if (n0 == '') {
24
+       br = strchr(n, '');
25
+       if (br == NULL)
26
+           return -EINVAL;
27
+       n++;
28
+       *br = 0;
29
+   }
30
+   if (br && col && col < br)
31
+       col = NULL;
32
+
33
+   if (col) {
34
+       *col = '\0';
35
+       port = pw_net_parse_port(col+1, default_port);
36
+   } else {
37
+       port = pw_net_parse_port(n, default_port);
38
+       n = strdupa(default_address ? default_address : "0.0.0.0");
39
+   }
40
+   return pw_net_parse_address(n, port, addr, len);
41
+}
42
+
43
 static inline int pw_net_get_ip(const struct sockaddr_storage *sa, char *ip, size_t len, bool *ip4, uint16_t *port)
44
 {
45
    if (sa->ss_family == AF_INET) {
46
@@ -75,4 +113,17 @@
47
    return ip;
48
 }
49
 
50
+static inline bool pw_net_addr_is_any(struct sockaddr_storage *addr)
51
+{
52
+   if (addr->ss_family == AF_INET) {
53
+       struct sockaddr_in *sa = (struct sockaddr_in*)addr;
54
+       return sa->sin_addr.s_addr == INADDR_ANY;
55
+   } else if (addr->ss_family == AF_INET6) {
56
+       struct sockaddr_in6 *sa = (struct sockaddr_in6*)addr;
57
+       return memcmp(&sa->sin6_addr, &in6addr_any, sizeof(sa->sin6_addr));
58
+   }
59
+   return false;
60
+}
61
+
62
+
63
 #endif /* NETWORK_UTILS_H */
64
pipewire-1.2.0.tar.gz/src/pipewire/conf.c -> pipewire-1.2.2.tar.bz2/src/pipewire/conf.c Changed
154
 
1
@@ -945,9 +945,10 @@
2
 
3
    n = realloc(strv, sizeof(char*) * (len + 2));
4
    if (n == NULL) {
5
-       free(strv);
6
+       pw_free_strv(strv);
7
        return NULL;
8
    }
9
+
10
    strv = n;
11
 
12
    memmove(strv+pos+1, strv+pos, sizeof(char*) * (len+1-pos));
13
@@ -955,15 +956,16 @@
14
    return strv;
15
 }
16
 
17
-static int do_exec(struct pw_context *context, const char *path, const char *args)
18
+static int do_exec(struct pw_context *context, char *const *argv)
19
 {
20
    int pid, res;
21
 
22
    pid = fork();
23
 
24
    if (pid == 0) {
25
-       char **arg;
26
-       int n_args;
27
+       char buf1024;
28
+       char *const *p;
29
+       struct spa_strbuf s;
30
 
31
        /* Double fork to avoid zombies; we don't want to set SIGCHLD handler */
32
        pid = fork();
33
@@ -975,23 +977,16 @@
34
            exit(0);
35
        }
36
 
37
-       arg = pw_strv_parse(args, strlen(args), INT_MAX, &n_args);
38
-       if (arg == NULL) {
39
-           pw_log_error("error parsing arguments: %m");
40
-           goto done;
41
-       }
42
-       arg = pw_strv_insert_at(arg, n_args, 0, path);
43
-       if (arg == NULL) {
44
-           pw_log_error("error constructing arguments: %m");
45
-           goto done;
46
-       }
47
-       pw_log_info("exec %s '%s'", path, args);
48
-       res = execvp(path, arg);
49
-       pw_free_strv(arg);
50
+       spa_strbuf_init(&s, buf, sizeof(buf));
51
+       for (p = argv; *p; ++p)
52
+           spa_strbuf_append(&s, " '%s'", *p);
53
+
54
+       pw_log_info("exec%s", s.buffer);
55
+       res = execvp(argv0, argv);
56
 
57
        if (res == -1) {
58
            res = -errno;
59
-           pw_log_error("execvp error '%s': %m", path);
60
+           pw_log_error("execvp error '%s': %m", argv0);
61
        }
62
 done:
63
        exit(1);
64
@@ -1016,6 +1011,36 @@
65
  *   }
66
  * 
67
  */
68
+
69
+static char **make_exec_argv(const char *path, const char *value, int len)
70
+{
71
+   char **argv = NULL;
72
+   int n_args;
73
+
74
+   if (spa_json_is_container(value, len)) {
75
+       if (!spa_json_is_array(value, len)) {
76
+           errno = EINVAL;
77
+           return NULL;
78
+       }
79
+       argv = pw_strv_parse(value, len, INT_MAX, &n_args);
80
+   } else {
81
+       spa_autofree char *s = calloc(1, len + 1);
82
+       if (!s)
83
+           return NULL;
84
+
85
+       if (spa_json_parse_stringn(value, len, s, len + 1) < 0) {
86
+           errno = EINVAL;
87
+           return NULL;
88
+       }
89
+       argv = pw_split_strv(s, " \t", INT_MAX, &n_args);
90
+   }
91
+
92
+   if (!argv)
93
+       return NULL;
94
+
95
+   return pw_strv_insert_at(argv, n_args, 0, path);
96
+}
97
+
98
 static int parse_exec(void *user_data, const char *location,
99
        const char *section, const char *str, size_t len)
100
 {
101
@@ -1034,7 +1059,9 @@
102
    }
103
 
104
    while ((r = spa_json_enter_object(&it1, &it2)) > 0) {
105
-       char *path = NULL, *args = NULL;
106
+       char *path = NULL;
107
+       const char *args_val = "";
108
+       int args_len = 2;
109
        bool have_match = true;
110
 
111
        while (spa_json_get_string(&it2, key, sizeof(key)) > 0) {
112
@@ -1053,13 +1080,13 @@
113
            } else if (spa_streq(key, "args")) {
114
                if (spa_json_is_container(val, l))
115
                    l = spa_json_container_len(&it2, val, l);
116
-               args = (char*)val;
117
-               spa_json_parse_stringn(val, l, args, l+1);
118
+               args_val = val;
119
+               args_len = l;
120
            } else if (spa_streq(key, "condition")) {
121
                if (!spa_json_is_array(val, l)) {
122
                    pw_log_warn("expected array for condition in '%.*s'",
123
                            (int)len, str);
124
-                   break;
125
+                   goto next;
126
                }
127
                spa_json_enter(&it2, &it3);
128
                have_match = find_match(&it3, &context->properties->dict, true);
129
@@ -1072,11 +1099,23 @@
130
            continue;
131
 
132
        if (path != NULL) {
133
-           res = do_exec(context, path, args);
134
+           char **argv = make_exec_argv(path, args_val, args_len);
135
+
136
+           if (!argv) {
137
+               pw_log_warn("expected array or string for args in '%.*s'",
138
+                       (int)len, str);
139
+               goto next;
140
+           }
141
+
142
+           res = do_exec(context, argv);
143
+           pw_free_strv(argv);
144
            if (res < 0)
145
                break;
146
            d->count++;
147
        }
148
+
149
+   next:
150
+       continue;
151
    }
152
    if (r < 0)
153
        pw_log_warn("malformed object array in '%.*s'", (int)len, str);
154
pipewire-1.2.0.tar.gz/src/pipewire/context.c -> pipewire-1.2.2.tar.bz2/src/pipewire/context.c Changed
127
 
1
@@ -1163,13 +1163,14 @@
2
  * This ensures that we only activate the paths from the runnable nodes to the
3
  * driver nodes and leave the other nodes idle.
4
  */
5
-static int collect_nodes(struct pw_context *context, struct pw_impl_node *node, struct spa_list *collect,
6
-       char **sync)
7
+static int collect_nodes(struct pw_context *context, struct pw_impl_node *node, struct spa_list *collect)
8
 {
9
    struct spa_list queue;
10
    struct pw_impl_node *n, *t;
11
    struct pw_impl_port *p;
12
    struct pw_impl_link *l;
13
+   uint32_t n_sync;
14
+   char *syncMAX_SYNC+1;
15
 
16
    pw_log_debug("node %p: '%s'", node, node->name);
17
 
18
@@ -1178,20 +1179,30 @@
19
    spa_list_append(&queue, &node->sort_link);
20
    node->visited = true;
21
 
22
+   n_sync = 0;
23
+   sync0 = NULL;
24
+
25
    /* now follow all the links from the nodes in the queue
26
     * and add the peers to the queue. */
27
    spa_list_consume(n, &queue, sort_link) {
28
        spa_list_remove(&n->sort_link);
29
        spa_list_append(collect, &n->sort_link);
30
 
31
-       pw_log_debug(" next node %p: '%s' runnable:%u", n, n->name, n->runnable);
32
+       pw_log_debug(" next node %p: '%s' runnable:%u active:%d",
33
+               n, n->name, n->runnable, n->active);
34
 
35
        if (!n->active)
36
            continue;
37
 
38
-       if (sync0 != NULL) {
39
-           if (pw_strv_find_common(n->sync_groups, sync) < 0)
40
-               continue;
41
+       if (n->sync) {
42
+           for (uint32_t i = 0; n->sync_groupsi; i++) {
43
+               if (n_sync >= MAX_SYNC)
44
+                   break;
45
+               if (pw_strv_find(sync, n->sync_groupsi) >= 0)
46
+                   continue;
47
+               syncn_sync++ = n->sync_groupsi;
48
+               syncn_sync = NULL;
49
+           }
50
        }
51
 
52
        spa_list_for_each(p, &n->input_ports, link) {
53
@@ -1242,6 +1253,8 @@
54
            spa_list_for_each(t, &context->node_list, link) {
55
                if (t->exported || !t->active || t->visited)
56
                    continue;
57
+               /* the other node will be scheduled with this one if it's in
58
+                * the same group or link group */
59
                if (pw_strv_find_common(t->groups, n->groups) < 0 &&
60
                    pw_strv_find_common(t->link_groups, n->link_groups) < 0 &&
61
                    pw_strv_find_common(t->sync_groups, sync) < 0)
62
@@ -1253,7 +1266,8 @@
63
                spa_list_append(&queue, &t->sort_link);
64
            }
65
        }
66
-       pw_log_debug(" next node %p: '%s' runnable:%u", n, n->name, n->runnable);
67
+       pw_log_debug(" next node %p: '%s' runnable:%u %p %p %p", n, n->name, n->runnable,
68
+               n->groups, n->link_groups, sync);
69
    }
70
    spa_list_for_each(n, collect, sort_link)
71
        if (!n->driving && n->runnable) {
72
@@ -1497,10 +1511,9 @@
73
    struct pw_impl_node *n, *s, *target, *fallback;
74
    const uint32_t *rates;
75
    uint32_t max_quantum, min_quantum, def_quantum, rate_quantum, floor_quantum, ceil_quantum;
76
-   uint32_t n_rates, def_rate, n_sync;
77
+   uint32_t n_rates, def_rate;
78
    bool freewheel, global_force_rate, global_force_quantum, transport_start;
79
    struct spa_list collect;
80
-   char *syncMAX_SYNC+1;
81
 
82
    pw_log_info("%p: busy:%d reason:%s", context, impl->recalc, reason);
83
 
84
@@ -1514,23 +1527,11 @@
85
    freewheel = false;
86
    transport_start = false;
87
 
88
-   /* clean up the flags first and collect sync */
89
-   n_sync = 0;
90
-   sync0 = NULL;
91
+   /* clean up the flags first */
92
    spa_list_for_each(n, &context->node_list, link) {
93
        n->visited = false;
94
        n->checked = 0;
95
        n->runnable = n->always_process && n->active;
96
-       if (n->sync) {
97
-           for (uint32_t i = 0; n->sync_groupsi; i++) {
98
-               if (n_sync >= MAX_SYNC)
99
-                   break;
100
-               if (pw_strv_find(sync, n->sync_groupsi) >= 0)
101
-                   continue;
102
-               syncn_sync++ = n->sync_groupsi;
103
-               syncn_sync = NULL;
104
-           }
105
-       }
106
    }
107
 
108
    get_quantums(context, &def_quantum, &min_quantum, &max_quantum, &rate_quantum,
109
@@ -1551,7 +1552,7 @@
110
 
111
        if (!n->visited) {
112
            spa_list_init(&collect);
113
-           collect_nodes(context, n, &collect, sync);
114
+           collect_nodes(context, n, &collect);
115
            move_to_driver(context, &collect, n);
116
        }
117
        /* from now on we are only interested in active driving nodes
118
@@ -1605,7 +1606,7 @@
119
 
120
        /* collect all nodes in this group */
121
        spa_list_init(&collect);
122
-       collect_nodes(context, n, &collect, sync);
123
+       collect_nodes(context, n, &collect);
124
 
125
        driver = NULL;
126
        spa_list_for_each(t, &collect, sort_link) {
127
pipewire-1.2.0.tar.gz/src/pipewire/impl-link.c -> pipewire-1.2.2.tar.bz2/src/pipewire/impl-link.c Changed
27
 
1
@@ -754,9 +754,11 @@
2
    pw_impl_port_recalc_latency(this->input);
3
    pw_impl_port_recalc_tag(this->input);
4
 
5
-   if ((res = pw_impl_port_use_buffers(port, mix, 0, NULL, 0)) < 0) {
6
+   if ((res = port_set_io(this, this->input, SPA_IO_Buffers, NULL, 0, mix)) < 0)
7
+       pw_log_warn("%p: port %p set_io error %s", this, port, spa_strerror(res));
8
+   if ((res = pw_impl_port_use_buffers(port, mix, 0, NULL, 0)) < 0)
9
        pw_log_warn("%p: port %p clear error %s", this, port, spa_strerror(res));
10
-   }
11
+
12
    pw_impl_port_release_mix(port, mix);
13
 
14
    pw_work_queue_cancel(impl->work, &this->input_link, SPA_ID_INVALID);
15
@@ -1375,8 +1377,9 @@
16
    this->name = spa_aprintf("%d.%d.%d -> %d.%d.%d",
17
            output_node->info.id, output->port_id, this->rt.out_mix.port.port_id,
18
            input_node->info.id, input->port_id, this->rt.in_mix.port.port_id);
19
-   pw_log_info("(%s) (%s) -> (%s) async:%04x:%04x:%d", this->name, output_node->name,
20
-           input_node->name, output->flags, input->flags, impl->async);
21
+   pw_log_info("(%s) (%s) -> (%s) async:%d:%04x:%04x:%d", this->name, output_node->name,
22
+           input_node->name, output_node->driving,
23
+           output->flags, input->flags, impl->async);
24
 
25
    pw_impl_port_emit_link_added(output, this);
26
    pw_impl_port_emit_link_added(input, this);
27
pipewire-1.2.0.tar.gz/src/pipewire/impl-node.c -> pipewire-1.2.2.tar.bz2/src/pipewire/impl-node.c Changed
201
 
1
@@ -11,6 +11,8 @@
2
 #include <malloc.h>
3
 #include <limits.h>
4
 
5
+#include "config.h"
6
+
7
 #include <spa/support/system.h>
8
 #include <spa/pod/parser.h>
9
 #include <spa/pod/filter.h>
10
@@ -112,13 +114,16 @@
11
 {
12
    struct pw_node_activation_state *state = &t->activation->state0;
13
    if (!t->active) {
14
-       if ((!node->async || node->driving) && !node->exported) {
15
-           SPA_ATOMIC_INC(state->required);
16
-           SPA_ATOMIC_INC(state->pending);
17
+       if (!node->async) {
18
+           if (!node->exported) {
19
+               SPA_ATOMIC_INC(state->required);
20
+               SPA_ATOMIC_INC(state->pending);
21
+           }
22
        }
23
        t->active = true;
24
-       pw_log_debug("%p: target state:%p id:%d pending:%d/%d",
25
-               node, state, t->id, state->pending, state->required);
26
+       pw_log_debug("%p: target state:%p id:%d pending:%d/%d %d:%d:%d",
27
+               node, state, t->id, state->pending, state->required,
28
+               node->async, node->driving, node->exported);
29
    }
30
 }
31
 
32
@@ -126,7 +131,7 @@
33
 {
34
    if (t->active) {
35
        struct pw_node_activation_state *state = &t->activation->state0;
36
-       if (!node->async || node->driving) {
37
+       if (!node->async) {
38
            /* the driver copies the required to the pending state
39
             * so first try to resume the node and then decrement the
40
             * required state. This way we either resume with the old value
41
@@ -137,8 +142,9 @@
42
                SPA_ATOMIC_DEC(state->required);
43
        }
44
        t->active = false;
45
-       pw_log_debug("%p: target state:%p id:%d pending:%d/%d trigger:%"PRIu64,
46
-               node, state, t->id, state->pending, state->required, trigger);
47
+       pw_log_debug("%p: target state:%p id:%d pending:%d/%d %d:%d:%d trigger:%"PRIu64,
48
+               node, state, t->id, state->pending, state->required,
49
+               node->async, node->driving, node->exported, trigger);
50
    }
51
 }
52
 
53
@@ -173,7 +179,8 @@
54
    uint64_t dummy;
55
    int res;
56
 
57
-   pw_log_trace("%p: prepare %d remote:%d", this, this->rt.prepared, this->remote);
58
+   pw_log_trace("%p: prepare %d remote:%d exported:%d", this, this->rt.prepared,
59
+           this->remote, this->exported);
60
 
61
    if (this->rt.prepared)
62
        return 0;
63
@@ -212,20 +219,21 @@
64
    int old_state;
65
    uint64_t trigger = 0;
66
 
67
-   pw_log_trace("%p: unprepare %d remote:%d", this, this->rt.prepared, this->remote);
68
+   pw_log_trace("%p: unprepare %d remote:%d exported:%d", this, this->rt.prepared,
69
+           this->remote, this->exported);
70
 
71
-   if (!this->rt.prepared)
72
-       return 0;
73
-
74
-   if (!this->remote || this->rt.target.activation->client_version < 1) {
75
+   if (!this->exported) {
76
        /* We mark ourself as finished now, this will avoid going further into the process loop
77
         * in case our fd was ready (removing ourselfs from the loop should avoid that as well).
78
         * If we were supposed to be scheduled make sure we continue the graph for the peers we
79
         * were supposed to trigger */
80
        old_state = SPA_ATOMIC_XCHG(this->rt.target.activation->status, PW_NODE_ACTIVATION_INACTIVE);
81
-       if (old_state != PW_NODE_ACTIVATION_FINISHED)
82
+       if (PW_NODE_ACTIVATION_PENDING_TRIGGER(old_state))
83
            trigger = get_time_ns(this->rt.target.system);
84
    }
85
+   if (!this->rt.prepared)
86
+       return 0;
87
+
88
    if (!this->remote)
89
        spa_loop_remove_source(loop, &this->source);
90
 
91
@@ -857,7 +865,7 @@
92
        if (node->rt.prepared) {
93
            int old_state = SPA_ATOMIC_LOAD(node->rt.target.activation->status);
94
            uint64_t trigger = 0;
95
-           if (old_state != PW_NODE_ACTIVATION_FINISHED)
96
+           if (PW_NODE_ACTIVATION_PENDING_TRIGGER(old_state))
97
                trigger = get_time_ns(node->rt.target.system);
98
            deactivate_target(node, t, trigger);
99
        }
100
@@ -1009,17 +1017,7 @@
101
 
102
    remove_segment_owner(old, node->info.id);
103
 
104
-   was_driving = node->driving;
105
-
106
-   /* When a node was driver (and is waiting for all nodes to complete
107
-    * the Start command) cancel the pending state and let the new driver
108
-    * calculate a new state so that the Start command is sent to the
109
-    * node */
110
-   if (was_driving && !node->driving)
111
-       impl->pending_state = node->info.state;
112
-
113
-   pw_log_debug("%p: driver %p driving:%u", node,
114
-       driver, node->driving);
115
+   pw_log_debug("%p: driver %p driving:%u", node, driver, node->driving);
116
    pw_log_info("(%s-%u) -> change driver (%s-%d -> %s-%d)",
117
            node->name, node->info.id,
118
            old->name, old->info.id, driver->name, driver->info.id);
119
@@ -1036,11 +1034,20 @@
120
     * scheduled so it won't trigger yet */
121
    node->to_driver_peer = pw_node_peer_ref(node, driver);
122
 
123
+   was_driving = node->driving;
124
+
125
    /* then set the new driver node activation */
126
    pw_impl_node_set_io(node, SPA_IO_Position,
127
            &driver->rt.target.activation->position,
128
            sizeof(struct spa_io_position));
129
 
130
+   /* When a node was driver (and is waiting for all nodes to complete
131
+    * the Start command) cancel the pending state and let the new driver
132
+    * calculate a new state so that the Start command is sent to the
133
+    * node */
134
+   if (was_driving && !node->driving)
135
+       impl->pending_state = node->info.state;
136
+
137
    /* and then make the driver trigger the node */
138
    node->from_driver_peer = pw_node_peer_ref(driver, node);
139
 
140
@@ -1196,6 +1203,7 @@
141
        recalc_reason = "transport changed";
142
    }
143
    async = pw_properties_get_bool(node->properties, PW_KEY_NODE_ASYNC, false);
144
+   async &= !node->driver;
145
    if (async != node->async) {
146
        pw_log_info("%p: async %d -> %d", node, node->async, async);
147
        node->async = async;
148
@@ -1996,10 +2004,14 @@
149
    struct pw_impl_node *node = data;
150
    struct pw_impl_node *driver = node->driver_node;
151
    struct pw_node_activation *a = node->rt.target.activation;
152
+   struct pw_node_activation_state *state = &a->state0;
153
    struct spa_system *data_system = node->rt.target.system;
154
    struct pw_node_target *t, *reposition_target = NULL;;
155
    struct pw_impl_port *p;
156
-   uint64_t nsec;
157
+   struct spa_io_clock *cl = &node->rt.position->clock;
158
+   int sync_type, all_ready, update_sync, target_sync, old_status;
159
+   uint32_t owner2, reposition_owner, pending;
160
+   uint64_t min_timeout = UINT64_MAX, nsec;
161
 
162
    pw_log_trace_fp("%p: ready driver:%d exported:%d %p status:%d prepared:%d", node,
163
            node->driver, node->exported, driver, status, node->rt.prepared);
164
@@ -2012,129 +2024,118 @@
165
        pw_log_info("%p: ready non-active node %s in state %d", node, node->name, node->info.state);
166
        return -EIO;
167
    }
168
+   if (SPA_UNLIKELY(node != driver)) {
169
+       pw_log_warn("%p: ready non-driver node %s", node, node->name);
170
+       return -EIO;
171
+   }
172
 
173
    nsec = get_time_ns(data_system);
174
 
175
-   if (SPA_LIKELY(node == driver)) {
176
-       struct pw_node_activation_state *state = &a->state0;
177
-       struct spa_io_clock *cl = &node->rt.position->clock;
178
-       int sync_type, all_ready, update_sync, target_sync;
179
-       uint32_t owner2, reposition_owner;
180
-       uint64_t min_timeout = UINT64_MAX;
181
-       int32_t pending;
182
-       int old_status;
183
-
184
-       if (SPA_UNLIKELY((pending = pw_node_activation_state_xchg(state)) > 0)) {
185
-           pw_impl_node_rt_emit_incomplete(driver);
186
-           old_status = SPA_ATOMIC_LOAD(a->status);
187
-           if (old_status != PW_NODE_ACTIVATION_FINISHED) {
188
-               SPA_ATOMIC_STORE(a->status, PW_NODE_ACTIVATION_TRIGGERED);
189
-               process_node(node, nsec);
190
-               debug_xrun_graph(node, nsec);
191
-           }
192
+   if (SPA_UNLIKELY((pending = pw_node_activation_state_xchg(state)) > 0)) {
193
+       pw_impl_node_rt_emit_incomplete(driver);
194
+       old_status = SPA_ATOMIC_LOAD(a->status);
195
+       if (old_status != PW_NODE_ACTIVATION_FINISHED) {
196
+           SPA_ATOMIC_STORE(a->status, PW_NODE_ACTIVATION_TRIGGERED);
197
+           SPA_FLAG_SET(cl->flags, SPA_IO_CLOCK_FLAG_XRUN_RECOVER);
198
+           process_node(node, nsec);
199
+           SPA_FLAG_CLEAR(cl->flags, SPA_IO_CLOCK_FLAG_XRUN_RECOVER);
200
+           debug_xrun_graph(node, nsec);
201
pipewire-1.2.0.tar.gz/src/pipewire/impl-port.c -> pipewire-1.2.2.tar.bz2/src/pipewire/impl-port.c Changed
126
 
1
@@ -345,7 +345,6 @@
2
 int pw_impl_port_init_mix(struct pw_impl_port *port, struct pw_impl_port_mix *mix)
3
 {
4
    uint32_t port_id;
5
-   struct pw_impl_node *node = port->node;
6
    int res = 0;
7
 
8
    port_id = pw_map_insert_new(&port->mix_port_map, mix);
9
@@ -389,13 +388,6 @@
10
            port->n_mix, port->port_id, mix->port.port_id,
11
            mix->id, mix->peer_id, mix->io, spa_strerror(res));
12
 
13
-   if (port->n_mix == 1) {
14
-       pw_log_debug("%p: setting port io", port);
15
-       spa_node_port_set_io(node->node,
16
-                    port->direction, port->port_id,
17
-                    SPA_IO_Buffers,
18
-                    &port->rt.io, sizeof(port->rt.io));
19
-   }
20
    return res;
21
 
22
 error_remove_port:
23
@@ -410,7 +402,6 @@
24
 {
25
    int res = 0;
26
    uint32_t port_id = mix->port.port_id;
27
-   struct pw_impl_node *node = port->node;
28
 
29
    pw_map_remove(&port->mix_port_map, port_id);
30
    spa_list_remove(&mix->link);
31
@@ -430,11 +421,6 @@
32
 
33
    if (port->n_mix == 0) {
34
        pw_log_debug("%p: clearing port io", port);
35
-       spa_node_port_set_io(node->node,
36
-                    port->direction, port->port_id,
37
-                    SPA_IO_Buffers,
38
-                    NULL, 0);
39
-
40
        pw_impl_port_set_param(port, SPA_PARAM_Format, 0, NULL);
41
    }
42
    return res;
43
@@ -830,11 +816,6 @@
44
        spa_list_for_each(mix, &port->mix_list, link)
45
            spa_node_add_port(port->mix, mix->port.direction, mix->port.port_id, NULL);
46
 
47
-       spa_node_port_set_io(port->mix,
48
-                pw_direction_reverse(port->direction), 0,
49
-                SPA_IO_Buffers,
50
-                &port->rt.io, sizeof(port->rt.io));
51
-
52
        if (port->node && port->node->rt.position) {
53
            spa_node_set_io(port->mix,
54
                     SPA_IO_Position,
55
@@ -1836,6 +1817,13 @@
56
 
57
    pw_log_debug("%p: %d set param %d %p", port, port->state, id, param);
58
 
59
+   if (id == SPA_PARAM_Format) {
60
+       pw_loop_invoke(node->data_loop, do_remove_port, SPA_ID_INVALID, NULL, 0, true, port);
61
+       spa_node_port_set_io(node->node,
62
+                    port->direction, port->port_id,
63
+                    SPA_IO_Buffers, NULL, 0);
64
+   }
65
+
66
    /* set parameter on node */
67
    res = spa_node_port_set_param(node->node,
68
            port->direction, port->port_id,
69
@@ -1867,9 +1855,6 @@
70
    }
71
 
72
    if (id == SPA_PARAM_Format) {
73
-       pw_log_debug("%p: %d %p %d", port, port->state, param, res);
74
-
75
-       pw_loop_invoke(node->data_loop, do_remove_port, SPA_ID_INVALID, NULL, 0, true, port);
76
        /* setting the format always destroys the negotiated buffers */
77
        if (port->direction == PW_DIRECTION_OUTPUT) {
78
            struct pw_impl_link *l;
79
@@ -1915,6 +1900,10 @@
80
                port, port->direction, port->port_id, n_buffers, node->node,
81
                alloc_flags);
82
 
83
+       spa_node_port_set_io(node->node,
84
+                    port->direction, port->port_id,
85
+                    SPA_IO_Buffers, NULL, 0);
86
+
87
        pw_loop_invoke(node->data_loop, do_remove_port, SPA_ID_INVALID, NULL, 0, true, port);
88
 
89
        pw_buffers_clear(&port->mix_buffers);
90
@@ -1946,8 +1935,17 @@
91
                 pw_direction_reverse(port->direction), 0,
92
                 0, buffers, n_buffers);
93
    }
94
-   if (n_buffers > 0)
95
+   if (n_buffers > 0) {
96
+       spa_node_port_set_io(node->node,
97
+                    port->direction, port->port_id,
98
+                    SPA_IO_Buffers,
99
+                    &port->rt.io, sizeof(port->rt.io));
100
+       spa_node_port_set_io(port->mix,
101
+                pw_direction_reverse(port->direction), 0,
102
+                SPA_IO_Buffers,
103
+                &port->rt.io, sizeof(port->rt.io));
104
        pw_loop_invoke(node->data_loop, do_add_port, SPA_ID_INVALID, NULL, 0, false, port);
105
+   }
106
    return res;
107
 }
108
 
109
@@ -1972,11 +1970,15 @@
110
        mix->have_buffers = false;
111
        if (port->n_mix == 1)
112
            pw_impl_port_update_state(port, PW_IMPL_PORT_STATE_READY, 0, NULL);
113
+
114
+       spa_node_port_set_io(port->mix,
115
+               mix->port.direction, mix->port.port_id,
116
+               SPA_IO_Buffers, NULL, 0);
117
    }
118
 
119
    /* first negotiate with the node, this makes it possible to let the
120
     * node allocate buffer memory if needed */
121
-   if (port->state == PW_IMPL_PORT_STATE_READY) {
122
+   if (port->state == PW_IMPL_PORT_STATE_READY && !port->destroying) {
123
        res = negotiate_mixer_buffers(port, flags, buffers, n_buffers);
124
 
125
        if (res < 0) {
126
pipewire-1.2.0.tar.gz/src/pipewire/private.h -> pipewire-1.2.2.tar.bz2/src/pipewire/private.h Changed
10
 
1
@@ -563,6 +563,8 @@
2
  */
3
 #define PW_VERSION_NODE_ACTIVATION 1
4
 
5
+#define PW_NODE_ACTIVATION_PENDING_TRIGGER(status) ((status) <= PW_NODE_ACTIVATION_AWAKE)
6
+
7
 /* nodes start as INACTIVE, when they are ready to be scheduled, they add their
8
  * fd to the loop and change status to FINISHED. When the node shuts down, the
9
  * status is set back to INACTIVE.
10
pipewire-1.2.0.tar.gz/src/pipewire/thread.c -> pipewire-1.2.2.tar.bz2/src/pipewire/thread.c Changed
19
 
1
@@ -90,10 +90,16 @@
2
    pthread_attr_t *attr = NULL, attributes;
3
    const char *str;
4
    int err;
5
+   int (*create_func)(pthread_t *, const pthread_attr_t *attr, void *(*start)(void*), void *) = NULL;
6
 
7
    attr = pw_thread_fill_attr(props, &attributes);
8
 
9
-   err = pthread_create(&pt, attr, start, arg);
10
+   if (props == NULL ||
11
+      (str = spa_dict_lookup(props, SPA_KEY_THREAD_CREATOR)) == NULL ||
12
+      sscanf(str, "pointer:%p", &create_func) != 1)
13
+       create_func = pthread_create;
14
+
15
+   err = create_func(&pt, attr, start, arg);
16
 
17
    if (attr)
18
        pthread_attr_destroy(attr);
19