Overview

Request 5855 (accepted)

New release

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

pipewire-aptx.changes Changed
x
 
1
@@ -1,4 +1,9 @@
2
 -------------------------------------------------------------------
3
+Wed Oct 18 08:54:11 UTC 2023 - Bjørn Lie <zaitor@opensuse.org>
4
+
5
+- Update to version 0.3.82
6
+
7
+-------------------------------------------------------------------
8
 Sun Oct  8 16:26:36 UTC 2023 - Bjørn Lie <zaitor@opensuse.org>
9
 
10
 - Update to version 0.3.81
11
pipewire-aptx.spec Changed
10
 
1
@@ -7,7 +7,7 @@
2
 %define soversion 0_2
3
 
4
 Name:           pipewire-aptx
5
-Version:        0.3.81
6
+Version:        0.3.82
7
 Release:        0
8
 Summary:        PipeWire Bluetooth aptX codec plugin
9
 License:        MIT
10
pipewire-0.3.81.tar.gz/.gitlab/ci/check_missing_headers.sh -> pipewire-0.3.82.tar.gz/.gitlab/ci/check_missing_headers.sh Changed
10
 
1
@@ -5,7 +5,7 @@
2
 
3
 LIST=""
4
 
5
-for i in $(find spa/include -name '*.h' -a -not -path 'spa/include/spa/utils/cleanup.h' | sed s#spa/include/##);
6
+for i in $(find spa/include -name '*.h' | sed s#spa/include/##);
7
 do
8
     -f "$PREFIX/include/spa-0.2/$i"  || LIST="$i $LIST"
9
 done
10
pipewire-0.3.81.tar.gz/NEWS -> pipewire-0.3.82.tar.gz/NEWS Changed
80
 
1
@@ -1,3 +1,68 @@
2
+# PipeWire 0.3.82 (2023-10-13)
3
+
4
+This is the second 1.0 release candidate that is API and ABI compatible
5
+with previous 0.3.x releases.
6
+
7
+## Highlights
8
+  - Fix a regression in some devices when the Pro-Audio profile was selected.
9
+    Only enable the IRQ based scheduling and device linking in specific
10
+    safe cases. (#3556)
11
+  - Improve rate switching. In some cases the graph rate would not switch
12
+    correctly. (#2929)
13
+  - Fix regression in alsa wakeups that would cause silence in VMs.
14
+  - Fix a leak in the SBC codecs for SCO.
15
+  - More improvements to the RAOP module.
16
+  - Other small improvements and fixes.
17
+
18
+
19
+## PipeWire
20
+  - Improve client property checks.
21
+  - Allow non-power-of-2 quantums when forced.
22
+  - Improve rate switching. In some cases the graph rate would not switch
23
+    correctly. (#2929)
24
+  - The PIPEWIRE_QUANTUM env variable now forces the size and rate in the
25
+    graph for the duration of the application. The softer PIPEWIRE_LATENCY
26
+    and PIPEWIRE_RATE can still be used to merely suggest a maximum latency
27
+    and a rate.
28
+
29
+## modules
30
+  - Remove the RTSP FLUSH request in RAOP because it does not seem necessary.
31
+  - The RAOP module now uses the common RTP stream functions.
32
+  - Add sockets option to protocol-native to make pipewire listen on multiple
33
+    sockets.
34
+
35
+## SPA
36
+  - Clean up some of the log functions.
37
+  - Add an option in ALSA to disable linking devices together.
38
+  - Only link pcms together when 1 capture and 1 playback pcm. For more complex
39
+    devices we can't be sure which ones can be linked. (#3556)
40
+  - disable tsched only when using linked devices.
41
+  - Add some extra checks in ALSA to avoid segfaults. (#3554)
42
+  - Add Tag support to alsa-sink and alsa-source.
43
+  - Use dynamic pod builder when we can.
44
+  - Set priority.driver on midi-bridge to allow it as a fallback driver. (#3562)
45
+  - Fix regression in alsa wakeups. (#3565)
46
+  - The PTP clock can now be found from the interface in node-driver.
47
+
48
+## pulse-server
49
+  - Some small cleanups and internal improvements.
50
+  - Add some memory debugging messages.
51
+  - Add Tag messages to streams.
52
+
53
+## Bluetooth
54
+  - Fix a leak in the SBC codecs for SCO.
55
+
56
+## JACK
57
+  - Patch up midi events in the destination buffer instead of writing to the
58
+    source buffer. (#3580)
59
+  - Group all jack clients together to avoid transport issues. (#3562)
60
+
61
+## ALSA-plugins
62
+  - Add also.deny option to block alsa clients from opening the PCM.
63
+
64
+Older versions:
65
+
66
+
67
 # PipeWire 0.3.81 (2023-10-06)
68
 
69
 This is the first 1.0 release candidate that is API and ABI compatible
70
@@ -80,9 +145,6 @@
71
   - jack_property now always manages to actually change the metadata because
72
     it waits for a roundtrip before exiting.
73
 
74
-Older versions:
75
-
76
-
77
 # PipeWire 0.3.80 (2023-09-14)
78
 
79
 This is a bugfix release that is API and ABI compatible with previous
80
pipewire-0.3.81.tar.gz/README.md -> pipewire-0.3.82.tar.gz/README.md Changed
13
 
1
@@ -52,9 +52,8 @@
2
                   the samplerate.
3
 * `PIPEWIRE_RATE=<num/denom>`      to configure a rate for the graph.
4
 * `PIPEWIRE_QUANTUM=<num/denom>`   to configure latency as a fraction and a
5
-                  samplerate. This function will attempt to change
6
-                  the graph samplerate to `denom` and use the
7
-                  specified `num` as the buffer size.
8
+                   samplerate. This function will force the graph samplerate to
9
+                   `denom` and force the specified `num` as the buffer size.
10
 * `PIPEWIRE_NODE=<id>`             to request a link to the specified node. The
11
                     id can be a node.name or object.serial of the target node.
12
 
13
pipewire-0.3.81.tar.gz/meson.build -> pipewire-0.3.82.tar.gz/meson.build Changed
35
 
1
@@ -1,5 +1,5 @@
2
 project('pipewire', 'c' ,
3
-  version : '0.3.81',
4
+  version : '0.3.82',
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
@@ -232,6 +232,7 @@
9
   'sys/random.h', 'HAVE_SYS_RANDOM_H',
10
   'sys/vfs.h', 'HAVE_SYS_VFS_H',
11
   'pwd.h', 'HAVE_PWD_H',
12
+  'grp.h', 'HAVE_GRP_H',
13
 
14
 
15
 foreach h : check_headers
16
@@ -247,6 +248,10 @@
17
 summary({'libsystemd': systemd_dep.found()}, bool_yn: true)
18
 cdata.set('HAVE_SYSTEMD', systemd.found() and systemd_dep.found())
19
 
20
+selinux_dep = dependency('libselinux', required: get_option('selinux'))
21
+summary({'libselinux': selinux_dep.found()}, bool_yn: true)
22
+cdata.set('HAVE_SELINUX', selinux_dep.found())
23
+
24
 configinc = include_directories('.')
25
 includes_inc = include_directories('include')
26
 pipewire_inc = include_directories('src')
27
@@ -436,6 +441,7 @@
28
   'sigabbrev_np', '#include <string.h>', '-D_GNU_SOURCE', ,
29
   'XSetIOErrorExitHandler', '#include <X11/Xlib.h>', , x11_dep,
30
   'malloc_trim', '#include <malloc.h>', , ,
31
+  'malloc_info', '#include <malloc.h>', , ,
32
 
33
 
34
 foreach f : check_functions
35
pipewire-0.3.81.tar.gz/meson_options.txt -> pipewire-0.3.82.tar.gz/meson_options.txt Changed
12
 
1
@@ -42,6 +42,10 @@
2
        description: 'Install systemd user service file (ignored without systemd)',
3
        type: 'feature',
4
        value: 'enabled')
5
+option('selinux',
6
+       description: 'Enable SELinux integration',
7
+       type: 'feature',
8
+       value: 'auto')
9
 option('pipewire-alsa',
10
        description: 'Enable pipewire-alsa integration',
11
        type: 'feature',
12
pipewire-0.3.81.tar.gz/pipewire-alsa/alsa-plugins/pcm_pipewire.c -> pipewire-0.3.82.tar.gz/pipewire-alsa/alsa-plugins/pcm_pipewire.c Changed
14
 
1
@@ -1238,6 +1238,12 @@
2
    if (str != NULL)
3
        pw_properties_update_string(pw->props, str, strlen(str));
4
 
5
+   if ((str = pw_properties_get(pw->props, "alsa.deny")) != NULL &&
6
+       spa_atob(str)) {
7
+       err = -EACCES;
8
+       goto error;
9
+   }
10
+
11
    str = getenv("PIPEWIRE_NODE");
12
    if (str != NULL && str0)
13
        pw_properties_set(pw->props, PW_KEY_TARGET_OBJECT, str);
14
pipewire-0.3.81.tar.gz/pipewire-jack/src/pipewire-jack.c -> pipewire-0.3.82.tar.gz/pipewire-jack/src/pipewire-jack.c Changed
95
 
1
@@ -1332,15 +1332,6 @@
2
    return b.state.offset;
3
 }
4
 
5
-static inline void fix_midi_event(uint8_t *data, size_t size)
6
-{
7
-   /* fixup NoteOn with vel 0 */
8
-   if (size > 2 && (data0 & 0xF0) == 0x90 && data2 == 0x00) {
9
-       data0 = 0x80 + (data0 & 0x0F);
10
-       data2 = 0x40;
11
-   }
12
-}
13
-
14
 static inline int event_sort(struct spa_pod_control *a, struct spa_pod_control *b)
15
 {
16
    if (a->offset < b->offset)
17
@@ -1373,6 +1364,29 @@
18
    }
19
 }
20
 
21
+static inline void fix_midi_event(uint8_t *data, size_t size)
22
+{
23
+   /* fixup NoteOn with vel 0 */
24
+   if (size > 2 && (data0 & 0xF0) == 0x90 && data2 == 0x00) {
25
+       data0 = 0x80 + (data0 & 0x0F);
26
+       data2 = 0x40;
27
+   }
28
+}
29
+
30
+static inline int midi_event_write(void *port_buffer,
31
+                      jack_nframes_t time,
32
+                      const jack_midi_data_t *data,
33
+                      size_t data_size, bool fix)
34
+{
35
+   jack_midi_data_t *retbuf = jack_midi_event_reserve (port_buffer, time, data_size);
36
+        if (SPA_UNLIKELY(retbuf == NULL))
37
+                return -ENOBUFS;
38
+   memcpy (retbuf, data, data_size);
39
+   if (fix)
40
+       fix_midi_event(retbuf, data_size);
41
+   return 0;
42
+}
43
+
44
 static void convert_to_midi(struct spa_pod_sequence **seq, uint32_t n_seq, void *midi, bool fix)
45
 {
46
    struct spa_pod_control *cn_seq;
47
@@ -1405,10 +1419,7 @@
48
            uint8_t *data = SPA_POD_BODY(&next->value);
49
            size_t size = SPA_POD_BODY_SIZE(&next->value);
50
 
51
-           if (fix)
52
-               fix_midi_event(data, size);
53
-
54
-           if ((res = jack_midi_event_write(midi, next->offset, data, size)) < 0)
55
+           if ((res = midi_event_write(midi, next->offset, data, size, fix)) < 0)
56
                pw_log_warn("midi %p: can't write event: %s", midi,
57
                        spa_strerror(res));
58
            break;
59
@@ -3804,10 +3815,10 @@
60
    if ((str = getenv("PIPEWIRE_QUANTUM")) != NULL) {
61
        struct spa_fraction q;
62
        if (sscanf(str, "%u/%u", &q.num, &q.denom) == 2 && q.denom != 0) {
63
-           pw_properties_setf(client->props, PW_KEY_NODE_RATE,
64
+           pw_properties_setf(client->props, PW_KEY_NODE_FORCE_RATE,
65
                    "1/%u", q.denom);
66
-           pw_properties_setf(client->props, PW_KEY_NODE_LATENCY,
67
-                   "%u/%u", q.num, q.denom);
68
+           pw_properties_setf(client->props, PW_KEY_NODE_FORCE_QUANTUM,
69
+                   "%u", q.num);
70
        } else {
71
            pw_log_warn("invalid PIPEWIRE_QUANTUM: %s", str);
72
        }
73
@@ -3828,7 +3839,7 @@
74
    if (pw_properties_get(client->props, PW_KEY_NODE_NAME) == NULL)
75
        pw_properties_set(client->props, PW_KEY_NODE_NAME, client_name);
76
    if (pw_properties_get(client->props, PW_KEY_NODE_GROUP) == NULL)
77
-       pw_properties_setf(client->props, PW_KEY_NODE_GROUP, "jack-%d", getpid());
78
+       pw_properties_setf(client->props, PW_KEY_NODE_GROUP, "group.dsp.0");
79
    if (pw_properties_get(client->props, PW_KEY_NODE_DESCRIPTION) == NULL)
80
        pw_properties_set(client->props, PW_KEY_NODE_DESCRIPTION, client_name);
81
    if (pw_properties_get(client->props, PW_KEY_MEDIA_TYPE) == NULL)
82
@@ -6924,11 +6935,7 @@
83
                       const jack_midi_data_t *data,
84
                       size_t data_size)
85
 {
86
-   jack_midi_data_t *retbuf = jack_midi_event_reserve (port_buffer, time, data_size);
87
-        if (SPA_UNLIKELY(retbuf == NULL))
88
-                return -ENOBUFS;
89
-   memcpy (retbuf, data, data_size);
90
-   return 0;
91
+   return midi_event_write(port_buffer, time, data, data_size, false);
92
 }
93
 
94
 SPA_EXPORT
95
pipewire-0.3.81.tar.gz/spa/include/meson.build -> pipewire-0.3.82.tar.gz/spa/include/meson.build Changed
9
 
1
@@ -15,7 +15,4 @@
2
 spa_headers = 'spa'  # used by doxygen
3
 install_subdir('spa',
4
   install_dir : get_option('includedir') / spa_name,
5
-  exclude_files : 
6
-    'utils/cleanup.h',
7
-  ,
8
 )
9
pipewire-0.3.81.tar.gz/spa/include/spa/pod/dynamic.h -> pipewire-0.3.82.tar.gz/spa/include/spa/pod/dynamic.h Changed
40
 
1
@@ -10,6 +10,7 @@
2
 #endif
3
 
4
 #include <spa/pod/builder.h>
5
+#include <spa/utils/cleanup.h>
6
 
7
 struct spa_pod_dynamic_builder {
8
    struct spa_pod_builder b;
9
@@ -23,14 +24,15 @@
10
    struct spa_pod_dynamic_builder *d = (struct spa_pod_dynamic_builder*)data;
11
    int32_t old_size = d->b.size;
12
    int32_t new_size = SPA_ROUND_UP_N(size, d->extend);
13
-   void *old_data = d->b.data;
14
+   void *old_data = d->b.data, *new_data;
15
 
16
    if (old_data == d->data)
17
        d->b.data = NULL;
18
-   if ((d->b.data = realloc(d->b.data, new_size)) == NULL)
19
+   if ((new_data = realloc(d->b.data, new_size)) == NULL)
20
        return -errno;
21
-   if (old_data == d->data && d->b.data != old_data && old_size > 0)
22
-       memcpy(d->b.data, old_data, old_size);
23
+   if (old_data == d->data && new_data != old_data && old_size > 0)
24
+       memcpy(new_data, old_data, old_size);
25
+   d->b.data = new_data;
26
    d->b.size = new_size;
27
         return 0;
28
 }
29
@@ -54,6 +56,10 @@
30
        free(builder->b.data);
31
 }
32
 
33
+SPA_DEFINE_AUTO_CLEANUP(spa_pod_dynamic_builder, struct spa_pod_dynamic_builder, {
34
+   spa_pod_dynamic_builder_clean(thing);
35
+})
36
+
37
 #ifdef __cplusplus
38
 }  /* extern "C" */
39
 #endif
40
pipewire-0.3.81.tar.gz/spa/include/spa/support/log.h -> pipewire-0.3.82.tar.gz/spa/include/spa/support/log.h Changed
53
 
1
@@ -194,28 +194,29 @@
2
 #define SPA_LOG_TOPIC(v, t) \
3
    (struct spa_log_topic){ .version = (v), .topic = (t)}
4
 
5
-#define spa_log_topic_init(l, topic)               \
6
-do {                               \
7
-   struct spa_log *_l = l;                 \
8
-   if (SPA_LIKELY(_l)) {                   \
9
-       struct spa_interface *_if = &_l->iface;     \
10
-       spa_interface_call(_if, struct spa_log_methods, \
11
-               topic_init, 1, topic);      \
12
-   }                           \
13
-} while(0)
14
-
15
-/* Unused, left for backwards compat */
16
-#define spa_log_level_enabled(l,lev) ((l) && (l)->level >= (lev))
17
-
18
-#define spa_log_level_topic_enabled(l,topic,lev)       \
19
-({                             \
20
-   struct spa_log *_log = l;               \
21
-   enum spa_log_level _lev = _log ? _log->level : SPA_LOG_LEVEL_NONE;      \
22
-   struct spa_log_topic *_t = (struct spa_log_topic *)(topic); \
23
-   if (_t && _t->has_custom_level)                         \
24
-       _lev = _t->level;               \
25
-   _lev >= (lev);                      \
26
-})
27
+static inline void spa_log_topic_init(struct spa_log *log, struct spa_log_topic *topic)
28
+{
29
+   if (SPA_UNLIKELY(!log))
30
+       return;
31
+
32
+   spa_interface_call(&log->iface, struct spa_log_methods, topic_init, 1, topic);
33
+}
34
+
35
+static inline bool spa_log_level_topic_enabled(const struct spa_log *log,
36
+                          const struct spa_log_topic *topic,
37
+                          enum spa_log_level level)
38
+{
39
+   enum spa_log_level max_level;
40
+
41
+   if (topic && topic->has_custom_level)
42
+       max_level = topic->level;
43
+   else if (log)
44
+       max_level = log->level;
45
+   else
46
+       max_level = SPA_LOG_LEVEL_NONE;
47
+
48
+   return level <= max_level;
49
+}
50
 
51
 /* Transparently calls to version 0 log if v1 is not supported */
52
 #define spa_log_logt(l,lev,topic,...)                  \
53
pipewire-0.3.81.tar.gz/spa/include/spa/utils/cleanup.h -> pipewire-0.3.82.tar.gz/spa/include/spa/utils/cleanup.h Changed
116
 
1
@@ -5,10 +5,48 @@
2
 #ifndef SPA_UTILS_CLEANUP_H
3
 #define SPA_UTILS_CLEANUP_H
4
 
5
-#if !defined(__has_attribute) || !__has_attribute(__cleanup__)
6
-#error "attribute `cleanup` is required"
7
+#define spa_exchange(var, new_value) \
8
+__extension__ ({ \
9
+   __typeof__(var) *_ptr = &(var); \
10
+   __typeof__(var) _old_value = *_ptr; \
11
+   *_ptr = (new_value); \
12
+   _old_value; \
13
+})
14
+
15
+/* ========================================================================== */
16
+
17
+#if __GNUC__ >= 10 || defined(__clang__)
18
+#define spa_steal_ptr(ptr) ((__typeof__(*(ptr)) *) spa_exchange((ptr), NULL))
19
+#else
20
+#define spa_steal_ptr(ptr) spa_exchange((ptr), NULL)
21
 #endif
22
 
23
+#define spa_clear_ptr(ptr, destructor) \
24
+__extension__ ({ \
25
+   __typeof__(ptr) _old_value = spa_steal_ptr(ptr); \
26
+   if (_old_value) \
27
+       destructor(_old_value); \
28
+   (void) 0; \
29
+})
30
+
31
+/* ========================================================================== */
32
+
33
+#include <unistd.h>
34
+
35
+#define spa_steal_fd(fd) spa_exchange((fd), -1)
36
+
37
+#define spa_clear_fd(fd) \
38
+__extension__ ({ \
39
+   int _old_value = spa_steal_fd(fd), _res = 0; \
40
+   if (_old_value >= 0) \
41
+       _res = close(_old_value); \
42
+   _res; \
43
+})
44
+
45
+/* ========================================================================== */
46
+
47
+#if defined(__has_attribute) && __has_attribute(__cleanup__)
48
+
49
 #define spa_cleanup(func) __attribute__((__cleanup__(func)))
50
 
51
 #define SPA_DEFINE_AUTO_CLEANUP(name, type, ...) \
52
@@ -33,34 +71,10 @@
53
    spa_cleanup(_spa_autoptr_cleanup_func_ ## name) \
54
    _spa_autoptr_cleanup_type_ ## name
55
 
56
-#define spa_exchange(var, new_value) \
57
-__extension__ ({ \
58
-   __typeof__(var) *_ptr = &(var); \
59
-   __typeof__(var) _old_value = *_ptr; \
60
-   *_ptr = (new_value); \
61
-   _old_value; \
62
-})
63
-
64
-#if __GNUC__ >= 10 || defined(__clang__)
65
-#define spa_steal_ptr(ptr) ((__typeof__(*(ptr)) *) spa_exchange((ptr), NULL))
66
-#else
67
-#define spa_steal_ptr(ptr) spa_exchange((ptr), NULL)
68
-#endif
69
-
70
-#define spa_steal_fd(fd) spa_exchange((fd), -1)
71
-
72
 /* ========================================================================== */
73
 
74
 #include <stdlib.h>
75
 
76
-#define spa_clear_ptr(ptr, destructor) \
77
-__extension__ ({ \
78
-   __typeof__(ptr) _old_value = spa_steal_ptr(ptr); \
79
-   if (_old_value) \
80
-       destructor(_old_value); \
81
-   (void) 0; \
82
-})
83
-
84
 static inline void _spa_autofree_cleanup_func(void *p)
85
 {
86
    free(*(void **) p);
87
@@ -69,16 +83,6 @@
88
 
89
 /* ========================================================================== */
90
 
91
-#include <unistd.h>
92
-
93
-#define spa_clear_fd(fd) \
94
-__extension__ ({ \
95
-   int _old_value = spa_steal_fd(fd), _res = 0; \
96
-   if (_old_value >= 0) \
97
-       _res = close(_old_value); \
98
-   _res; \
99
-})
100
-
101
 static inline void _spa_autoclose_cleanup_func(int *fd)
102
 {
103
    spa_clear_fd(*fd);
104
@@ -101,4 +105,11 @@
105
    spa_clear_ptr(*thing, closedir);
106
 })
107
 
108
+#else
109
+
110
+#define SPA_DEFINE_AUTO_CLEANUP(name, type, ...)
111
+#define SPA_DEFINE_AUTOPTR_CLEANUP(name, type, ...)
112
+
113
+#endif
114
+
115
 #endif /* SPA_UTILS_CLEANUP_H */
116
pipewire-0.3.81.tar.gz/spa/plugins/alsa/acp/acp.c -> pipewire-0.3.82.tar.gz/spa/plugins/alsa/acp/acp.c Changed
65
 
1
@@ -296,7 +296,7 @@
2
 static int add_pro_profile(pa_card *impl, uint32_t index)
3
 {
4
    snd_ctl_t *ctl_hndl;
5
-   int err, dev, count = 0;
6
+   int err, dev, count = 0, n_capture = 0, n_playback = 0;
7
    pa_alsa_profile *ap;
8
    pa_alsa_profile_set *ps = impl->profile_set;
9
    pa_alsa_mapping *m;
10
@@ -304,6 +304,7 @@
11
    snd_pcm_info_t *pcminfo;
12
    pa_sample_spec ss;
13
    snd_pcm_uframes_t try_period_size, try_buffer_size;
14
+   uint32_t idx;
15
 
16
    if (impl->use_ucm) {
17
        const char *verb = find_best_verb(impl);
18
@@ -388,11 +389,10 @@
19
                pa_alsa_init_proplist_pcm(NULL, m->output_proplist, m->output_pcm);
20
                pa_proplist_setf(m->output_proplist, "clock.name", "api.alsa.%u", index);
21
                pa_proplist_setf(m->output_proplist, "device.profile.pro", "true");
22
-               pa_proplist_setf(m->output_proplist, "node.group", "pro-audio-%u", index);
23
-               pa_proplist_setf(m->output_proplist, "node.link-group", "pro-audio-%u", index);
24
                pa_alsa_close(&m->output_pcm);
25
                m->supported = true;
26
                pa_channel_map_init_auto(&m->channel_map, m->sample_spec.channels, PA_CHANNEL_MAP_AUX);
27
+               n_playback++;
28
            }
29
            pa_idxset_put(ap->output_mappings, m, NULL);
30
            free(name);
31
@@ -421,11 +421,10 @@
32
                pa_alsa_init_proplist_pcm(NULL, m->input_proplist, m->input_pcm);
33
                pa_proplist_setf(m->input_proplist, "clock.name", "api.alsa.%u", index);
34
                pa_proplist_setf(m->input_proplist, "device.profile.pro", "true");
35
-               pa_proplist_setf(m->input_proplist, "node.group", "pro-audio-%u", index);
36
-               pa_proplist_setf(m->input_proplist, "node.link-group", "pro-audio-%u", index);
37
                pa_alsa_close(&m->input_pcm);
38
                m->supported = true;
39
                pa_channel_map_init_auto(&m->channel_map, m->sample_spec.channels, PA_CHANNEL_MAP_AUX);
40
+               n_capture++;
41
            }
42
            pa_idxset_put(ap->input_mappings, m, NULL);
43
            free(name);
44
@@ -433,6 +432,20 @@
45
    }
46
    snd_ctl_close(ctl_hndl);
47
 
48
+   if (n_capture == 1 && n_playback == 1) {
49
+       PA_IDXSET_FOREACH(m, ap->output_mappings, idx) {
50
+           pa_proplist_setf(m->output_proplist, "node.group", "pro-audio-%u", index);
51
+           pa_proplist_setf(m->output_proplist, "node.link-group", "pro-audio-%u", index);
52
+           pa_proplist_setf(m->output_proplist, "api.alsa.auto-link", "true");
53
+           pa_proplist_setf(m->output_proplist, "api.alsa.disable-tsched", "true");
54
+       }
55
+       PA_IDXSET_FOREACH(m, ap->input_mappings, idx) {
56
+           pa_proplist_setf(m->input_proplist, "node.group", "pro-audio-%u", index);
57
+           pa_proplist_setf(m->input_proplist, "node.link-group", "pro-audio-%u", index);
58
+           pa_proplist_setf(m->input_proplist, "api.alsa.auto-link", "true");
59
+           pa_proplist_setf(m->input_proplist, "api.alsa.disable-tsched", "true");
60
+       }
61
+   }
62
    return 0;
63
 }
64
 
65
pipewire-0.3.81.tar.gz/spa/plugins/alsa/alsa-acp-device.c -> pipewire-0.3.82.tar.gz/spa/plugins/alsa/alsa-acp-device.c Changed
83
 
1
@@ -26,6 +26,7 @@
2
 #include <spa/param/param.h>
3
 #include <spa/pod/filter.h>
4
 #include <spa/pod/parser.h>
5
+#include <spa/pod/dynamic.h>
6
 #include <spa/debug/pod.h>
7
 #include <spa/debug/log.h>
8
 
9
@@ -484,7 +485,8 @@
10
 {
11
    struct impl *this = object;
12
    struct spa_pod *param;
13
-   struct spa_pod_builder b = { 0 };
14
+   spa_auto(spa_pod_dynamic_builder) b = { 0 };
15
+   struct spa_pod_builder_state state;
16
    uint8_t buffer4096;
17
    struct spa_result_device_params result;
18
    uint32_t count = 0;
19
@@ -496,6 +498,9 @@
20
    spa_return_val_if_fail(this != NULL, -EINVAL);
21
    spa_return_val_if_fail(num != 0, -EINVAL);
22
 
23
+   spa_pod_dynamic_builder_init(&b, buffer, sizeof(buffer), 4096);
24
+   spa_pod_builder_get_state(&b.b, &state);
25
+
26
    card = this->card;
27
 
28
    result.id = id;
29
@@ -503,7 +508,7 @@
30
       next:
31
    result.index = result.next++;
32
 
33
-   spa_pod_builder_init(&b, buffer, sizeof(buffer));
34
+   spa_pod_builder_reset(&b.b, &state);
35
 
36
    switch (id) {
37
    case SPA_PARAM_EnumProfile:
38
@@ -511,7 +516,7 @@
39
            return 0;
40
 
41
        pr = card->profilesresult.index;
42
-       param = build_profile(&b, id, pr, false);
43
+       param = build_profile(&b.b, id, pr, false);
44
        break;
45
 
46
    case SPA_PARAM_Profile:
47
@@ -519,7 +524,7 @@
48
            return 0;
49
 
50
        pr = card->profilescard->active_profile_index;
51
-       param = build_profile(&b, id, pr, true);
52
+       param = build_profile(&b.b, id, pr, true);
53
        break;
54
 
55
    case SPA_PARAM_EnumRoute:
56
@@ -527,7 +532,7 @@
57
            return 0;
58
 
59
        p = card->portsresult.index;
60
-       param = build_route(&b, id, p, NULL, SPA_ID_INVALID);
61
+       param = build_route(&b.b, id, p, NULL, SPA_ID_INVALID);
62
        break;
63
 
64
    case SPA_PARAM_Route:
65
@@ -543,7 +548,7 @@
66
            result.index++;
67
        }
68
        result.next = result.index + 1;
69
-       param = build_route(&b, id, p, dev, card->active_profile_index);
70
+       param = build_route(&b.b, id, p, dev, card->active_profile_index);
71
        if (param == NULL)
72
            return -errno;
73
        break;
74
@@ -552,7 +557,7 @@
75
        return -ENOENT;
76
    }
77
 
78
-   if (spa_pod_filter(&b, &result.param, param, filter) < 0)
79
+   if (spa_pod_filter(&b.b, &result.param, param, filter) < 0)
80
        goto next;
81
 
82
    spa_device_emit_result(&this->hooks, seq, 0,
83
pipewire-0.3.81.tar.gz/spa/plugins/alsa/alsa-pcm-sink.c -> pipewire-0.3.82.tar.gz/spa/plugins/alsa/alsa-pcm-sink.c Changed
316
 
1
@@ -15,6 +15,7 @@
2
 #include <spa/utils/string.h>
3
 #include <spa/param/audio/format.h>
4
 #include <spa/pod/filter.h>
5
+#include <spa/pod/dynamic.h>
6
 #include <spa/debug/log.h>
7
 #include <spa/debug/pod.h>
8
 
9
@@ -100,7 +101,8 @@
10
 {
11
    struct state *this = object;
12
    struct spa_pod *param;
13
-   struct spa_pod_builder b = { 0 };
14
+   spa_auto(spa_pod_dynamic_builder) b = { 0 };
15
+   struct spa_pod_builder_state state;
16
    uint8_t buffer4096;
17
    struct spa_result_node_params result;
18
    uint32_t count = 0;
19
@@ -108,12 +110,15 @@
20
    spa_return_val_if_fail(this != NULL, -EINVAL);
21
    spa_return_val_if_fail(num != 0, -EINVAL);
22
 
23
+   spa_pod_dynamic_builder_init(&b, buffer, sizeof(buffer), 4096);
24
+   spa_pod_builder_get_state(&b.b, &state);
25
+
26
    result.id = id;
27
    result.next = start;
28
-      next:
29
+next:
30
    result.index = result.next++;
31
 
32
-   spa_pod_builder_init(&b, buffer, sizeof(buffer));
33
+   spa_pod_builder_reset(&b.b, &state);
34
 
35
    switch (id) {
36
    case SPA_PARAM_PropInfo:
37
@@ -122,7 +127,7 @@
38
 
39
        switch (result.index) {
40
        case 0:
41
-           param = spa_pod_builder_add_object(&b,
42
+           param = spa_pod_builder_add_object(&b.b,
43
                SPA_TYPE_OBJECT_PropInfo, id,
44
                SPA_PROP_INFO_id,   SPA_POD_Id(SPA_PROP_device),
45
                SPA_PROP_INFO_name, SPA_POD_String(SPA_KEY_API_ALSA_PATH),
46
@@ -130,21 +135,21 @@
47
                SPA_PROP_INFO_type, SPA_POD_Stringn(p->device, sizeof(p->device)));
48
            break;
49
        case 1:
50
-           param = spa_pod_builder_add_object(&b,
51
+           param = spa_pod_builder_add_object(&b.b,
52
                SPA_TYPE_OBJECT_PropInfo, id,
53
                SPA_PROP_INFO_id,   SPA_POD_Id(SPA_PROP_deviceName),
54
                SPA_PROP_INFO_description, SPA_POD_String("The ALSA device name"),
55
                SPA_PROP_INFO_type, SPA_POD_Stringn(p->device_name, sizeof(p->device_name)));
56
            break;
57
        case 2:
58
-           param = spa_pod_builder_add_object(&b,
59
+           param = spa_pod_builder_add_object(&b.b,
60
                SPA_TYPE_OBJECT_PropInfo, id,
61
                SPA_PROP_INFO_id,   SPA_POD_Id(SPA_PROP_cardName),
62
                SPA_PROP_INFO_description, SPA_POD_String("The ALSA card name"),
63
                SPA_PROP_INFO_type, SPA_POD_Stringn(p->card_name, sizeof(p->card_name)));
64
            break;
65
        case 3:
66
-           param = spa_pod_builder_add_object(&b,
67
+           param = spa_pod_builder_add_object(&b.b,
68
                SPA_TYPE_OBJECT_PropInfo, id,
69
                SPA_PROP_INFO_id,   SPA_POD_Id(SPA_PROP_latencyOffsetNsec),
70
                SPA_PROP_INFO_description, SPA_POD_String("Latency offset (ns)"),
71
@@ -153,7 +158,7 @@
72
        case 4:
73
            if (!this->is_iec958 && !this->is_hdmi)
74
                goto next;
75
-           param = spa_pod_builder_add_object(&b,
76
+           param = spa_pod_builder_add_object(&b.b,
77
                SPA_TYPE_OBJECT_PropInfo, id,
78
                SPA_PROP_INFO_id,   SPA_POD_Id(SPA_PROP_iec958Codecs),
79
                SPA_PROP_INFO_name, SPA_POD_String("iec958.codecs"),
80
@@ -163,7 +168,7 @@
81
                                 SPA_PROP_INFO_container, SPA_POD_Id(SPA_TYPE_Array));
82
            break;
83
        default:
84
-           param = spa_alsa_enum_propinfo(this, result.index - 5, &b);
85
+           param = spa_alsa_enum_propinfo(this, result.index - 5, &b.b);
86
            if (param == NULL)
87
                return 0;
88
        }
89
@@ -177,9 +182,9 @@
90
 
91
        switch (result.index) {
92
        case 0:
93
-           spa_pod_builder_push_object(&b, &f,
94
+           spa_pod_builder_push_object(&b.b, &f,
95
                                 SPA_TYPE_OBJECT_Props, id);
96
-           spa_pod_builder_add(&b,
97
+           spa_pod_builder_add(&b.b,
98
                SPA_PROP_device,       SPA_POD_Stringn(p->device, sizeof(p->device)),
99
                SPA_PROP_deviceName,   SPA_POD_Stringn(p->device_name, sizeof(p->device_name)),
100
                SPA_PROP_cardName,     SPA_POD_Stringn(p->card_name, sizeof(p->card_name)),
101
@@ -188,12 +193,12 @@
102
 
103
            if (this->is_iec958 || this->is_hdmi) {
104
                n_codecs = spa_alsa_get_iec958_codecs(this, codecs, SPA_N_ELEMENTS(codecs));
105
-               spa_pod_builder_prop(&b, SPA_PROP_iec958Codecs, 0);
106
-               spa_pod_builder_array(&b, sizeof(uint32_t), SPA_TYPE_Id,
107
+               spa_pod_builder_prop(&b.b, SPA_PROP_iec958Codecs, 0);
108
+               spa_pod_builder_array(&b.b, sizeof(uint32_t), SPA_TYPE_Id,
109
                        n_codecs, codecs);
110
            }
111
-           spa_alsa_add_prop_params(this, &b);
112
-           param = spa_pod_builder_pop(&b, &f);
113
+           spa_alsa_add_prop_params(this, &b.b);
114
+           param = spa_pod_builder_pop(&b.b, &f);
115
            break;
116
        default:
117
            return 0;
118
@@ -203,13 +208,13 @@
119
    case SPA_PARAM_IO:
120
        switch (result.index) {
121
        case 0:
122
-           param = spa_pod_builder_add_object(&b,
123
+           param = spa_pod_builder_add_object(&b.b,
124
                SPA_TYPE_OBJECT_ParamIO, id,
125
                SPA_PARAM_IO_id,   SPA_POD_Id(SPA_IO_Clock),
126
                SPA_PARAM_IO_size, SPA_POD_Int(sizeof(struct spa_io_clock)));
127
            break;
128
        case 1:
129
-           param = spa_pod_builder_add_object(&b,
130
+           param = spa_pod_builder_add_object(&b.b,
131
                SPA_TYPE_OBJECT_ParamIO, id,
132
                SPA_PARAM_IO_id,   SPA_POD_Id(SPA_IO_Position),
133
                SPA_PARAM_IO_size, SPA_POD_Int(sizeof(struct spa_io_position)));
134
@@ -222,7 +227,7 @@
135
    case SPA_PARAM_ProcessLatency:
136
        switch (result.index) {
137
        case 0:
138
-           param = spa_process_latency_build(&b, id, &this->process_latency);
139
+           param = spa_process_latency_build(&b.b, id, &this->process_latency);
140
            break;
141
        default:
142
            return 0;
143
@@ -233,7 +238,7 @@
144
        return -ENOENT;
145
    }
146
 
147
-   if (spa_pod_filter(&b, &result.param, param, filter) < 0)
148
+   if (spa_pod_filter(&b.b, &result.param, param, filter) < 0)
149
        goto next;
150
 
151
    spa_node_emit_result(&this->hooks, seq, 0, SPA_RESULT_TYPE_NODE_PARAMS, &result);
152
@@ -469,7 +474,8 @@
153
 
154
    struct state *this = object;
155
    struct spa_pod *param;
156
-   struct spa_pod_builder b = { 0 };
157
+   spa_auto(spa_pod_dynamic_builder) b = { 0 };
158
+   struct spa_pod_builder_state state;
159
    uint8_t buffer1024;
160
    struct spa_result_node_params result;
161
    uint32_t count = 0;
162
@@ -479,12 +485,15 @@
163
 
164
    spa_return_val_if_fail(CHECK_PORT(this, direction, port_id), -EINVAL);
165
 
166
+   spa_pod_dynamic_builder_init(&b, buffer, sizeof(buffer), 4096);
167
+   spa_pod_builder_get_state(&b.b, &state);
168
+
169
    result.id = id;
170
    result.next = start;
171
       next:
172
    result.index = result.next++;
173
 
174
-   spa_pod_builder_init(&b, buffer, sizeof(buffer));
175
+   spa_pod_builder_reset(&b.b, &state);
176
 
177
    switch (id) {
178
    case SPA_PARAM_EnumFormat:
179
@@ -498,15 +507,15 @@
180
 
181
        switch (this->current_format.media_subtype) {
182
        case SPA_MEDIA_SUBTYPE_raw:
183
-           param = spa_format_audio_raw_build(&b, id,
184
+           param = spa_format_audio_raw_build(&b.b, id,
185
                    &this->current_format.info.raw);
186
            break;
187
        case SPA_MEDIA_SUBTYPE_iec958:
188
-           param = spa_format_audio_iec958_build(&b, id,
189
+           param = spa_format_audio_iec958_build(&b.b, id,
190
                    &this->current_format.info.iec958);
191
            break;
192
        case SPA_MEDIA_SUBTYPE_dsd:
193
-           param = spa_format_audio_dsd_build(&b, id,
194
+           param = spa_format_audio_dsd_build(&b.b, id,
195
                    &this->current_format.info.dsd);
196
            break;
197
        default:
198
@@ -520,7 +529,7 @@
199
        if (result.index > 0)
200
            return 0;
201
 
202
-       param = spa_pod_builder_add_object(&b,
203
+       param = spa_pod_builder_add_object(&b.b,
204
            SPA_TYPE_OBJECT_ParamBuffers, id,
205
            SPA_PARAM_BUFFERS_buffers, SPA_POD_CHOICE_RANGE_Int(2, 1, MAX_BUFFERS),
206
            SPA_PARAM_BUFFERS_blocks,  SPA_POD_Int(this->blocks),
207
@@ -534,7 +543,7 @@
208
    case SPA_PARAM_Meta:
209
        switch (result.index) {
210
        case 0:
211
-           param = spa_pod_builder_add_object(&b,
212
+           param = spa_pod_builder_add_object(&b.b,
213
                SPA_TYPE_OBJECT_ParamMeta, id,
214
                SPA_PARAM_META_type, SPA_POD_Id(SPA_META_Header),
215
                SPA_PARAM_META_size, SPA_POD_Int(sizeof(struct spa_meta_header)));
216
@@ -547,13 +556,13 @@
217
    case SPA_PARAM_IO:
218
        switch (result.index) {
219
        case 0:
220
-           param = spa_pod_builder_add_object(&b,
221
+           param = spa_pod_builder_add_object(&b.b,
222
                SPA_TYPE_OBJECT_ParamIO, id,
223
                SPA_PARAM_IO_id,   SPA_POD_Id(SPA_IO_Buffers),
224
                SPA_PARAM_IO_size, SPA_POD_Int(sizeof(struct spa_io_buffers)));
225
            break;
226
        case 1:
227
-           param = spa_pod_builder_add_object(&b,
228
+           param = spa_pod_builder_add_object(&b.b,
229
                SPA_TYPE_OBJECT_ParamIO, id,
230
                SPA_PARAM_IO_id,   SPA_POD_Id(SPA_IO_RateMatch),
231
                SPA_PARAM_IO_size, SPA_POD_Int(sizeof(struct spa_io_rate_match)));
232
@@ -570,19 +579,28 @@
233
            struct spa_latency_info latency = this->latencyresult.index;
234
            if (latency.direction == SPA_DIRECTION_INPUT)
235
                spa_process_latency_info_add(&this->process_latency, &latency);
236
-           param = spa_latency_build(&b, id, &latency);
237
+           param = spa_latency_build(&b.b, id, &latency);
238
            break;
239
        }
240
        default:
241
            return 0;
242
        }
243
        break;
244
-
245
+   case SPA_PARAM_Tag:
246
+       switch (result.index) {
247
+       case 0: case 1:
248
+           if ((param = this->tagresult.index) == NULL)
249
+               goto next;
250
+           break;
251
+       default:
252
+           return 0;
253
+       }
254
+       break;
255
    default:
256
        return -ENOENT;
257
    }
258
 
259
-   if (spa_pod_filter(&b, &result.param, param, filter) < 0)
260
+   if (spa_pod_filter(&b.b, &result.param, param, filter) < 0)
261
        goto next;
262
 
263
    spa_node_emit_result(&this->hooks, seq, 0, SPA_RESULT_TYPE_NODE_PARAMS, &result);
264
@@ -687,12 +705,13 @@
265
        break;
266
    case SPA_PARAM_Latency:
267
    {
268
+       enum spa_direction other = SPA_DIRECTION_REVERSE(direction);
269
        struct spa_latency_info info;
270
        if (param == NULL)
271
-           info = SPA_LATENCY_INFO(SPA_DIRECTION_REVERSE(direction));
272
+           info = SPA_LATENCY_INFO(other);
273
        else if ((res = spa_latency_parse(param, &info)) < 0)
274
            return res;
275
-       if (direction == info.direction)
276
+       if (info.direction != other)
277
            return -EINVAL;
278
 
279
        this->latencyinfo.direction = info;
280
@@ -702,9 +721,25 @@
281
        break;
282
    }
283
    case SPA_PARAM_Tag:
284
-       if (param != NULL)
285
-           spa_debug_log_pod(this->log, SPA_LOG_LEVEL_DEBUG, 0, NULL, param);
286
+   {
287
+       enum spa_direction other = SPA_DIRECTION_REVERSE(direction);
288
+       if (param != NULL) {
289
+           struct spa_tag_info info;
290
+           void *state = NULL;
291
+           if (spa_tag_parse(param, &info, &state) < 0 ||
292
+               info.direction != other)
293
+               return -EINVAL;
294
+       }
295
+       if (spa_tag_compare(param, this->tagother) != 0) {
296
+           free(this->tagother);
297
+           this->tagother = param ? spa_pod_copy(param) : NULL;
298
+
299
+           this->port_info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS;
300
+           this->port_paramsPORT_Tag.user++;
301
+           emit_port_info(this, false);
302
+       }
303
        break;
304
+   }
305
    default:
306
        res = -ENOENT;
307
        break;
308
@@ -956,6 +991,7 @@
309
    this->port_paramsPORT_Format = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE);
310
    this->port_paramsPORT_Buffers = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0);
311
    this->port_paramsPORT_Latency = SPA_PARAM_INFO(SPA_PARAM_Latency, SPA_PARAM_INFO_READWRITE);
312
+   this->port_paramsPORT_Tag = SPA_PARAM_INFO(SPA_PARAM_Tag, SPA_PARAM_INFO_READWRITE);
313
    this->port_info.params = this->port_params;
314
    this->port_info.n_params = N_PORT_PARAMS;
315
 
316
pipewire-0.3.81.tar.gz/spa/plugins/alsa/alsa-pcm-source.c -> pipewire-0.3.82.tar.gz/spa/plugins/alsa/alsa-pcm-source.c Changed
297
 
1
@@ -16,6 +16,7 @@
2
 #include <spa/monitor/device.h>
3
 #include <spa/param/audio/format.h>
4
 #include <spa/pod/filter.h>
5
+#include <spa/pod/dynamic.h>
6
 
7
 #include "alsa.h"
8
 
9
@@ -100,7 +101,8 @@
10
    struct state *this = object;
11
    struct spa_pod *param;
12
    uint8_t buffer4096;
13
-   struct spa_pod_builder b = { 0 };
14
+   spa_auto(spa_pod_dynamic_builder) b = { 0 };
15
+   struct spa_pod_builder_state state;
16
    struct props *p;
17
    struct spa_result_node_params result;
18
    uint32_t count = 0;
19
@@ -108,6 +110,9 @@
20
    spa_return_val_if_fail(this != NULL, -EINVAL);
21
    spa_return_val_if_fail(num != 0, -EINVAL);
22
 
23
+   spa_pod_dynamic_builder_init(&b, buffer, sizeof(buffer), 4096);
24
+   spa_pod_builder_get_state(&b.b, &state);
25
+
26
    p = &this->props;
27
 
28
    result.id = id;
29
@@ -115,13 +120,13 @@
30
       next:
31
    result.index = result.next++;
32
 
33
-   spa_pod_builder_init(&b, buffer, sizeof(buffer));
34
+   spa_pod_builder_reset(&b.b, &state);
35
 
36
    switch (id) {
37
    case SPA_PARAM_PropInfo:
38
        switch (result.index) {
39
        case 0:
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_device),
44
                SPA_PROP_INFO_name, SPA_POD_String(SPA_KEY_API_ALSA_PATH),
45
@@ -129,28 +134,28 @@
46
                SPA_PROP_INFO_type, SPA_POD_Stringn(p->device, sizeof(p->device)));
47
            break;
48
        case 1:
49
-           param = spa_pod_builder_add_object(&b,
50
+           param = spa_pod_builder_add_object(&b.b,
51
                SPA_TYPE_OBJECT_PropInfo, id,
52
                SPA_PROP_INFO_id,   SPA_POD_Id(SPA_PROP_deviceName),
53
                SPA_PROP_INFO_description, SPA_POD_String("The ALSA device name"),
54
                SPA_PROP_INFO_type, SPA_POD_Stringn(p->device_name, sizeof(p->device_name)));
55
            break;
56
        case 2:
57
-           param = spa_pod_builder_add_object(&b,
58
+           param = spa_pod_builder_add_object(&b.b,
59
                SPA_TYPE_OBJECT_PropInfo, id,
60
                SPA_PROP_INFO_id,   SPA_POD_Id(SPA_PROP_cardName),
61
                SPA_PROP_INFO_description, SPA_POD_String("The ALSA card name"),
62
                SPA_PROP_INFO_type, SPA_POD_Stringn(p->card_name, sizeof(p->card_name)));
63
            break;
64
        case 3:
65
-           param = spa_pod_builder_add_object(&b,
66
+           param = spa_pod_builder_add_object(&b.b,
67
                SPA_TYPE_OBJECT_PropInfo, id,
68
                SPA_PROP_INFO_id,   SPA_POD_Id(SPA_PROP_latencyOffsetNsec),
69
                SPA_PROP_INFO_description, SPA_POD_String("Latency offset (ns)"),
70
                SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Long(0LL, 0LL, 2 * SPA_NSEC_PER_SEC));
71
            break;
72
        default:
73
-           param = spa_alsa_enum_propinfo(this, result.index - 4, &b);
74
+           param = spa_alsa_enum_propinfo(this, result.index - 4, &b.b);
75
            if (param == NULL)
76
                return 0;
77
        }
78
@@ -162,16 +167,16 @@
79
 
80
        switch (result.index) {
81
        case 0:
82
-           spa_pod_builder_push_object(&b, &f,
83
+           spa_pod_builder_push_object(&b.b, &f,
84
                                 SPA_TYPE_OBJECT_Props, id);
85
-           spa_pod_builder_add(&b,
86
+           spa_pod_builder_add(&b.b,
87
                SPA_PROP_device,       SPA_POD_Stringn(p->device, sizeof(p->device)),
88
                SPA_PROP_deviceName,   SPA_POD_Stringn(p->device_name, sizeof(p->device_name)),
89
                SPA_PROP_cardName,     SPA_POD_Stringn(p->card_name, sizeof(p->card_name)),
90
                SPA_PROP_latencyOffsetNsec,   SPA_POD_Long(this->process_latency.ns),
91
                0);
92
-           spa_alsa_add_prop_params(this, &b);
93
-           param = spa_pod_builder_pop(&b, &f);
94
+           spa_alsa_add_prop_params(this, &b.b);
95
+           param = spa_pod_builder_pop(&b.b, &f);
96
            break;
97
        default:
98
            return 0;
99
@@ -181,13 +186,13 @@
100
    case SPA_PARAM_IO:
101
        switch (result.index) {
102
        case 0:
103
-           param = spa_pod_builder_add_object(&b,
104
+           param = spa_pod_builder_add_object(&b.b,
105
                SPA_TYPE_OBJECT_ParamIO, id,
106
                SPA_PARAM_IO_id,   SPA_POD_Id(SPA_IO_Clock),
107
                SPA_PARAM_IO_size, SPA_POD_Int(sizeof(struct spa_io_clock)));
108
            break;
109
        case 1:
110
-           param = spa_pod_builder_add_object(&b,
111
+           param = spa_pod_builder_add_object(&b.b,
112
                SPA_TYPE_OBJECT_ParamIO, id,
113
                SPA_PARAM_IO_id,   SPA_POD_Id(SPA_IO_Position),
114
                SPA_PARAM_IO_size, SPA_POD_Int(sizeof(struct spa_io_position)));
115
@@ -200,7 +205,7 @@
116
    case SPA_PARAM_ProcessLatency:
117
        switch (result.index) {
118
        case 0:
119
-           param = spa_process_latency_build(&b, id, &this->process_latency);
120
+           param = spa_process_latency_build(&b.b, id, &this->process_latency);
121
            break;
122
        default:
123
            return 0;
124
@@ -211,7 +216,7 @@
125
        return -ENOENT;
126
    }
127
 
128
-   if (spa_pod_filter(&b, &result.param, param, filter) < 0)
129
+   if (spa_pod_filter(&b.b, &result.param, param, filter) < 0)
130
        goto next;
131
 
132
    spa_node_emit_result(&this->hooks, seq, 0, SPA_RESULT_TYPE_NODE_PARAMS, &result);
133
@@ -431,22 +436,25 @@
134
 {
135
    struct state *this = object;
136
    struct spa_pod *param;
137
-   struct spa_pod_builder b = { 0 };
138
+   spa_auto(spa_pod_dynamic_builder) b = { 0 };
139
+   struct spa_pod_builder_state state;
140
    uint8_t buffer1024;
141
    struct spa_result_node_params result;
142
    uint32_t count = 0;
143
 
144
    spa_return_val_if_fail(this != NULL, -EINVAL);
145
    spa_return_val_if_fail(num != 0, -EINVAL);
146
-
147
    spa_return_val_if_fail(CHECK_PORT(this, direction, port_id), -EINVAL);
148
 
149
+   spa_pod_dynamic_builder_init(&b, buffer, sizeof(buffer), 4096);
150
+   spa_pod_builder_get_state(&b.b, &state);
151
+
152
    result.id = id;
153
    result.next = start;
154
       next:
155
    result.index = result.next++;
156
 
157
-   spa_pod_builder_init(&b, buffer, sizeof(buffer));
158
+   spa_pod_builder_reset(&b.b, &state);
159
 
160
    switch (id) {
161
    case SPA_PARAM_EnumFormat:
162
@@ -458,7 +466,7 @@
163
        if (result.index > 0)
164
            return 0;
165
 
166
-       param = spa_format_audio_raw_build(&b, id, &this->current_format.info.raw);
167
+       param = spa_format_audio_raw_build(&b.b, id, &this->current_format.info.raw);
168
        break;
169
 
170
    case SPA_PARAM_Buffers:
171
@@ -467,7 +475,7 @@
172
        if (result.index > 0)
173
            return 0;
174
 
175
-       param = spa_pod_builder_add_object(&b,
176
+       param = spa_pod_builder_add_object(&b.b,
177
            SPA_TYPE_OBJECT_ParamBuffers, id,
178
            SPA_PARAM_BUFFERS_buffers, SPA_POD_CHOICE_RANGE_Int(2, 1, MAX_BUFFERS),
179
            SPA_PARAM_BUFFERS_blocks,  SPA_POD_Int(this->blocks),
180
@@ -481,7 +489,7 @@
181
    case SPA_PARAM_Meta:
182
        switch (result.index) {
183
        case 0:
184
-           param = spa_pod_builder_add_object(&b,
185
+           param = spa_pod_builder_add_object(&b.b,
186
                SPA_TYPE_OBJECT_ParamMeta, id,
187
                SPA_PARAM_META_type, SPA_POD_Id(SPA_META_Header),
188
                SPA_PARAM_META_size, SPA_POD_Int(sizeof(struct spa_meta_header)));
189
@@ -494,13 +502,13 @@
190
    case SPA_PARAM_IO:
191
        switch (result.index) {
192
        case 0:
193
-           param = spa_pod_builder_add_object(&b,
194
+           param = spa_pod_builder_add_object(&b.b,
195
                SPA_TYPE_OBJECT_ParamIO, id,
196
                SPA_PARAM_IO_id,   SPA_POD_Id(SPA_IO_Buffers),
197
                SPA_PARAM_IO_size, SPA_POD_Int(sizeof(struct spa_io_buffers)));
198
            break;
199
        case 1:
200
-           param = spa_pod_builder_add_object(&b,
201
+           param = spa_pod_builder_add_object(&b.b,
202
                SPA_TYPE_OBJECT_ParamIO, id,
203
                SPA_PARAM_IO_id,   SPA_POD_Id(SPA_IO_RateMatch),
204
                SPA_PARAM_IO_size, SPA_POD_Int(sizeof(struct spa_io_rate_match)));
205
@@ -517,19 +525,29 @@
206
            struct spa_latency_info latency = this->latencyresult.index;
207
            if (latency.direction == SPA_DIRECTION_OUTPUT)
208
                spa_process_latency_info_add(&this->process_latency, &latency);
209
-           param = spa_latency_build(&b, id, &latency);
210
+           param = spa_latency_build(&b.b, id, &latency);
211
            break;
212
        }
213
        default:
214
            return 0;
215
        }
216
        break;
217
+   case SPA_PARAM_Tag:
218
+       switch (result.index) {
219
+       case 0: case 1:
220
+           if ((param = this->tagresult.index) == NULL)
221
+               goto next;
222
+           break;
223
+       default:
224
+           return 0;
225
+       }
226
+       break;
227
 
228
    default:
229
        return -ENOENT;
230
    }
231
 
232
-   if (spa_pod_filter(&b, &result.param, param, filter) < 0)
233
+   if (spa_pod_filter(&b.b, &result.param, param, filter) < 0)
234
        goto next;
235
 
236
    spa_node_emit_result(&this->hooks, seq, 0, SPA_RESULT_TYPE_NODE_PARAMS, &result);
237
@@ -609,7 +627,7 @@
238
             const struct spa_pod *param)
239
 {
240
    struct state *this = object;
241
-   int res;
242
+   int res = 0;
243
 
244
    spa_return_val_if_fail(this != NULL, -EINVAL);
245
 
246
@@ -621,19 +639,39 @@
247
        break;
248
    case SPA_PARAM_Latency:
249
    {
250
+       enum spa_direction other = SPA_DIRECTION_REVERSE(direction);
251
        struct spa_latency_info info;
252
        if (param == NULL)
253
-           info = SPA_LATENCY_INFO(SPA_DIRECTION_REVERSE(direction));
254
+           info = SPA_LATENCY_INFO(other);
255
        else if ((res = spa_latency_parse(param, &info)) < 0)
256
            return res;
257
-       if (direction == info.direction)
258
+       if (info.direction != other)
259
            return -EINVAL;
260
 
261
        this->latencyinfo.direction = info;
262
        this->port_info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS;
263
        this->port_paramsPORT_Latency.user++;
264
        emit_port_info(this, false);
265
-       res = 0;
266
+       break;
267
+   }
268
+   case SPA_PARAM_Tag:
269
+   {
270
+       enum spa_direction other = SPA_DIRECTION_REVERSE(direction);
271
+       if (param != NULL) {
272
+           struct spa_tag_info info;
273
+           void *state = NULL;
274
+           if (spa_tag_parse(param, &info, &state) < 0 ||
275
+               info.direction != other)
276
+               return -EINVAL;
277
+       }
278
+       if (spa_tag_compare(param, this->tagother) != 0) {
279
+           free(this->tagother);
280
+           this->tagother = param ? spa_pod_copy(param) : NULL;
281
+
282
+           this->port_info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS;
283
+           this->port_paramsPORT_Tag.user++;
284
+           emit_port_info(this, false);
285
+       }
286
        break;
287
    }
288
    default:
289
@@ -901,6 +939,7 @@
290
    this->port_paramsPORT_Format = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE);
291
    this->port_paramsPORT_Buffers = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0);
292
    this->port_paramsPORT_Latency = SPA_PARAM_INFO(SPA_PARAM_Latency, SPA_PARAM_INFO_READWRITE);
293
+   this->port_paramsPORT_Tag = SPA_PARAM_INFO(SPA_PARAM_Tag, SPA_PARAM_INFO_READWRITE);
294
    this->port_info.params = this->port_params;
295
    this->port_info.n_params = N_PORT_PARAMS;
296
 
297
pipewire-0.3.81.tar.gz/spa/plugins/alsa/alsa-pcm.c -> pipewire-0.3.82.tar.gz/spa/plugins/alsa/alsa-pcm.c Changed
138
 
1
@@ -131,6 +131,8 @@
2
        state->multi_rate = spa_atob(s);
3
    } else if (spa_streq(k, "api.alsa.htimestamp")) {
4
        state->htimestamp = spa_atob(s);
5
+   } else if (spa_streq(k, "api.alsa.auto-link")) {
6
+       state->auto_link = spa_atob(s);
7
    } else if (spa_streq(k, "latency.internal.rate")) {
8
        state->process_latency.rate = atoi(s);
9
    } else if (spa_streq(k, "latency.internal.ns")) {
10
@@ -512,7 +514,6 @@
11
 
12
    state->multi_rate = true;
13
    state->htimestamp = false;
14
-   state->disable_tsched = state->is_pro;
15
    for (i = 0; info && i < info->n_items; i++) {
16
        const char *k = info->itemsi.key;
17
        const char *s = info->itemsi.value;
18
@@ -574,6 +575,9 @@
19
        spa_log_warn(state->log, "output close failed: %s", snd_strerror(err));
20
    fclose(state->log_file);
21
 
22
+   free(state->tag0);
23
+   free(state->tag1);
24
+
25
    return err;
26
 }
27
 
28
@@ -1991,7 +1995,7 @@
29
 
30
    CHECK(set_swparams(state), "swparams");
31
 
32
-   if ((err = snd_pcm_prepare(state->hndl)) < 0 && err != -EBUSY) {
33
+   if ((!state->linked) && (err = snd_pcm_prepare(state->hndl)) < 0 && err != -EBUSY) {
34
        spa_log_error(state->log, "%s: snd_pcm_prepare error: %s",
35
                state->name, snd_strerror(err));
36
        return err;
37
@@ -2398,10 +2402,13 @@
38
    if (SPA_UNLIKELY((res = check_position_config(state)) < 0))
39
        return res;
40
 
41
-   if (SPA_UNLIKELY((res = get_status(state, current_time, &avail, &delay, &target)) < 0))
42
+   if (SPA_UNLIKELY((res = get_status(state, current_time, &avail, &delay, &target)) < 0)) {
43
+       spa_log_error(state->log, "get_status error");
44
+       state->next_time += state->threshold * 1e9 / state->rate;
45
        return res;
46
+   }
47
 
48
-   if (SPA_UNLIKELY(!following && delay > target + state->max_error)) {
49
+   if (SPA_UNLIKELY(!following && state->alsa_started && delay > target + state->max_error)) {
50
        spa_log_trace(state->log, "%p: early wakeup %ld %lu %lu", state,
51
                avail, delay, target);
52
        if (delay > target * 3)
53
@@ -2412,7 +2419,7 @@
54
    if (SPA_UNLIKELY((res = update_time(state, current_time, delay, target, following)) < 0))
55
        return res;
56
 
57
-   if (following && !state->linked) {
58
+   if (following && state->alsa_started && !state->linked) {
59
        if (SPA_UNLIKELY(state->alsa_sync)) {
60
            enum spa_log_level lev;
61
 
62
@@ -2553,11 +2560,9 @@
63
 
64
 int spa_alsa_write(struct state *state)
65
 {
66
-   int res = 0;
67
    if (state->following && state->rt.driver == NULL) {
68
        uint64_t current_time = state->position->clock.nsec;
69
-       if ((res = alsa_write_sync(state, current_time)) < 0)
70
-           return res;
71
+       alsa_write_sync(state, current_time);
72
    }
73
    return alsa_write_frames(state);
74
 }
75
@@ -2656,8 +2661,11 @@
76
    if (SPA_UNLIKELY((res = check_position_config(state)) < 0))
77
        return res;
78
 
79
-   if (SPA_UNLIKELY((res = get_status(state, current_time, &avail, &delay, &target)) < 0))
80
+   if (SPA_UNLIKELY((res = get_status(state, current_time, &avail, &delay, &target)) < 0)) {
81
+       spa_log_error(state->log, "get_status error");
82
+       state->next_time += state->threshold * 1e9 / state->rate;
83
        return res;
84
+   }
85
 
86
    if (SPA_UNLIKELY(!following && avail < state->read_size)) {
87
        spa_log_trace(state->log, "%p: early wakeup %ld %ld %ld %d", state,
88
@@ -2671,7 +2679,7 @@
89
        return res;
90
 
91
    max_read = state->buffer_frames;
92
-   if (following) {
93
+   if (following && !state->linked) {
94
        if (state->alsa_sync) {
95
            enum spa_log_level lev;
96
 
97
@@ -2767,11 +2775,9 @@
98
 
99
 int spa_alsa_read(struct state *state)
100
 {
101
-   int res;
102
    if (state->following && state->rt.driver == NULL) {
103
        uint64_t current_time = state->position->clock.nsec;
104
-       if ((res = alsa_read_sync(state, current_time)) < 0)
105
-           return res;
106
+       alsa_read_sync(state, current_time);
107
    }
108
    return alsa_read_frames(state);
109
 }
110
@@ -3019,6 +3025,9 @@
111
    struct state *follower;
112
    int err;
113
 
114
+   if (!state->opened)
115
+       return -EIO;
116
+
117
    spa_alsa_pause(state);
118
 
119
    if (state->prepared)
120
@@ -3034,7 +3043,7 @@
121
    spa_list_for_each(follower, &state->followers, driver_link) {
122
        if (follower != state && !follower->matching) {
123
            spa_alsa_prepare(follower);
124
-           if (!follower->linked)
125
+           if (!follower->linked && state->auto_link)
126
                do_link(state, follower);
127
        }
128
    }
129
@@ -3051,6 +3060,8 @@
130
 
131
    if (state->started)
132
        return 0;
133
+   else if (!state->opened)
134
+       return -EIO;
135
 
136
    spa_alsa_prepare(state);
137
 
138
pipewire-0.3.81.tar.gz/spa/plugins/alsa/alsa-pcm.h -> pipewire-0.3.82.tar.gz/spa/plugins/alsa/alsa-pcm.h Changed
36
 
1
@@ -30,6 +30,7 @@
2
 #include <spa/param/param.h>
3
 #include <spa/param/latency-utils.h>
4
 #include <spa/param/audio/format-utils.h>
5
+#include <spa/param/tag-utils.h>
6
 
7
 #include "alsa.h"
8
 
9
@@ -165,7 +166,8 @@
10
 #define PORT_Format        3
11
 #define PORT_Buffers       4
12
 #define PORT_Latency       5
13
-#define N_PORT_PARAMS      6
14
+#define PORT_Tag       6
15
+#define N_PORT_PARAMS      7
16
    struct spa_param_info port_paramsN_PORT_PARAMS;
17
    enum spa_direction port_direction;
18
    struct spa_io_buffers *io;
19
@@ -214,6 +216,7 @@
20
    unsigned int htimestamp:1;
21
    unsigned int is_pro:1;
22
    unsigned int sources_added:1;
23
+   unsigned int auto_link:1;
24
    unsigned int linked:1;
25
 
26
    uint64_t iec958_codecs;
27
@@ -233,6 +236,8 @@
28
    struct spa_latency_info latency2;
29
    struct spa_process_latency_info process_latency;
30
 
31
+   struct spa_pod *tag2;
32
+
33
    /* Rate match via an ALSA ctl */
34
    snd_ctl_t *ctl;
35
    snd_ctl_elem_value_t *pitch_elem;
36
pipewire-0.3.81.tar.gz/spa/plugins/alsa/alsa-seq-bridge.c -> pipewire-0.3.82.tar.gz/spa/plugins/alsa/alsa-seq-bridge.c Changed
9
 
1
@@ -195,6 +195,7 @@
2
    { SPA_KEY_DEVICE_API, "alsa" },
3
    { SPA_KEY_MEDIA_CLASS, "Midi/Bridge" },
4
    { SPA_KEY_NODE_DRIVER, "true" },
5
+   { "priority.driver", "1" },
6
 };
7
 
8
 static void emit_node_info(struct seq_state *this, bool full)
9
pipewire-0.3.81.tar.gz/spa/plugins/alsa/alsa.c -> pipewire-0.3.82.tar.gz/spa/plugins/alsa/alsa.c Changed
20
 
1
@@ -9,6 +9,8 @@
2
 #include <spa/support/plugin.h>
3
 #include <spa/support/log.h>
4
 
5
+#include "alsa.h"
6
+
7
 extern const struct spa_handle_factory spa_alsa_source_factory;
8
 extern const struct spa_handle_factory spa_alsa_sink_factory;
9
 extern const struct spa_handle_factory spa_alsa_udev_factory;
10
@@ -20,8 +22,7 @@
11
 extern const struct spa_handle_factory spa_alsa_compress_offload_device_factory;
12
 #endif
13
 
14
-struct spa_log_topic log_topic = SPA_LOG_TOPIC(0, "spa.alsa");
15
-struct spa_log_topic *alsa_log_topic = &log_topic;
16
+struct spa_log_topic alsa_log_topic = SPA_LOG_TOPIC(0, "spa.alsa");
17
 
18
 SPA_EXPORT
19
 int spa_handle_factory_enum(const struct spa_handle_factory **factory, uint32_t *index)
20
pipewire-0.3.81.tar.gz/spa/plugins/alsa/alsa.h -> pipewire-0.3.82.tar.gz/spa/plugins/alsa/alsa.h Changed
17
 
1
@@ -8,12 +8,12 @@
2
 #include <spa/support/log.h>
3
 
4
 #undef SPA_LOG_TOPIC_DEFAULT
5
-#define SPA_LOG_TOPIC_DEFAULT alsa_log_topic
6
-extern struct spa_log_topic *alsa_log_topic;
7
+#define SPA_LOG_TOPIC_DEFAULT &alsa_log_topic
8
+extern struct spa_log_topic alsa_log_topic;
9
 
10
 static inline void alsa_log_topic_init(struct spa_log *log)
11
 {
12
-   spa_log_topic_init(log, alsa_log_topic);
13
+   spa_log_topic_init(log, &alsa_log_topic);
14
 }
15
 
16
 #endif /* SPA_ALSA_H */
17
pipewire-0.3.81.tar.gz/spa/plugins/audioconvert/audioadapter.c -> pipewire-0.3.82.tar.gz/spa/plugins/audioconvert/audioadapter.c Changed
118
 
1
@@ -26,8 +26,8 @@
2
 #include <spa/debug/log.h>
3
 
4
 #undef SPA_LOG_TOPIC_DEFAULT
5
-#define SPA_LOG_TOPIC_DEFAULT log_topic
6
-static struct spa_log_topic *log_topic = &SPA_LOG_TOPIC(0, "spa.audioadapter");
7
+#define SPA_LOG_TOPIC_DEFAULT &log_topic
8
+static struct spa_log_topic log_topic = SPA_LOG_TOPIC(0, "spa.audioadapter");
9
 
10
 #define DEFAULT_ALIGN  16
11
 
12
@@ -153,7 +153,8 @@
13
 {
14
    struct impl *this = object;
15
    uint8_t buffer4096;
16
-   struct spa_pod_dynamic_builder b;
17
+   spa_auto(spa_pod_dynamic_builder) b = { 0 };
18
+   struct spa_pod_builder_state state;
19
    struct spa_result_node_params result;
20
    uint32_t count = 0;
21
    int res;
22
@@ -161,6 +162,9 @@
23
    spa_return_val_if_fail(this != NULL, -EINVAL);
24
    spa_return_val_if_fail(num != 0, -EINVAL);
25
 
26
+   spa_pod_dynamic_builder_init(&b, buffer, sizeof(buffer), 4096);
27
+   spa_pod_builder_get_state(&b.b, &state);
28
+
29
    result.id = id;
30
    result.next = start;
31
 next:
32
@@ -168,7 +172,7 @@
33
 
34
    spa_log_debug(this->log, "%p: %d id:%u", this, seq, id);
35
 
36
-   spa_pod_dynamic_builder_init(&b, buffer, sizeof(buffer), 4096);
37
+   spa_pod_builder_reset(&b.b, &state);
38
 
39
    switch (id) {
40
    case SPA_PARAM_EnumPortConfig:
41
@@ -215,16 +219,12 @@
42
    default:
43
        return -ENOENT;
44
    }
45
-
46
-   if (res == 1) {
47
-       spa_node_emit_result(&this->hooks, seq, 0, SPA_RESULT_TYPE_NODE_PARAMS, &result);
48
-       count++;
49
-   }
50
-   spa_pod_dynamic_builder_clean(&b);
51
-
52
    if (res != 1)
53
        return res;
54
 
55
+   spa_node_emit_result(&this->hooks, seq, 0, SPA_RESULT_TYPE_NODE_PARAMS, &result);
56
+   count++;
57
+
58
    if (count != num)
59
        goto next;
60
 
61
@@ -580,8 +580,9 @@
62
 static int recalc_tag(struct impl *this, struct spa_node *src, enum spa_direction direction,
63
        uint32_t port_id, struct spa_node *dst)
64
 {
65
-   struct spa_pod_builder b = { 0 };
66
-   uint8_t buffer1024;
67
+   spa_auto(spa_pod_dynamic_builder) b = { 0 };
68
+   struct spa_pod_builder_state state;
69
+   uint8_t buffer2048;
70
    struct spa_pod *param;
71
    uint32_t index = 0;
72
    struct spa_tag_info info;
73
@@ -592,26 +593,25 @@
74
    if (this->target == this->follower)
75
        return 0;
76
 
77
+   spa_pod_dynamic_builder_init(&b, buffer, sizeof(buffer), 2048);
78
+   spa_pod_builder_get_state(&b.b, &state);
79
+
80
    while (true) {
81
-       void *state = NULL;
82
-       spa_pod_builder_init(&b, buffer, sizeof(buffer));
83
+       void *tag_state = NULL;
84
+       spa_pod_builder_reset(&b.b, &state);
85
        if ((res = spa_node_port_enum_params_sync(src,
86
                        direction, port_id, SPA_PARAM_Tag,
87
-                       &index, NULL, &param, &b)) != 1) {
88
+                       &index, NULL, &param, &b.b)) != 1) {
89
            param = NULL;
90
            break;
91
        }
92
-       if ((res = spa_tag_parse(param, &info, &state)) < 0)
93
+       if ((res = spa_tag_parse(param, &info, &tag_state)) < 0)
94
            return res;
95
        if (info.direction == direction)
96
            break;
97
    }
98
-   if ((res = spa_node_port_set_param(dst,
99
-                   SPA_DIRECTION_REVERSE(direction), 0,
100
-                   SPA_PARAM_Tag, 0, param)) < 0)
101
-       return res;
102
-
103
-   return 0;
104
+   return spa_node_port_set_param(dst, SPA_DIRECTION_REVERSE(direction), 0,
105
+                   SPA_PARAM_Tag, 0, param);
106
 }
107
 
108
 
109
@@ -1755,7 +1755,7 @@
110
    this = (struct impl *) handle;
111
 
112
    this->log = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_Log);
113
-   spa_log_topic_init(this->log, log_topic);
114
+   spa_log_topic_init(this->log, &log_topic);
115
 
116
    this->cpu = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_CPU);
117
 
118
pipewire-0.3.81.tar.gz/spa/plugins/audioconvert/audioconvert.c -> pipewire-0.3.82.tar.gz/spa/plugins/audioconvert/audioconvert.c Changed
21
 
1
@@ -36,8 +36,8 @@
2
 #include "wavfile.h"
3
 
4
 #undef SPA_LOG_TOPIC_DEFAULT
5
-#define SPA_LOG_TOPIC_DEFAULT log_topic
6
-static struct spa_log_topic *log_topic = &SPA_LOG_TOPIC(0, "spa.audioconvert");
7
+#define SPA_LOG_TOPIC_DEFAULT &log_topic
8
+static struct spa_log_topic log_topic = SPA_LOG_TOPIC(0, "spa.audioconvert");
9
 
10
 #define DEFAULT_RATE       48000
11
 #define DEFAULT_CHANNELS   2
12
@@ -3354,7 +3354,7 @@
13
    this = (struct impl *) handle;
14
 
15
    this->log = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_Log);
16
-   spa_log_topic_init(this->log, log_topic);
17
+   spa_log_topic_init(this->log, &log_topic);
18
 
19
    this->cpu = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_CPU);
20
    if (this->cpu) {
21
pipewire-0.3.81.tar.gz/spa/plugins/audiomixer/audiomixer.c -> pipewire-0.3.82.tar.gz/spa/plugins/audiomixer/audiomixer.c Changed
21
 
1
@@ -23,8 +23,8 @@
2
 #include "mix-ops.h"
3
 
4
 #undef SPA_LOG_TOPIC_DEFAULT
5
-#define SPA_LOG_TOPIC_DEFAULT log_topic
6
-static struct spa_log_topic *log_topic = &SPA_LOG_TOPIC(0, "spa.audiomixer");
7
+#define SPA_LOG_TOPIC_DEFAULT &log_topic
8
+static struct spa_log_topic log_topic = SPA_LOG_TOPIC(0, "spa.audiomixer");
9
 
10
 #define DEFAULT_RATE       48000
11
 #define DEFAULT_CHANNELS   2
12
@@ -918,7 +918,7 @@
13
    this = (struct impl *) handle;
14
 
15
    this->log = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_Log);
16
-   spa_log_topic_init(this->log, log_topic);
17
+   spa_log_topic_init(this->log, &log_topic);
18
 
19
    this->data_loop = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_DataLoop);
20
    if (this->data_loop == NULL) {
21
pipewire-0.3.81.tar.gz/spa/plugins/audiomixer/mixer-dsp.c -> pipewire-0.3.82.tar.gz/spa/plugins/audiomixer/mixer-dsp.c Changed
21
 
1
@@ -23,8 +23,8 @@
2
 #include "mix-ops.h"
3
 
4
 #undef SPA_LOG_TOPIC_DEFAULT
5
-#define SPA_LOG_TOPIC_DEFAULT log_topic
6
-static struct spa_log_topic *log_topic = &SPA_LOG_TOPIC(0, "spa.mixer-dsp");
7
+#define SPA_LOG_TOPIC_DEFAULT &log_topic
8
+static struct spa_log_topic log_topic = SPA_LOG_TOPIC(0, "spa.mixer-dsp");
9
 
10
 #define MAX_BUFFERS    64
11
 #define MAX_PORTS  512
12
@@ -855,7 +855,7 @@
13
    this = (struct impl *) handle;
14
 
15
    this->log = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_Log);
16
-   spa_log_topic_init(this->log, log_topic);
17
+   spa_log_topic_init(this->log, &log_topic);
18
 
19
    this->data_loop = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_DataLoop);
20
    if (this->data_loop == NULL) {
21
pipewire-0.3.81.tar.gz/spa/plugins/avb/avb.c -> pipewire-0.3.82.tar.gz/spa/plugins/avb/avb.c Changed
16
 
1
@@ -7,11 +7,12 @@
2
 #include <spa/support/plugin.h>
3
 #include <spa/support/log.h>
4
 
5
+#include "avb.h"
6
+
7
 extern const struct spa_handle_factory spa_avb_sink_factory;
8
 extern const struct spa_handle_factory spa_avb_source_factory;
9
 
10
-struct spa_log_topic log_topic = SPA_LOG_TOPIC(0, "spa.avb");
11
-struct spa_log_topic *avb_log_topic = &log_topic;
12
+struct spa_log_topic avb_log_topic = SPA_LOG_TOPIC(0, "spa.avb");
13
 
14
 SPA_EXPORT
15
 int spa_handle_factory_enum(const struct spa_handle_factory **factory, uint32_t *index)
16
pipewire-0.3.81.tar.gz/spa/plugins/avb/avb.h -> pipewire-0.3.82.tar.gz/spa/plugins/avb/avb.h Changed
17
 
1
@@ -8,12 +8,12 @@
2
 #include <spa/support/log.h>
3
 
4
 #undef SPA_LOG_TOPIC_DEFAULT
5
-#define SPA_LOG_TOPIC_DEFAULT avb_log_topic
6
-extern struct spa_log_topic *avb_log_topic;
7
+#define SPA_LOG_TOPIC_DEFAULT &avb_log_topic
8
+extern struct spa_log_topic avb_log_topic;
9
 
10
 static inline void avb_log_topic_init(struct spa_log *log)
11
 {
12
-   spa_log_topic_init(log, avb_log_topic);
13
+   spa_log_topic_init(log, &avb_log_topic);
14
 }
15
 
16
 #endif /* SPA_AVB_H */
17
pipewire-0.3.81.tar.gz/spa/plugins/bluez5/sco-sink.c -> pipewire-0.3.82.tar.gz/spa/plugins/bluez5/sco-sink.c Changed
29
 
1
@@ -662,7 +662,9 @@
2
 
3
    /* Init mSBC if needed */
4
    if (this->transport->codec == HFP_AUDIO_CODEC_MSBC) {
5
-       sbc_init_msbc(&this->msbc, 0);
6
+       res = sbc_init_msbc(&this->msbc, 0);
7
+       if (res < 0)
8
+           return res;
9
        /* Libsbc expects audio samples by default in host endianness, mSBC requires little endian */
10
        this->msbc.endian = SBC_LE;
11
 
12
@@ -705,6 +707,7 @@
13
 fail:
14
    free(this->buffer);
15
    this->buffer = NULL;
16
+   sbc_finish(&this->msbc);
17
    return res;
18
 }
19
 
20
@@ -819,6 +822,8 @@
21
        this->buffer = NULL;
22
        this->buffer_head = this->buffer_next = this->buffer;
23
    }
24
+
25
+   sbc_finish(&this->msbc);
26
 }
27
 
28
 static int do_stop(struct impl *this)
29
pipewire-0.3.81.tar.gz/spa/plugins/bluez5/sco-source.c -> pipewire-0.3.82.tar.gz/spa/plugins/bluez5/sco-source.c Changed
30
 
1
@@ -687,7 +687,10 @@
2
 
3
    /* Init mSBC if needed */
4
    if (this->transport->codec == HFP_AUDIO_CODEC_MSBC) {
5
-       sbc_init_msbc(&this->msbc, 0);
6
+       res = sbc_init_msbc(&this->msbc, 0);
7
+       if (res < 0)
8
+           return res;
9
+
10
        /* Libsbc expects audio samples by default in host endianness, mSBC requires little endian */
11
        this->msbc.endian = SBC_LE;
12
        this->msbc_seq_initialized = false;
13
@@ -708,6 +711,7 @@
14
    return 0;
15
 
16
 fail:
17
+   sbc_finish(&this->msbc);
18
    return res;
19
 }
20
 
21
@@ -798,6 +802,8 @@
22
    spa_loop_invoke(this->data_loop, do_remove_transport_source, 0, NULL, 0, true, this);
23
 
24
    spa_bt_decode_buffer_clear(&port->buffer);
25
+
26
+   sbc_finish(&this->msbc);
27
 }
28
 
29
 static int do_stop(struct impl *this)
30
pipewire-0.3.81.tar.gz/spa/plugins/libcamera/libcamera.c -> pipewire-0.3.82.tar.gz/spa/plugins/libcamera/libcamera.c Changed
11
 
1
@@ -9,8 +9,7 @@
2
 
3
 #include "libcamera.h"
4
 
5
-struct spa_log_topic log_topic = SPA_LOG_TOPIC(0, "spa.libcamera");
6
-struct spa_log_topic *libcamera_log_topic = &log_topic;
7
+struct spa_log_topic libcamera_log_topic = SPA_LOG_TOPIC(0, "spa.libcamera");
8
 
9
 SPA_EXPORT
10
 int spa_handle_factory_enum(const struct spa_handle_factory **factory,
11
pipewire-0.3.81.tar.gz/spa/plugins/libcamera/libcamera.h -> pipewire-0.3.82.tar.gz/spa/plugins/libcamera/libcamera.h Changed
17
 
1
@@ -18,12 +18,12 @@
2
 extern const struct spa_handle_factory spa_libcamera_device_factory;
3
 
4
 #undef SPA_LOG_TOPIC_DEFAULT
5
-#define SPA_LOG_TOPIC_DEFAULT libcamera_log_topic
6
-extern struct spa_log_topic *libcamera_log_topic;
7
+#define SPA_LOG_TOPIC_DEFAULT &libcamera_log_topic
8
+extern struct spa_log_topic libcamera_log_topic;
9
 
10
 static inline void libcamera_log_topic_init(struct spa_log *log)
11
 {
12
-   spa_log_topic_init(log, libcamera_log_topic);
13
+   spa_log_topic_init(log, &libcamera_log_topic);
14
 }
15
 
16
 #ifdef __cplusplus
17
pipewire-0.3.81.tar.gz/spa/plugins/support/log-patterns.c -> pipewire-0.3.82.tar.gz/spa/plugins/support/log-patterns.c Changed
22
 
1
@@ -22,6 +22,7 @@
2
               struct spa_log_topic *t)
3
 {
4
    enum spa_log_level level = default_level;
5
+   bool has_custom_level = false;
6
    const char *topic = t->topic;
7
    struct support_log_pattern *pattern;
8
 
9
@@ -29,10 +30,11 @@
10
        if (fnmatch(pattern->pattern, topic, 0) != 0)
11
            continue;
12
        level = pattern->level;
13
-       t->has_custom_level = true;
14
+       has_custom_level = true;
15
    }
16
 
17
    t->level = level;
18
+   t->has_custom_level = has_custom_level;
19
 }
20
 
21
 int
22
pipewire-0.3.81.tar.gz/spa/plugins/support/node-driver.c -> pipewire-0.3.82.tar.gz/spa/plugins/support/node-driver.c Changed
77
 
1
@@ -8,6 +8,11 @@
2
 #include <string.h>
3
 #include <stdio.h>
4
 #include <fcntl.h>
5
+#if !defined(__FreeBSD__) && !defined(__MidnightBSD__)
6
+#include <linux/ethtool.h>
7
+#include <linux/sockios.h>
8
+#endif
9
+#include <net/if.h>
10
 
11
 #include <spa/support/plugin.h>
12
 #include <spa/support/log.h>
13
@@ -485,6 +490,33 @@
14
    return sizeof(struct impl);
15
 }
16
 
17
+int get_phc_index(struct spa_system *s, const char *name) {
18
+#ifdef ETHTOOL_GET_TS_INFO
19
+   struct ethtool_ts_info info = {0};
20
+   struct ifreq ifr = {0};
21
+   int fd, err;
22
+
23
+   info.cmd = ETHTOOL_GET_TS_INFO;
24
+   strncpy(ifr.ifr_name, name, IFNAMSIZ - 1);
25
+   ifr.ifr_data = (char *) &info;
26
+   fd = socket(AF_INET, SOCK_DGRAM, 0);
27
+
28
+   if (fd < 0) {
29
+       return -1;
30
+   }
31
+
32
+   err = spa_system_ioctl(s, fd, SIOCETHTOOL, &ifr);
33
+   close(fd);
34
+   if (err < 0) {
35
+       return err;
36
+   }
37
+
38
+   return info.phc_index;
39
+#else
40
+   return -1;
41
+#endif
42
+}
43
+
44
 static int
45
 impl_init(const struct spa_handle_factory *factory,
46
      struct spa_handle *handle,
47
@@ -553,9 +585,28 @@
48
                this->props.clock_id = DEFAULT_CLOCK_ID;
49
            }
50
        } else if (spa_streq(k, "clock.device")) {
51
+           if (this->clock_fd >= 0) {
52
+               close(this->clock_fd);
53
+           }
54
            this->clock_fd = open(s, O_RDWR);
55
+
56
+           if (this->clock_fd == -1) {
57
+               spa_log_warn(this->log, "failed to open clock device '%s'", s);
58
+           } else {
59
+               this->props.clock_id = FD_TO_CLOCKID(this->clock_fd);
60
+           }
61
+       } else if (spa_streq(k, "clock.interface") && this->clock_fd < 0) {
62
+           int phc_index = get_phc_index(this->data_system, s);
63
+           if (phc_index < 0) {
64
+               spa_log_warn(this->log, "failed to get phc device index for interface '%s'", s);
65
+           } else {
66
+               char dev19;
67
+               spa_scnprintf(dev, sizeof(dev), "/dev/ptp%d", phc_index);
68
+               this->clock_fd = open(dev, O_RDWR);
69
+           }
70
+
71
            if (this->clock_fd == -1) {
72
-               spa_log_info(this->log, "failed to open clock device '%s'", s);
73
+               spa_log_warn(this->log, "failed to open clock device '%s'", s);
74
            } else {
75
                this->props.clock_id = FD_TO_CLOCKID(this->clock_fd);
76
            }
77
pipewire-0.3.81.tar.gz/spa/plugins/v4l2/v4l2.c -> pipewire-0.3.82.tar.gz/spa/plugins/v4l2/v4l2.c Changed
17
 
1
@@ -7,12 +7,13 @@
2
 #include <spa/support/plugin.h>
3
 #include <spa/support/log.h>
4
 
5
+#include "v4l2.h"
6
+
7
 extern const struct spa_handle_factory spa_v4l2_source_factory;
8
 extern const struct spa_handle_factory spa_v4l2_udev_factory;
9
 extern const struct spa_handle_factory spa_v4l2_device_factory;
10
 
11
-struct spa_log_topic log_topic = SPA_LOG_TOPIC(0, "spa.v4l2");
12
-struct spa_log_topic *v4l2_log_topic = &log_topic;
13
+struct spa_log_topic v4l2_log_topic = SPA_LOG_TOPIC(0, "spa.v4l2");
14
 
15
 SPA_EXPORT
16
 int spa_handle_factory_enum(const struct spa_handle_factory **factory,
17
pipewire-0.3.81.tar.gz/spa/plugins/v4l2/v4l2.h -> pipewire-0.3.82.tar.gz/spa/plugins/v4l2/v4l2.h Changed
22
 
1
@@ -4,15 +4,17 @@
2
 
3
 #include <errno.h>
4
 
5
+#include <linux/videodev2.h>
6
+
7
 #include <spa/support/log.h>
8
 
9
 #undef SPA_LOG_TOPIC_DEFAULT
10
-#define SPA_LOG_TOPIC_DEFAULT v4l2_log_topic
11
-extern struct spa_log_topic *v4l2_log_topic;
12
+#define SPA_LOG_TOPIC_DEFAULT &v4l2_log_topic
13
+extern struct spa_log_topic v4l2_log_topic;
14
 
15
 static inline void v4l2_log_topic_init(struct spa_log *log)
16
 {
17
-   spa_log_topic_init(log, v4l2_log_topic);
18
+   spa_log_topic_init(log, &v4l2_log_topic);
19
 }
20
 
21
 struct spa_v4l2_device {
22
pipewire-0.3.81.tar.gz/spa/plugins/videoconvert/videoadapter.c -> pipewire-0.3.82.tar.gz/spa/plugins/videoconvert/videoadapter.c Changed
21
 
1
@@ -25,8 +25,8 @@
2
 #include <spa/debug/log.h>
3
 
4
 #undef SPA_LOG_TOPIC_DEFAULT
5
-#define SPA_LOG_TOPIC_DEFAULT log_topic
6
-static struct spa_log_topic *log_topic = &SPA_LOG_TOPIC(0, "spa.videoadapter");
7
+#define SPA_LOG_TOPIC_DEFAULT &log_topic
8
+static struct spa_log_topic log_topic = SPA_LOG_TOPIC(0, "spa.videoadapter");
9
 
10
 #define DEFAULT_ALIGN  16
11
 
12
@@ -1554,7 +1554,7 @@
13
    this = (struct impl *) handle;
14
 
15
    this->log = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_Log);
16
-   spa_log_topic_init(this->log, log_topic);
17
+   spa_log_topic_init(this->log, &log_topic);
18
 
19
    this->cpu = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_CPU);
20
 
21
pipewire-0.3.81.tar.gz/src/daemon/client-rt.conf.in -> pipewire-0.3.82.tar.gz/src/daemon/client-rt.conf.in Changed
9
 
1
@@ -111,6 +111,7 @@
2
 
3
 
4
 alsa.properties = {
5
+    #alsa.deny = false
6
     # ALSA params take a single value, an array  of values
7
     # or a range { min=.. max=... }
8
     #alsa.access =  MMAP_INTERLEAVED MMAP_NONINTERLEAVED RW_INTERLEAVED RW_NONINTERLEAVED 
9
pipewire-0.3.81.tar.gz/src/daemon/pipewire-aes67.conf.in -> pipewire-0.3.82.tar.gz/src/daemon/pipewire-aes67.conf.in Changed
27
 
1
@@ -23,9 +23,11 @@
2
 }
3
 
4
 context.objects = 
5
-    # An example clock reading from /dev/ptp0. Another option is to sync the
6
-    # ptp clock to CLOCK_TAI and then set clock.id = tai.
7
-    # If both device and ID are given and available, device takes precedence
8
+    # An example clock reading from /dev/ptp0. You can also specify the network interface name,
9
+    # pipewire will query the interface for the current active PHC index. Another option is to
10
+    # sync the ptp clock to CLOCK_TAI and then set clock.id = tai, keep in mind that tai may
11
+    # also be synced by a NTP client.
12
+    # The precedence is: device, interface, id
13
     { factory = spa-node-factory
14
         args = {
15
             factory.name    = support.node.driver
16
@@ -34,8 +36,9 @@
17
             # This driver should only be used for network nodes marked with group
18
             priority.driver = 0
19
             clock.name      = "clock.system.ptp0"
20
+            #clock.id        = tai
21
             clock.device    = "/dev/ptp0"
22
-            clock.id        = tai
23
+            #clock.interface = "eth0"
24
             object.export   = true
25
         }
26
     }
27
pipewire-0.3.81.tar.gz/src/daemon/pipewire.conf.in -> pipewire-0.3.82.tar.gz/src/daemon/pipewire.conf.in Changed
15
 
1
@@ -102,7 +102,12 @@
2
     }
3
 
4
     # The native communication protocol.
5
-    { name = libpipewire-module-protocol-native }
6
+    { name = libpipewire-module-protocol-native
7
+        args = {
8
+            # List of server Unix sockets, and optionally permissions
9
+            #sockets =  { name = "pipewire-0" }, { name = "pipewire-manager-0" } 
10
+        }
11
+    }
12
 
13
     # The profile module. Allows application to access profiler
14
     # and performance data. It provides an interface that is used
15
pipewire-0.3.81.tar.gz/src/modules/flatpak-utils.h -> pipewire-0.3.82.tar.gz/src/modules/flatpak-utils.h Changed
31
 
1
@@ -76,20 +76,20 @@
2
    spa_autoclose int root_fd = openat(AT_FDCWD, root_path, O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_CLOEXEC | O_NOCTTY);
3
    if (root_fd < 0) {
4
        res = -errno;
5
+       pw_log_info("failed to open \"%s\": %s", root_path, spa_strerror(res));
6
+
7
        if (res == -EACCES) {
8
-           struct statfs buf;
9
-           /* Access to the root dir isn't allowed. This can happen if the root is on a fuse
10
-            * filesystem, such as in a toolbox container. We will never have a fuse rootfs
11
-            * in the flatpak case, so in that case its safe to ignore this and
12
-            * continue to detect other types of apps. */
13
-           if (statfs(root_path, &buf) == 0 &&
14
-               buf.f_type == 0x65735546) /* FUSE_SUPER_MAGIC */
15
-               return 0;
16
+           /* If we can't access the root filesystem, consider not sandboxed.
17
+            * This should not happen but for now it is a workaround for selinux
18
+            * where we can't access the gnome-shell root when it connects for
19
+            * screen sharing.
20
+            */
21
+           return 0;
22
        }
23
+
24
        /* Not able to open the root dir shouldn't happen. Probably the app died and
25
         * we're failing due to /proc/$pid not existing. In that case fail instead
26
         * of treating this as privileged. */
27
-       pw_log_info("failed to open \"%s\": %s", root_path, spa_strerror(res));
28
        return res;
29
    }
30
 
31
pipewire-0.3.81.tar.gz/src/modules/meson.build -> pipewire-0.3.82.tar.gz/src/modules/meson.build Changed
28
 
1
@@ -313,6 +313,10 @@
2
   pipewire_module_protocol_deps += systemd_dep
3
 endif
4
 
5
+if selinux_dep.found()
6
+  pipewire_module_protocol_deps += selinux_dep
7
+endif
8
+
9
 pipewire_module_protocol_native = shared_library('pipewire-module-protocol-native',
10
    'module-protocol-native.c',
11
     'module-protocol-native/local-socket.c',
12
@@ -607,12 +611,13 @@
13
 if build_module_raop
14
   pipewire_module_raop_sink = shared_library('pipewire-module-raop-sink',
15
      'module-raop-sink.c',
16
-      'module-raop/rtsp-client.c' ,
17
+      'module-raop/rtsp-client.c',
18
+      'module-rtp/stream.c' ,
19
     include_directories : configinc,
20
     install : true,
21
     install_dir : modules_install_dir,
22
     install_rpath: modules_install_dir,
23
-    dependencies : mathlib, dl_lib, rt_lib, pipewire_dep, openssl_lib,
24
+    dependencies : mathlib, dl_lib, rt_lib, pipewire_dep, opus_dep, openssl_lib,
25
   )
26
 endif
27
 summary({'raop-sink (requires OpenSSL)': build_module_raop}, bool_yn: true, section: 'Optional Modules')
28
pipewire-0.3.81.tar.gz/src/modules/module-access.c -> pipewire-0.3.82.tar.gz/src/modules/module-access.c Changed
21
 
1
@@ -263,17 +263,11 @@
2
 
3
    res = pw_check_flatpak(pid, &flatpak_app_id, NULL);
4
    if (res != 0) {
5
-       if (res < 0) {
6
-           if (res == -EACCES) {
7
-               access = "unrestricted";
8
-               goto granted;
9
-           }
10
+       if (res < 0)
11
            pw_log_warn("%p: client %p sandbox check failed: %s",
12
                impl, client, spa_strerror(res));
13
-       }
14
-       else if (res > 0) {
15
+       else
16
            pw_log_debug(" %p: flatpak client %p added", impl, client);
17
-       }
18
        access = "flatpak";
19
        itemsnitems++ = SPA_DICT_ITEM_INIT("pipewire.access.portal.app_id",
20
                flatpak_app_id);
21
pipewire-0.3.81.tar.gz/src/modules/module-filter-chain.c -> pipewire-0.3.82.tar.gz/src/modules/module-filter-chain.c Changed
21
 
1
@@ -147,7 +147,9 @@
2
  *
3
  * Normally the volume of the sink/source is handled by the stream software volume.
4
  * With the capture.volumes and playback.volumes properties this can be handled
5
- * by a control port in the graph instead.
6
+ * by a control port in the graph instead. Use capture.volumes for the volume of the
7
+ * input of the filter (when for example used as a sink). Use playback,volumes for
8
+ * the volume of the output of the filter (when for example used as a source).
9
  *
10
  * The min and max values (defaults 0.0 and 1.0) respectively can be used to scale
11
  * and translate the volume min and max values.
12
@@ -1947,7 +1949,7 @@
13
 /**
14
  * {
15
  *   control = name:portname
16
- *   min = <float, defaukt 0.0>
17
+ *   min = <float, default 0.0>
18
  *   max = <float, default 1.0>
19
  *   scale = <string, default "linear", options "linear","cubic">
20
  * }
21
pipewire-0.3.81.tar.gz/src/modules/module-protocol-native.c -> pipewire-0.3.82.tar.gz/src/modules/module-protocol-native.c Changed
358
 
1
@@ -15,9 +15,13 @@
2
 #include <fcntl.h>
3
 #include <sys/file.h>
4
 #include <ctype.h>
5
+#include <limits.h>
6
 #ifdef HAVE_PWD_H
7
 #include <pwd.h>
8
 #endif
9
+#ifdef HAVE_GRP_H
10
+#include <grp.h>
11
+#endif
12
 #if defined(__FreeBSD__) || defined(__MidnightBSD__)
13
 #include <sys/ucred.h>
14
 #endif
15
@@ -27,13 +31,19 @@
16
 #include <spa/pod/builder.h>
17
 #include <spa/utils/result.h>
18
 #include <spa/utils/string.h>
19
+#include <spa/utils/json.h>
20
 
21
 #ifdef HAVE_SYSTEMD
22
 #include <systemd/sd-daemon.h>
23
 #endif
24
 
25
+#ifdef HAVE_SELINUX
26
+#include <selinux/selinux.h>
27
+#endif
28
+
29
 #include <pipewire/impl.h>
30
 #include <pipewire/extensions/protocol-native.h>
31
+#include <pipewire/cleanup.h>
32
 
33
 #include "pipewire/private.h"
34
 
35
@@ -63,7 +73,17 @@
36
  *
37
  * ## Module Options
38
  *
39
- * The module has no options.
40
+ * The module supports the following arguments:
41
+ *
42
+ * - `sockets`: ` { name = "socket-name", owner = "owner", group = "group", mode = "mode", selinux.context = "context" }, ... `
43
+ *
44
+ *   Array of Unix socket names and (optionally) owner/permissions to serve,
45
+ *   if the context is a server. If not absolute paths, the sockets are created
46
+ *   in the default runtime directory. If not specified, one socket with
47
+ *   a default name is created.
48
+ *
49
+ *   The permissions have no effect for sockets from Systemd socket activation.
50
+ *   Those should be configured via the systemd.socket(5) mechanism.
51
  *
52
  * ## General Options
53
  *
54
@@ -107,6 +127,13 @@
55
    { name = libpipewire-module-protocol-native }
56
  * 
57
  *\endcode
58
+ *
59
+ *\code{.unparsed}
60
+ * context.modules = 
61
+ *  { name = libpipewire-module-protocol-native,
62
+ *    args = { sockets =  { name = "pipewire-0" }, { name = "pipewire-1" }  } }
63
+ * 
64
+ *\endcode
65
  */
66
 
67
 #ifndef UNIX_PATH_MAX
68
@@ -165,12 +192,23 @@
69
        free(impl);
70
 }
71
 
72
+struct socket_info {
73
+   char *name;
74
+   uid_t uid;
75
+   gid_t gid;
76
+   int mode;
77
+   char *selinux_context;
78
+   unsigned int has_owner:1;
79
+   unsigned int has_mode:1;
80
+};
81
+
82
 struct server {
83
    struct pw_protocol_server this;
84
 
85
    int fd_lock;
86
    struct sockaddr_un addr;
87
    char lock_addrUNIX_PATH_MAX + LOCK_SUFFIXLEN;
88
+   struct socket_info socket_info;
89
 
90
    struct pw_loop *loop;
91
    struct spa_source *source;
92
@@ -540,6 +578,8 @@
93
    if (props == NULL)
94
        goto exit;
95
 
96
+   pw_properties_set(props, PW_KEY_SEC_SOCKET, s->socket_info.name);
97
+
98
 #if defined(__linux__)
99
    len = sizeof(ucred);
100
    if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &len) < 0) {
101
@@ -789,6 +829,31 @@
102
    return res;
103
 }
104
 
105
+static int set_socket_permissions(struct server *s)
106
+{
107
+   struct socket_info *info = &s->socket_info;
108
+   const char *path = s->addr.sun_path;
109
+
110
+   if (info->has_owner)
111
+       if (chown(path, info->uid, info->gid) < 0)
112
+           return -errno;
113
+
114
+   if (info->has_mode)
115
+       if (chmod(path, info->mode) < 0)
116
+           return -errno;
117
+
118
+   if (info->selinux_context) {
119
+#ifdef HAVE_SELINUX
120
+       if (setfilecon(path, info->selinux_context) < 0)
121
+           return -errno;
122
+#else
123
+       return -EOPNOTSUPP;
124
+#endif
125
+   }
126
+
127
+   return 0;
128
+}
129
+
130
 static int add_socket(struct pw_protocol *protocol, struct server *s)
131
 {
132
    socklen_t size;
133
@@ -836,11 +901,22 @@
134
            goto error_close;
135
        }
136
 
137
+       if ((res = set_socket_permissions(s)) < 0) {
138
+           errno = -res;
139
+           pw_log_error("server %p: failed to set socket %s permissions: %m",
140
+                   s, s->socket_info.name);
141
+           goto error_close;
142
+       }
143
+
144
        if (listen(fd, 128) < 0) {
145
            res = -errno;
146
            pw_log_error("server %p: listen() failed with error: %m", s);
147
            goto error_close;
148
        }
149
+   } else {
150
+       if (s->socket_info.has_owner || s->socket_info.has_mode || s->socket_info.selinux_context)
151
+           pw_log_info("server %p: permissions ignored for socket %s from systemd",
152
+                   s, s->socket_info.name);
153
    }
154
 
155
    res = write_socket_address(s);
156
@@ -1250,6 +1326,8 @@
157
        unlink(s->lock_addr);
158
    if (s->fd_lock != -1)
159
        close(s->fd_lock);
160
+   free(s->socket_info.name);
161
+   free(s->socket_info.selinux_context);
162
    free(s);
163
 }
164
 
165
@@ -1311,9 +1389,10 @@
166
 }
167
 
168
 static struct pw_protocol_server *
169
-impl_add_server(struct pw_protocol *protocol,
170
+add_server(struct pw_protocol *protocol,
171
        struct pw_impl_core *core,
172
-                const struct spa_dict *props)
173
+       const struct spa_dict *props,
174
+       struct socket_info *socket_info)
175
 {
176
    struct pw_protocol_server *this;
177
    struct server *s;
178
@@ -1325,7 +1404,16 @@
179
 
180
    this = &s->this;
181
 
182
-   name = get_server_name(props);
183
+   if (socket_info) {
184
+       s->socket_info = *socket_info;
185
+       s->socket_info.name = strdup(socket_info->name);
186
+       s->socket_info.selinux_context = socket_info->selinux_context ?
187
+           strdup(socket_info->selinux_context) : NULL;
188
+       name = socket_info->name;
189
+   } else {
190
+       name = get_server_name(props);
191
+       s->socket_info.name = strdup(name);
192
+   }
193
 
194
    if ((res = init_socket_name(s, name)) < 0)
195
        goto error;
196
@@ -1349,6 +1437,14 @@
197
    return NULL;
198
 }
199
 
200
+static struct pw_protocol_server *
201
+impl_add_server(struct pw_protocol *protocol,
202
+       struct pw_impl_core *core,
203
+                const struct spa_dict *props)
204
+{
205
+   return add_server(protocol, core, props, NULL);
206
+}
207
+
208
 static const struct pw_protocol_implementation protocol_impl = {
209
    PW_VERSION_PROTOCOL_IMPLEMENTATION,
210
    .new_client = impl_new_client,
211
@@ -1462,14 +1558,121 @@
212
    return 0;
213
 }
214
 
215
+static int create_servers(struct pw_protocol *this, struct pw_impl_core *core,
216
+       const struct pw_properties *props, const struct pw_properties *args)
217
+{
218
+   const char *sockets = args ? pw_properties_get(args, "sockets") : NULL;
219
+   struct spa_json it3;
220
+
221
+   if (sockets == NULL) {
222
+       if (add_server(this, core, &props->dict, NULL) == NULL)
223
+           return -errno;
224
+
225
+       return 0;
226
+   }
227
+
228
+   spa_json_init(&it0, sockets, strlen(sockets));
229
+
230
+   if (spa_json_enter_array(&it0, &it1) <= 0)
231
+       goto error_invalid;
232
+
233
+   while (spa_json_enter_object(&it1, &it2) > 0) {
234
+       struct socket_info info = {0};
235
+       char key256;
236
+       char namePATH_MAX;
237
+       char selinux_contextPATH_MAX;
238
+
239
+       info.uid = getuid();
240
+       info.gid = getgid();
241
+
242
+       while (spa_json_get_string(&it2, key, sizeof(key)) > 0) {
243
+           const char *value;
244
+           int len;
245
+
246
+           if ((len = spa_json_next(&it2, &value)) <= 0)
247
+               goto error_invalid;
248
+
249
+           if (spa_streq(key, "name")) {
250
+               if (spa_json_parse_stringn(value, len, name, sizeof(name)) < 0)
251
+                   goto error_invalid;
252
+               info.name = name;
253
+           } else if (spa_streq(key, "selinux.context")) {
254
+               if (spa_json_parse_stringn(value, len, selinux_context, sizeof(selinux_context)) < 0)
255
+                   goto error_invalid;
256
+               info.selinux_context = selinux_context;
257
+           } else if (spa_streq(key, "owner")) {
258
+               char buffer16384;
259
+               char ownerPATH_MAX;
260
+               struct passwd pwd, *result = NULL;
261
+               int64_t val;
262
+
263
+               if (spa_json_parse_stringn(value, len, owner, sizeof(owner)) < 0)
264
+                   goto error_invalid;
265
+
266
+               if (spa_atoi64(owner, &val, 10))
267
+                   info.uid = val;
268
+               else if (getpwnam_r(owner, &pwd, buffer, sizeof(buffer), &result) == 0 && result)
269
+                   info.uid = result->pw_uid;
270
+               else
271
+                   goto error_invalid;
272
+
273
+               info.has_owner = true;
274
+           } else if (spa_streq(key, "group")) {
275
+               char buffer16384;
276
+               char groupPATH_MAX;
277
+               struct group grp, *result = NULL;
278
+               int64_t val;
279
+
280
+               if (spa_json_parse_stringn(value, len, group, sizeof(group)) < 0)
281
+                   goto error_invalid;
282
+
283
+               if (spa_atoi64(group, &val, 10))
284
+                   info.gid = val;
285
+               else if (getgrnam_r(group, &grp, buffer, sizeof(buffer), &result) == 0 && result)
286
+                   info.gid = result->gr_gid;
287
+               else
288
+                   goto error_invalid;
289
+
290
+               info.has_owner = true;
291
+           } else if (spa_streq(key, "mode")) {
292
+               char modePATH_MAX;
293
+               int64_t val;
294
+
295
+               if (spa_json_parse_stringn(value, len, mode, sizeof(mode)) < 0)
296
+                   goto error_invalid;
297
+
298
+               if (spa_atoi64(mode, &val, 0))
299
+                   info.mode = val;
300
+               else
301
+                   goto error_invalid;
302
+
303
+               info.has_mode = true;
304
+           }
305
+       }
306
+
307
+       if (info.name == NULL)
308
+           goto error_invalid;
309
+
310
+       if (add_server(this, core, &props->dict, &info) == NULL)
311
+           return -errno;
312
+   }
313
+
314
+   return 0;
315
+
316
+error_invalid:
317
+   pw_log_error("invalid module 'sockets' argument: %s", sockets);
318
+   return -EINVAL;
319
+}
320
+
321
 SPA_EXPORT
322
-int pipewire__module_init(struct pw_impl_module *module, const char *args)
323
+int pipewire__module_init(struct pw_impl_module *module, const char *args_str)
324
 {
325
    struct pw_context *context = pw_impl_module_get_context(module);
326
    struct pw_protocol *this;
327
    struct pw_impl_core *core = context->core;
328
    struct protocol_data *d;
329
    const struct pw_properties *props;
330
+   spa_autoptr(pw_properties) args = NULL;
331
    int res;
332
 
333
    PW_LOG_TOPIC_INIT(mod_topic);
334
@@ -1480,6 +1683,8 @@
335
        return -EEXIST;
336
    }
337
 
338
+   args = args_str ? pw_properties_new_string(args_str) : NULL;
339
+
340
    this = pw_protocol_new(context, PW_TYPE_INFO_PROTOCOL_Native, sizeof(struct protocol_data));
341
    if (this == NULL)
342
        return -errno;
343
@@ -1501,12 +1706,9 @@
344
    props = pw_context_get_properties(context);
345
    d->local = create_server(this, core, &props->dict);
346
 
347
-   if (need_server(context, &props->dict)) {
348
-       if (impl_add_server(this, core, &props->dict) == NULL) {
349
-           res = -errno;
350
+   if (need_server(context, &props->dict))
351
+       if ((res = create_servers(this, core, props, args)) < 0)
352
            goto error_cleanup;
353
-       }
354
-   }
355
 
356
    pw_impl_module_add_listener(module, &d->module_listener, &module_events, d);
357
 
358
pipewire-0.3.81.tar.gz/src/modules/module-protocol-pulse/manager.h -> pipewire-0.3.82.tar.gz/src/modules/module-protocol-pulse/manager.h Changed
27
 
1
@@ -9,11 +9,14 @@
2
 extern "C" {
3
 #endif
4
 
5
+#include <stdio.h>
6
+
7
 #include <spa/utils/defs.h>
8
 #include <spa/pod/pod.h>
9
 
10
 #include <pipewire/pipewire.h>
11
 
12
+struct client;
13
 struct pw_manager_object;
14
 
15
 struct pw_manager_events {
16
@@ -68,8 +71,8 @@
17
    struct pw_properties *props;
18
    struct pw_proxy *proxy;
19
    char *message_object_path;
20
-   int (*message_handler)(struct pw_manager *m, struct pw_manager_object *o,
21
-                          const char *message, const char *params, char **response);
22
+   int (*message_handler)(struct client *client, struct pw_manager_object *o,
23
+                          const char *message, const char *params, FILE *response);
24
 
25
    void *info;
26
    struct spa_param_info *params;
27
pipewire-0.3.81.tar.gz/src/modules/module-protocol-pulse/message-handler.c -> pipewire-0.3.82.tar.gz/src/modules/module-protocol-pulse/message-handler.c Changed
119
 
1
@@ -3,8 +3,10 @@
2
 /* SPDX-License-Identifier: MIT */
3
 
4
 #include <stdint.h>
5
+#include <stdio.h>
6
 
7
 #include <regex.h>
8
+#include <malloc.h>
9
 
10
 #include <spa/param/props.h>
11
 #include <spa/pod/builder.h>
12
@@ -15,12 +17,13 @@
13
 
14
 #include <pipewire/pipewire.h>
15
 
16
+#include "client.h"
17
 #include "collect.h"
18
 #include "log.h"
19
 #include "manager.h"
20
 #include "message-handler.h"
21
 
22
-static int bluez_card_object_message_handler(struct pw_manager *m, struct pw_manager_object *o, const char *message, const char *params, char **response)
23
+static int bluez_card_object_message_handler(struct client *client, struct pw_manager_object *o, const char *message, const char *params, FILE *response)
24
 {
25
    struct transport_codec_info codecs64;
26
    uint32_t n_codecs, active;
27
@@ -60,66 +63,62 @@
28
 
29
        pw_device_set_param((struct pw_device *)o->proxy,
30
                SPA_PARAM_Props, 0, param);
31
-       return 0;
32
    } else if (spa_streq(message, "list-codecs")) {
33
        uint32_t i;
34
-       FILE *r;
35
-       size_t size;
36
        bool first = true;
37
 
38
-       r = open_memstream(response, &size);
39
-       if (r == NULL)
40
-           return -errno;
41
-
42
-       fputc('', r);
43
+       fputc('', response);
44
        for (i = 0; i < n_codecs; ++i) {
45
            const char *desc = codecsi.description;
46
-           fprintf(r, "%s{\"name\":\"%d\",\"description\":\"%s\"}",
47
+           fprintf(response, "%s{\"name\":\"%d\",\"description\":\"%s\"}",
48
                    first ? "" : ",",
49
                    (int)codecsi.id, desc ? desc : "Unknown");
50
            first = false;
51
        }
52
-       fputc('', r);
53
-
54
-       return fclose(r) ? -errno : 0;
55
+       fputc('', response);
56
    } else if (spa_streq(message, "get-codec")) {
57
        if (active == SPA_ID_INVALID)
58
-           *response = strdup("null");
59
+           fputs("null", response);
60
        else
61
-           *response = spa_aprintf("\"%d\"", (int)codecsactive.id);
62
-       return *response ? 0 : -ENOMEM;
63
+           fprintf(response, "\"%d\"", (int) codecsactive.id);
64
+   } else {
65
+       return -ENOSYS;
66
    }
67
 
68
-   return -ENOSYS;
69
+   return 0;
70
 }
71
 
72
-static int core_object_message_handler(struct pw_manager *m, struct pw_manager_object *o, const char *message, const char *params, char **response)
73
+static int core_object_message_handler(struct client *client, struct pw_manager_object *o, const char *message, const char *params, FILE *response)
74
 {
75
    pw_log_debug(": core %p object message:'%s' params:'%s'", o, message, params);
76
 
77
    if (spa_streq(message, "list-handlers")) {
78
-       FILE *r;
79
-       size_t size;
80
        bool first = true;
81
 
82
-       r = open_memstream(response, &size);
83
-       if (r == NULL)
84
-           return -errno;
85
-
86
-       fputc('', r);
87
-       spa_list_for_each(o, &m->object_list, link) {
88
+       fputc('', response);
89
+       spa_list_for_each(o, &client->manager->object_list, link) {
90
            if (o->message_object_path) {
91
-               fprintf(r, "%s{\"name\":\"%s\",\"description\":\"%s\"}",
92
+               fprintf(response, "%s{\"name\":\"%s\",\"description\":\"%s\"}",
93
                        first ? "" : ",",
94
                        o->message_object_path, o->type);
95
                first = false;
96
            }
97
        }
98
-       fputc('', r);
99
-       return fclose(r) ? -errno : 0;
100
+       fputc('', response);
101
+#ifdef HAVE_MALLOC_INFO
102
+   } else if (spa_streq(message, "pipewire-pulse:malloc-info")) {
103
+       malloc_info(0, response);
104
+#endif
105
+#ifdef HAVE_MALLOC_TRIM
106
+   } else if (spa_streq(message, "pipewire-pulse:malloc-trim")) {
107
+       int res = malloc_trim(0);
108
+       fprintf(response, "%d", res);
109
+#endif
110
+   } else {
111
+       return -ENOSYS;
112
    }
113
 
114
-   return -ENOSYS;
115
+   return 0;
116
 }
117
 
118
 void register_object_message_handlers(struct pw_manager_object *o)
119
pipewire-0.3.81.tar.gz/src/modules/module-protocol-pulse/pulse-server.c -> pipewire-0.3.82.tar.gz/src/modules/module-protocol-pulse/pulse-server.c Changed
101
 
1
@@ -1820,6 +1820,8 @@
2
            PW_STREAM_FLAG_MAP_BUFFERS,
3
            params, n_params);
4
 
5
+   stream_update_tag_param(stream);
6
+
7
    return 0;
8
 
9
 error_errno:
10
@@ -3215,7 +3217,8 @@
11
        if (stream == NULL || stream->type == STREAM_TYPE_UPLOAD)
12
            return -ENOENT;
13
 
14
-       pw_stream_update_properties(stream->stream, &props->dict);
15
+       if (pw_stream_update_properties(stream->stream, &props->dict) > 0)
16
+           stream_update_tag_param(stream);
17
    } else {
18
        if (pw_properties_update(client->props, &props->dict) > 0) {
19
            client_update_quirks(client);
20
@@ -5099,12 +5102,12 @@
21
 {
22
    struct impl *impl = client->impl;
23
    struct pw_manager *manager = client->manager;
24
-   const char *object_path = NULL;
25
-   const char *message = NULL;
26
-   const char *params = NULL;
27
-   struct message *reply;
28
+   const char *object_path = NULL, *message = NULL, *params = NULL;
29
    struct pw_manager_object *o;
30
-   int len = 0;
31
+   spa_autofree char *response_str = NULL;
32
+   size_t path_len = 0, response_len = 0;
33
+   FILE *response;
34
+   int res = -ENOENT;
35
 
36
    if (message_get(m,
37
            TAG_STRING, &object_path,
38
@@ -5120,36 +5123,42 @@
39
    if (object_path == NULL || message == NULL)
40
        return -EINVAL;
41
 
42
-   len = strlen(object_path);
43
-   if (len > 0 && object_pathlen - 1 == '/')
44
-       --len;
45
-
46
-   spa_autofree char *path = strndup(object_path, len);
47
+   path_len = strlen(object_path);
48
+   if (path_len > 0 && object_pathpath_len - 1 == '/')
49
+       --path_len;
50
+   spa_autofree char *path = strndup(object_path, path_len);
51
    if (path == NULL)
52
        return -ENOMEM;
53
 
54
-   spa_autofree char *response = NULL;
55
-   int res = -ENOENT;
56
-
57
    spa_list_for_each(o, &manager->object_list, link) {
58
-       if (o->message_object_path && spa_streq(o->message_object_path, path)) {
59
-           if (o->message_handler)
60
-               res = o->message_handler(manager, o, message, params, &response);
61
-           else
62
-               res = -ENOSYS;
63
+       if (spa_streq(o->message_object_path, path))
64
            break;
65
-       }
66
    }
67
+   if (spa_list_is_end(o, &manager->object_list, link))
68
+       return -ENOENT;
69
 
70
-   if (res < 0)
71
-       return res;
72
+   if (o->message_handler == NULL)
73
+       return -ENOSYS;
74
 
75
-   pw_log_debug("%p: object message response:'%s'", impl, response ? response : "<null>");
76
+   response = open_memstream(&response_str, &response_len);
77
+   if (response == NULL)
78
+       return -errno;
79
 
80
-   reply = reply_new(client, tag);
81
-   message_put(reply, TAG_STRING, response, TAG_INVALID);
82
+   res = o->message_handler(client, o, message, params, response);
83
 
84
-   return client_queue_message(client, reply);
85
+   if (fclose(response))
86
+       return -errno;
87
+
88
+   pw_log_debug("%p: object message response: (%d) '%s'", impl, res, response_str ? response_str : "<null>");
89
+
90
+   if (res >= 0) {
91
+       struct message *reply = reply_new(client, tag);
92
+
93
+       message_put(reply, TAG_STRING, response_str, TAG_INVALID);
94
+       res = client_queue_message(client, reply);
95
+   }
96
+
97
+   return res;
98
 }
99
 
100
 static int do_error_access(struct client *client, uint32_t command, uint32_t tag, struct message *m)
101
pipewire-0.3.81.tar.gz/src/modules/module-protocol-pulse/stream.c -> pipewire-0.3.82.tar.gz/src/modules/module-protocol-pulse/stream.c Changed
48
 
1
@@ -8,6 +8,9 @@
2
 
3
 #include <spa/utils/hook.h>
4
 #include <spa/utils/ringbuffer.h>
5
+#include <spa/pod/dynamic.h>
6
+#include <spa/param/tag-utils.h>
7
+
8
 #include <pipewire/log.h>
9
 #include <pipewire/loop.h>
10
 #include <pipewire/map.h>
11
@@ -412,3 +415,36 @@
12
    }
13
    return client_queue_message(client, reply);
14
 }
15
+
16
+int stream_update_tag_param(struct stream *stream)
17
+{
18
+   struct spa_pod_dynamic_builder b;
19
+   const struct pw_properties *props = pw_stream_get_properties(stream->stream);
20
+   const struct spa_pod *param1;
21
+   struct spa_dict_item items64;
22
+   uint32_t i, n_items = 0;
23
+   uint8_t buffer4096;
24
+
25
+   if (props == NULL)
26
+       return -EIO;
27
+
28
+   spa_pod_dynamic_builder_init(&b, buffer, sizeof(buffer), 4096);
29
+
30
+   for (i = 0; i < props->dict.n_items; i++) {
31
+       if (n_items < SPA_N_ELEMENTS(items) &&
32
+           spa_strstartswith(props->dict.itemsi.key, "media."))
33
+               itemsn_items++ = props->dict.itemsi;
34
+   }
35
+   if (n_items > 0) {
36
+       struct spa_pod_frame f;
37
+       spa_tag_build_start(&b.b, &f, SPA_PARAM_Tag, SPA_DIRECTION_OUTPUT);
38
+       spa_tag_build_add_dict(&b.b, &SPA_DICT_INIT(items, n_items));
39
+       param0 = spa_tag_build_end(&b.b, &f);
40
+   } else {
41
+       param0 = NULL;
42
+   }
43
+   if (param0 != NULL)
44
+       pw_stream_update_params(stream->stream, param, 1);
45
+   spa_pod_dynamic_builder_clean(&b);
46
+   return 0;
47
+}
48
pipewire-0.3.81.tar.gz/src/modules/module-protocol-pulse/stream.h -> pipewire-0.3.82.tar.gz/src/modules/module-protocol-pulse/stream.h Changed
8
 
1
@@ -116,5 +116,6 @@
2
 int stream_send_request(struct stream *stream);
3
 int stream_update_minreq(struct stream *stream, uint32_t minreq);
4
 int stream_send_moved(struct stream *stream, uint32_t peer_index, const char *peer_name);
5
+int stream_update_tag_param(struct stream *stream);
6
 
7
 #endif /* PULSER_SERVER_STREAM_H */
8
pipewire-0.3.81.tar.gz/src/modules/module-raop-sink.c -> pipewire-0.3.82.tar.gz/src/modules/module-raop-sink.c Changed
1019
 
1
@@ -45,6 +45,7 @@
2
 
3
 #include "module-raop/rtsp-client.h"
4
 #include "module-rtp/rtp.h"
5
+#include "module-rtp/stream.h"
6
 
7
 /** \page page_module_raop_sink PipeWire Module: AirPlay Sink
8
  *
9
@@ -121,36 +122,37 @@
10
 PW_LOG_TOPIC_STATIC(mod_topic, "mod." NAME);
11
 #define PW_LOG_TOPIC_DEFAULT mod_topic
12
 
13
-#define FRAMES_PER_TCP_PACKET 4096
14
-#define FRAMES_PER_UDP_PACKET 352
15
+#define BUFFER_SIZE        (1u<<22)
16
+#define BUFFER_MASK        (BUFFER_SIZE-1)
17
+#define BUFFER_SIZE2       (BUFFER_SIZE>>1)
18
+#define BUFFER_MASK2       (BUFFER_SIZE2-1)
19
 
20
-#define RAOP_LATENCY_MIN   11025u
21
-#define DEFAULT_LATENCY_MS "1500"
22
+#define FRAMES_PER_TCP_PACKET  4096
23
+#define FRAMES_PER_UDP_PACKET  352
24
 
25
-#define DEFAULT_TCP_AUDIO_PORT   6000
26
-#define DEFAULT_UDP_AUDIO_PORT   6000
27
-#define DEFAULT_UDP_CONTROL_PORT 6001
28
-#define DEFAULT_UDP_TIMING_PORT  6002
29
+#define RAOP_AUDIO_PORT        6000
30
+#define RAOP_UDP_CONTROL_PORT  6001
31
+#define RAOP_UDP_TIMING_PORT   6002
32
 
33
 #define AES_CHUNK_SIZE     16
34
 #ifndef MD5_DIGEST_LENGTH
35
 #define MD5_DIGEST_LENGTH  16
36
 #endif
37
-#define MD5_HASH_LENGTH (2*MD5_DIGEST_LENGTH)
38
+#define MD5_HASH_LENGTH        (2*MD5_DIGEST_LENGTH)
39
 
40
 #define DEFAULT_USER_NAME  "PipeWire"
41
 #define RAOP_AUTH_USER_NAME    "iTunes"
42
 
43
-#define MAX_PORT_RETRY 128
44
+#define MAX_PORT_RETRY     128
45
 
46
-#define DEFAULT_FORMAT "S16"
47
-#define DEFAULT_RATE 44100
48
-#define DEFAULT_CHANNELS 2
49
-#define DEFAULT_POSITION " FL FR "
50
+#define RAOP_FORMAT        "S16LE"
51
+#define RAOP_STRIDE        (2*DEFAULT_CHANNELS)
52
+#define RAOP_RATE      44100
53
+#define RAOP_LATENCY_MS        250
54
 
55
-#define VOLUME_MAX 0.0
56
-#define VOLUME_MIN -30.0
57
-#define VOLUME_MUTE    -144.0
58
+#define VOLUME_MAX     0.0
59
+#define VOLUME_MIN     -30.0
60
+#define VOLUME_MUTE        -144.0
61
 
62
 #define MODULE_USAGE   "( raop.ip=<ip address of host> ) "                 \
63
            "( raop.port=<remote port> ) "                      \
64
@@ -163,8 +165,8 @@
65
            "( node.latency=<latency as fraction> ) "               \
66
            "( node.name=<name of the nodes> ) "                    \
67
            "( node.description=<description of the nodes> ) "          \
68
-           "( audio.format=<format, default:"DEFAULT_FORMAT"> ) "          \
69
-           "( audio.rate=<sample rate, default: "SPA_STRINGIFY(DEFAULT_RATE)"> ) "         \
70
+           "( audio.format=<format, default:"RAOP_FORMAT"> ) "         \
71
+           "( audio.rate=<sample rate, default: "SPA_STRINGIFY(RAOP_RATE)"> ) "            \
72
            "( audio.channels=<number of channels, default:"SPA_STRINGIFY(DEFAULT_CHANNELS)"> ) "   \
73
            "( audio.position=<channel map, default:"DEFAULT_POSITION"> ) "     \
74
            "( stream.props=<properties> ) "
75
@@ -212,10 +214,7 @@
76
    struct spa_hook core_listener;
77
 
78
    struct pw_properties *stream_props;
79
-   struct pw_stream *stream;
80
-   struct spa_hook stream_listener;
81
-   struct spa_audio_info_raw info;
82
-   uint32_t frame_size;
83
+   struct rtp_stream *stream;
84
 
85
    struct pw_rtsp_client *rtsp;
86
    struct spa_hook rtsp_listener;
87
@@ -246,15 +245,15 @@
88
    int server_fd;
89
    struct spa_source *server_source;
90
 
91
-   uint32_t block_size;
92
+   uint32_t psamples;
93
+   uint64_t rate;
94
+   uint32_t mtu;
95
+   uint32_t stride;
96
    uint32_t latency;
97
 
98
-   uint16_t seq, cseq;
99
-   uint32_t rtptime;
100
    uint32_t ssrc;
101
    uint32_t sync;
102
    uint32_t sync_period;
103
-   unsigned int first:1;
104
    unsigned int connected:1;
105
    unsigned int ready:1;
106
    unsigned int recording:1;
107
@@ -262,17 +261,14 @@
108
    bool mute;
109
    float volume;
110
 
111
-   uint8_t bufferFRAMES_PER_TCP_PACKET * 4;
112
+   struct spa_ringbuffer ring;
113
+   uint8_t bufferBUFFER_SIZE;
114
+
115
+   struct spa_io_position *io_position;
116
+
117
    uint32_t filled;
118
 };
119
 
120
-static void stream_destroy(void *d)
121
-{
122
-   struct impl *impl = d;
123
-   spa_hook_remove(&impl->stream_listener);
124
-   impl->stream = NULL;
125
-}
126
-
127
 static inline void bit_writer(uint8_t **p, int *pos, uint8_t data, int len)
128
 {
129
    int rb = 8 - *pos - len;
130
@@ -307,11 +303,9 @@
131
    return timespec_to_ntp(&now);
132
 }
133
 
134
-static int send_udp_sync_packet(struct impl *impl,
135
-       struct sockaddr *dest_addr, socklen_t addrlen)
136
+static int send_udp_sync_packet(struct impl *impl, uint32_t rtptime, unsigned int first)
137
 {
138
    uint32_t out3;
139
-   uint32_t rtptime = impl->rtptime;
140
    uint32_t latency = impl->latency;
141
    uint64_t transmitted;
142
    struct rtp_header header;
143
@@ -321,11 +315,11 @@
144
 
145
    spa_zero(header);
146
    header.v = 2;
147
-   if (impl->first)
148
+   if (first)
149
        header.x = 1;
150
    header.m = 1;
151
    header.pt = 84;
152
-   header.sequence_number = htons(impl->cseq);
153
+   header.sequence_number = 7;
154
    header.timestamp = htonl(rtptime - latency);
155
 
156
    iov0.iov_base = &header;
157
@@ -339,8 +333,8 @@
158
    iov1.iov_base = out;
159
    iov1.iov_len = sizeof(out);
160
 
161
-   msg.msg_name = dest_addr;
162
-   msg.msg_namelen = addrlen;
163
+   msg.msg_name = NULL;
164
+   msg.msg_namelen = 0;
165
    msg.msg_iov = iov;
166
    msg.msg_iovlen = 2;
167
    msg.msg_control = NULL;
168
@@ -353,10 +347,8 @@
169
        pw_log_warn("error sending control packet: %d", res);
170
    }
171
 
172
-   impl->cseq = (impl->cseq + 1) & 0xffff;
173
-
174
-   pw_log_debug("raop control sync: cseq:%d first:%d latency:%u now:%"PRIx64" rtptime:%u",
175
-           impl->cseq, impl->first, latency, transmitted, rtptime);
176
+   pw_log_debug("raop control sync: first:%d latency:%u now:%"PRIx64" rtptime:%u",
177
+           first, latency, transmitted, rtptime);
178
 
179
    return res;
180
 }
181
@@ -440,194 +432,86 @@
182
    return bp - b + 1;
183
 }
184
 
185
-static int flush_to_udp_packet(struct impl *impl)
186
+static ssize_t send_packet(int fd, struct msghdr *msg)
187
 {
188
-   const size_t max = 8 + impl->block_size;
189
-   uint32_t outmax, len, n_frames;
190
-   struct rtp_header header;
191
-   struct iovec iov2;
192
+   ssize_t n;
193
+   n = sendmsg(fd, msg, MSG_NOSIGNAL);
194
+   if (n < 0)
195
+       pw_log_debug("sendmsg() failed: %m");
196
+   return n;
197
+}
198
+
199
+static void stream_send_packet(void *data, struct iovec *iov, size_t iovlen)
200
+{
201
+   struct impl *impl = data;
202
+   const size_t max = 8 + impl->mtu;
203
+   uint32_t tcp_pkt1, outmax, len, n_frames, rtptime;
204
+   struct iovec out_vec3;
205
+   struct rtp_header *header;
206
    struct msghdr msg;
207
    uint8_t *dst;
208
-   int res;
209
 
210
    if (!impl->recording)
211
-       return 0;
212
-
213
-   if (impl->first || ++impl->sync == impl->sync_period) {
214
-       impl->sync = 0;
215
-       send_udp_sync_packet(impl, NULL, 0);
216
-   }
217
-
218
-   spa_zero(header);
219
-   header.v = 2;
220
-   header.pt = 96;
221
-   if (impl->first)
222
-       header.m = 1;
223
-   header.sequence_number = htons(impl->seq);
224
-   header.timestamp = htonl(impl->rtptime);
225
-   header.ssrc = htonl(impl->ssrc);
226
+       return;
227
 
228
-   iov0.iov_base = &header;
229
-   iov0.iov_len = 12;
230
+   header = (struct rtp_header*)iov0.iov_base;
231
+   if (header->v != 2)
232
+       pw_log_warn("invalid rtp packet version");
233
 
234
-   n_frames = impl->filled / impl->frame_size;
235
-   dst = (uint8_t*)&out0;
236
+   rtptime = htonl(header->timestamp);
237
 
238
-   switch (impl->codec) {
239
-   case CODEC_PCM:
240
-   case CODEC_ALAC:
241
-       len = write_codec_pcm(dst, impl->buffer, n_frames);
242
-       break;
243
-   default:
244
-       len = 8 + impl->block_size;
245
-       memset(dst, 0, len);
246
-       break;
247
+   if (header->m || ++impl->sync == impl->sync_period) {
248
+       send_udp_sync_packet(impl, rtptime, header->m);
249
+       impl->sync = 0;
250
    }
251
-   if (impl->encryption == CRYPTO_RSA)
252
-       aes_encrypt(impl, dst, len);
253
-
254
-   iov1.iov_base = out;
255
-   iov1.iov_len = len;
256
 
257
-   impl->rtptime += n_frames;
258
-   impl->seq = (impl->seq + 1) & 0xffff;
259
+   n_frames = iov1.iov_len / impl->stride;
260
 
261
    msg.msg_name = NULL;
262
    msg.msg_namelen = 0;
263
-   msg.msg_iov = iov;
264
-   msg.msg_iovlen = 2;
265
+   msg.msg_iov = out_vec;
266
+   msg.msg_iovlen = 0;
267
    msg.msg_control = NULL;
268
    msg.msg_controllen = 0;
269
    msg.msg_flags = 0;
270
 
271
-   res = sendmsg(impl->server_fd, &msg, MSG_NOSIGNAL);
272
-   if (res < 0) {
273
-       res = -errno;
274
-       pw_log_warn("error streaming packet: %d", res);
275
-   }
276
-
277
-   impl->first = false;
278
-
279
-   return res;
280
-}
281
-
282
-static int flush_to_tcp_packet(struct impl *impl)
283
-{
284
-   const size_t max = 8 + impl->block_size;
285
-   uint32_t tcp_pkt1, outmax, len, n_frames;
286
-   struct rtp_header header;
287
-   struct iovec iov3;
288
-   struct msghdr msg;
289
-   uint8_t *dst;
290
-   int res;
291
-
292
-   if (!impl->recording)
293
-       return 0;
294
-
295
-   tcp_pkt0 = htonl(0x24000000);
296
-
297
-   iov0.iov_base = &tcp_pkt;
298
-   iov0.iov_len = 4;
299
-
300
-   spa_zero(header);
301
-   header.v = 2;
302
-   header.pt = 96;
303
-   header.sequence_number = htons(impl->seq);
304
-   header.timestamp = htonl(impl->rtptime);
305
-   header.ssrc = htonl(impl->ssrc);
306
-
307
-   iov1.iov_base = &header;
308
-   iov1.iov_len = 12;
309
-
310
-   n_frames = impl->filled / impl->frame_size;
311
    dst = (uint8_t*)&out0;
312
 
313
    switch (impl->codec) {
314
    case CODEC_PCM:
315
    case CODEC_ALAC:
316
-       len = write_codec_pcm(dst, impl->buffer, n_frames);
317
+       len = write_codec_pcm(dst, (void *)iov1.iov_base, n_frames);
318
        break;
319
    default:
320
-       len = 8 + impl->block_size;
321
+       len = 8 + impl->mtu;
322
        memset(dst, 0, len);
323
        break;
324
    }
325
    if (impl->encryption == CRYPTO_RSA)
326
        aes_encrypt(impl, dst, len);
327
 
328
-   out0 |= htonl((uint32_t) len + 12);
329
-
330
-   iov2.iov_base = out;
331
-   iov2.iov_len = len;
332
-
333
-   impl->rtptime += n_frames;
334
-   impl->seq = (impl->seq + 1) & 0xffff;
335
-
336
-   msg.msg_name = NULL;
337
-   msg.msg_namelen = 0;
338
-   msg.msg_iov = iov;
339
-   msg.msg_iovlen = 2;
340
-   msg.msg_control = NULL;
341
-   msg.msg_controllen = 0;
342
-   msg.msg_flags = 0;
343
-
344
-   res = sendmsg(impl->server_fd, &msg, MSG_NOSIGNAL);
345
-   if (res < 0) {
346
-       res = -errno;
347
-       pw_log_warn("error streaming packet: %d", res);
348
+   if (impl->protocol == PROTO_TCP) {
349
+       out0 |= htonl((uint32_t) len + 12);
350
+       tcp_pkt0 = htonl(0x24000000);
351
+       out_vecmsg.msg_iovlen++ = (struct iovec) { tcp_pkt, 4 };
352
    }
353
 
354
-   impl->first = false;
355
+   out_vecmsg.msg_iovlen++ = (struct iovec) { header, 12 };
356
+   out_vecmsg.msg_iovlen++ = (struct iovec) { out, len };
357
 
358
-   return res;
359
+   pw_log_debug("raop sending %ld", out_vec0.iov_len + out_vec1.iov_len + out_vec2.iov_len);
360
+
361
+   send_packet(impl->server_fd, &msg);
362
 }
363
 
364
-static void playback_stream_process(void *d)
365
+static inline void
366
+set_iovec(struct spa_ringbuffer *rbuf, void *buffer, uint32_t size,
367
+       uint32_t offset, struct iovec *iov, uint32_t len)
368
 {
369
-   struct impl *impl = d;
370
-   struct pw_buffer *buf;
371
-   struct spa_data *bd;
372
-   uint8_t *data;
373
-   uint32_t offs, size;
374
-
375
-   if ((buf = pw_stream_dequeue_buffer(impl->stream)) == NULL) {
376
-       pw_log_debug("out of buffers: %m");
377
-       return;
378
-   }
379
-
380
-   bd = &buf->buffer->datas0;
381
-
382
-   offs = SPA_MIN(bd->chunk->offset, bd->maxsize);
383
-   size = SPA_MIN(bd->chunk->size, bd->maxsize - offs);
384
-   data = SPA_PTROFF(bd->data, offs, uint8_t);
385
-
386
-   while (size > 0 && impl->block_size > 0) {
387
-       uint32_t avail, to_fill;
388
-
389
-       avail = impl->block_size - impl->filled;
390
-       to_fill = SPA_MIN(avail, size);
391
-
392
-       memcpy(&impl->bufferimpl->filled, data, to_fill);
393
-
394
-       impl->filled += to_fill;
395
-       avail -= to_fill;
396
-       size -= to_fill;
397
-       data += to_fill;
398
-
399
-       if (avail == 0) {
400
-           switch (impl->protocol) {
401
-           case PROTO_UDP:
402
-               flush_to_udp_packet(impl);
403
-               break;
404
-           case PROTO_TCP:
405
-               flush_to_tcp_packet(impl);
406
-               break;
407
-           }
408
-           impl->filled = 0;
409
-       }
410
-   }
411
-
412
-   pw_stream_queue_buffer(impl->stream, buf);
413
+   iov0.iov_len = SPA_MIN(len, size - offset);
414
+   iov0.iov_base = SPA_PTROFF(buffer, offset, void);
415
+   iov1.iov_len = len - iov0.iov_len;
416
+   iov1.iov_base = buffer;
417
 }
418
 
419
 static int create_udp_socket(struct impl *impl, uint16_t *port)
420
@@ -953,27 +837,6 @@
421
    return 0;
422
 }
423
 
424
-static int rtsp_do_flush(struct impl *impl)
425
-{
426
-   int res;
427
-
428
-   if (!impl->recording)
429
-       return 0;
430
-
431
-   pw_properties_set(impl->headers, "Range", "npt=0-");
432
-   pw_properties_setf(impl->headers, "RTP-Info",
433
-           "seq=%u;rtptime=%u", impl->seq, impl->rtptime);
434
-
435
-   impl->recording = false;
436
-
437
-   res = rtsp_send(impl, "FLUSH", NULL, NULL, rtsp_log_reply_status);
438
-
439
-   pw_properties_set(impl->headers, "Range", NULL);
440
-   pw_properties_set(impl->headers, "RTP-Info", NULL);
441
-
442
-   return res;
443
-}
444
-
445
 static int rtsp_send_volume(struct impl *impl)
446
 {
447
    if (!impl->recording)
448
@@ -993,6 +856,11 @@
449
                    NULL, NULL, 0, rtsp_log_reply_status, impl);
450
 }
451
 
452
+static uint32_t msec_to_samples(struct impl *impl, uint32_t msec)
453
+{
454
+   return msec * impl->rate / 1000;
455
+}
456
+
457
 static int rtsp_record_reply(void *data, int status, const struct spa_dict *headers, const struct pw_array *content)
458
 {
459
    struct impl *impl = data;
460
@@ -1024,17 +892,18 @@
461
 
462
    spa_zero(latency);
463
    latency.direction = PW_DIRECTION_INPUT;
464
-   latency.min_rate = latency.max_rate = impl->latency + RAOP_LATENCY_MIN;
465
+   latency.min_rate = latency.max_rate = impl->latency + msec_to_samples(impl, RAOP_LATENCY_MS);
466
 
467
    n_params = 0;
468
    spa_pod_builder_init(&b, buffer, sizeof(buffer));
469
    paramsn_params++ = spa_latency_build(&b, SPA_PARAM_Latency, &latency);
470
 
471
-   pw_stream_update_params(impl->stream, params, n_params);
472
+   rtp_stream_update_params(impl->stream, params, n_params);
473
+
474
+   rtp_stream_set_first(impl->stream);
475
 
476
-   impl->first = true;
477
    impl->sync = 0;
478
-   impl->sync_period = impl->info.rate / (impl->block_size / impl->frame_size);
479
+   impl->sync_period = impl->rate / (impl->mtu / impl->stride);
480
    impl->recording = true;
481
 
482
    rtsp_send_volume(impl);
483
@@ -1046,13 +915,18 @@
484
 static int rtsp_do_record(struct impl *impl)
485
 {
486
    int res;
487
+   uint16_t seq;
488
+   uint32_t rtptime;
489
 
490
    if (!impl->ready || impl->recording)
491
        return 0;
492
 
493
+   seq = rtp_stream_get_seq(impl->stream);
494
+   rtptime = rtp_stream_get_time(impl->stream, &impl->rate);
495
+
496
    pw_properties_set(impl->headers, "Range", "npt=0-");
497
    pw_properties_setf(impl->headers, "RTP-Info",
498
-           "seq=%u;rtptime=%u", impl->seq, impl->rtptime);
499
+           "seq=%u;rtptime=%u", seq, rtptime);
500
 
501
    res = rtsp_send(impl, "RECORD", NULL, NULL, rtsp_record_reply);
502
 
503
@@ -1085,7 +959,7 @@
504
            goto error;
505
 
506
        impl->ready = true;
507
-       if (pw_stream_get_state(impl->stream, NULL) == PW_STREAM_STATE_STREAMING)
508
+       if (rtp_stream_get_state(impl->stream, NULL) == PW_STREAM_STATE_STREAMING)
509
            rtsp_do_record(impl);
510
    }
511
    return;
512
@@ -1100,7 +974,6 @@
513
    size_t len;
514
    uint64_t ntp;
515
    uint16_t control_port, timing_port;
516
-   int res;
517
 
518
    pw_log_info("setup status: %d", status);
519
 
520
@@ -1132,12 +1005,6 @@
521
        return 0;
522
    }
523
 
524
-   if ((res = pw_getrandom(&impl->seq, sizeof(impl->seq), 0)) < 0 ||
525
-       (res = pw_getrandom(&impl->rtptime, sizeof(impl->rtptime), 0)) <  0) {
526
-       pw_log_error("error generating random seq and rtptime: %s", spa_strerror(res));
527
-       return 0;
528
-   }
529
-
530
    pw_log_info("server port:%u", impl->server_port);
531
 
532
    switch (impl->protocol) {
533
@@ -1176,7 +1043,7 @@
534
                SPA_IO_IN, false, on_control_source_io, impl);
535
 
536
        impl->ready = true;
537
-       if (pw_stream_get_state(impl->stream, NULL) == PW_STREAM_STATE_STREAMING)
538
+       if (rtp_stream_get_state(impl->stream, NULL) == PW_STREAM_STATE_STREAMING)
539
            rtsp_do_record(impl);
540
        break;
541
    default:
542
@@ -1196,8 +1063,8 @@
543
        break;
544
 
545
    case PROTO_UDP:
546
-       impl->control_port = DEFAULT_UDP_CONTROL_PORT;
547
-       impl->timing_port = DEFAULT_UDP_TIMING_PORT;
548
+       impl->control_port = RAOP_UDP_CONTROL_PORT;
549
+       impl->timing_port = RAOP_UDP_TIMING_PORT;
550
 
551
        impl->control_fd = create_udp_socket(impl, &impl->control_port);
552
        impl->timing_fd = create_udp_socket(impl, &impl->timing_port);
553
@@ -1336,19 +1203,14 @@
554
 {
555
    const char *host;
556
    uint8_t rsakey512;
557
+   uint32_t rtp_latency;
558
    char key512*2;
559
    char iv16*2;
560
-   int res, frames, rsa_len, ip_version;
561
+   int res, rsa_len, ip_version;
562
    spa_autofree char *sdp = NULL;
563
    char local_ip256;
564
    host = pw_properties_get(impl->props, "raop.ip");
565
-
566
-   if (impl->protocol == PROTO_TCP)
567
-       frames = FRAMES_PER_TCP_PACKET;
568
-   else
569
-       frames = FRAMES_PER_UDP_PACKET;
570
-
571
-   impl->block_size = frames * impl->frame_size;
572
+   rtp_latency = msec_to_samples(impl, RAOP_LATENCY_MS);
573
 
574
    pw_rtsp_client_get_local_ip(impl->rtsp, &ip_version,
575
            local_ip, sizeof(local_ip));
576
@@ -1364,7 +1226,7 @@
577
                "a=rtpmap:96 AppleLossless\r\n"
578
                "a=fmtp:96 %d 0 16 40 10 14 2 255 0 0 %u\r\n",
579
                impl->session_id, ip_version, local_ip,
580
-               ip_version, host, frames, impl->info.rate);
581
+               ip_version, host, impl->psamples, (uint32_t)impl->rate);
582
        if (!sdp)
583
            return -errno;
584
        break;
585
@@ -1379,8 +1241,8 @@
586
                "a=fmtp:96 %d 0 16 40 10 14 2 255 0 0 %u\r\n"
587
                "a=min-latency:%d",
588
                impl->session_id, ip_version, local_ip,
589
-               ip_version, host, frames, impl->info.rate,
590
-               RAOP_LATENCY_MIN);
591
+               ip_version, host, impl->psamples, (uint32_t)impl->rate,
592
+               rtp_latency);
593
        if (!sdp)
594
            return -errno;
595
        break;
596
@@ -1416,7 +1278,7 @@
597
                "a=rsaaeskey:%s\r\n"
598
                "a=aesiv:%s\r\n",
599
                impl->session_id, ip_version, local_ip,
600
-               ip_version, host, frames, impl->info.rate,
601
+               ip_version, host, impl->psamples, (uint32_t)impl->rate,
602
                key, iv);
603
        if (!sdp)
604
            return -errno;
605
@@ -1638,24 +1500,23 @@
606
    .message = rtsp_message,
607
 };
608
 
609
-static void stream_state_changed(void *d, enum pw_stream_state old,
610
-       enum pw_stream_state state, const char *error)
611
+static void stream_destroy(void *d)
612
 {
613
    struct impl *impl = d;
614
-   switch (state) {
615
-   case PW_STREAM_STATE_ERROR:
616
-   case PW_STREAM_STATE_UNCONNECTED:
617
+   impl->stream = NULL;
618
+}
619
+
620
+static void stream_state_changed(void *data, bool started, const char *error)
621
+{
622
+   struct impl *impl = data;
623
+
624
+   if (error) {
625
+       pw_log_error("stream error: %s", error);
626
        pw_impl_module_schedule_destroy(impl->module);
627
-       break;
628
-   case PW_STREAM_STATE_PAUSED:
629
-       rtsp_do_flush(impl);
630
-       break;
631
-   case PW_STREAM_STATE_STREAMING:
632
-       rtsp_do_record(impl);
633
-       break;
634
-   default:
635
-       break;
636
+       return;
637
    }
638
+   if (started)
639
+       rtsp_do_record(impl);
640
 }
641
 
642
 static int rtsp_do_connect(struct impl *impl)
643
@@ -1701,6 +1562,8 @@
644
 
645
 static int rtsp_do_teardown(struct impl *impl)
646
 {
647
+   impl->recording = false;
648
+
649
    if (!impl->ready)
650
        return 0;
651
 
652
@@ -1768,7 +1631,7 @@
653
    }
654
    param = spa_pod_builder_pop(&b, &f0);
655
 
656
-   pw_stream_set_param(impl->stream, id, param);
657
+   rtp_stream_set_param(impl->stream, id, param);
658
 }
659
 
660
 static void stream_param_changed(void *data, uint32_t id, const struct spa_pod *param)
661
@@ -1791,57 +1654,14 @@
662
    }
663
 }
664
 
665
-static const struct pw_stream_events playback_stream_events = {
666
-   PW_VERSION_STREAM_EVENTS,
667
+static const struct rtp_stream_events stream_events = {
668
+   RTP_VERSION_STREAM_EVENTS,
669
    .destroy = stream_destroy,
670
    .state_changed = stream_state_changed,
671
    .param_changed = stream_param_changed,
672
-   .process = playback_stream_process
673
+   .send_packet = stream_send_packet
674
 };
675
 
676
-static int create_stream(struct impl *impl)
677
-{
678
-   int res;
679
-   uint32_t n_params;
680
-   const struct spa_pod *params1;
681
-   uint8_t buffer1024;
682
-   struct spa_pod_builder b;
683
-
684
-   impl->stream = pw_stream_new(impl->core, "RAOP sink", impl->stream_props);
685
-   impl->stream_props = NULL;
686
-
687
-   if (impl->stream == NULL)
688
-       return -errno;
689
-
690
-   pw_stream_add_listener(impl->stream,
691
-           &impl->stream_listener,
692
-           &playback_stream_events, impl);
693
-
694
-   n_params = 0;
695
-   spa_pod_builder_init(&b, buffer, sizeof(buffer));
696
-   paramsn_params++ = spa_format_audio_raw_build(&b,
697
-           SPA_PARAM_EnumFormat, &impl->info);
698
-
699
-   if ((res = pw_stream_connect(impl->stream,
700
-           PW_DIRECTION_INPUT,
701
-           PW_ID_ANY,
702
-           PW_STREAM_FLAG_MAP_BUFFERS |
703
-           PW_STREAM_FLAG_RT_PROCESS,
704
-           params, n_params)) < 0)
705
-       return res;
706
-
707
-   impl->headers = pw_properties_new(NULL, NULL);
708
-
709
-   impl->rtsp = pw_rtsp_client_new(impl->loop, NULL, 0);
710
-   if (impl->rtsp == NULL)
711
-       return -errno;
712
-
713
-   pw_rtsp_client_add_listener(impl->rtsp, &impl->rtsp_listener,
714
-           &rtsp_events, impl);
715
-
716
-   return 0;
717
-}
718
-
719
 static void core_error(void *data, uint32_t id, int seq, int res, const char *message)
720
 {
721
    struct impl *impl = data;
722
@@ -1873,7 +1693,7 @@
723
 static void impl_destroy(struct impl *impl)
724
 {
725
    if (impl->stream)
726
-       pw_stream_destroy(impl->stream);
727
+       rtp_stream_destroy(impl->stream);
728
    if (impl->core && impl->do_disconnect)
729
        pw_core_disconnect(impl->core);
730
 
731
@@ -1902,97 +1722,6 @@
732
    .destroy = module_destroy,
733
 };
734
 
735
-static inline uint32_t format_from_name(const char *name, size_t len)
736
-{
737
-   int i;
738
-   for (i = 0; spa_type_audio_formati.name; i++) {
739
-       if (strncmp(name, spa_debug_type_short_name(spa_type_audio_formati.name), len) == 0)
740
-           return spa_type_audio_formati.type;
741
-   }
742
-   return SPA_AUDIO_FORMAT_UNKNOWN;
743
-}
744
-
745
-static uint32_t channel_from_name(const char *name)
746
-{
747
-   int i;
748
-   for (i = 0; spa_type_audio_channeli.name; i++) {
749
-       if (spa_streq(name, spa_debug_type_short_name(spa_type_audio_channeli.name)))
750
-           return spa_type_audio_channeli.type;
751
-   }
752
-   return SPA_AUDIO_CHANNEL_UNKNOWN;
753
-}
754
-
755
-static void parse_position(struct spa_audio_info_raw *info, const char *val, size_t len)
756
-{
757
-   struct spa_json it2;
758
-   char v256;
759
-
760
-   spa_json_init(&it0, val, len);
761
-        if (spa_json_enter_array(&it0, &it1) <= 0)
762
-                spa_json_init(&it1, val, len);
763
-
764
-   info->channels = 0;
765
-   while (spa_json_get_string(&it1, v, sizeof(v)) > 0 &&
766
-       info->channels < SPA_AUDIO_MAX_CHANNELS) {
767
-       info->positioninfo->channels++ = channel_from_name(v);
768
-   }
769
-}
770
-
771
-static void parse_audio_info(const struct pw_properties *props, struct spa_audio_info_raw *info)
772
-{
773
-   const char *str;
774
-
775
-   spa_zero(*info);
776
-   if ((str = pw_properties_get(props, PW_KEY_AUDIO_FORMAT)) == NULL)
777
-       str = DEFAULT_FORMAT;
778
-   info->format = format_from_name(str, strlen(str));
779
-
780
-   info->rate = pw_properties_get_uint32(props, PW_KEY_AUDIO_RATE, info->rate);
781
-   if (info->rate == 0)
782
-       info->rate = DEFAULT_RATE;
783
-
784
-   info->channels = pw_properties_get_uint32(props, PW_KEY_AUDIO_CHANNELS, info->channels);
785
-   info->channels = SPA_MIN(info->channels, SPA_AUDIO_MAX_CHANNELS);
786
-   if ((str = pw_properties_get(props, SPA_KEY_AUDIO_POSITION)) != NULL)
787
-       parse_position(info, str, strlen(str));
788
-   if (info->channels == 0)
789
-       parse_position(info, DEFAULT_POSITION, strlen(DEFAULT_POSITION));
790
-}
791
-
792
-static int calc_frame_size(struct spa_audio_info_raw *info)
793
-{
794
-   int res = info->channels;
795
-   switch (info->format) {
796
-   case SPA_AUDIO_FORMAT_U8:
797
-   case SPA_AUDIO_FORMAT_S8:
798
-   case SPA_AUDIO_FORMAT_ALAW:
799
-   case SPA_AUDIO_FORMAT_ULAW:
800
-       return res;
801
-   case SPA_AUDIO_FORMAT_S16:
802
-   case SPA_AUDIO_FORMAT_S16_OE:
803
-   case SPA_AUDIO_FORMAT_U16:
804
-       return res * 2;
805
-   case SPA_AUDIO_FORMAT_S24:
806
-   case SPA_AUDIO_FORMAT_S24_OE:
807
-   case SPA_AUDIO_FORMAT_U24:
808
-       return res * 3;
809
-   case SPA_AUDIO_FORMAT_S24_32:
810
-   case SPA_AUDIO_FORMAT_S24_32_OE:
811
-   case SPA_AUDIO_FORMAT_S32:
812
-   case SPA_AUDIO_FORMAT_S32_OE:
813
-   case SPA_AUDIO_FORMAT_U32:
814
-   case SPA_AUDIO_FORMAT_U32_OE:
815
-   case SPA_AUDIO_FORMAT_F32:
816
-   case SPA_AUDIO_FORMAT_F32_OE:
817
-       return res * 4;
818
-   case SPA_AUDIO_FORMAT_F64:
819
-   case SPA_AUDIO_FORMAT_F64_OE:
820
-       return res * 8;
821
-   default:
822
-       return 0;
823
-   }
824
-}
825
-
826
 static void copy_props(struct impl *impl, struct pw_properties *props, const char *key)
827
 {
828
    const char *str;
829
@@ -2009,7 +1738,7 @@
830
    struct pw_properties *props = NULL;
831
    struct impl *impl;
832
    const char *str, *name, *hostname, *ip, *port;
833
-   int res;
834
+   int res = 0;
835
 
836
    PW_LOG_TOPIC_INIT(mod_topic);
837
 
838
@@ -2057,67 +1786,15 @@
839
        goto error;
840
    }
841
 
842
-   if (pw_properties_get(props, PW_KEY_NODE_VIRTUAL) == NULL)
843
-       pw_properties_set(props, PW_KEY_NODE_VIRTUAL, "true");
844
-
845
-   if (pw_properties_get(props, PW_KEY_MEDIA_CLASS) == NULL)
846
-       pw_properties_set(props, PW_KEY_MEDIA_CLASS, "Audio/Sink");
847
-
848
-   if (pw_properties_get(props, PW_KEY_DEVICE_ICON_NAME) == NULL)
849
-       pw_properties_set(props, PW_KEY_DEVICE_ICON_NAME, "audio-speakers");
850
-
851
-   if ((name = pw_properties_get(props, "raop.name")) == NULL)
852
-       name = "RAOP";
853
-
854
-   if ((str = strstr(name, "@"))) {
855
-       str++;
856
-       if (strlen(str) > 0)
857
-           name = str;
858
-   }
859
-   if ((hostname = pw_properties_get(props, "raop.hostname")) == NULL)
860
-       hostname = name;
861
-
862
-   if (pw_properties_get(props, PW_KEY_NODE_NAME) == NULL)
863
-       pw_properties_setf(props, PW_KEY_NODE_NAME, "raop_sink.%s.%s.%s",
864
-               hostname, ip, port);
865
-   if (pw_properties_get(props, PW_KEY_NODE_DESCRIPTION) == NULL)
866
-       pw_properties_setf(props, PW_KEY_NODE_DESCRIPTION,
867
-                   "%s", name);
868
-   if (pw_properties_get(props, PW_KEY_NODE_LATENCY) == NULL)
869
-       pw_properties_set(props, PW_KEY_NODE_LATENCY, "352/44100");
870
-
871
-   if ((str = pw_properties_get(props, "stream.props")) != NULL)
872
-       pw_properties_update_string(impl->stream_props, str, strlen(str));
873
-
874
-   copy_props(impl, props, PW_KEY_AUDIO_FORMAT);
875
-   copy_props(impl, props, PW_KEY_AUDIO_RATE);
876
-   copy_props(impl, props, PW_KEY_AUDIO_CHANNELS);
877
-   copy_props(impl, props, SPA_KEY_AUDIO_POSITION);
878
-   copy_props(impl, props, PW_KEY_DEVICE_ICON_NAME);
879
-   copy_props(impl, props, PW_KEY_NODE_NAME);
880
-   copy_props(impl, props, PW_KEY_NODE_DESCRIPTION);
881
-   copy_props(impl, props, PW_KEY_NODE_GROUP);
882
-   copy_props(impl, props, PW_KEY_NODE_LATENCY);
883
-   copy_props(impl, props, PW_KEY_NODE_VIRTUAL);
884
-   copy_props(impl, props, PW_KEY_MEDIA_CLASS);
885
-
886
-   parse_audio_info(impl->stream_props, &impl->info);
887
-
888
-   impl->frame_size = calc_frame_size(&impl->info);
889
-   if (impl->frame_size == 0) {
890
-       pw_log_error("unsupported audio format:%d channels:%d",
891
-               impl->info.format, impl->info.channels);
892
-       res = -EINVAL;
893
-       goto error;
894
-   }
895
-
896
    if ((str = pw_properties_get(props, "raop.transport")) == NULL)
897
        str = "udp";
898
-   if (spa_streq(str, "udp"))
899
+   if (spa_streq(str, "udp")) {
900
        impl->protocol = PROTO_UDP;
901
-   else if (spa_streq(str, "tcp"))
902
+       impl->psamples = FRAMES_PER_UDP_PACKET;
903
+   } else if (spa_streq(str, "tcp")) {
904
        impl->protocol = PROTO_TCP;
905
-   else {
906
+       impl->psamples = FRAMES_PER_TCP_PACKET;
907
+   } else {
908
        pw_log_error( "can't handle transport %s", str);
909
        res = -EINVAL;
910
        goto error;
911
@@ -2151,9 +1828,78 @@
912
    str = pw_properties_get(props, "raop.password");
913
    impl->password = str ? strdup(str) : NULL;
914
 
915
-   if ((str = pw_properties_get(props, "raop.latency.ms")) == NULL)
916
-       str = DEFAULT_LATENCY_MS;
917
-   impl->latency = SPA_MAX(atoi(str) * impl->info.rate / 1000u, RAOP_LATENCY_MIN);
918
+   if ((name = pw_properties_get(props, "raop.name")) == NULL)
919
+       name = "RAOP";
920
+
921
+   if ((str = strchr(name, '@')) != NULL) {
922
+       str++;
923
+       if (strlen(str) > 0)
924
+           name = str;
925
+   }
926
+   if ((hostname = pw_properties_get(props, "raop.hostname")) == NULL)
927
+       hostname = name;
928
+
929
+   impl->rate = RAOP_RATE;
930
+   impl->latency = msec_to_samples(impl, RAOP_LATENCY_MS);
931
+   impl->stride = RAOP_STRIDE;
932
+   impl->mtu = impl->stride * impl->psamples;
933
+   impl->sync_period = impl->rate / impl->psamples;
934
+
935
+   if (pw_properties_get(props, PW_KEY_AUDIO_FORMAT) == NULL)
936
+       pw_properties_setf(props, PW_KEY_AUDIO_FORMAT, "%s", RAOP_FORMAT);
937
+   if (pw_properties_get(props, PW_KEY_AUDIO_RATE) == NULL)
938
+       pw_properties_setf(props, PW_KEY_AUDIO_RATE, "%ld", impl->rate);
939
+   if (pw_properties_get(props, PW_KEY_DEVICE_ICON_NAME) == NULL)
940
+       pw_properties_set(props, PW_KEY_DEVICE_ICON_NAME, "audio-speakers");
941
+   if (pw_properties_get(props, PW_KEY_NODE_NAME) == NULL)
942
+       pw_properties_setf(props, PW_KEY_NODE_NAME, "raop_sink.%s.%s.%s",
943
+               hostname, ip, port);
944
+   if (pw_properties_get(props, PW_KEY_NODE_DESCRIPTION) == NULL)
945
+       pw_properties_setf(props, PW_KEY_NODE_DESCRIPTION, "%s", name);
946
+   if (pw_properties_get(props, PW_KEY_NODE_LATENCY) == NULL)
947
+       pw_properties_setf(props, PW_KEY_NODE_LATENCY, "%d/%ld",
948
+               impl->psamples, impl->rate);
949
+   if (pw_properties_get(props, PW_KEY_NODE_VIRTUAL) == NULL)
950
+       pw_properties_set(props, PW_KEY_NODE_VIRTUAL, "true");
951
+   if (pw_properties_get(props, PW_KEY_MEDIA_CLASS) == NULL)
952
+       pw_properties_set(props, PW_KEY_MEDIA_CLASS, "Audio/Sink");
953
+   if (pw_properties_get(props, PW_KEY_MEDIA_FORMAT) == NULL)
954
+       pw_properties_setf(props, PW_KEY_MEDIA_FORMAT, "%d", SPA_AUDIO_FORMAT_S16_LE);
955
+   if (pw_properties_get(props, "net.mtu") == NULL)
956
+       pw_properties_setf(props, "net.mtu", "%d", impl->mtu);
957
+   if (pw_properties_get(props, "rtp.sender-ts-offset") == NULL)
958
+       pw_properties_setf(props, "rtp.sender-ts-offset", "%d", 0);
959
+   if (pw_properties_get(props, "sess.ts-direct") == NULL)
960
+       pw_properties_set(props, "sess.ts-direct", 0);
961
+   if (pw_properties_get(props, "sess.media") == NULL)
962
+       pw_properties_set(props, "sess.media", "raop");
963
+   if (pw_properties_get(props, "sess.latency.msec") == NULL)
964
+       pw_properties_setf(props, "sess.latency.msec", "%d", RAOP_LATENCY_MS);
965
+
966
+   if ((str = pw_properties_get(props, "stream.props")) != NULL)
967
+       pw_properties_update_string(impl->stream_props, str, strlen(str));
968
+
969
+   copy_props(impl, props, PW_KEY_AUDIO_FORMAT);
970
+   copy_props(impl, props, PW_KEY_AUDIO_RATE);
971
+   copy_props(impl, props, PW_KEY_AUDIO_CHANNELS);
972
+   copy_props(impl, props, SPA_KEY_AUDIO_POSITION);
973
+   copy_props(impl, props, PW_KEY_DEVICE_ICON_NAME);
974
+   copy_props(impl, props, PW_KEY_NODE_NAME);
975
+   copy_props(impl, props, PW_KEY_NODE_DESCRIPTION);
976
+   copy_props(impl, props, PW_KEY_NODE_GROUP);
977
+   copy_props(impl, props, PW_KEY_NODE_LATENCY);
978
+   copy_props(impl, props, PW_KEY_NODE_VIRTUAL);
979
+   copy_props(impl, props, PW_KEY_MEDIA_CLASS);
980
+   copy_props(impl, props, PW_KEY_MEDIA_FORMAT);
981
+   copy_props(impl, props, "net.mtu");
982
+   copy_props(impl, props, "rtp.sender-ts-offset");
983
+   copy_props(impl, props, "sess.media");
984
+   copy_props(impl, props, "sess.name");
985
+   copy_props(impl, props, "sess.min-ptime");
986
+   copy_props(impl, props, "sess.max-ptime");
987
+   copy_props(impl, props, "sess.latency.msec");
988
+   copy_props(impl, props, "sess.ts-refclk");
989
+   copy_props(impl, props, "sess.ts-direct");
990
 
991
    impl->core = pw_context_get_object(impl->context, PW_TYPE_INTERFACE_Core);
992
    if (impl->core == NULL) {
993
@@ -2178,9 +1924,24 @@
994
            &impl->core_listener,
995
            &core_events, impl);
996
 
997
-   if ((res = create_stream(impl)) < 0)
998
+   impl->stream = rtp_stream_new(impl->core,
999
+           PW_DIRECTION_INPUT, pw_properties_copy(impl->stream_props),
1000
+           &stream_events, impl);
1001
+   if (impl->stream == NULL) {
1002
+       res = -errno;
1003
+       pw_log_error("can't create raop stream: %m");
1004
+       goto error;
1005
+   }
1006
+
1007
+   impl->headers = pw_properties_new(NULL, NULL);
1008
+
1009
+   impl->rtsp = pw_rtsp_client_new(impl->loop, NULL, 0);
1010
+   if (impl->rtsp == NULL)
1011
        goto error;
1012
 
1013
+   pw_rtsp_client_add_listener(impl->rtsp, &impl->rtsp_listener,
1014
+           &rtsp_events, impl);
1015
+
1016
    pw_impl_module_add_listener(module, &impl->module_listener, &module_events, impl);
1017
 
1018
    pw_impl_module_update_properties(module, &SPA_DICT_INIT_ARRAY(module_props));
1019
pipewire-0.3.81.tar.gz/src/modules/module-rt.c -> pipewire-0.3.82.tar.gz/src/modules/module-rt.c Changed
19
 
1
@@ -36,7 +36,7 @@
2
 #include <sys/thr.h>
3
 #endif
4
 #if defined(__GNU__)
5
-#include <mach.h>
6
+#include <hurd.h>
7
 #endif
8
 #include <fcntl.h>
9
 #include <unistd.h>
10
@@ -225,7 +225,7 @@
11
    thr_self(&pid);
12
    return (pid_t)pid;
13
 #elif defined(__GNU__)
14
-       mach_port_t thread = mach_thread_self();
15
+       mach_port_t thread = hurd_thread_self();
16
        return (pid_t)thread;
17
 #else
18
 #error "No gettid impl"
19
pipewire-0.3.81.tar.gz/src/modules/module-rtp/audio.c -> pipewire-0.3.82.tar.gz/src/modules/module-rtp/audio.c Changed
26
 
1
@@ -226,6 +226,10 @@
2
    iov0.iov_len = sizeof(header);
3
 
4
    while (avail >= tosend) {
5
+       if (impl->marker_on_first && impl->first)
6
+           header.m = 1;
7
+       else
8
+           header.m = 0;
9
        header.sequence_number = htons(impl->seq);
10
        header.timestamp = htonl(impl->ts_offset + timestamp);
11
 
12
@@ -234,11 +238,12 @@
13
            (timestamp * stride) & BUFFER_MASK,
14
            &iov1, tosend * stride);
15
 
16
-       pw_log_trace("sending %d timestamp:%d", tosend, timestamp);
17
+       pw_log_trace("sending %d avail:%d ts_offset:%d timestamp:%d", tosend, avail, impl->ts_offset, timestamp);
18
 
19
        rtp_stream_emit_send_packet(impl, iov, 3);
20
 
21
        impl->seq++;
22
+       impl->first = false;
23
        timestamp += tosend;
24
        avail -= tosend;
25
    }
26
pipewire-0.3.81.tar.gz/src/modules/module-rtp/stream.c -> pipewire-0.3.82.tar.gz/src/modules/module-rtp/stream.c Changed
115
 
1
@@ -32,6 +32,7 @@
2
                            struct rtp_stream_events, m, v, ##__VA_ARGS__)
3
 #define rtp_stream_emit_destroy(s)     rtp_stream_emit(s, destroy, 0)
4
 #define rtp_stream_emit_state_changed(s,n,e)   rtp_stream_emit(s, state_changed,0,n,e)
5
+#define rtp_stream_emit_param_changed(s,i,p)   rtp_stream_emit(s, param_changed,0,i,p)
6
 #define rtp_stream_emit_send_packet(s,i,l) rtp_stream_emit(s, send_packet,0,i,l)
7
 #define rtp_stream_emit_send_feedback(s,seq)   rtp_stream_emit(s, send_feedback,0,seq)
8
 
9
@@ -58,6 +59,7 @@
10
    unsigned have_ssrc:1;
11
    unsigned ignore_ssrc:1;
12
    unsigned have_seq:1;
13
+   unsigned marker_on_first:1;
14
    uint32_t ts_offset;
15
    uint32_t psamples;
16
    uint32_t mtu;
17
@@ -102,6 +104,7 @@
18
    { SPA_MEDIA_SUBTYPE_raw, SPA_AUDIO_FORMAT_ALAW, 1, "PCMA", "audio" },
19
    { SPA_MEDIA_SUBTYPE_raw, SPA_AUDIO_FORMAT_ULAW, 1, "PCMU", "audio" },
20
    { SPA_MEDIA_SUBTYPE_raw, SPA_AUDIO_FORMAT_S16_BE, 2, "L16", "audio" },
21
+   { SPA_MEDIA_SUBTYPE_raw, SPA_AUDIO_FORMAT_S16_LE, 2, "L16", "audio" },
22
    { SPA_MEDIA_SUBTYPE_raw, SPA_AUDIO_FORMAT_S24_BE, 3, "L24", "audio" },
23
    { SPA_MEDIA_SUBTYPE_control, 0, 1, "rtp-midi", "audio" },
24
    { SPA_MEDIA_SUBTYPE_opus, 0, 4, "opus", "audio" },
25
@@ -132,6 +135,8 @@
26
    if (impl->started)
27
        return 0;
28
 
29
+   impl->first = true;
30
+
31
    rtp_stream_emit_state_changed(impl, true, NULL);
32
 
33
    impl->started = true;
34
@@ -176,10 +181,17 @@
35
    }
36
 }
37
 
38
+static void on_stream_param_changed (void *d, uint32_t id, const struct spa_pod *param)
39
+{
40
+   struct impl *impl = d;
41
+   rtp_stream_emit_param_changed(impl, id, param);
42
+};
43
+
44
 static const struct pw_stream_events stream_events = {
45
    PW_VERSION_STREAM_EVENTS,
46
    .destroy = stream_destroy,
47
    .state_changed = on_stream_state_changed,
48
+   .param_changed = on_stream_param_changed,
49
    .io_changed = stream_io_changed,
50
 };
51
 
52
@@ -287,6 +299,12 @@
53
        impl->info.media_subtype = SPA_MEDIA_SUBTYPE_raw;
54
        impl->payload = 127;
55
    }
56
+   else if (spa_streq(str, "raop")) {
57
+       impl->info.media_type = SPA_MEDIA_TYPE_audio;
58
+       impl->info.media_subtype = SPA_MEDIA_SUBTYPE_raw;
59
+       impl->payload = 0x60;
60
+       impl->marker_on_first = 1;
61
+   }
62
    else if (spa_streq(str, "midi")) {
63
        impl->info.media_type = SPA_MEDIA_TYPE_application;
64
        impl->info.media_subtype = SPA_MEDIA_SUBTYPE_control;
65
@@ -364,6 +382,7 @@
66
    if (pw_properties_get(props, PW_KEY_NODE_NETWORK) == NULL)
67
        pw_properties_set(props, PW_KEY_NODE_NETWORK, "true");
68
 
69
+   impl->marker_on_first = pw_properties_get_bool(props, "sess.marker-on-first", false);
70
    impl->ignore_ssrc = pw_properties_get_bool(props, "sess.ignore-ssrc", false);
71
    impl->direct_timestamp = pw_properties_get_bool(props, "sess.ts-direct", false);
72
 
73
@@ -530,3 +549,40 @@
74
    return pos->clock.position * impl->rate *
75
        pos->clock.rate.num / pos->clock.rate.denom;
76
 }
77
+
78
+uint16_t rtp_stream_get_seq(struct rtp_stream *s)
79
+{
80
+   struct impl *impl = (struct impl*)s;
81
+
82
+   return impl->seq;
83
+}
84
+
85
+void rtp_stream_set_first(struct rtp_stream *s)
86
+{
87
+   struct impl *impl = (struct impl*)s;
88
+
89
+   impl->first = true;
90
+}
91
+
92
+enum pw_stream_state rtp_stream_get_state(struct rtp_stream *s, const char **error)
93
+{
94
+   struct impl *impl = (struct impl*)s;
95
+
96
+   return pw_stream_get_state(impl->stream, error);
97
+}
98
+
99
+int rtp_stream_set_param(struct rtp_stream *s, uint32_t id, const struct spa_pod *param)
100
+{
101
+   struct impl *impl = (struct impl*)s;
102
+
103
+   return pw_stream_set_param(impl->stream, id, param);
104
+}
105
+
106
+int rtp_stream_update_params(struct rtp_stream *s,
107
+           const struct spa_pod **params,
108
+           uint32_t n_params)
109
+{
110
+   struct impl *impl = (struct impl*)s;
111
+   
112
+   return pw_stream_update_params(impl->stream, params, n_params);
113
+}
114
\ No newline at end of file
115
pipewire-0.3.81.tar.gz/src/modules/module-rtp/stream.h -> pipewire-0.3.82.tar.gz/src/modules/module-rtp/stream.h Changed
32
 
1
@@ -31,9 +31,11 @@
2
 
3
    void (*state_changed) (void *data, bool started, const char *error);
4
 
5
+   void (*param_changed) (void *data, uint32_t id, const struct spa_pod *param);
6
+
7
    void (*send_packet) (void *data, struct iovec *iov, size_t iovlen);
8
 
9
-   void (*send_feedback) (void *data, uint32_t senum);
10
+   void (*send_feedback) (void *data, uint32_t seqnum);
11
 };
12
 
13
 struct rtp_stream *rtp_stream_new(struct pw_core *core,
14
@@ -46,6 +48,17 @@
15
 
16
 uint64_t rtp_stream_get_time(struct rtp_stream *s, uint64_t *rate);
17
 
18
+uint16_t rtp_stream_get_seq(struct rtp_stream *s);
19
+
20
+void rtp_stream_set_first(struct rtp_stream *s);
21
+
22
+enum pw_stream_state rtp_stream_get_state(struct rtp_stream *s, const char **error);
23
+
24
+int rtp_stream_set_param(struct rtp_stream *s, uint32_t id, const struct spa_pod *param);
25
+
26
+int rtp_stream_update_params(struct rtp_stream *stream,
27
+           const struct spa_pod **params,
28
+           uint32_t n_params);
29
 
30
 #ifdef __cplusplus
31
 }
32
pipewire-0.3.81.tar.gz/src/pipewire/context.c -> pipewire-0.3.82.tar.gz/src/pipewire/context.c Changed
80
 
1
@@ -1027,7 +1027,7 @@
2
            context, n, n->name);
3
 
4
    if (n->info.state >= PW_NODE_STATE_IDLE)
5
-       n->reconfigure = true;
6
+       n->need_resume = !n->pause_on_idle;
7
    pw_impl_node_set_state(n, PW_NODE_STATE_SUSPENDED);
8
 }
9
 
10
@@ -1309,7 +1309,7 @@
11
        uint32_t target_quantum, target_rate, current_rate, current_quantum;
12
        uint64_t quantum_stamp = 0, rate_stamp = 0;
13
        bool force_rate, force_quantum, restore_rate = false, restore_quantum = false;
14
-       bool do_reconfigure = false, was_target_pending;
15
+       bool do_reconfigure = false, need_resume, was_target_pending;
16
        const uint32_t *node_rates;
17
        uint32_t node_n_rates, node_def_rate;
18
        uint32_t node_max_quantum, node_min_quantum, node_def_quantum, node_rate_quantum;
19
@@ -1399,13 +1399,22 @@
20
        if (force_rate)
21
            lock_rate = false;
22
 
23
-       if (n->reconfigure)
24
+       need_resume = n->need_resume;
25
+       if (need_resume) {
26
            running = true;
27
+           n->need_resume = false;
28
+       }
29
 
30
        current_rate = n->target_rate.denom;
31
        if (!restore_rate &&
32
-          (lock_rate || n->reconfigure || !running ||
33
-           (!force_rate && (n->info.state > PW_NODE_STATE_IDLE))))
34
+          (lock_rate || need_resume || !running ||
35
+           (!force_rate && (n->info.state > PW_NODE_STATE_IDLE)))) {
36
+           pw_log_debug("%p: keep rate:1/%u restore:%u lock:%u resume:%u "
37
+                   "running:%u force:%u state:%s", context,
38
+                   current_rate, restore_rate, lock_rate, need_resume,
39
+                   running, force_rate,
40
+                   pw_node_state_as_string(n->info.state));
41
+
42
            /* when we don't need to restore or rate and
43
             * when someone wants us to lock the rate of this driver or
44
             * when we are in the process of reconfiguring the driver or
45
@@ -1413,6 +1422,7 @@
46
             * when the driver is busy and we don't need to force a rate,
47
             * keep the current rate */
48
            target_rate = current_rate;
49
+       }
50
        else {
51
            /* Here we are allowed to change the rate of the driver.
52
             * Start with the default rate. If the desired rate is
53
@@ -1464,9 +1474,15 @@
54
 
55
        current_quantum = n->target_quantum;
56
        if (!restore_quantum &&
57
-          (lock_quantum || n->reconfigure || !running ||
58
-           (!force_quantum && (n->info.state > PW_NODE_STATE_IDLE))))
59
+          (lock_quantum || need_resume || !running ||
60
+           (!force_quantum && (n->info.state > PW_NODE_STATE_IDLE)))) {
61
+           pw_log_debug("%p: keep quantum:%u restore:%u lock:%u resume:%u "
62
+                   "running:%u force:%u state:%s", context,
63
+                   current_quantum, restore_quantum, lock_quantum, need_resume,
64
+                   running, force_quantum,
65
+                   pw_node_state_as_string(n->info.state));
66
            target_quantum = current_quantum;
67
+       }
68
        else {
69
            target_quantum = node_def_quantum;
70
            if (latency.denom != 0)
71
@@ -1474,7 +1490,7 @@
72
            target_quantum = SPA_CLAMP(target_quantum, node_min_quantum, node_max_quantum);
73
            target_quantum = SPA_MIN(target_quantum, lim_quantum);
74
 
75
-           if (settings->clock_power_of_two_quantum)
76
+           if (settings->clock_power_of_two_quantum && !force_quantum)
77
                target_quantum = flp2(target_quantum);
78
        }
79
 
80
pipewire-0.3.81.tar.gz/src/pipewire/filter.c -> pipewire-0.3.82.tar.gz/src/pipewire/filter.c Changed
15
 
1
@@ -1659,10 +1659,10 @@
2
    if ((str = getenv("PIPEWIRE_QUANTUM")) != NULL) {
3
        struct spa_fraction q;
4
        if (sscanf(str, "%u/%u", &q.num, &q.denom) == 2 && q.denom != 0) {
5
-           pw_properties_setf(filter->properties, PW_KEY_NODE_RATE,
6
+           pw_properties_setf(filter->properties, PW_KEY_NODE_FORCE_RATE,
7
                    "1/%u", q.denom);
8
-           pw_properties_setf(filter->properties, PW_KEY_NODE_LATENCY,
9
-                   "%u/%u", q.num, q.denom);
10
+           pw_properties_setf(filter->properties, PW_KEY_NODE_FORCE_QUANTUM,
11
+                   "%u", q.num);
12
        }
13
    }
14
    if ((str = getenv("PIPEWIRE_LATENCY")) != NULL)
15
pipewire-0.3.81.tar.gz/src/pipewire/impl-client.c -> pipewire-0.3.82.tar.gz/src/pipewire/impl-client.c Changed
74
 
1
@@ -152,30 +152,53 @@
2
    return false;
3
 }
4
 
5
-static int update_properties(struct pw_impl_client *client, const struct spa_dict *dict, bool filter)
6
+static bool check_client_property_update(struct pw_impl_client *client,
7
+       const char *key, const char *old, const char *new)
8
 {
9
    static const char * const ignored = {
10
+       PW_KEY_PROTOCOL,
11
        PW_KEY_OBJECT_ID,
12
+       PW_KEY_OBJECT_SERIAL,
13
+       PW_KEY_ACCESS,
14
        NULL
15
    };
16
 
17
+   /* Refuse specific restricted keys */
18
+   if (has_key(ignored, key))
19
+       goto deny;
20
+
21
+   /* Refuse all security keys */
22
+   if (spa_strstartswith(key, "pipewire.sec."))
23
+       goto deny;
24
+
25
+   /* Restrict other pipewire.* keys */
26
+   if (spa_strstartswith(key, "pipewire.")) {
27
+       /* Refuse changing existing values */
28
+       if (old != NULL)
29
+           goto deny;
30
+   }
31
+
32
+   return true;
33
+
34
+deny:
35
+   if (!spa_streq(old, new))
36
+       pw_log_warn("%p: refuse property update '%s' from '%s' to '%s'",
37
+               client, key, old ? old : "<unset>", new ? new : "<unset>");
38
+   return false;
39
+}
40
+
41
+static int update_properties(struct pw_impl_client *client, const struct spa_dict *dict, bool filter)
42
+{
43
    struct pw_resource *resource;
44
    int changed = 0;
45
    uint32_t i;
46
-   const char *old;
47
 
48
         for (i = 0; i < dict->n_items; i++) {
49
        if (filter) {
50
-           if (spa_strstartswith(dict->itemsi.key, "pipewire.") &&
51
-               (old = pw_properties_get(client->properties, dict->itemsi.key)) != NULL &&
52
-               (dict->itemsi.value == NULL || !spa_streq(old, dict->itemsi.value))) {
53
-               pw_log_warn("%p: refuse property update '%s' from '%s' to '%s'",
54
-                       client, dict->itemsi.key, old,
55
-                       dict->itemsi.value);
56
-               continue;
57
+           const char *old = pw_properties_get(client->properties, dict->itemsi.key);
58
+           const char *new = dict->itemsi.value;
59
 
60
-           }
61
-           if (has_key(ignored, dict->itemsi.key))
62
+           if (!check_client_property_update(client, dict->itemsi.key, old, new))
63
                continue;
64
        }
65
                 changed += pw_properties_set(client->properties, dict->itemsi.key, dict->itemsi.value);
66
@@ -501,6 +524,7 @@
67
        PW_KEY_SEC_UID,
68
        PW_KEY_SEC_GID,
69
        PW_KEY_SEC_LABEL,
70
+       PW_KEY_SEC_SOCKET,
71
        NULL
72
    };
73
 
74
pipewire-0.3.81.tar.gz/src/pipewire/impl-node.c -> pipewire-0.3.82.tar.gz/src/pipewire/impl-node.c Changed
16
 
1
@@ -418,14 +418,6 @@
2
        spa_list_for_each(resource, &node->global->resource_list, link)
3
            pw_resource_error(resource, res, error);
4
    }
5
-   if (node->reconfigure) {
6
-       if (state == PW_NODE_STATE_SUSPENDED &&
7
-           node->pause_on_idle) {
8
-           node->reconfigure = false;
9
-       }
10
-       if (state == PW_NODE_STATE_RUNNING)
11
-           node->reconfigure = false;
12
-   }
13
    if (old == PW_NODE_STATE_RUNNING &&
14
        state == PW_NODE_STATE_IDLE &&
15
        node->suspend_on_idle) {
16
pipewire-0.3.81.tar.gz/src/pipewire/keys.h -> pipewire-0.3.82.tar.gz/src/pipewire/keys.h Changed
10
 
1
@@ -38,6 +38,8 @@
2
 #define PW_KEY_SEC_GID         "pipewire.sec.gid"  /**< client gid, set by protocol*/
3
 #define PW_KEY_SEC_LABEL       "pipewire.sec.label"    /**< client security label, set by protocol*/
4
 
5
+#define PW_KEY_SEC_SOCKET      "pipewire.sec.socket"   /**< client socket name, set by protocol */
6
+
7
 #define PW_KEY_LIBRARY_NAME_SYSTEM "library.name.system"   /**< name of the system library to use */
8
 #define PW_KEY_LIBRARY_NAME_LOOP   "library.name.loop" /**< name of the loop library to use */
9
 #define PW_KEY_LIBRARY_NAME_DBUS   "library.name.dbus" /**< name of the dbus library to use */
10
pipewire-0.3.81.tar.gz/src/pipewire/log.c -> pipewire-0.3.82.tar.gz/src/pipewire/log.c Changed
15
 
1
@@ -233,13 +233,6 @@
2
    }
3
 }
4
 
5
-SPA_EXPORT
6
-void
7
-_pw_log_topic_new(struct spa_log_topic *topic)
8
-{
9
-   spa_log_topic_init(global_log, topic);
10
-}
11
-
12
 void
13
 pw_log_init(void)
14
 {
15
pipewire-0.3.81.tar.gz/src/pipewire/log.h -> pipewire-0.3.82.tar.gz/src/pipewire/log.h Changed
19
 
1
@@ -72,17 +72,6 @@
2
        int line, const char *func,
3
        const char *fmt, va_list args) SPA_PRINTF_FUNC(5, 0);
4
 
5
-/** Initialize the log topic. The returned topic is owned by the pipewire
6
- * context and the topic must not be modified or freed.
7
- * Do not use this function directly, use one of PW_LOG_TOPIC_* instead.
8
- *
9
- * \see PW_LOG_TOPIC_STATIC
10
- * \see PW_LOG_TOPIC_EXTERN
11
- * \see PW_LOG_TOPIC
12
- */
13
-void
14
-_pw_log_topic_new(struct spa_log_topic *topic);
15
-
16
 /**
17
  * Declare a static log topic named \a var. The usual usage is:
18
  * \code
19
pipewire-0.3.81.tar.gz/src/pipewire/map.h -> pipewire-0.3.82.tar.gz/src/pipewire/map.h Changed
21
 
1
@@ -189,7 +189,7 @@
2
  * \param id the index to look at
3
  * \return the item at \a id or NULL when no such item exists
4
  */
5
-static inline void *pw_map_lookup(struct pw_map *map, uint32_t id)
6
+static inline void *pw_map_lookup(const struct pw_map *map, uint32_t id)
7
 {
8
    if (SPA_LIKELY(pw_map_check_id(map, id))) {
9
        union pw_map_item *item = pw_map_get_item(map, id);
10
@@ -207,8 +207,8 @@
11
  * \param data data to pass to \a func
12
  * \return the result of the last call to \a func or 0 when all callbacks returned 0.
13
  */
14
-static inline int pw_map_for_each(struct pw_map *map,
15
-                  int (*func) (void *item_data, void *data), void *data)
16
+static inline int pw_map_for_each(const struct pw_map *map,
17
+                 int (*func) (void *item_data, void *data), void *data)
18
 {
19
    union pw_map_item *item;
20
    int res = 0;
21
pipewire-0.3.81.tar.gz/src/pipewire/private.h -> pipewire-0.3.82.tar.gz/src/pipewire/private.h Changed
10
 
1
@@ -671,7 +671,7 @@
2
    unsigned int added:1;       /**< the node was add to graph */
3
    unsigned int pause_on_idle:1;   /**< Pause processing when IDLE */
4
    unsigned int suspend_on_idle:1;
5
-   unsigned int reconfigure:1;
6
+   unsigned int need_resume:1;
7
    unsigned int forced_rate:1;
8
    unsigned int forced_quantum:1;
9
    unsigned int trigger:1;     /**< has the TRIGGER property and needs an extra
10
pipewire-0.3.81.tar.gz/src/pipewire/stream.c -> pipewire-0.3.82.tar.gz/src/pipewire/stream.c Changed
15
 
1
@@ -2034,10 +2034,10 @@
2
    if ((str = getenv("PIPEWIRE_QUANTUM")) != NULL) {
3
        struct spa_fraction q;
4
        if (sscanf(str, "%u/%u", &q.num, &q.denom) == 2 && q.denom != 0) {
5
-           pw_properties_setf(stream->properties, PW_KEY_NODE_RATE,
6
+           pw_properties_setf(stream->properties, PW_KEY_NODE_FORCE_RATE,
7
                    "1/%u", q.denom);
8
-           pw_properties_setf(stream->properties, PW_KEY_NODE_LATENCY,
9
-                   "%u/%u", q.num, q.denom);
10
+           pw_properties_setf(stream->properties, PW_KEY_NODE_FORCE_QUANTUM,
11
+                   "%u", q.num);
12
        }
13
    }
14
    if ((str = getenv("PIPEWIRE_LATENCY")) != NULL)
15
pipewire-0.3.81.tar.gz/src/tools/pw-cat.c -> pipewire-0.3.82.tar.gz/src/tools/pw-cat.c Changed
11
 
1
@@ -1977,7 +1977,8 @@
2
        uint32_t i, n_items = 0;
3
 
4
        for (i = 0; i < data.props->dict.n_items; i++) {
5
-           if (spa_strstartswith(data.props->dict.itemsi.key, "media."))
6
+           if (n_items < SPA_N_ELEMENTS(items) &&
7
+               spa_strstartswith(data.props->dict.itemsi.key, "media."))
8
                itemsn_items++ = data.props->dict.itemsi;
9
        }
10
        if (n_items > 0) {
11
Refresh

No build results available

Refresh

No rpmlint results available

Request History
Bjørn Lie's avatar

zaitor created request over 1 year ago

New release


Bjørn Lie's avatar

zaitor accepted request over 1 year ago

Xin