Changes of Revision 13

pipewire-0.3.54.tar.gz/src/daemon/filter-chain/duplicate-FL.conf Deleted
x
 
1
@@ -1,49 +0,0 @@
2
-# An example filter chain for duplicating the FL channel
3
-# to FL and FR.
4
-#
5
-# Copy this file into a conf.d/ directory
6
-#
7
-context.modules = 
8
-    { name = libpipewire-module-filter-chain
9
-        args = {
10
-            node.description = "Remap example"
11
-            media.name       = "Remap example"
12
-            filter.graph = {
13
-                nodes = 
14
-                    {
15
-                        name   = copyIL
16
-                        type   = builtin
17
-                        label  = copy
18
-                    }
19
-                    {
20
-                        name   = copyOL
21
-                        type   = builtin
22
-                        label  = copy
23
-                    }
24
-                    {
25
-                        name   = copyOR
26
-                        type   = builtin
27
-                        label  = copy
28
-                    }
29
-                
30
-                links = 
31
-           # we can only tee from nodes, not inputs so we need
32
-           # to copy the inputs and then tee.
33
-                    { output = "copyIL:Out" input = "copyOL:In" }
34
-                    { output = "copyIL:Out" input = "copyOR:In" }
35
-                
36
-                inputs  =  "copyIL:In" 
37
-                outputs =  "copyOL:Out" "copyOR:Out" 
38
-            }
39
-            capture.props = {
40
-                node.name        = "remap_input.remap-FL-to-FL-FR"
41
-                audio.position  =  FL 
42
-                stream.dont-remix = true
43
-            }
44
-            playback.props = {
45
-                node.name        = "remap_output.remap-FL-to-FL-FR"
46
-                audio.position  =  FL FR 
47
-            }
48
-        }
49
-    }
50
-
51
pipewire-0.3.54.tar.gz/NEWS -> pipewire-0.3.56.tar.gz/NEWS Changed
125
 
1
@@ -1,3 +1,113 @@
2
+# PipeWire 0.3.56 (2022-07-19)
3
+
4
+This is a quick bugfix release that is API and ABI compatible with previous
5
+0.3.x releases.
6
+
7
+## Highlights
8
+  - A critical bug that could crash JACK apps was fixed.
9
+  - Some more regressions in audiomixer were fixed. This should fix crackling
10
+    and stuttering in some cases as well as some channel mapping regressions.
11
+  - A bug in the alsa plugin was fixed that could cause stuttering in VMs.
12
+  - Bluetooth sources should have improved latency and rate control.
13
+  - Many more bugfixes and improvements.
14
+
15
+
16
+## Modules
17
+  - An experimental AVB module was added. It can expose PipeWire as an AVB
18
+    entity and initiate (broken) streaming between entities.
19
+  - module-loopback now handles the cases where the input and output channels
20
+    are different without crashing or producing silence.
21
+  - The filter-chain module now correctly calculates the output size without
22
+    crashing in some cases. It also skips invalid ports instead of crashing.
23
+  - Handle and report pthread errors better.
24
+
25
+## SPA
26
+  - The resampler qualities were tweaked a little.
27
+  - A bug that would sometimes cut off the last part of a buffer was fixed in
28
+    the alsa plugin. This could cause broken audio in VMs. (#2536)
29
+  - Access to the alsa mixer and devices is now checked more thoroughly.
30
+    (#2534)
31
+  - The spa-resample tool can now also handle large downsampling rates without
32
+    crashing.
33
+  - Audioconverter now uses rounding for float to int conversions, which
34
+    reduces distortions. Compilation of the c functions was separated and uses
35
+    its own optimization flags now. Unit tests were added. (#2543)
36
+  - Noise shaping was improved in audioconvert. A new Wannamaker 3 tap shaper
37
+    was added.
38
+  - Audioconvert now uses a pattern for generating keep alive noise. This
39
+    should have much less energy and be even more inaudible. (#2540)
40
+  - A channel mapping bug was fixed in audioconvert. Unit tests were added.
41
+  - The dsp audio mixer would sometimes not mix enough and cause dropouts.
42
+    (#2525)
43
+
44
+## JACK
45
+  - A critical bug in the mixer was fixed. It would cause most JACK apps to
46
+    segfault at startup.
47
+
48
+## Bluetooth
49
+  - A new rate control algorithm was implemented for the sources.
50
+  - The media role on HSP/HFP streams is now fixed.
51
+
52
+## Pulse Server
53
+  - Add the resampler delay to delay reporting as well.
54
+
55
+
56
+Older versions:
57
+
58
+# PipeWire 0.3.55 (2022-07-12)
59
+
60
+This is a quick bugfix release that is API and ABI compatible with previous
61
+0.3.x releases.
62
+
63
+## Highlights
64
+  - Fix some more critical bugs in the new audioconvert and the queueing
65
+    in pw-stream that causes stuttering and hickups.
66
+  - HFP hardware volumes are now saved and restored.
67
+  - Format conversions and mixing was improved.
68
+  - Small bug fixes and improvements.
69
+
70
+## PipeWire
71
+  - The queueing in pw-stream was improved with support for buffer prefetch
72
+    in async mode.
73
+  - Add a pw-filter unit test.
74
+
75
+## tools
76
+  - pw-midiplay should now work again after improvements in pw-stream.
77
+
78
+## modules
79
+  - The RAOP module was improved to support auth_setup.
80
+  - The RAOP module should now handle timing packets better.
81
+  - Add some more filter-chain examples.
82
+  - The filter-chain now has a separate config file with the boilerplate
83
+    settings. The examples are now just config snippets that can be dropped
84
+    in .conf.d/ directories, such as the filter-chain.conf.d/ one.
85
+  - Start suggesting to use target.object instead of node.target in docs
86
+    and examples.
87
+
88
+## SPA
89
+  - Use the cosh window again for the resampler. It should now
90
+    give better resampler quality. (#2483)
91
+  - Rework the mixer functions. They were rewritten for higher precision and
92
+    better performance. Add unit tests and benchmarks.
93
+  - Improve format conversion for 32bits for avoid errors in clang because
94
+    of undefined behaviour at extreme ranges.
95
+  - Fix a bug in audioconvert where it would not consume the right
96
+    amount of samples when the resampler was disabled. This could cause
97
+    skipping and hickups. (#2519)
98
+  - Fix bug in audioconvert where it would try to convert the input samples
99
+    multiple times, causing strange artifacts when upmixing.
100
+  - Be more strict about valid JSON floats.
101
+  - device.vendor.id and device.product.id should now always show up in
102
+    0xXXXX format and should not be converted to floats in pw-dump anymore.
103
+  - Add triangular dither, add unit tests for noise generation, add some
104
+    more optimizations.
105
+
106
+## Bluetooth
107
+  - HFP and A2DP now expose different routes and thus can have different
108
+    volumes.
109
+  - HW Volumes for HFP are now synced better. Volume changes from HW buttons
110
+    are now also saved.
111
+
112
 # PipeWire 0.3.54 (2022-07-07)
113
 
114
 This is a quick bugfix release that is API and ABI compatible with previous
115
@@ -47,9 +157,6 @@
116
   - The source was rewritten to use a ringbuffer. This avoids regressions
117
     caused by audioconvert. 
118
 
119
-Older versions:
120
-
121
-
122
 # PipeWire 0.3.53 (2022-06-30)
123
 
124
 This is a bugfix release that is API and ABI compatible with previous
125
pipewire-0.3.54.tar.gz/doc/pipewire-modules.dox -> pipewire-0.3.56.tar.gz/doc/pipewire-modules.dox Changed
9
 
1
@@ -51,6 +51,7 @@
2
 
3
 - \subpage page_module_access
4
 - \subpage page_module_adapter
5
+- \subpage page_module_avb
6
 - \subpage page_module_client_device
7
 - \subpage page_module_client_node
8
 - \subpage page_module_echo_cancel
9
pipewire-0.3.54.tar.gz/doc/tutorial4.c -> pipewire-0.3.56.tar.gz/doc/tutorial4.c Changed
10
 
1
@@ -96,7 +96,7 @@
2
 
3
    pw_stream_connect(data.stream,
4
              PW_DIRECTION_OUTPUT,
5
-             argc > 1 ? (uint32_t)atoi(argv1) : PW_ID_ANY,
6
+             PW_ID_ANY,
7
              PW_STREAM_FLAG_AUTOCONNECT |
8
              PW_STREAM_FLAG_MAP_BUFFERS |
9
              PW_STREAM_FLAG_RT_PROCESS,
10
pipewire-0.3.54.tar.gz/doc/tutorial4.dox -> pipewire-0.3.56.tar.gz/doc/tutorial4.dox Changed
12
 
1
@@ -118,8 +118,8 @@
2
    pw_main_loop_run(data.loop);
3
 \endcode
4
 
5
-To connect we specify that we have a `PW_DIRECTION_OUTPUT` stream. `PW_ID_ANY`
6
-means that we are ok with connecting to any consumer. Next we set some flags:
7
+To connect we specify that we have a `PW_DIRECTION_OUTPUT` stream. The third argument
8
+is always `PW_ID_ANY`. Next we set some flags:
9
 
10
 - `PW_STREAM_FLAG_AUTOCONNECT`: Automatically connect this stream. This instructs
11
   the session manager to link us to some consumer.
12
pipewire-0.3.54.tar.gz/doc/tutorial5.c -> pipewire-0.3.56.tar.gz/doc/tutorial5.c Changed
39
 
1
@@ -83,19 +83,23 @@
2
    const struct spa_pod *params1;
3
    uint8_t buffer1024;
4
    struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer));
5
+   struct pw_properties *props;
6
 
7
    pw_init(&argc, &argv);
8
 
9
    data.loop = pw_main_loop_new(NULL);
10
 
11
+   props = pw_properties_new(PW_KEY_MEDIA_TYPE, "Video",
12
+           PW_KEY_MEDIA_CATEGORY, "Capture",
13
+           PW_KEY_MEDIA_ROLE, "Camera",
14
+           NULL);
15
+   if (argc > 1)
16
+       pw_properties_set(props, PW_KEY_TARGET_OBJECT, argv1);
17
+
18
    data.stream = pw_stream_new_simple(
19
            pw_main_loop_get_loop(data.loop),
20
            "video-capture",
21
-           pw_properties_new(
22
-               PW_KEY_MEDIA_TYPE, "Video",
23
-               PW_KEY_MEDIA_CATEGORY, "Capture",
24
-               PW_KEY_MEDIA_ROLE, "Camera",
25
-               NULL),
26
+           props,
27
            &stream_events,
28
            &data);
29
 
30
@@ -122,7 +126,7 @@
31
 
32
    pw_stream_connect(data.stream,
33
              PW_DIRECTION_INPUT,
34
-             argc > 1 ? (uint32_t)atoi(argv1) : PW_ID_ANY,
35
+             PW_ID_ANY,
36
              PW_STREAM_FLAG_AUTOCONNECT |
37
              PW_STREAM_FLAG_MAP_BUFFERS,
38
              params, 1);
39
pipewire-0.3.54.tar.gz/doc/tutorial5.dox -> pipewire-0.3.56.tar.gz/doc/tutorial5.dox Changed
53
 
1
@@ -23,18 +23,25 @@
2
 Video Capture stream.
3
 
4
 \code{.c}
5
+   props = pw_properties_new(PW_KEY_MEDIA_TYPE, "Video",
6
+           PW_KEY_MEDIA_CATEGORY, "Capture",
7
+           PW_KEY_MEDIA_ROLE, "Camera",
8
+           NULL);
9
+   if (argc > 1)
10
+       pw_properties_set(props, PW_KEY_TARGET_OBJECT, argv1);
11
+
12
    data.stream = pw_stream_new_simple(
13
            pw_main_loop_get_loop(data.loop),
14
            "video-capture",
15
-           pw_properties_new(
16
-               PW_KEY_MEDIA_TYPE, "Video",
17
-               PW_KEY_MEDIA_CATEGORY, "Capture",
18
-               PW_KEY_MEDIA_ROLE, "Camera",
19
-               NULL),
20
+           props,
21
            &stream_events,
22
            &data);
23
 \endcode
24
 
25
+We also optionally allow the user to pass the name of the target node where the session
26
+manager is supposed to connect the node. The user may also give the value of the
27
+unique target node serial (`PW_KEY_OBJECT_SERIAL`) as the value.
28
+
29
 In addition to the `process` event, we are also going to listen to a new event,
30
 `param_changed`:
31
 
32
@@ -122,7 +129,7 @@
33
 \code{.c}
34
    pw_stream_connect(data.stream,
35
              PW_DIRECTION_INPUT,
36
-             argc > 1 ? (uint32_t)atoi(argv1) : PW_ID_ANY,
37
+             PW_ID_ANY,
38
              PW_STREAM_FLAG_AUTOCONNECT |
39
              PW_STREAM_FLAG_MAP_BUFFERS,
40
              params, 1);
41
@@ -130,9 +137,8 @@
42
    pw_main_loop_run(data.loop);
43
 \endcode
44
 
45
-To connect we specify that we have a `PW_DIRECTION_INPUT` stream. `PW_ID_ANY`
46
-means that we are ok with connecting to any producer. We also allow the user
47
-to pass an optional target id.
48
+To connect we specify that we have a `PW_DIRECTION_INPUT` stream. The third
49
+argument is always `PW_ID_ANY`.
50
 
51
 We're setting the `PW_STREAM_FLAG_AUTOCONNECT` flag to make an automatic
52
 connection to a suitable camera and `PW_STREAM_FLAG_MAP_BUFFERS` to let the
53
pipewire-0.3.54.tar.gz/meson.build -> pipewire-0.3.56.tar.gz/meson.build Changed
8
 
1
@@ -1,5 +1,5 @@
2
 project('pipewire', 'c' ,
3
-  version : '0.3.54',
4
+  version : '0.3.56',
5
   license :  'MIT', 'LGPL-2.1-or-later', 'GPL-2.0-only' ,
6
   meson_version : '>= 0.59.0',
7
   default_options :  'warning_level=3',
8
pipewire-0.3.54.tar.gz/meson_options.txt -> pipewire-0.3.56.tar.gz/meson_options.txt Changed
9
 
1
@@ -245,3 +245,7 @@
2
        description: 'Build legacy rtkit module',
3
        type: 'boolean',
4
        value: 'true')
5
+option('avb',
6
+       description: 'Enable AVB code',
7
+       type: 'feature',
8
+       value: 'auto')
9
pipewire-0.3.54.tar.gz/pipewire-jack/src/meson.build -> pipewire-0.3.56.tar.gz/pipewire-jack/src/meson.build Changed
10
 
1
@@ -78,7 +78,7 @@
2
   endif
3
 
4
   pkgconfig.generate(filebase : 'jack',
5
-  libraries : pipewire_jack, pipewire_jackserver,
6
+  libraries : pipewire_jack,
7
   name : 'jack',
8
   description : 'PipeWire JACK API',
9
   version : '1.9.17',
10
pipewire-0.3.54.tar.gz/pipewire-jack/src/metadata.c -> pipewire-0.3.56.tar.gz/pipewire-jack/src/metadata.c Changed
10
 
1
@@ -210,7 +210,7 @@
2
    pthread_mutex_unlock(&globals.lock);
3
 
4
    if (c->property_callback && changed > 0) {
5
-       pw_log_info("emit %lu %s", subject, key);
6
+       pw_log_info("emit %"PRIu64" %s", (uint64_t)subject, key);
7
        c->property_callback(subject, key, change, c->property_arg);
8
    }
9
    return changed;
10
pipewire-0.3.54.tar.gz/pipewire-jack/src/pipewire-jack.c -> pipewire-0.3.56.tar.gz/pipewire-jack/src/pipewire-jack.c Changed
161
 
1
@@ -67,7 +67,7 @@
2
 #define JACK_PORT_TYPE_SIZE             32
3
 #define MONITOR_EXT            " Monitor"
4
 
5
-#define MAX_MIDI_MIX           1024
6
+#define MAX_MIX                1024
7
 #define MAX_BUFFER_FRAMES      8192
8
 
9
 #define MAX_ALIGN          16
10
@@ -106,9 +106,9 @@
11
 #define OBJECT_CHUNK       8
12
 #define RECYCLE_THRESHOLD  128
13
 
14
-typedef void (*mix2_func) (float *dst, float *src1, float *src2, int n_samples);
15
+typedef void (*mix_func) (float *dst, float *src, uint32_t n_src, bool aligned, uint32_t n_samples);
16
 
17
-static mix2_func mix2;
18
+static mix_func mix_function;
19
 
20
 struct object {
21
    struct spa_list link;
22
@@ -736,38 +736,40 @@
23
 
24
 #if defined (__SSE__)
25
 #include <xmmintrin.h>
26
-static void mix2_sse(float *dst, float *src1, float *src2, int n_samples)
27
+static void mix_sse(float *dst, float *src, uint32_t n_src, bool aligned, uint32_t n_samples)
28
 {
29
-   int n, unrolled;
30
-   __m128 in2;
31
+   uint32_t i, n, unrolled;
32
+   __m128 in1;
33
 
34
-   if (SPA_IS_ALIGNED(src1, 16) &&
35
-       SPA_IS_ALIGNED(src2, 16) &&
36
-       SPA_IS_ALIGNED(dst, 16))
37
-       unrolled = n_samples / 4;
38
+   if (SPA_IS_ALIGNED(dst, 16) && aligned)
39
+       unrolled = n_samples & ~3;
40
    else
41
        unrolled = 0;
42
 
43
-   for (n = 0; unrolled--; n += 4) {
44
-       in0 = _mm_load_ps(&src1n),
45
-       in1 = _mm_load_ps(&src2n),
46
-       in0 = _mm_add_ps(in0, in1);
47
+   for (n = 0; n < unrolled; n += 4) {
48
+       in0 = _mm_load_ps(&src0n);
49
+       for (i = 1; i < n_src; i++)
50
+           in0 = _mm_add_ps(in0, _mm_load_ps(&srcin));
51
        _mm_store_ps(&dstn, in0);
52
    }
53
    for (; n < n_samples; n++) {
54
-       in0 = _mm_load_ss(&src1n),
55
-       in1 = _mm_load_ss(&src2n),
56
-       in0 = _mm_add_ss(in0, in1);
57
+       in0 = _mm_load_ss(&src0n);
58
+       for (i = 1; i < n_src; i++)
59
+           in0 = _mm_add_ss(in0, _mm_load_ss(&srcin));
60
        _mm_store_ss(&dstn, in0);
61
    }
62
 }
63
 #endif
64
 
65
-static void mix2_c(float *dst, float *src1, float *src2, int n_samples)
66
+static void mix_c(float *dst, float *src, uint32_t n_src, bool aligned, uint32_t n_samples)
67
 {
68
-   int i;
69
-   for (i = 0; i < n_samples; i++)
70
-       dsti = src1i + src2i;
71
+   uint32_t n, i;
72
+   for (n = 0; n < n_samples; n++)  {
73
+       float t = src0n;
74
+       for (i = 1; i < n_src; i++)
75
+           t += srcin;
76
+       dstn = t;
77
+   }
78
 }
79
 
80
 SPA_EXPORT
81
@@ -3281,13 +3283,13 @@
82
 
83
    support = pw_context_get_support(client->context.context, &n_support);
84
 
85
-   mix2 = mix2_c;
86
+   mix_function = mix_c;
87
    cpu_iface = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_CPU);
88
    if (cpu_iface) {
89
 #if defined (__SSE__)
90
        uint32_t flags = spa_cpu_get_flags(cpu_iface);
91
        if (flags & SPA_CPU_FLAG_SSE)
92
-           mix2 = mix2_sse;
93
+           mix_function = mix_sse;
94
 #endif
95
    }
96
    client->context.old_thread_utils =
97
@@ -4416,13 +4418,14 @@
98
 {
99
    struct mix *mix;
100
    struct buffer *b;
101
-   int layer = 0;
102
    void *ptr = NULL;
103
+   float *mix_ptrMAX_MIX, *np;
104
+   uint32_t n_ptr = 0;
105
+   bool ptr_aligned = true;
106
 
107
    spa_list_for_each(mix, &p->mix, port_link) {
108
        struct spa_data *d;
109
        uint32_t offset, size;
110
-       void *np;
111
 
112
        pw_log_trace_fp("%p: port %s mix %d.%d get buffer %d",
113
                p->client, p->object->port.name, p->port_id, mix->id, frames);
114
@@ -4436,14 +4439,20 @@
115
        if (size / sizeof(float) < frames)
116
            continue;
117
 
118
-       np = SPA_PTROFF(d->data, offset, void);
119
-       if (layer++ == 0) {
120
-           ptr = np;
121
-       } else {
122
-           mix2(p->emptyptr, ptr, np, frames);
123
-           ptr = p->emptyptr;
124
-           p->zeroed = false;
125
-       }
126
+       np = SPA_PTROFF(d->data, offset, float);
127
+       if (!SPA_IS_ALIGNED(np, 16))
128
+           ptr_aligned = false;
129
+
130
+       mix_ptrn_ptr++ = np;
131
+       if (n_ptr == MAX_MIX)
132
+           break;
133
+   }
134
+   if (n_ptr == 1) {
135
+       ptr = mix_ptr0;
136
+   } else if (n_ptr > 1) {
137
+       ptr = p->emptyptr;
138
+       mix_function(ptr, mix_ptr, n_ptr, ptr_aligned, frames);
139
+       p->zeroed = false;
140
    }
141
    if (ptr == NULL)
142
        ptr = init_buffer(p);
143
@@ -4454,7 +4463,7 @@
144
 {
145
    struct mix *mix;
146
    void *ptr = p->emptyptr;
147
-   struct spa_pod_sequence *seqMAX_MIDI_MIX;
148
+   struct spa_pod_sequence *seqMAX_MIX;
149
    uint32_t n_seq = 0;
150
 
151
    jack_midi_clear_buffer(ptr);
152
@@ -4478,7 +4487,7 @@
153
            continue;
154
 
155
        seqn_seq++ = pod;
156
-       if (n_seq == MAX_MIDI_MIX)
157
+       if (n_seq == MAX_MIX)
158
            break;
159
    }
160
    convert_to_midi(seq, n_seq, ptr, p->client->fix_midi_events);
161
pipewire-0.3.54.tar.gz/pipewire-v4l2/src/v4l2-func.c -> pipewire-0.3.56.tar.gz/pipewire-v4l2/src/v4l2-func.c Changed
18
 
1
@@ -22,6 +22,16 @@
2
  * DEALINGS IN THE SOFTWARE.
3
  */
4
 
5
+
6
+/*
7
+ * We need to export open* etc., but _FORTIFY_SOURCE defines conflicting
8
+ * always_inline versions. Disable _FORTIFY_SOURCE for this file, so we
9
+ * can define our overrides.
10
+ */
11
+#ifdef _FORTIFY_SOURCE
12
+#undef _FORTIFY_SOURCE
13
+#endif
14
+
15
 #include <stdio.h>
16
 #include <errno.h>
17
 #include <fcntl.h>
18
pipewire-0.3.54.tar.gz/spa/include/spa/node/node.h -> pipewire-0.3.56.tar.gz/spa/include/spa/node/node.h Changed
14
 
1
@@ -632,6 +632,12 @@
2
     *
3
     * When the node can accept new input in the next cycle, the
4
     * SPA_STATUS_NEED_DATA bit will be set.
5
+    *
6
+    * Note that the node might return SPA_STATUS_NEED_DATA even when
7
+    * no input ports have this status. This means that the amount of
8
+    * data still available on the input ports is likely not going to
9
+    * be enough for the next cycle and the host might need to prefetch
10
+    * data for the next cycle.
11
     */
12
    int (*process) (void *object);
13
 };
14
pipewire-0.3.54.tar.gz/spa/include/spa/utils/defs.h -> pipewire-0.3.56.tar.gz/spa/include/spa/utils/defs.h Changed
17
 
1
@@ -131,13 +131,13 @@
2
 ({             \
3
    __typeof__(a) _min_a = (a); \
4
    __typeof__(b) _min_b = (b); \
5
-   SPA_LIKELY(_min_a < _min_b) ? _min_a : _min_b;  \
6
+   SPA_LIKELY(_min_a <= _min_b) ? _min_a : _min_b; \
7
 })
8
 #define SPA_MAX(a,b)       \
9
 ({             \
10
    __typeof__(a) _max_a = (a); \
11
    __typeof__(b) _max_b = (b); \
12
-   SPA_LIKELY(_max_a > _max_b) ? _max_a : _max_b;  \
13
+   SPA_LIKELY(_max_a >= _max_b) ? _max_a : _max_b; \
14
 })
15
 #define SPA_CLAMP(v,low,high)              \
16
 ({                         \
17
pipewire-0.3.54.tar.gz/spa/include/spa/utils/json.h -> pipewire-0.3.56.tar.gz/spa/include/spa/utils/json.h Changed
10
 
1
@@ -240,6 +240,8 @@
2
 static inline int spa_json_parse_float(const char *val, int len, float *result)
3
 {
4
    char *end;
5
+   if (strspn(val, "+-0123456789.Ee") < (size_t)len)
6
+       return 0;
7
    *result = spa_strtof(val, &end);
8
    return len > 0 && end == val + len;
9
 }
10
pipewire-0.3.54.tar.gz/spa/plugins/alsa/alsa-pcm.c -> pipewire-0.3.56.tar.gz/spa/plugins/alsa/alsa-pcm.c Changed
27
 
1
@@ -1971,13 +1971,14 @@
2
        size_t n_bytes, n_frames;
3
        struct buffer *b;
4
        struct spa_data *d;
5
-       uint32_t i, offs, size;
6
+       uint32_t i, offs, size, last_offset;
7
 
8
        b = spa_list_first(&state->ready, struct buffer, link);
9
        d = b->buf->datas;
10
 
11
        offs = d0.chunk->offset + state->ready_offset;
12
-       size = d0.chunk->size - state->ready_offset;
13
+       last_offset = d0.chunk->size;
14
+       size = last_offset - state->ready_offset;
15
 
16
        offs = SPA_MIN(offs, d0.maxsize);
17
        size = SPA_MIN(d0.maxsize - offs, size);
18
@@ -2003,7 +2004,7 @@
19
 
20
        state->ready_offset += n_bytes;
21
 
22
-       if (state->ready_offset >= size) {
23
+       if (state->ready_offset >= last_offset) {
24
            spa_list_remove(&b->link);
25
            SPA_FLAG_SET(b->flags, BUFFER_FLAG_OUT);
26
            state->io->buffer_id = b->id;
27
pipewire-0.3.54.tar.gz/spa/plugins/alsa/alsa-udev.c -> pipewire-0.3.56.tar.gz/spa/plugins/alsa/alsa-udev.c Changed
87
 
1
@@ -477,9 +477,14 @@
2
    if ((str = udev_device_get_property_value(dev, "SUBSYSTEM")) && *str) {
3
        itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_SUBSYSTEM, str);
4
    }
5
-   if ((str = udev_device_get_property_value(dev, "ID_VENDOR_ID")) && *str)
6
-       itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_VENDOR_ID, str);
7
-
8
+   if ((str = udev_device_get_property_value(dev, "ID_VENDOR_ID")) && *str) {
9
+       int32_t val;
10
+       if (spa_atoi32(str, &val, 16)) {
11
+           char *dec = alloca(12); /* 0xffffffff is max */
12
+           snprintf(dec, 12, "0x%04x", val);
13
+           itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_VENDOR_ID, dec);
14
+       }
15
+   }
16
    str = udev_device_get_property_value(dev, "ID_VENDOR_FROM_DATABASE");
17
    if (!(str && *str)) {
18
        str = udev_device_get_property_value(dev, "ID_VENDOR_ENC");
19
@@ -494,9 +499,14 @@
20
    if (str && *str) {
21
        itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_VENDOR_NAME, str);
22
    }
23
-   if ((str = udev_device_get_property_value(dev, "ID_MODEL_ID")) && *str)
24
-       itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_PRODUCT_ID, str);
25
-
26
+   if ((str = udev_device_get_property_value(dev, "ID_MODEL_ID")) && *str) {
27
+       int32_t val;
28
+       if (spa_atoi32(str, &val, 16)) {
29
+           char *dec = alloca(12); /* 0xffffffff is max */
30
+           snprintf(dec, 12, "0x%04x", val);
31
+           itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_PRODUCT_ID, dec);
32
+       }
33
+   }
34
    str = udev_device_get_property_value(dev, "ID_MODEL_FROM_DATABASE");
35
    if (!(str && *str)) {
36
        str = udev_device_get_property_value(dev, "ID_MODEL_ENC");
37
@@ -528,11 +538,35 @@
38
 
39
 static bool check_access(struct impl *this, struct device *device)
40
 {
41
-   char path128;
42
-   bool accessible;
43
+   char path128, prefix32;
44
+   DIR *snd = NULL;
45
+   struct dirent *entry;
46
+   bool accessible = false;
47
 
48
    snprintf(path, sizeof(path), "/dev/snd/controlC%u", device->id);
49
-   accessible = access(path, R_OK|W_OK) >= 0;
50
+   if (access(path, R_OK|W_OK) >= 0 && (snd = opendir("/dev/snd"))) {
51
+       /*
52
+        * It's possible that controlCX is accessible before pcmCX* or
53
+        * the other way around. Return true only if all devices are
54
+                 * accessible.
55
+        */
56
+
57
+       accessible = true;
58
+       spa_scnprintf(prefix, sizeof(prefix), "pcmC%uD", device->id);
59
+       while ((entry = readdir(snd)) != NULL) {
60
+           if (!(entry->d_type == DT_CHR &&
61
+                   spa_strstartswith(entry->d_name, prefix)))
62
+               continue;
63
+
64
+           snprintf(path, sizeof(path), "/dev/snd/%.32s", entry->d_name);
65
+           if (access(path, R_OK|W_OK) < 0) {
66
+               accessible = false;
67
+               break;
68
+           }
69
+       }
70
+       closedir(snd);
71
+   }
72
+
73
    if (accessible != device->accessible)
74
        spa_log_debug(this->log, "%s accessible:%u", path, accessible);
75
    device->accessible = accessible;
76
@@ -645,10 +679,6 @@
77
            /* Device becomes accessible or not busy */
78
            if ((event->mask & (IN_ATTRIB | IN_CLOSE_WRITE))) {
79
                bool access;
80
-
81
-               if ((event->mask & IN_ATTRIB) &&
82
-                       spa_strstartswith(event->name, "pcm"))
83
-                   continue;
84
                if (sscanf(event->name, "controlC%u", &id) != 1 &&
85
                        sscanf(event->name, "pcmC%uD", &id) != 1)
86
                    continue;
87
pipewire-0.3.54.tar.gz/spa/plugins/audioconvert/audioconvert.c -> pipewire-0.3.56.tar.gz/spa/plugins/audioconvert/audioconvert.c Changed
201
 
1
@@ -628,8 +628,8 @@
2
            param = spa_pod_builder_add_object(&b,
3
                SPA_TYPE_OBJECT_PropInfo, id,
4
                SPA_PROP_INFO_name, SPA_POD_String("dither.noise"),
5
-               SPA_PROP_INFO_description, SPA_POD_String("Add dithering noise"),
6
-               SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Int(this->dir1.conv.noise, 0, 16),
7
+               SPA_PROP_INFO_description, SPA_POD_String("Add noise bits"),
8
+               SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Int(this->dir1.conv.noise_bits, 0, 16),
9
                SPA_PROP_INFO_params, SPA_POD_Bool(true));
10
            break;
11
        case 23:
12
@@ -643,7 +643,7 @@
13
                0);
14
            spa_pod_builder_prop(&b, SPA_PROP_INFO_labels, 0);
15
            spa_pod_builder_push_struct(&b, &f1);
16
-           for (i = 0; i < SPA_N_ELEMENTS(channelmix_upmix_info); i++) {
17
+           for (i = 0; i < SPA_N_ELEMENTS(dither_method_info); i++) {
18
                spa_pod_builder_string(&b, dither_method_infoi.label);
19
                spa_pod_builder_string(&b, dither_method_infoi.description);
20
            }
21
@@ -719,7 +719,7 @@
22
            spa_pod_builder_string(&b, "resample.disable");
23
            spa_pod_builder_bool(&b, p->resample_disabled);
24
            spa_pod_builder_string(&b, "dither.noise");
25
-           spa_pod_builder_int(&b, this->dir1.conv.noise);
26
+           spa_pod_builder_int(&b, this->dir1.conv.noise_bits);
27
            spa_pod_builder_string(&b, "dither.method");
28
            spa_pod_builder_string(&b, dither_method_infothis->dir1.conv.method.label);
29
            spa_pod_builder_pop(&b, &f1);
30
@@ -792,7 +792,7 @@
31
    else if (spa_streq(k, "resample.disable"))
32
        this->props.resample_disabled = spa_atob(s);
33
    else if (spa_streq(k, "dither.noise"))
34
-       spa_atou32(s, &this->dir1.conv.noise, 0);
35
+       spa_atou32(s, &this->dir1.conv.noise_bits, 0);
36
    else if (spa_streq(k, "dither.method"))
37
        this->dir1.conv.method = dither_method_from_label(s);
38
    else
39
@@ -1452,7 +1452,7 @@
40
    spa_log_debug(this->log, "%p: got converter features %08x:%08x quant:%d:%d"
41
            " passthrough:%d remap:%d %s", this,
42
            this->cpu_flags, out->conv.cpu_flags, out->conv.method,
43
-           out->conv.noise, out->conv.is_passthrough, remap, out->conv.func_name);
44
+           out->conv.noise_bits, out->conv.is_passthrough, remap, out->conv.func_name);
45
 
46
    return 0;
47
 }
48
@@ -2246,6 +2246,33 @@
49
    struct spa_io_buffers *io, *ctrlio = NULL;
50
    const struct spa_pod_sequence *ctrl = NULL;
51
 
52
+   /* calculate quantum scale, this is how many samples we need to produce or
53
+    * consume. Also update the rate scale, this is sent to the resampler to adjust
54
+    * the rate, either when the graph clock changed or when the user adjusted the
55
+    * rate.  */
56
+   if (SPA_LIKELY(this->io_position)) {
57
+       double r =  this->rate_scale;
58
+
59
+       quant_samples = this->io_position->clock.duration;
60
+       if (this->direction == SPA_DIRECTION_INPUT) {
61
+           if (this->io_position->clock.rate.denom != this->resample.o_rate)
62
+               r = (double) this->io_position->clock.rate.denom / this->resample.o_rate;
63
+           else
64
+               r = 1.0;
65
+       } else {
66
+           if (this->io_position->clock.rate.denom != this->resample.i_rate)
67
+               r = (double) this->resample.i_rate / this->io_position->clock.rate.denom;
68
+           else
69
+               r = 1.0;
70
+       }
71
+       if (this->rate_scale != r) {
72
+           spa_log_info(this->log, "scale %f->%f", this->rate_scale, r);
73
+           this->rate_scale = r;
74
+       }
75
+   }
76
+   else
77
+       quant_samples = this->quantum_limit;
78
+
79
    dir = &this->dirSPA_DIRECTION_INPUT;
80
    in_passthrough = dir->conv.is_passthrough;
81
    max_in = UINT32_MAX;
82
@@ -2335,57 +2362,17 @@
83
        }
84
    }
85
 
86
-   /* calculate quantum scale */
87
-   if (SPA_LIKELY(this->io_position)) {
88
-       double r =  this->rate_scale;
89
-
90
-       quant_samples = this->io_position->clock.duration;
91
-       if (this->direction == SPA_DIRECTION_INPUT) {
92
-           if (this->io_position->clock.rate.denom != this->resample.o_rate)
93
-               r = (double) this->io_position->clock.rate.denom / this->resample.o_rate;
94
-           else
95
-               r = 1.0;
96
-       } else {
97
-           if (this->io_position->clock.rate.denom != this->resample.i_rate)
98
-               r = (double) this->resample.i_rate / this->io_position->clock.rate.denom;
99
-           else
100
-               r = 1.0;
101
-       }
102
-       if (this->rate_scale != r) {
103
-           spa_log_info(this->log, "scale %f->%f", this->rate_scale, r);
104
-           this->rate_scale = r;
105
-       }
106
-   }
107
-   else
108
-       quant_samples = this->quantum_limit;
109
-
110
-   if (SPA_UNLIKELY(draining))
111
-       n_samples = SPA_MIN(max_in, this->quantum_limit);
112
-   else {
113
-       n_samples = max_in - SPA_MIN(max_in, this->in_offset);
114
-   }
115
-
116
-   resample_passthrough = resample_is_passthrough(this);
117
-
118
+   /* calculate how many samples we are going to produce. */
119
    if (this->direction == SPA_DIRECTION_INPUT) {
120
-       uint32_t out = resample_update_rate_match(this, resample_passthrough, quant_samples, 0);
121
-       if (!in_avail || this->drained) {
122
-           spa_log_trace_fp(this->log, "%p: no input drained:%d", this, this->drained);
123
-           /* no input, ask for more */
124
-           res |= this->drained ? SPA_STATUS_DRAINED : SPA_STATUS_NEED_DATA;
125
-           return res;
126
-       }
127
        /* in split mode we need to output exactly the size of the
128
         * duration so we don't try to flush early */
129
-       n_samples = SPA_MIN(n_samples, out);
130
        max_out = quant_samples;
131
        flush_out = false;
132
    } else {
133
        /* in merge mode we consume one duration of samples and
134
         * always output the resulting data */
135
-       n_samples = SPA_MIN(n_samples, quant_samples);
136
        max_out = this->quantum_limit;
137
-       flush_out = flush_in = true;
138
+       flush_out = true;
139
    }
140
 
141
    dir = &this->dirSPA_DIRECTION_OUTPUT;
142
@@ -2418,6 +2405,7 @@
143
                    dst_datasremap = SPA_PTR_ALIGN(this->scratch, MAX_ALIGN, void);
144
                    spa_log_trace_fp(this->log, "%p: empty output %d->%d", this,
145
                        i * port->blocks + j, remap);
146
+                   max_out = SPA_MIN(max_out, this->empty_size / port->stride);
147
                }
148
            }
149
        } else {
150
@@ -2436,7 +2424,7 @@
151
                        volume *= this->props.channel.mute ? 0.0f :
152
                            this->props.channel.volumesremap;
153
 
154
-                   mon_max = SPA_MIN(bd->maxsize / port->stride, n_samples);
155
+                   mon_max = SPA_MIN(bd->maxsize / port->stride, max_in);
156
 
157
                    volume_process(&this->volume, bd->data, src_datasremap,
158
                            volume, mon_max);
159
@@ -2465,6 +2453,39 @@
160
            }
161
        }
162
    }
163
+
164
+
165
+   /* calculate how many samples at most we are going to consume. If we're
166
+    * draining, we consume as much as we can. Otherwise we consume what is
167
+    * left. */
168
+   if (SPA_UNLIKELY(draining))
169
+       n_samples = SPA_MIN(max_in, this->quantum_limit);
170
+   else {
171
+       n_samples = max_in - SPA_MIN(max_in, this->in_offset);
172
+   }
173
+   /* we only need to output the remaining samples */
174
+   n_out = max_out - SPA_MIN(max_out, this->out_offset);
175
+
176
+   resample_passthrough = resample_is_passthrough(this);
177
+
178
+   /* calculate how many samples we are going to consume. */
179
+   if (this->direction == SPA_DIRECTION_INPUT) {
180
+       uint32_t n_in;
181
+       /* then figure out how much input samples we need to consume */
182
+       n_in = resample_update_rate_match(this, resample_passthrough, n_out, 0);
183
+       if (!in_avail || this->drained) {
184
+           spa_log_trace_fp(this->log, "%p: no input drained:%d", this, this->drained);
185
+           /* no input, ask for more */
186
+           res |= this->drained ? SPA_STATUS_DRAINED : SPA_STATUS_NEED_DATA;
187
+           return res;
188
+       }
189
+       n_samples = SPA_MIN(n_samples, n_in);
190
+   } else {
191
+       /* in merge mode we consume one duration of samples */
192
+       n_samples = SPA_MIN(n_samples, quant_samples);
193
+       flush_in = true;
194
+   }
195
+
196
    mix_passthrough = SPA_FLAG_IS_SET(this->mix.flags, CHANNELMIX_FLAG_IDENTITY) &&
197
        (ctrlport == NULL || ctrlport->ctrl == NULL);
198
 
199
@@ -2482,27 +2503,35 @@
200
        dst_remap = (void **)dst_datas;
201
pipewire-0.3.54.tar.gz/spa/plugins/audioconvert/biquad.c -> pipewire-0.3.56.tar.gz/spa/plugins/audioconvert/biquad.c Changed
10
 
1
@@ -9,8 +9,6 @@
2
  */
3
 
4
 
5
-#include "config.h"
6
-
7
 #include <spa/utils/defs.h>
8
 
9
 #include <math.h>
10
pipewire-0.3.54.tar.gz/spa/plugins/audioconvert/crossover.c -> pipewire-0.3.56.tar.gz/spa/plugins/audioconvert/crossover.c Changed
10
 
1
@@ -3,8 +3,6 @@
2
  * found in the LICENSE file.
3
  */
4
 
5
-#include "config.h"
6
-
7
 #include <float.h>
8
 #include <string.h>
9
 
10
pipewire-0.3.54.tar.gz/spa/plugins/audioconvert/fmt-ops-avx2.c -> pipewire-0.3.56.tar.gz/spa/plugins/audioconvert/fmt-ops-avx2.c Changed
201
 
1
@@ -34,6 +34,15 @@
2
 #  define _mm256_setr_m128i(v0, v1) _mm256_set_m128i((v1), (v0))
3
 #endif
4
 
5
+#define _MM_CLAMP_PS(r,min,max)                \
6
+   _mm_min_ps(_mm_max_ps(r, min), max)
7
+
8
+#define _MM256_CLAMP_PS(r,min,max)         \
9
+   _mm256_min_ps(_mm256_max_ps(r, min), max)
10
+
11
+#define _MM_CLAMP_SS(r,min,max)                \
12
+   _mm_min_ss(_mm_max_ss(r, min), max)
13
+
14
 static void
15
 conv_s16_to_f32d_1s_avx2(void *data, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src,
16
        uint32_t n_channels, uint32_t n_samples)
17
@@ -538,8 +547,9 @@
18
    uint32_t n, unrolled;
19
    __m128 in1;
20
    __m128i out4;
21
-   __m128 scale = _mm_set1_ps(S32_SCALE);
22
-   __m128 int_max = _mm_set1_ps(S32_MAX);
23
+   __m128 scale = _mm_set1_ps(S24_SCALE);
24
+   __m128 int_max = _mm_set1_ps(S24_MAX);
25
+   __m128 int_min = _mm_set1_ps(S24_MIN);
26
 
27
    if (SPA_IS_ALIGNED(s0, 16))
28
        unrolled = n_samples & ~3;
29
@@ -548,8 +558,9 @@
30
 
31
    for(n = 0; n < unrolled; n += 4) {
32
        in0 = _mm_mul_ps(_mm_load_ps(&s0n), scale);
33
-       in0 = _mm_min_ps(in0, int_max);
34
-       out0 = _mm_cvttps_epi32(in0);
35
+       in0 = _MM_CLAMP_PS(in0, int_min, int_max);
36
+       out0 = _mm_cvtps_epi32(in0);
37
+       out0 = _mm_slli_epi32(out0, 8);
38
        out1 = _mm_shuffle_epi32(out0, _MM_SHUFFLE(0, 3, 2, 1));
39
        out2 = _mm_shuffle_epi32(out0, _MM_SHUFFLE(1, 0, 3, 2));
40
        out3 = _mm_shuffle_epi32(out0, _MM_SHUFFLE(2, 1, 0, 3));
41
@@ -563,8 +574,8 @@
42
    for(; n < n_samples; n++) {
43
        in0 = _mm_load_ss(&s0n);
44
        in0 = _mm_mul_ss(in0, scale);
45
-       in0 = _mm_min_ss(in0, int_max);
46
-       *d = _mm_cvtss_si32(in0);
47
+       in0 = _MM_CLAMP_SS(in0, int_min, int_max);
48
+       *d = _mm_cvtss_si32(in0) << 8;
49
        d += n_channels;
50
    }
51
 }
52
@@ -578,8 +589,9 @@
53
    uint32_t n, unrolled;
54
    __m256 in2;
55
    __m256i out2, t2;
56
-   __m256 scale = _mm256_set1_ps(S32_SCALE);
57
-   __m256 int_max = _mm256_set1_ps(S32_MAX);
58
+   __m256 scale = _mm256_set1_ps(S24_SCALE);
59
+   __m256 int_min = _mm256_set1_ps(S24_MIN);
60
+   __m256 int_max = _mm256_set1_ps(S24_MAX);
61
 
62
    if (SPA_IS_ALIGNED(s0, 32) &&
63
        SPA_IS_ALIGNED(s1, 32))
64
@@ -591,11 +603,13 @@
65
        in0 = _mm256_mul_ps(_mm256_load_ps(&s0n), scale);
66
        in1 = _mm256_mul_ps(_mm256_load_ps(&s1n), scale);
67
 
68
-       in0 = _mm256_min_ps(in0, int_max);
69
-       in1 = _mm256_min_ps(in1, int_max);
70
+       in0 = _MM256_CLAMP_PS(in0, int_min, int_max);
71
+       in1 = _MM256_CLAMP_PS(in1, int_min, int_max);
72
 
73
-       out0 = _mm256_cvttps_epi32(in0);    /* a0 a1 a2 a3 a4 a5 a6 a7 */
74
-       out1 = _mm256_cvttps_epi32(in1);    /* b0 b1 b2 b3 b4 b5 b6 b7 */
75
+       out0 = _mm256_cvtps_epi32(in0); /* a0 a1 a2 a3 a4 a5 a6 a7 */
76
+       out1 = _mm256_cvtps_epi32(in1); /* b0 b1 b2 b3 b4 b5 b6 b7 */
77
+       out0 = _mm256_slli_epi32(out0, 8);
78
+       out1 = _mm256_slli_epi32(out1, 8);
79
 
80
        t0 = _mm256_unpacklo_epi32(out0, out1); /* a0 b0 a1 b1 a4 b4 a5 b5 */
81
        t1 = _mm256_unpackhi_epi32(out0, out1); /* a2 b2 a3 b3 a6 b6 a7 b7 */
82
@@ -624,8 +638,9 @@
83
    for(; n < n_samples; n++) {
84
        __m128 in2;
85
        __m128i out2;
86
-       __m128 scale = _mm_set1_ps(S32_SCALE);
87
-       __m128 int_max = _mm_set1_ps(S32_MAX);
88
+       __m128 scale = _mm_set1_ps(S24_SCALE);
89
+       __m128 int_min = _mm_set1_ps(S24_MIN);
90
+       __m128 int_max = _mm_set1_ps(S24_MAX);
91
 
92
        in0 = _mm_load_ss(&s0n);
93
        in1 = _mm_load_ss(&s1n);
94
@@ -633,8 +648,9 @@
95
        in0 = _mm_unpacklo_ps(in0, in1);
96
 
97
        in0 = _mm_mul_ps(in0, scale);
98
-       in0 = _mm_min_ps(in0, int_max);
99
-       out0 = _mm_cvttps_epi32(in0);
100
+       in0 = _MM_CLAMP_PS(in0, int_min, int_max);
101
+       out0 = _mm_cvtps_epi32(in0);
102
+       out0 = _mm_slli_epi32(out0, 8);
103
        _mm_storel_epi64((__m128i*)d, out0);
104
        d += n_channels;
105
    }
106
@@ -649,8 +665,9 @@
107
    uint32_t n, unrolled;
108
    __m256 in4;
109
    __m256i out4, t4;
110
-   __m256 scale = _mm256_set1_ps(S32_SCALE);
111
-   __m256 int_max = _mm256_set1_ps(S32_MAX);
112
+   __m256 scale = _mm256_set1_ps(S24_SCALE);
113
+   __m256 int_min = _mm256_set1_ps(S24_MIN);
114
+   __m256 int_max = _mm256_set1_ps(S24_MAX);
115
 
116
    if (SPA_IS_ALIGNED(s0, 32) &&
117
        SPA_IS_ALIGNED(s1, 32) &&
118
@@ -666,15 +683,19 @@
119
        in2 = _mm256_mul_ps(_mm256_load_ps(&s2n), scale);
120
        in3 = _mm256_mul_ps(_mm256_load_ps(&s3n), scale);
121
 
122
-       in0 = _mm256_min_ps(in0, int_max);
123
-       in1 = _mm256_min_ps(in1, int_max);
124
-       in2 = _mm256_min_ps(in2, int_max);
125
-       in3 = _mm256_min_ps(in3, int_max);
126
+       in0 = _MM256_CLAMP_PS(in0, int_min, int_max);
127
+       in1 = _MM256_CLAMP_PS(in1, int_min, int_max);
128
+       in2 = _MM256_CLAMP_PS(in2, int_min, int_max);
129
+       in3 = _MM256_CLAMP_PS(in3, int_min, int_max);
130
 
131
-       out0 = _mm256_cvttps_epi32(in0); /* a0 a1 a2 a3 a4 a5 a6 a7 */
132
-       out1 = _mm256_cvttps_epi32(in1); /* b0 b1 b2 b3 b4 b5 b6 b7 */
133
-       out2 = _mm256_cvttps_epi32(in2); /* c0 c1 c2 c3 c4 c5 c6 c7 */
134
-       out3 = _mm256_cvttps_epi32(in3); /* d0 d1 d2 d3 d4 d5 d6 d7 */
135
+       out0 = _mm256_cvtps_epi32(in0); /* a0 a1 a2 a3 a4 a5 a6 a7 */
136
+       out1 = _mm256_cvtps_epi32(in1); /* b0 b1 b2 b3 b4 b5 b6 b7 */
137
+       out2 = _mm256_cvtps_epi32(in2); /* c0 c1 c2 c3 c4 c5 c6 c7 */
138
+       out3 = _mm256_cvtps_epi32(in3); /* d0 d1 d2 d3 d4 d5 d6 d7 */
139
+       out0 = _mm256_slli_epi32(out0, 8);
140
+       out1 = _mm256_slli_epi32(out1, 8);
141
+       out2 = _mm256_slli_epi32(out2, 8);
142
+       out3 = _mm256_slli_epi32(out3, 8);
143
 
144
        t0 = _mm256_unpacklo_epi32(out0, out1); /* a0 b0 a1 b1 a4 b4 a5 b5 */
145
        t1 = _mm256_unpackhi_epi32(out0, out1); /* a2 b2 a3 b3 a6 b6 a7 b7 */
146
@@ -699,8 +720,9 @@
147
    for(; n < n_samples; n++) {
148
        __m128 in4;
149
        __m128i out4;
150
-       __m128 scale = _mm_set1_ps(S32_SCALE);
151
-       __m128 int_max = _mm_set1_ps(S32_MAX);
152
+       __m128 scale = _mm_set1_ps(S24_SCALE);
153
+       __m128 int_min = _mm_set1_ps(S24_MIN);
154
+       __m128 int_max = _mm_set1_ps(S24_MAX);
155
 
156
        in0 = _mm_load_ss(&s0n);
157
        in1 = _mm_load_ss(&s1n);
158
@@ -712,8 +734,9 @@
159
        in0 = _mm_unpacklo_ps(in0, in1);
160
 
161
        in0 = _mm_mul_ps(in0, scale);
162
-       in0 = _mm_min_ps(in0, int_max);
163
-       out0 = _mm_cvttps_epi32(in0);
164
+       in0 = _MM_CLAMP_PS(in0, int_min, int_max);
165
+       out0 = _mm_cvtps_epi32(in0);
166
+       out0 = _mm_slli_epi32(out0, 8);
167
        _mm_storeu_si128((__m128i*)d, out0);
168
        d += n_channels;
169
    }
170
@@ -755,8 +778,8 @@
171
    for(n = 0; n < unrolled; n += 8) {
172
        in0 = _mm_mul_ps(_mm_load_ps(&s0n), int_scale);
173
        in1 = _mm_mul_ps(_mm_load_ps(&s0n+4), int_scale);
174
-       out0 = _mm_cvttps_epi32(in0);
175
-       out1 = _mm_cvttps_epi32(in1);
176
+       out0 = _mm_cvtps_epi32(in0);
177
+       out1 = _mm_cvtps_epi32(in1);
178
        out0 = _mm_packs_epi32(out0, out1);
179
 
180
        d0*n_channels = _mm_extract_epi16(out0, 0);
181
@@ -771,7 +794,7 @@
182
    }
183
    for(; n < n_samples; n++) {
184
        in0 = _mm_mul_ss(_mm_load_ss(&s0n), int_scale);
185
-       in0 = _mm_min_ss(int_max, _mm_max_ss(in0, int_min));
186
+       in0 = _MM_CLAMP_SS(in0, int_min, int_max);
187
        *d = _mm_cvtss_si32(in0);
188
        d += n_channels;
189
    }
190
@@ -798,8 +821,8 @@
191
        in0 = _mm256_mul_ps(_mm256_load_ps(&s0n+0), int_scale);
192
        in1 = _mm256_mul_ps(_mm256_load_ps(&s1n+0), int_scale);
193
 
194
-       out0 = _mm256_cvttps_epi32(in0); /* a0 a1 a2 a3 a4 a5 a6 a7 */
195
-       out1 = _mm256_cvttps_epi32(in1); /* b0 b1 b2 b3 b4 b5 b6 b7 */
196
+       out0 = _mm256_cvtps_epi32(in0); /* a0 a1 a2 a3 a4 a5 a6 a7 */
197
+       out1 = _mm256_cvtps_epi32(in1); /* b0 b1 b2 b3 b4 b5 b6 b7 */
198
 
199
        t0 = _mm256_unpacklo_epi32(out0, out1); /* a0 b0 a1 b1 a4 b4 a5 b5 */
200
        t1 = _mm256_unpackhi_epi32(out0, out1); /* a2 b2 a3 b3 a6 b6 a7 b7 */
201
pipewire-0.3.54.tar.gz/spa/plugins/audioconvert/fmt-ops-c.c -> pipewire-0.3.56.tar.gz/spa/plugins/audioconvert/fmt-ops-c.c Changed
201
 
1
@@ -33,7 +33,7 @@
2
 #include "fmt-ops.h"
3
 #include "law.h"
4
 
5
-#define MAKE_COPY(size)                                \
6
+#define MAKE_COPY(size)                                \
7
 void conv_copy ##size## d_c(struct convert *conv,              \
8
        void * SPA_RESTRICT dst, const void * SPA_RESTRICT src, \
9
        uint32_t n_samples)                     \
10
@@ -55,7 +55,7 @@
11
 MAKE_COPY(32);
12
 MAKE_COPY(64);
13
 
14
-#define MAKE_D_TO_D(sname,stype,dname,dtype,func)              \
15
+#define MAKE_D_TO_D(sname,stype,dname,dtype,func)              \
16
 void conv_ ##sname## d_to_ ##dname## d_c(struct convert *conv,         \
17
        void * SPA_RESTRICT dst, const void * SPA_RESTRICT src, \
18
                 uint32_t n_samples)                        \
19
@@ -65,11 +65,11 @@
20
        const stype *s = srci;                  \
21
        dtype *d = dsti;                        \
22
        for (j = 0; j < n_samples; j++)                 \
23
-           dj = func (sj);                 \
24
+           dj = func (sj);                 \
25
    }                                   \
26
 }
27
 
28
-#define MAKE_I_TO_I(sname,stype,dname,dtype,func)              \
29
+#define MAKE_I_TO_I(sname,stype,dname,dtype,func)              \
30
 void conv_ ##sname## _to_ ##dname## _c(struct convert *conv,           \
31
        void * SPA_RESTRICT dst, const void * SPA_RESTRICT src, \
32
                 uint32_t n_samples)                        \
33
@@ -79,10 +79,10 @@
34
    dtype *d = dst0;                            \
35
    n_samples *= conv->n_channels;                      \
36
    for (j = 0; j < n_samples; j++)                     \
37
-       dj = func (sj);                     \
38
+       dj = func (sj);                     \
39
 }
40
 
41
-#define MAKE_I_TO_D(sname,stype,dname,dtype,func)              \
42
+#define MAKE_I_TO_D(sname,stype,dname,dtype,func)              \
43
 void conv_ ##sname## _to_ ##dname## d_c(struct convert *conv,          \
44
        void * SPA_RESTRICT dst, const void * SPA_RESTRICT src, \
45
                 uint32_t n_samples)                        \
46
@@ -92,11 +92,11 @@
47
    uint32_t i, j, n_channels = conv->n_channels;               \
48
    for (j = 0; j < n_samples; j++) {                   \
49
        for (i = 0; i < n_channels; i++)                \
50
-           dij = func (*s++);                  \
51
+           dij = func (*s++);                  \
52
    }                                   \
53
 }
54
 
55
-#define MAKE_D_TO_I(sname,stype,dname,dtype,func)              \
56
+#define MAKE_D_TO_I(sname,stype,dname,dtype,func)              \
57
 void conv_ ##sname## d_to_ ##dname## _c(struct convert *conv,          \
58
        void * SPA_RESTRICT dst, const void * SPA_RESTRICT src, \
59
                 uint32_t n_samples)                        \
60
@@ -106,7 +106,7 @@
61
    uint32_t i, j, n_channels = conv->n_channels;               \
62
    for (j = 0; j < n_samples; j++) {                   \
63
        for (i = 0; i < n_channels; i++)                \
64
-           *d++ = func (sij);                  \
65
+           *d++ = func (sij);                  \
66
    }                                   \
67
 }
68
 
69
@@ -164,8 +164,7 @@
70
 MAKE_I_TO_I(f64, double, f32, float, (float));
71
 MAKE_I_TO_D(f64, double, f32, float, (float));
72
 MAKE_D_TO_I(f64, double, f32, float, (float));
73
-MAKE_I_TO_D(f64s, double, f32, float, bswap_64); /* FIXME */
74
-
75
+MAKE_I_TO_D(f64s, uint64_t, f32, float, (float)F64S_TO_F64);
76
 
77
 /* from f32 */
78
 MAKE_D_TO_D(f32, float, u8, uint8_t, F32_TO_U8);
79
@@ -221,7 +220,7 @@
80
 MAKE_I_TO_I(f32, float, f64, double, (double));
81
 MAKE_I_TO_D(f32, float, f64, double, (double));
82
 MAKE_D_TO_I(f32, float, f64, double, (double));
83
-MAKE_D_TO_I(f32, float, f64s, double, bswap_32); /* FIXME */
84
+MAKE_D_TO_I(f32, float, f64s, uint64_t, F64_TO_F64S);
85
 
86
 
87
 static inline int32_t
88
@@ -231,132 +230,154 @@
89
         return (int32_t)(*state);
90
 }
91
 
92
-static inline void update_dither_c(struct convert *conv, uint32_t n_samples)
93
+static inline void update_noise_c(struct convert *conv, uint32_t n_samples)
94
 {
95
    uint32_t n;
96
-   float *dither = conv->dither, scale = conv->scale;
97
+   float *noise = conv->noise, scale = conv->scale;
98
    uint32_t *state = &conv->random0;
99
-
100
-   for (n = 0; n < n_samples; n++)
101
-       dithern = lcnoise(state) * scale;
102
+   int32_t *prev = &conv->prev0, old, new;
103
+
104
+   switch (conv->noise_method) {
105
+   case NOISE_METHOD_RECTANGULAR:
106
+       for (n = 0; n < n_samples; n++)
107
+           noisen = lcnoise(state) * scale;
108
+       break;
109
+   case NOISE_METHOD_TRIANGULAR:
110
+       for (n = 0; n < n_samples; n++)
111
+           noisen = (lcnoise(state) - lcnoise(state)) * scale;
112
+       break;
113
+   case NOISE_METHOD_TRIANGULAR_HF:
114
+       old = *prev;
115
+       for (n = 0; n < n_samples; n++) {
116
+           new = lcnoise(state);
117
+           noisen = (new - old) * scale;
118
+           old = new;
119
+       }
120
+       *prev = old;
121
+       break;
122
+   case NOISE_METHOD_PATTERN:
123
+       old = *prev;
124
+       for (n = 0; n < n_samples; n++)
125
+           noisen = conv->scale * (1-((old++>>10)&1));
126
+       *prev = old;
127
+       break;
128
+   }
129
 }
130
 
131
-#define MAKE_D_dither(dname,dtype,func)                    \
132
-void conv_f32d_to_ ##dname## d_dither_c(struct convert *conv,          \
133
+#define MAKE_D_noise(dname,dtype,func)                     \
134
+void conv_f32d_to_ ##dname## d_noise_c(struct convert *conv,           \
135
        void * SPA_RESTRICT dst, const void * SPA_RESTRICT src, \
136
                 uint32_t n_samples)                        \
137
 {                                      \
138
-   uint32_t i, j, k, chunk, n_channels = conv->n_channels, dither_size = conv->dither_size;    \
139
-   float *dither = conv->dither;                       \
140
-   update_dither_c(conv, SPA_MIN(n_samples, dither_size));         \
141
+   uint32_t i, j, k, chunk, n_channels = conv->n_channels, noise_size = conv->noise_size;  \
142
+   float *noise = conv->noise;                     \
143
+   update_noise_c(conv, SPA_MIN(n_samples, noise_size));           \
144
    for (i = 0; i < n_channels; i++) {                  \
145
        const float *s = srci;                  \
146
        dtype *d = dsti;                        \
147
        for (j = 0; j < n_samples;) {                   \
148
-           chunk = SPA_MIN(n_samples - j, dither_size);        \
149
+           chunk = SPA_MIN(n_samples - j, noise_size);     \
150
            for (k = 0; k < chunk; k++, j++)            \
151
-               dj = func (sj, ditherk);            \
152
+               dj = func (sj, noisek);         \
153
        }                               \
154
    }                                   \
155
 }
156
 
157
-#define MAKE_I_dither(dname,dtype,func)                    \
158
-void conv_f32d_to_ ##dname## _dither_c(struct convert *conv,           \
159
+#define MAKE_I_noise(dname,dtype,func)                     \
160
+void conv_f32d_to_ ##dname## _noise_c(struct convert *conv,            \
161
        void * SPA_RESTRICT dst, const void * SPA_RESTRICT src, \
162
                 uint32_t n_samples)                        \
163
 {                                      \
164
    const float **s = (const float **) src;                 \
165
    dtype *d = dst0;                            \
166
-   uint32_t i, j, k, chunk, n_channels = conv->n_channels, dither_size = conv->dither_size;    \
167
-   float *dither = conv->dither;                       \
168
-   update_dither_c(conv, SPA_MIN(n_samples, dither_size));         \
169
+   uint32_t i, j, k, chunk, n_channels = conv->n_channels, noise_size = conv->noise_size;  \
170
+   float *noise = conv->noise;                     \
171
+   update_noise_c(conv, SPA_MIN(n_samples, noise_size));           \
172
    for (j = 0; j < n_samples;) {                       \
173
-       chunk = SPA_MIN(n_samples - j, dither_size);            \
174
+       chunk = SPA_MIN(n_samples - j, noise_size);         \
175
        for (k = 0; k < chunk; k++, j++) {              \
176
            for (i = 0; i < n_channels; i++)            \
177
-               *d++ = func (sij, ditherk);     \
178
+               *d++ = func (sij, noisek);      \
179
        }                               \
180
    }                                   \
181
 }
182
 
183
-MAKE_D_dither(u8, uint8_t, F32_TO_U8_D);
184
-MAKE_I_dither(u8, uint8_t, F32_TO_U8_D);
185
-MAKE_D_dither(s8, int8_t, F32_TO_S8_D);
186
-MAKE_I_dither(s8, int8_t, F32_TO_S8_D);
187
-MAKE_D_dither(s16, int16_t, F32_TO_S16_D);
188
-MAKE_I_dither(s16, int16_t, F32_TO_S16_D);
189
-MAKE_I_dither(s16s, uint16_t, F32_TO_S16S_D);
190
-MAKE_D_dither(s32, int32_t, F32_TO_S32_D);
191
-MAKE_I_dither(s32, int32_t, F32_TO_S32_D);
192
-MAKE_I_dither(s32s, uint32_t, F32_TO_S32S_D);
193
-MAKE_D_dither(s24, int24_t, F32_TO_S24_D);
194
-MAKE_I_dither(s24, int24_t, F32_TO_S24_D);
195
-MAKE_I_dither(s24s, int24_t, F32_TO_S24_D);
196
-MAKE_D_dither(s24_32, int32_t, F32_TO_S24_32_D);
197
-MAKE_I_dither(s24_32, int32_t, F32_TO_S24_32_D);
198
-MAKE_I_dither(s24_32s, int32_t, F32_TO_S24_32S_D);
199
-
200
-
201
pipewire-0.3.54.tar.gz/spa/plugins/audioconvert/fmt-ops-sse2.c -> pipewire-0.3.56.tar.gz/spa/plugins/audioconvert/fmt-ops-sse2.c Changed
201
 
1
@@ -26,6 +26,12 @@
2
 
3
 #include <emmintrin.h>
4
 
5
+#define _MM_CLAMP_PS(r,min,max)                \
6
+   _mm_min_ps(_mm_max_ps(r, min), max)
7
+
8
+#define _MM_CLAMP_SS(r,min,max)                \
9
+   _mm_min_ss(_mm_max_ss(r, min), max)
10
+
11
 static void
12
 conv_s16_to_f32d_1s_sse2(void *data, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src,
13
        uint32_t n_channels, uint32_t n_samples)
14
@@ -338,7 +344,7 @@
15
    float *d0 = dst0;
16
    uint32_t n, unrolled;
17
    __m128i in;
18
-   __m128 out, factor = _mm_set1_ps(1.0f / S32_SCALE);
19
+   __m128 out, factor = _mm_set1_ps(1.0f / S24_SCALE);
20
 
21
    if (SPA_IS_ALIGNED(d0, 16))
22
        unrolled = n_samples & ~3;
23
@@ -350,13 +356,14 @@
24
                    s1*n_channels,
25
                    s2*n_channels,
26
                    s3*n_channels);
27
+       in = _mm_srai_epi32(in, 8);
28
        out = _mm_cvtepi32_ps(in);
29
        out = _mm_mul_ps(out, factor);
30
        _mm_store_ps(&d0n, out);
31
        s += 4*n_channels;
32
    }
33
    for(; n < n_samples; n++) {
34
-       out = _mm_cvtsi32_ss(factor, s0);
35
+       out = _mm_cvtsi32_ss(factor, s0>>8);
36
        out = _mm_mul_ss(out, factor);
37
        _mm_store_ss(&d0n, out);
38
        s += n_channels;
39
@@ -383,8 +390,9 @@
40
    uint32_t n, unrolled;
41
    __m128 in1;
42
    __m128i out4;
43
-   __m128 scale = _mm_set1_ps(S32_SCALE);
44
-   __m128 int_max = _mm_set1_ps(S32_MAX);
45
+   __m128 scale = _mm_set1_ps(S24_SCALE);
46
+   __m128 int_min = _mm_set1_ps(S24_MIN);
47
+   __m128 int_max = _mm_set1_ps(S24_MAX);
48
 
49
    if (SPA_IS_ALIGNED(s0, 16))
50
        unrolled = n_samples & ~3;
51
@@ -393,8 +401,9 @@
52
 
53
    for(n = 0; n < unrolled; n += 4) {
54
        in0 = _mm_mul_ps(_mm_load_ps(&s0n), scale);
55
-       in0 = _mm_min_ps(in0, int_max);
56
-       out0 = _mm_cvttps_epi32(in0);
57
+       in0 = _MM_CLAMP_PS(in0, int_min, int_max);
58
+       out0 = _mm_cvtps_epi32(in0);
59
+       out0 = _mm_slli_epi32(out0, 8);
60
        out1 = _mm_shuffle_epi32(out0, _MM_SHUFFLE(0, 3, 2, 1));
61
        out2 = _mm_shuffle_epi32(out0, _MM_SHUFFLE(1, 0, 3, 2));
62
        out3 = _mm_shuffle_epi32(out0, _MM_SHUFFLE(2, 1, 0, 3));
63
@@ -408,8 +417,8 @@
64
    for(; n < n_samples; n++) {
65
        in0 = _mm_load_ss(&s0n);
66
        in0 = _mm_mul_ss(in0, scale);
67
-       in0 = _mm_min_ss(in0, int_max);
68
-       *d = _mm_cvtss_si32(in0);
69
+       in0 = _MM_CLAMP_SS(in0, int_min, int_max);
70
+       *d = _mm_cvtss_si32(in0) << 8;
71
        d += n_channels;
72
    }
73
 }
74
@@ -423,8 +432,9 @@
75
    uint32_t n, unrolled;
76
    __m128 in2;
77
    __m128i out2, t2;
78
-   __m128 scale = _mm_set1_ps(S32_SCALE);
79
-   __m128 int_max = _mm_set1_ps(S32_MAX);
80
+   __m128 scale = _mm_set1_ps(S24_SCALE);
81
+   __m128 int_min = _mm_set1_ps(S24_MIN);
82
+   __m128 int_max = _mm_set1_ps(S24_MAX);
83
 
84
    if (SPA_IS_ALIGNED(s0, 16) &&
85
        SPA_IS_ALIGNED(s1, 16))
86
@@ -436,11 +446,13 @@
87
        in0 = _mm_mul_ps(_mm_load_ps(&s0n), scale);
88
        in1 = _mm_mul_ps(_mm_load_ps(&s1n), scale);
89
 
90
-       in0 = _mm_min_ps(in0, int_max);
91
-       in1 = _mm_min_ps(in1, int_max);
92
+       in0 = _MM_CLAMP_PS(in0, int_min, int_max);
93
+       in1 = _MM_CLAMP_PS(in1, int_min, int_max);
94
 
95
-       out0 = _mm_cvttps_epi32(in0);
96
-       out1 = _mm_cvttps_epi32(in1);
97
+       out0 = _mm_cvtps_epi32(in0);
98
+       out1 = _mm_cvtps_epi32(in1);
99
+       out0 = _mm_slli_epi32(out0, 8);
100
+       out1 = _mm_slli_epi32(out1, 8);
101
 
102
        t0 = _mm_unpacklo_epi32(out0, out1);
103
        t1 = _mm_unpackhi_epi32(out0, out1);
104
@@ -458,8 +470,9 @@
105
        in0 = _mm_unpacklo_ps(in0, in1);
106
 
107
        in0 = _mm_mul_ps(in0, scale);
108
-       in0 = _mm_min_ps(in0, int_max);
109
-       out0 = _mm_cvttps_epi32(in0);
110
+       in0 = _MM_CLAMP_PS(in0, int_min, int_max);
111
+       out0 = _mm_cvtps_epi32(in0);
112
+       out0 = _mm_slli_epi32(out0, 8);
113
        _mm_storel_epi64((__m128i*)d, out0);
114
        d += n_channels;
115
    }
116
@@ -474,8 +487,9 @@
117
    uint32_t n, unrolled;
118
    __m128 in4;
119
    __m128i out4;
120
-   __m128 scale = _mm_set1_ps(S32_SCALE);
121
-   __m128 int_max = _mm_set1_ps(S32_MAX);
122
+   __m128 scale = _mm_set1_ps(S24_SCALE);
123
+   __m128 int_min = _mm_set1_ps(S24_MIN);
124
+   __m128 int_max = _mm_set1_ps(S24_MAX);
125
 
126
    if (SPA_IS_ALIGNED(s0, 16) &&
127
        SPA_IS_ALIGNED(s1, 16) &&
128
@@ -491,17 +505,21 @@
129
        in2 = _mm_mul_ps(_mm_load_ps(&s2n), scale);
130
        in3 = _mm_mul_ps(_mm_load_ps(&s3n), scale);
131
 
132
-       in0 = _mm_min_ps(in0, int_max);
133
-       in1 = _mm_min_ps(in1, int_max);
134
-       in2 = _mm_min_ps(in2, int_max);
135
-       in3 = _mm_min_ps(in3, int_max);
136
+       in0 = _MM_CLAMP_PS(in0, int_min, int_max);
137
+       in1 = _MM_CLAMP_PS(in1, int_min, int_max);
138
+       in2 = _MM_CLAMP_PS(in2, int_min, int_max);
139
+       in3 = _MM_CLAMP_PS(in3, int_min, int_max);
140
 
141
        _MM_TRANSPOSE4_PS(in0, in1, in2, in3);
142
 
143
-       out0 = _mm_cvttps_epi32(in0);
144
-       out1 = _mm_cvttps_epi32(in1);
145
-       out2 = _mm_cvttps_epi32(in2);
146
-       out3 = _mm_cvttps_epi32(in3);
147
+       out0 = _mm_cvtps_epi32(in0);
148
+       out1 = _mm_cvtps_epi32(in1);
149
+       out2 = _mm_cvtps_epi32(in2);
150
+       out3 = _mm_cvtps_epi32(in3);
151
+       out0 = _mm_slli_epi32(out0, 8);
152
+       out1 = _mm_slli_epi32(out1, 8);
153
+       out2 = _mm_slli_epi32(out2, 8);
154
+       out3 = _mm_slli_epi32(out3, 8);
155
 
156
        _mm_storeu_si128((__m128i*)(d + 0*n_channels), out0);
157
        _mm_storeu_si128((__m128i*)(d + 1*n_channels), out1);
158
@@ -520,8 +538,9 @@
159
        in0 = _mm_unpacklo_ps(in0, in1);
160
 
161
        in0 = _mm_mul_ps(in0, scale);
162
-       in0 = _mm_min_ps(in0, int_max);
163
-       out0 = _mm_cvttps_epi32(in0);
164
+       in0 = _MM_CLAMP_PS(in0, int_min, int_max);
165
+       out0 = _mm_cvtps_epi32(in0);
166
+       out0 = _mm_slli_epi32(out0, 8);
167
        _mm_storeu_si128((__m128i*)d, out0);
168
        d += n_channels;
169
    }
170
@@ -542,43 +561,83 @@
171
        conv_f32d_to_s32_1s_sse2(conv, &di, &srci, n_channels, n_samples);
172
 }
173
 
174
-static inline void update_dither_sse2(struct convert *conv, uint32_t n_samples)
175
+/* 32 bit xorshift PRNG, see https://en.wikipedia.org/wiki/Xorshift */
176
+#define _MM_XORSHIFT_EPI32(r)              \
177
+({                         \
178
+   __m128i i, t;                   \
179
+   i = _mm_load_si128((__m128i*)r);        \
180
+   t = _mm_slli_epi32(i, 13);          \
181
+   i = _mm_xor_si128(i, t);            \
182
+   t = _mm_srli_epi32(i, 17);          \
183
+   i = _mm_xor_si128(i, t);            \
184
+   t = _mm_slli_epi32(i, 5);           \
185
+   i = _mm_xor_si128(i, t);            \
186
+   _mm_store_si128((__m128i*)r, i);        \
187
+   i;                      \
188
+})
189
+
190
+
191
+static inline void update_noise_sse2(struct convert *conv, uint32_t n_samples)
192
 {
193
    uint32_t n;
194
    const uint32_t *r = SPA_PTR_ALIGN(conv->random, 16, uint32_t);
195
-   float *dither = SPA_PTR_ALIGN(conv->dither, 16, float);
196
-   __m128 scale = _mm_set1_ps(conv->scale), out1;
197
-   __m128i in1, t1;
198
-
199
-   for (n = 0; n < n_samples; n += 4) {
200
-       /* 32 bit xorshift PRNG, see https://en.wikipedia.org/wiki/Xorshift */
201
pipewire-0.3.54.tar.gz/spa/plugins/audioconvert/fmt-ops.c -> pipewire-0.3.56.tar.gz/spa/plugins/audioconvert/fmt-ops.c Changed
201
 
1
@@ -46,9 +46,9 @@
2
    const char *name;
3
 
4
    uint32_t cpu_flags;
5
-#define CONV_DITHER    (1<<0)
6
+#define CONV_NOISE (1<<0)
7
 #define CONV_SHAPE (1<<1)
8
-   uint32_t dither_flags;
9
+   uint32_t conv_flags;
10
 };
11
 
12
 #define MAKE(fmt1,fmt2,chan,func,...) \
13
@@ -105,13 +105,13 @@
14
    MAKE(F32P, F32, 0, conv_32d_to_32_c),
15
 
16
 #if defined (HAVE_SSE2)
17
-   MAKE(F32_OE, F32P, 0, conv_32s_to_32sd_sse2, SPA_CPU_FLAG_SSE2),
18
+   MAKE(F32_OE, F32P, 0, conv_32s_to_32d_sse2, SPA_CPU_FLAG_SSE2),
19
 #endif
20
-   MAKE(F32_OE, F32P, 0, conv_32s_to_32sd_c),
21
+   MAKE(F32_OE, F32P, 0, conv_32s_to_32d_c),
22
 #if defined (HAVE_SSE2)
23
-   MAKE(F32P, F32_OE, 0, conv_32sd_to_32s_sse2, SPA_CPU_FLAG_SSE2),
24
+   MAKE(F32P, F32_OE, 0, conv_32d_to_32s_sse2, SPA_CPU_FLAG_SSE2),
25
 #endif
26
-   MAKE(F32P, F32_OE, 0, conv_32sd_to_32s_c),
27
+   MAKE(F32P, F32_OE, 0, conv_32d_to_32s_c),
28
 
29
    MAKE(U32, F32, 0, conv_u32_to_f32_c),
30
    MAKE(U32, F32P, 0, conv_u32_to_f32d_c),
31
@@ -171,20 +171,20 @@
32
    /* from f32 */
33
    MAKE(F32, U8, 0, conv_f32_to_u8_c),
34
    MAKE(F32P, U8P, 0, conv_f32d_to_u8d_shaped_c, 0, CONV_SHAPE),
35
-   MAKE(F32P, U8P, 0, conv_f32d_to_u8d_dither_c, 0, CONV_DITHER),
36
+   MAKE(F32P, U8P, 0, conv_f32d_to_u8d_noise_c, 0, CONV_NOISE),
37
    MAKE(F32P, U8P, 0, conv_f32d_to_u8d_c),
38
    MAKE(F32, U8P, 0, conv_f32_to_u8d_c),
39
    MAKE(F32P, U8, 0, conv_f32d_to_u8_shaped_c, 0, CONV_SHAPE),
40
-   MAKE(F32P, U8, 0, conv_f32d_to_u8_dither_c, 0, CONV_DITHER),
41
+   MAKE(F32P, U8, 0, conv_f32d_to_u8_noise_c, 0, CONV_NOISE),
42
    MAKE(F32P, U8, 0, conv_f32d_to_u8_c),
43
 
44
    MAKE(F32, S8, 0, conv_f32_to_s8_c),
45
    MAKE(F32P, S8P, 0, conv_f32d_to_s8d_shaped_c, 0, CONV_SHAPE),
46
-   MAKE(F32P, S8P, 0, conv_f32d_to_s8d_dither_c, 0, CONV_DITHER),
47
+   MAKE(F32P, S8P, 0, conv_f32d_to_s8d_noise_c, 0, CONV_NOISE),
48
    MAKE(F32P, S8P, 0, conv_f32d_to_s8d_c),
49
    MAKE(F32, S8P, 0, conv_f32_to_s8d_c),
50
    MAKE(F32P, S8, 0, conv_f32d_to_s8_shaped_c, 0, CONV_SHAPE),
51
-   MAKE(F32P, S8, 0, conv_f32d_to_s8_dither_c, 0, CONV_DITHER),
52
+   MAKE(F32P, S8, 0, conv_f32d_to_s8_noise_c, 0, CONV_NOISE),
53
    MAKE(F32P, S8, 0, conv_f32d_to_s8_c),
54
 
55
    MAKE(F32P, ALAW, 0, conv_f32d_to_alaw_c),
56
@@ -199,7 +199,10 @@
57
    MAKE(F32, S16, 0, conv_f32_to_s16_c),
58
 
59
    MAKE(F32P, S16P, 0, conv_f32d_to_s16d_shaped_c, 0, CONV_SHAPE),
60
-   MAKE(F32P, S16P, 0, conv_f32d_to_s16d_dither_c, 0, CONV_DITHER),
61
+#if defined (HAVE_SSE2)
62
+   MAKE(F32P, S16P, 0, conv_f32d_to_s16d_noise_sse2, SPA_CPU_FLAG_SSE2, CONV_NOISE),
63
+#endif
64
+   MAKE(F32P, S16P, 0, conv_f32d_to_s16d_noise_c, 0, CONV_NOISE),
65
 #if defined (HAVE_SSE2)
66
    MAKE(F32P, S16P, 0, conv_f32d_to_s16d_sse2, SPA_CPU_FLAG_SSE2),
67
 #endif
68
@@ -208,7 +211,10 @@
69
    MAKE(F32, S16P, 0, conv_f32_to_s16d_c),
70
 
71
    MAKE(F32P, S16, 0, conv_f32d_to_s16_shaped_c, 0, CONV_SHAPE),
72
-   MAKE(F32P, S16, 0, conv_f32d_to_s16_dither_c, 0, CONV_DITHER),
73
+#if defined (HAVE_SSE2)
74
+   MAKE(F32P, S16, 0, conv_f32d_to_s16_noise_sse2, SPA_CPU_FLAG_SSE2, CONV_NOISE),
75
+#endif
76
+   MAKE(F32P, S16, 0, conv_f32d_to_s16_noise_c, 0, CONV_NOISE),
77
 #if defined (HAVE_NEON)
78
    MAKE(F32P, S16, 0, conv_f32d_to_s16_neon, SPA_CPU_FLAG_NEON),
79
 #endif
80
@@ -224,21 +230,21 @@
81
    MAKE(F32P, S16, 0, conv_f32d_to_s16_c),
82
 
83
    MAKE(F32P, S16_OE, 0, conv_f32d_to_s16s_shaped_c, 0, CONV_SHAPE),
84
-   MAKE(F32P, S16_OE, 0, conv_f32d_to_s16s_dither_c, 0, CONV_DITHER),
85
+   MAKE(F32P, S16_OE, 0, conv_f32d_to_s16s_noise_c, 0, CONV_NOISE),
86
    MAKE(F32P, S16_OE, 0, conv_f32d_to_s16s_c),
87
 
88
    MAKE(F32, U32, 0, conv_f32_to_u32_c),
89
    MAKE(F32P, U32, 0, conv_f32d_to_u32_c),
90
 
91
    MAKE(F32, S32, 0, conv_f32_to_s32_c),
92
-   MAKE(F32P, S32P, 0, conv_f32d_to_s32d_dither_c, 0, CONV_DITHER),
93
+   MAKE(F32P, S32P, 0, conv_f32d_to_s32d_noise_c, 0, CONV_NOISE),
94
    MAKE(F32P, S32P, 0, conv_f32d_to_s32d_c),
95
    MAKE(F32, S32P, 0, conv_f32_to_s32d_c),
96
 
97
 #if defined (HAVE_SSE2)
98
-   MAKE(F32P, S32, 0, conv_f32d_to_s32_dither_sse2, SPA_CPU_FLAG_SSE2, CONV_DITHER),
99
+   MAKE(F32P, S32, 0, conv_f32d_to_s32_noise_sse2, SPA_CPU_FLAG_SSE2, CONV_NOISE),
100
 #endif
101
-   MAKE(F32P, S32, 0, conv_f32d_to_s32_dither_c, 0, CONV_DITHER),
102
+   MAKE(F32P, S32, 0, conv_f32d_to_s32_noise_c, 0, CONV_NOISE),
103
 
104
 #if defined (HAVE_AVX2)
105
    MAKE(F32P, S32, 0, conv_f32d_to_s32_avx2, SPA_CPU_FLAG_AVX2),
106
@@ -248,33 +254,33 @@
107
 #endif
108
    MAKE(F32P, S32, 0, conv_f32d_to_s32_c),
109
 
110
-   MAKE(F32P, S32_OE, 0, conv_f32d_to_s32s_dither_c, 0, CONV_DITHER),
111
+   MAKE(F32P, S32_OE, 0, conv_f32d_to_s32s_noise_c, 0, CONV_NOISE),
112
    MAKE(F32P, S32_OE, 0, conv_f32d_to_s32s_c),
113
 
114
    MAKE(F32, U24, 0, conv_f32_to_u24_c),
115
    MAKE(F32P, U24, 0, conv_f32d_to_u24_c),
116
 
117
    MAKE(F32, S24, 0, conv_f32_to_s24_c),
118
-   MAKE(F32P, S24P, 0, conv_f32d_to_s24d_dither_c, 0, CONV_DITHER),
119
+   MAKE(F32P, S24P, 0, conv_f32d_to_s24d_noise_c, 0, CONV_NOISE),
120
    MAKE(F32P, S24P, 0, conv_f32d_to_s24d_c),
121
    MAKE(F32, S24P, 0, conv_f32_to_s24d_c),
122
-   MAKE(F32P, S24, 0, conv_f32d_to_s24_dither_c, 0, CONV_DITHER),
123
+   MAKE(F32P, S24, 0, conv_f32d_to_s24_noise_c, 0, CONV_NOISE),
124
    MAKE(F32P, S24, 0, conv_f32d_to_s24_c),
125
 
126
-   MAKE(F32P, S24_OE, 0, conv_f32d_to_s24s_dither_c, 0, CONV_DITHER),
127
+   MAKE(F32P, S24_OE, 0, conv_f32d_to_s24s_noise_c, 0, CONV_NOISE),
128
    MAKE(F32P, S24_OE, 0, conv_f32d_to_s24s_c),
129
 
130
    MAKE(F32, U24_32, 0, conv_f32_to_u24_32_c),
131
    MAKE(F32P, U24_32, 0, conv_f32d_to_u24_32_c),
132
 
133
    MAKE(F32, S24_32, 0, conv_f32_to_s24_32_c),
134
-   MAKE(F32P, S24_32P, 0, conv_f32d_to_s24_32d_dither_c, 0, CONV_DITHER),
135
+   MAKE(F32P, S24_32P, 0, conv_f32d_to_s24_32d_noise_c, 0, CONV_NOISE),
136
    MAKE(F32P, S24_32P, 0, conv_f32d_to_s24_32d_c),
137
    MAKE(F32, S24_32P, 0, conv_f32_to_s24_32d_c),
138
-   MAKE(F32P, S24_32, 0, conv_f32d_to_s24_32_dither_c, 0, CONV_DITHER),
139
+   MAKE(F32P, S24_32, 0, conv_f32d_to_s24_32_noise_c, 0, CONV_NOISE),
140
    MAKE(F32P, S24_32, 0, conv_f32d_to_s24_32_c),
141
 
142
-   MAKE(F32P, S24_32_OE, 0, conv_f32d_to_s24_32s_dither_c, 0, CONV_DITHER),
143
+   MAKE(F32P, S24_32_OE, 0, conv_f32d_to_s24_32s_noise_c, 0, CONV_NOISE),
144
    MAKE(F32P, S24_32_OE, 0, conv_f32d_to_s24_32s_c),
145
 
146
    MAKE(F32, F64, 0, conv_f32_to_f64_c),
147
@@ -350,7 +356,7 @@
148
 #define MATCH_DITHER(a,b)  ((a) == 0 || ((a) & (b)) == a)
149
 
150
 static const struct conv_info *find_conv_info(uint32_t src_fmt, uint32_t dst_fmt,
151
-       uint32_t n_channels, uint32_t cpu_flags, uint32_t dither_flags)
152
+       uint32_t n_channels, uint32_t cpu_flags, uint32_t conv_flags)
153
 {
154
    size_t i;
155
 
156
@@ -359,7 +365,7 @@
157
            conv_tablei.dst_fmt == dst_fmt &&
158
            MATCH_CHAN(conv_tablei.n_channels, n_channels) &&
159
            MATCH_CPU_FLAGS(conv_tablei.cpu_flags, cpu_flags) &&
160
-           MATCH_DITHER(conv_tablei.dither_flags, dither_flags))
161
+           MATCH_DITHER(conv_tablei.conv_flags, conv_flags))
162
            return &conv_tablei;
163
    }
164
    return NULL;
165
@@ -368,8 +374,8 @@
166
 static void impl_convert_free(struct convert *conv)
167
 {
168
    conv->process = NULL;
169
-   free(conv->dither);
170
-   conv->dither = NULL;
171
+   free(conv->noise);
172
+   conv->noise = NULL;
173
 }
174
 
175
 static bool need_dither(uint32_t format)
176
@@ -389,37 +395,109 @@
177
    return false;
178
 }
179
 
180
+/* filters based on F-weighted curves
181
+ * from 'Psychoacoustically Optimal Noise Shaping' (**)
182
+ * this filter is the "F-Weighted" noise filter described by Wannamaker
183
+ * It is designed to produce minimum audibility: */
184
+static const float wan3 = { /* Table 3; 3 Coefficients */
185
+   1.623f, -0.982f, 0.109f
186
+};
187
+/* Noise shaping coefficients from1, moves most power of the
188
+ * error noise into inaudible frequency ranges.
189
+ *
190
+ * 1
191
+ * "Minimally Audible Noise Shaping", Stanley P. Lipshitz,
192
+ * John Vanderkooy, and Robert A. Wannamaker,
193
+ * J. Audio Eng. Soc., Vol. 39, No. 11, November 1991. */
194
+static const float lips44 = { /* improved E-weighted (appendix: 5) */
195
+   2.033f, -2.165f, 1.959f, -1.590f, 0.6149f
196
+};
197
+
198
+static const struct dither_info {
199
+   uint32_t method;
200
+   uint32_t noise_method;
201
pipewire-0.3.54.tar.gz/spa/plugins/audioconvert/fmt-ops.h -> pipewire-0.3.56.tar.gz/spa/plugins/audioconvert/fmt-ops.h Changed
201
 
1
@@ -35,93 +35,100 @@
2
 #include <spa/utils/defs.h>
3
 #include <spa/utils/string.h>
4
 
5
+#define f32_round(a)   lrintf(a)
6
+
7
+#define ITOF(type,v,scale,offs) \
8
+   (((type)(v)) * (1.0f / (scale)) - (offs))
9
+#define FTOI(type,v,scale,offs,noise,min,max) \
10
+   (type)f32_round(SPA_CLAMP((v) * (scale) + (offs) + (noise), min, max))
11
+
12
 #define FMT_OPS_MAX_ALIGN  32
13
 
14
 #define U8_MIN         0u
15
 #define U8_MAX         255u
16
 #define U8_SCALE       128.f
17
 #define U8_OFFS            128.f
18
-#define U8_TO_F32(v)       ((((uint8_t)(v)) * (1.0f / U8_SCALE)) - 1.0f)
19
-#define F32_TO_U8(v)       (uint8_t)SPA_CLAMP((v) * U8_SCALE + U8_OFFS, U8_MIN, U8_MAX)
20
-#define F32_TO_U8_D(v,d)   (uint8_t)SPA_CLAMP((v) * U8_SCALE + U8_OFFS + (d), U8_MIN, U8_MAX)
21
+#define U8_TO_F32(v)       ITOF(uint8_t, v, U8_SCALE, 1.0f)
22
+#define F32_TO_U8_D(v,d)   FTOI(uint8_t, v, U8_SCALE, U8_OFFS, d, U8_MIN, U8_MAX)
23
+#define F32_TO_U8(v)       F32_TO_U8_D(v, 0.0f)
24
 
25
 #define S8_MIN         -128
26
 #define S8_MAX         127
27
 #define S8_SCALE       128.0f
28
-#define S8_TO_F32(v)       (((int8_t)(v)) * (1.0f / S8_SCALE))
29
-#define F32_TO_S8(v)       (int8_t)SPA_CLAMP((v) * S8_SCALE, S8_MIN, S8_MAX)
30
-#define F32_TO_S8_D(v,d)   (int8_t)SPA_CLAMP((v) * S8_SCALE + (d), S8_MIN, S8_MAX)
31
+#define S8_TO_F32(v)       ITOF(int8_t, v, S8_SCALE, 0.0f)
32
+#define F32_TO_S8_D(v,d)   FTOI(int8_t, v, S8_SCALE, 0.0f, d, S8_MIN, S8_MAX)
33
+#define F32_TO_S8(v)       F32_TO_S8_D(v, 0.0f);
34
 
35
 #define U16_MIN            0u
36
 #define U16_MAX            65535u
37
 #define U16_SCALE      32768.f
38
 #define U16_OFFS       32768.f
39
-#define U16_TO_F32(v)      ((((uint16_t)(v)) * (1.0f / U16_SCALE)) - 1.0f)
40
-#define U16S_TO_F32(v)     (((uint16_t)bswap_16((uint16_t)(v)) * (1.0f / U16_OFFS)) - 1.0f)
41
-#define F32_TO_U16(v)      (uint16_t)SPA_CLAMP((v) * U16_SCALE + U16_OFFS, U16_MIN, U16_MAX)
42
-#define F32_TO_U16_D(v,d)  (uint16_t)SPA_CLAMP((v) * U16_SCALE + U16_OFFS + (d), U16_MIN, U16_MAX)
43
-#define F32_TO_U16S(v)     bswap_16(F32_TO_U16(v))
44
+#define U16_TO_F32(v)      ITOF(uint16_t, v, U16_SCALE, 1.0f)
45
+#define U16S_TO_F32(v)     U16_TO_F32(bswap_16(v))
46
+#define F32_TO_U16_D(v,d)  FTOI(uint16_t, v, U16_SCALE, U16_OFFS, d, U16_MIN, U16_MAX)
47
+#define F32_TO_U16(v)      F32_TO_U16_D(v, 0.0f);
48
 #define F32_TO_U16S_D(v,d) bswap_16(F32_TO_U16_D(v,d))
49
+#define F32_TO_U16S(v)     bswap_16(F32_TO_U16(v))
50
 
51
 #define S16_MIN            -32768
52
 #define S16_MAX            32767
53
 #define S16_SCALE      32768.0f
54
-#define S16_TO_F32(v)      (((int16_t)(v)) * (1.0f / S16_SCALE))
55
-#define S16S_TO_F32(v)     (((int16_t)bswap_16(v)) * (1.0f / S16_SCALE))
56
-#define F32_TO_S16(v)      (int16_t)SPA_CLAMP((v) * S16_SCALE, S16_MIN, S16_MAX)
57
-#define F32_TO_S16_D(v,d)  (int16_t)SPA_CLAMP((v) * S16_SCALE + (d), S16_MIN, S16_MAX)
58
-#define F32_TO_S16S(v)     bswap_16(F32_TO_S16(v))
59
+#define S16_TO_F32(v)      ITOF(int16_t, v, S16_SCALE, 0.0f)
60
+#define S16S_TO_F32(v)     S16_TO_F32(bswap_16(v))
61
+#define F32_TO_S16_D(v,d)  FTOI(int16_t, v, S16_SCALE, 0.0f, d, S16_MIN, S16_MAX)
62
+#define F32_TO_S16(v)      F32_TO_S16_D(v, 0.0f)
63
 #define F32_TO_S16S_D(v,d) bswap_16(F32_TO_S16_D(v,d))
64
+#define F32_TO_S16S(v)     bswap_16(F32_TO_S16(v))
65
 
66
 #define U24_MIN            0u
67
 #define U24_MAX            16777215u
68
 #define U24_SCALE      8388608.f
69
 #define U24_OFFS       8388608.f
70
-#define U24_TO_F32(v)      ((u24_to_u32(v) * (1.0f / U24_SCALE)) - 1.0f)
71
-#define F32_TO_U24(v)      u32_to_u24(SPA_CLAMP((v) * U24_SCALE + U24_OFFS, U24_MIN, U24_MAX))
72
-#define F32_TO_U24_D(v,d)  u32_to_u24(SPA_CLAMP((v) * U24_SCALE + U24_OFFS + (d), U24_MIN, U24_MAX))
73
+#define U24_TO_F32(v)      ITOF(uint32_t, u24_to_u32(v), U24_SCALE, 1.0f)
74
+#define F32_TO_U24_D(v,d)  u32_to_u24(FTOI(uint32_t, v, U24_SCALE, U24_OFFS, d, U24_MIN, U24_MAX))
75
+#define F32_TO_U24(v)      F32_TO_U24_D(v, 0.0f)
76
 
77
 #define S24_MIN            -8388608
78
 #define S24_MAX            8388607
79
 #define S24_SCALE      8388608.0f
80
-#define S24_TO_F32(v)      (s24_to_s32(v) * (1.0f / S24_SCALE))
81
-#define S24S_TO_F32(v)     (s24_to_s32(bswap_s24(v)) * (1.0f / S24_SCALE))
82
-#define F32_TO_S24(v)      s32_to_s24(SPA_CLAMP((v) * S24_SCALE, S24_MIN, S24_MAX))
83
+#define S24_TO_F32(v)      ITOF(int32_t, s24_to_s32(v), S24_SCALE, 0.0f)
84
+#define S24S_TO_F32(v)     S24_TO_F32(bswap_s24(v))
85
+#define F32_TO_S24_D(v,d)  s32_to_s24(FTOI(int32_t, v, S24_SCALE, 0.0f, d, S24_MIN, S24_MAX))
86
+#define F32_TO_S24(v)      F32_TO_S24_D(v, 0.0f)
87
 #define F32_TO_S24S(v)     bswap_s24(F32_TO_S24(v))
88
-#define F32_TO_S24_D(v,d)  s32_to_s24(SPA_CLAMP((v) * S24_SCALE + (d), S24_MIN, S24_MAX))
89
+
90
+#define U24_32_TO_F32(v)   U32_TO_F32((v)<<8)
91
+#define U24_32S_TO_F32(v)  U24_32_TO_F32(bswap_32(v))
92
+#define F32_TO_U24_32_D(v,d)   FTOI(uint32_t, v, U24_SCALE, U24_OFFS, d, U24_MIN, U24_MAX)
93
+#define F32_TO_U24_32(v)   F32_TO_U24_32_D(v, 0.0f)
94
+#define F32_TO_U24_32S(v)  bswap_32(F32_TO_U24_32(v))
95
+#define F32_TO_U24_32S_D(v,d)  bswap_32(F32_TO_U24_32_D(v,d))
96
 
97
 #define U32_MIN            0u
98
-#define U32_MAX            4294967295
99
+#define U32_MAX            4294967295u
100
 #define U32_SCALE      2147483648.f
101
 #define U32_OFFS       2147483648.f
102
-#define U32_TO_F32(v)      ((((uint32_t)(v)) * (1.0f / U32_SCALE)) - 1.0f)
103
-#define F32_TO_U32(v)      (uint32_t)SPA_CLAMP((v) * U32_SCALE + U32_OFFS, U32_MIN, U32_MAX)
104
-#define F32_TO_U32_D(v,d)  (uint32_t)SPA_CLAMP((v) * U32_SCALE + U32_OFFS + (d), U32_MIN, U32_MAX)
105
+#define U32_TO_F32(v)      ITOF(uint32_t, (v) >> 8, U24_SCALE, 1.0f)
106
+#define F32_TO_U32(v)      (F32_TO_U24_32(v) << 8)
107
+#define F32_TO_U32_D(v,d)  (F32_TO_U24_32_D(v,d) << 8)
108
+
109
+#define S24_32_TO_F32(v)   S32_TO_F32((v)<<8)
110
+#define S24_32S_TO_F32(v)  S24_32_TO_F32(bswap_32(v))
111
+#define F32_TO_S24_32_D(v,d)   FTOI(int32_t, v, S24_SCALE, 0.0f, d, S24_MIN, S24_MAX)
112
+#define F32_TO_S24_32(v)   F32_TO_S24_32_D(v, 0.0f)
113
+#define F32_TO_S24_32S(v)  bswap_32(F32_TO_S24_32(v))
114
+#define F32_TO_S24_32S_D(v,d)  bswap_32(F32_TO_S24_32_D(v,d))
115
 
116
 #define S32_MIN            -2147483648
117
-#define S32_MAX            2147483520
118
+#define S32_MAX            2147483647
119
 #define S32_SCALE      2147483648.f
120
-#define S32_TO_F32(v)      (((int32_t)(v)) * (1.0f / S32_SCALE))
121
-#define S32S_TO_F32(v)     (((int32_t)bswap_32(v)) * (1.0f / S32_SCALE))
122
-#define F32_TO_S32(v)      (int32_t)SPA_CLAMP((v) * S32_SCALE, S32_MIN, S32_MAX)
123
-#define F32_TO_S32_D(v,d)  (int32_t)SPA_CLAMP((v) * S32_SCALE + (d), S32_MIN, S32_MAX)
124
+#define S32_TO_F32(v)      ITOF(int32_t, (v) >> 8, S24_SCALE, 0.0f)
125
+#define S32S_TO_F32(v)     S32_TO_F32(bswap_32(v))
126
+#define F32_TO_S32(v)      (F32_TO_S24_32(v) << 8)
127
+#define F32_TO_S32_D(v,d)  (F32_TO_S24_32_D(v,d) << 8)
128
 #define F32_TO_S32S(v)     bswap_32(F32_TO_S32(v))
129
 #define F32_TO_S32S_D(v,d) bswap_32(F32_TO_S32_D(v,d))
130
 
131
-#define U24_32_TO_F32(v)   U32_TO_F32((v)<<8)
132
-#define U24_32S_TO_F32(v)  U32_TO_F32(((int32_t)bswap_32(v))<<8)
133
-#define F32_TO_U24_32(v)   (uint32_t)SPA_CLAMP((v) * U24_SCALE + U24_OFFS, U24_MIN, U24_MAX)
134
-#define F32_TO_U24_32S(v)  bswap_32(F32_TO_U24_32(v))
135
-#define F32_TO_U24_32_D(v,d)   (uint32_t)SPA_CLAMP((v) * U24_SCALE + U24_OFFS + (d), U24_MIN, U24_MAX)
136
-#define F32_TO_U24_32S_D(v,d)  bswap_32(F32_TO_U24_32_D(v,d))
137
-
138
-#define S24_32_TO_F32(v)   S32_TO_F32((v)<<8)
139
-#define S24_32S_TO_F32(v)  S32_TO_F32(((int32_t)bswap_32(v))<<8)
140
-#define F32_TO_S24_32(v)   (int32_t)SPA_CLAMP((v) * S24_SCALE, S24_MIN, S24_MAX)
141
-#define F32_TO_S24_32S(v)  bswap_32(F32_TO_S24_32(v))
142
-#define F32_TO_S24_32_D(v,d)   (int32_t)SPA_CLAMP((v) * S24_SCALE + (d), S24_MIN, S24_MAX)
143
-#define F32_TO_S24_32S_D(v,d)  bswap_32(F32_TO_S24_32_D(v,d))
144
-
145
 typedef struct {
146
 #if __BYTE_ORDER == __LITTLE_ENDIAN
147
    uint8_t v3;
148
@@ -181,21 +188,33 @@
149
    return (int24_t) { .v1 = src.v3, .v2 = src.v2, .v3 = src.v1 };
150
 }
151
 
152
+#define F32_TO_F32S(v) \
153
+   bswap_32((union { uint32_t i; float f; }){ .f = (v) }.i)
154
+#define F32S_TO_F32(v) \
155
+   ((union { uint32_t i; float f; }){ .i = bswap_32(v) }.f)
156
+
157
+#define F64_TO_F64S(v) \
158
+   bswap_32((union { uint64_t i; double d; }){ .d = (v) }.i)
159
+#define F64S_TO_F64(v) \
160
+   ((union { uint64_t i; double d; }){ .i = bswap_32(v) }.d)
161
+
162
 #define NS_MAX 8
163
 #define NS_MASK    (NS_MAX-1)
164
 
165
 struct shaper {
166
-   float eNS_MAX;
167
+   float eNS_MAX * 2;
168
    uint32_t idx;
169
    float r;
170
 };
171
 
172
 struct convert {
173
-   uint32_t noise;
174
+   uint32_t noise_bits;
175
 #define DITHER_METHOD_NONE     0
176
 #define DITHER_METHOD_RECTANGULAR  1
177
 #define DITHER_METHOD_TRIANGULAR   2
178
-#define DITHER_METHOD_SHAPED_5     3
179
+#define DITHER_METHOD_TRIANGULAR_HF    3
180
+#define DITHER_METHOD_WANNAMAKER_3 4
181
+#define DITHER_METHOD_LIPSHITZ     5
182
    uint32_t method;
183
 
184
    uint32_t src_fmt;
185
@@ -209,8 +228,17 @@
186
 
187
    float scale;
188
    uint32_t random16 + FMT_OPS_MAX_ALIGN/4;
189
-   float *dither;
190
-   uint32_t dither_size;
191
+   int32_t prev16 + FMT_OPS_MAX_ALIGN/4;
192
+#define NOISE_METHOD_NONE      0
193
+#define NOISE_METHOD_RECTANGULAR   1
194
+#define NOISE_METHOD_TRIANGULAR        2
195
+#define NOISE_METHOD_TRIANGULAR_HF 3
196
+#define NOISE_METHOD_PATTERN       4
197
+   uint32_t noise_method;
198
+   float *noise;
199
+   uint32_t noise_size;
200
+   const float *ns;
201
pipewire-0.3.54.tar.gz/spa/plugins/audioconvert/meson.build -> pipewire-0.3.56.tar.gz/spa/plugins/audioconvert/meson.build Changed
39
 
1
@@ -7,6 +7,20 @@
2
 simd_cargs = 
3
 simd_dependencies = 
4
 
5
+audioconvert_c = static_library('audioconvert_c',
6
+   'channelmix-ops-c.c',
7
+    'biquad.c',
8
+    'crossover.c',
9
+    'volume-ops-c.c',
10
+    'resample-native-c.c',
11
+    'resample-peaks-c.c',
12
+    'fmt-ops-c.c' ,
13
+  c_args : '-Ofast', '-ffast-math',
14
+  dependencies :  spa_dep ,
15
+  install : false
16
+  )
17
+simd_dependencies += audioconvert_c
18
+
19
 if have_sse
20
   audioconvert_sse = static_library('audioconvert_sse',
21
     'resample-native-sse.c',
22
@@ -86,15 +100,10 @@
23
 
24
 audioconvert_lib = static_library('audioconvert',
25
   'fmt-ops.c',
26
-    'biquad.c',
27
-    'crossover.c',
28
     'channelmix-ops.c',
29
-    'channelmix-ops-c.c',
30
     'resample-native.c',
31
     'resample-peaks.c',
32
-    'fmt-ops-c.c',
33
-    'volume-ops.c',
34
-    'volume-ops-c.c' ,
35
+    'volume-ops.c' ,
36
   c_args :  simd_cargs, '-O3',
37
   link_with : simd_dependencies,
38
   include_directories : configinc,
39
pipewire-0.3.56.tar.gz/spa/plugins/audioconvert/resample-native-c.c Added
67
 
1
@@ -0,0 +1,65 @@
2
+/* Spa
3
+ *
4
+ * Copyright © 2019 Wim Taymans
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a
7
+ * copy of this software and associated documentation files (the "Software"),
8
+ * to deal in the Software without restriction, including without limitation
9
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
+ * and/or sell copies of the Software, and to permit persons to whom the
11
+ * Software is furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice (including the next
14
+ * paragraph) shall be included in all copies or substantial portions of the
15
+ * Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23
+ * DEALINGS IN THE SOFTWARE.
24
+ */
25
+
26
+#include "resample-native-impl.h"
27
+
28
+static void inner_product_c(float *d, const float * SPA_RESTRICT s,
29
+       const float * SPA_RESTRICT taps, uint32_t n_taps)
30
+{
31
+   float sum = 0.0f;
32
+#if 1
33
+   uint32_t i, j, nt2 = n_taps/2;
34
+   for (i = 0, j = n_taps-1; i < nt2; i++, j--)
35
+       sum += si * tapsi + sj * tapsj;
36
+#else
37
+   uint32_t i;
38
+   for (i = 0; i < n_taps; i++)
39
+       sum += si * tapsi;
40
+#endif
41
+   *d = sum;
42
+}
43
+
44
+static void inner_product_ip_c(float *d, const float * SPA_RESTRICT s,
45
+   const float * SPA_RESTRICT t0, const float * SPA_RESTRICT t1, float x,
46
+   uint32_t n_taps)
47
+{
48
+   float sum2 = { 0.0f, 0.0f };
49
+   uint32_t i;
50
+#if 1
51
+   uint32_t j, nt2 = n_taps/2;
52
+   for (i = 0, j = n_taps-1; i < nt2; i++, j--) {
53
+       sum0 += si * t0i + sj * t0j;
54
+       sum1 += si * t1i + sj * t1j;
55
+   }
56
+#else
57
+   for (i = 0; i < n_taps; i++) {
58
+       sum0 += si * t0i;
59
+       sum1 += si * t1i;
60
+   }
61
+#endif
62
+   *d = (sum1 - sum0) * x + sum0;
63
+}
64
+
65
+MAKE_RESAMPLER_FULL(c);
66
+MAKE_RESAMPLER_INTER(c);
67
pipewire-0.3.54.tar.gz/spa/plugins/audioconvert/resample-native.c -> pipewire-0.3.56.tar.gz/spa/plugins/audioconvert/resample-native.c Changed
134
 
1
@@ -33,22 +33,22 @@
2
    double cutoff;
3
 };
4
 
5
-static const struct quality blackman_qualities = {
6
-   { 8, 0.5, },
7
-   { 16, 0.70, },
8
-   { 24, 0.76, },
9
-   { 32, 0.8, },
10
+static const struct quality window_qualities = {
11
+   { 8, 0.53, },
12
+   { 16, 0.67, },
13
+   { 24, 0.75, },
14
+   { 32, 0.80, },
15
    { 48, 0.85, },                  /* default */
16
-   { 64, 0.90, },
17
-   { 80, 0.92, },
18
-   { 96, 0.933, },
19
-   { 128, 0.950, },
20
-   { 144, 0.955, },
21
-   { 160, 0.958, },
22
-   { 192, 0.965, },
23
-   { 256, 0.975, },
24
-   { 896, 0.997, },
25
-   { 1024, 0.998, },
26
+   { 64, 0.88, },
27
+   { 80, 0.895, },
28
+   { 96, 0.910, },
29
+   { 128, 0.936, },
30
+   { 144, 0.945, },
31
+   { 160, 0.950, },
32
+   { 192, 0.960, },
33
+   { 256, 0.970, },
34
+   { 896, 0.990, },
35
+   { 1024, 0.995, },
36
 };
37
 
38
 static inline double sinc(double x)
39
@@ -69,13 +69,17 @@
40
 static inline double window_cosh(double x, double n_taps)
41
 {
42
    double R = 190.0, r;
43
-   double A = -325.1E-6 * (R * R) + 0.1677 * R - 3.149;
44
+   double A = (-325.1E-6 * R + 0.1677) * R - 3.149;
45
+   double x2;
46
    x =  2.0 * x / n_taps;
47
-   r = cosh(A * sqrt(1 - pow(x, 2))) / cosh(A);
48
+   x2 = x * x;
49
+   if (x2 >= 1.0)
50
+       return 0.0;
51
+   r = cosh(A * sqrt(1 - x2)) / cosh(A);
52
    return r;
53
 }
54
 
55
-#define window window_blackman
56
+#define window window_cosh
57
 
58
 static int build_filter(float *taps, uint32_t stride, uint32_t n_taps, uint32_t n_phases, double cutoff)
59
 {
60
@@ -93,46 +97,7 @@
61
    return 0;
62
 }
63
 
64
-static void inner_product_c(float *d, const float * SPA_RESTRICT s,
65
-       const float * SPA_RESTRICT taps, uint32_t n_taps)
66
-{
67
-   float sum = 0.0f;
68
-#if 1
69
-   uint32_t i, j, nt2 = n_taps/2;
70
-   for (i = 0, j = n_taps-1; i < nt2; i++, j--)
71
-       sum += si * tapsi + sj * tapsj;
72
-#else
73
-   uint32_t i;
74
-   for (i = 0; i < n_taps; i++)
75
-       sum += si * tapsi;
76
-#endif
77
-   *d = sum;
78
-}
79
-
80
-static void inner_product_ip_c(float *d, const float * SPA_RESTRICT s,
81
-   const float * SPA_RESTRICT t0, const float * SPA_RESTRICT t1, float x,
82
-   uint32_t n_taps)
83
-{
84
-   float sum2 = { 0.0f, 0.0f };
85
-   uint32_t i;
86
-#if 1
87
-   uint32_t j, nt2 = n_taps/2;
88
-   for (i = 0, j = n_taps-1; i < nt2; i++, j--) {
89
-       sum0 += si * t0i + sj * t0j;
90
-       sum1 += si * t1i + sj * t1j;
91
-   }
92
-#else
93
-   for (i = 0; i < n_taps; i++) {
94
-       sum0 += si * t0i;
95
-       sum1 += si * t1i;
96
-   }
97
-#endif
98
-   *d = (sum1 - sum0) * x + sum0;
99
-}
100
-
101
 MAKE_RESAMPLER_COPY(c);
102
-MAKE_RESAMPLER_FULL(c);
103
-MAKE_RESAMPLER_INTER(c);
104
 
105
 #define MAKE(fmt,copy,full,inter,...) \
106
    { SPA_AUDIO_FORMAT_ ##fmt, do_resample_ ##copy, #copy, \
107
@@ -356,7 +321,7 @@
108
    uint32_t c, n_taps, n_phases, filter_size, in_rate, out_rate, gcd, filter_stride;
109
    uint32_t history_stride, history_size, oversample;
110
 
111
-   r->quality = SPA_CLAMP(r->quality, 0, (int) SPA_N_ELEMENTS(blackman_qualities) - 1);
112
+   r->quality = SPA_CLAMP(r->quality, 0, (int) SPA_N_ELEMENTS(window_qualities) - 1);
113
    r->free = impl_native_free;
114
    r->update_rate = impl_native_update_rate;
115
    r->in_len = impl_native_in_len;
116
@@ -364,14 +329,15 @@
117
    r->reset = impl_native_reset;
118
    r->delay = impl_native_delay;
119
 
120
-   q = &blackman_qualitiesr->quality;
121
+   q = &window_qualitiesr->quality;
122
 
123
    gcd = calc_gcd(r->i_rate, r->o_rate);
124
 
125
    in_rate = r->i_rate / gcd;
126
    out_rate = r->o_rate / gcd;
127
 
128
-   scale = SPA_MIN(q->cutoff * out_rate / in_rate, 1.0);
129
+   scale = SPA_MIN(q->cutoff * out_rate / in_rate, q->cutoff);
130
+
131
    /* multiple of 8 taps to ease simd optimizations */
132
    n_taps = SPA_ROUND_UP_N((uint32_t)ceil(q->n_taps / scale), 8);
133
    n_taps = SPA_MIN(n_taps, 1u << 18);
134
pipewire-0.3.56.tar.gz/spa/plugins/audioconvert/resample-peaks-c.c Added
75
 
1
@@ -0,0 +1,73 @@
2
+/* Spa
3
+ *
4
+ * Copyright © 2018 Wim Taymans
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a
7
+ * copy of this software and associated documentation files (the "Software"),
8
+ * to deal in the Software without restriction, including without limitation
9
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
+ * and/or sell copies of the Software, and to permit persons to whom the
11
+ * Software is furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice (including the next
14
+ * paragraph) shall be included in all copies or substantial portions of the
15
+ * Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23
+ * DEALINGS IN THE SOFTWARE.
24
+ */
25
+
26
+#include <math.h>
27
+
28
+#include "resample-peaks-impl.h"
29
+
30
+void resample_peaks_process_c(struct resample *r,
31
+           const void * SPA_RESTRICT src, uint32_t *in_len,
32
+           void * SPA_RESTRICT dst, uint32_t *out_len)
33
+{
34
+   struct peaks_data *pd = r->data;
35
+   uint32_t c, i, o, end, chunk, o_count, i_count;
36
+
37
+   if (SPA_UNLIKELY(r->channels == 0))
38
+       return;
39
+
40
+   for (c = 0; c < r->channels; c++) {
41
+       const float *s = srcc;
42
+       float *d = dstc, m = pd->max_fc;
43
+
44
+       o_count = pd->o_count;
45
+       i_count = pd->i_count;
46
+       o = i = 0;
47
+
48
+       while (i < *in_len && o < *out_len) {
49
+           end = ((uint64_t) (o_count + 1) * r->i_rate) / r->o_rate;
50
+           end = end > i_count ? end - i_count : 0;
51
+           chunk = SPA_MIN(end, *in_len);
52
+
53
+           for (; i < chunk; i++)
54
+               m = SPA_MAX(fabsf(si), m);
55
+
56
+           if (i == end) {
57
+               do++ = m;
58
+               m = 0.0f;
59
+               o_count++;
60
+           }
61
+       }
62
+       pd->max_fc = m;
63
+   }
64
+
65
+   *out_len = o;
66
+   *in_len = i;
67
+   pd->o_count = o_count;
68
+   pd->i_count = i_count + i;
69
+
70
+   while (pd->i_count >= r->i_rate) {
71
+       pd->i_count -= r->i_rate;
72
+       pd->o_count -= r->o_rate;
73
+   }
74
+}
75
pipewire-0.3.54.tar.gz/spa/plugins/audioconvert/resample-peaks-impl.h -> pipewire-0.3.56.tar.gz/spa/plugins/audioconvert/resample-peaks-impl.h Changed
11
 
1
@@ -34,6 +34,9 @@
2
    float max_f;
3
 };
4
 
5
+void resample_peaks_process_c(struct resample *r,
6
+   const void * SPA_RESTRICT src, uint32_t *in_len,
7
+   void * SPA_RESTRICT dst, uint32_t *out_len);
8
 #if defined (HAVE_SSE)
9
 void resample_peaks_process_sse(struct resample *r,
10
    const void * SPA_RESTRICT src, uint32_t *in_len,
11
pipewire-0.3.54.tar.gz/spa/plugins/audioconvert/resample-peaks.c -> pipewire-0.3.56.tar.gz/spa/plugins/audioconvert/resample-peaks.c Changed
54
 
1
@@ -29,52 +29,6 @@
2
 
3
 #include "resample-peaks-impl.h"
4
 
5
-static void resample_peaks_process_c(struct resample *r,
6
-           const void * SPA_RESTRICT src, uint32_t *in_len,
7
-           void * SPA_RESTRICT dst, uint32_t *out_len)
8
-{
9
-   struct peaks_data *pd = r->data;
10
-   uint32_t c, i, o, end, chunk, o_count, i_count;
11
-
12
-   if (SPA_UNLIKELY(r->channels == 0))
13
-       return;
14
-
15
-   for (c = 0; c < r->channels; c++) {
16
-       const float *s = srcc;
17
-       float *d = dstc, m = pd->max_fc;
18
-
19
-       o_count = pd->o_count;
20
-       i_count = pd->i_count;
21
-       o = i = 0;
22
-
23
-       while (i < *in_len && o < *out_len) {
24
-           end = ((uint64_t) (o_count + 1) * r->i_rate) / r->o_rate;
25
-           end = end > i_count ? end - i_count : 0;
26
-           chunk = SPA_MIN(end, *in_len);
27
-
28
-           for (; i < chunk; i++)
29
-               m = SPA_MAX(fabsf(si), m);
30
-
31
-           if (i == end) {
32
-               do++ = m;
33
-               m = 0.0f;
34
-               o_count++;
35
-           }
36
-       }
37
-       pd->max_fc = m;
38
-   }
39
-
40
-   *out_len = o;
41
-   *in_len = i;
42
-   pd->o_count = o_count;
43
-   pd->i_count = i_count + i;
44
-
45
-   while (pd->i_count >= r->i_rate) {
46
-       pd->i_count -= r->i_rate;
47
-       pd->o_count -= r->o_rate;
48
-   }
49
-}
50
-
51
 struct resample_info {
52
    uint32_t format;
53
    uint32_t cpu_flags;
54
pipewire-0.3.54.tar.gz/spa/plugins/audioconvert/spa-resample.c -> pipewire-0.3.56.tar.gz/spa/plugins/audioconvert/spa-resample.c Changed
111
 
1
@@ -33,6 +33,7 @@
2
 #include <spa/support/log-impl.h>
3
 #include <spa/debug/mem.h>
4
 #include <spa/utils/string.h>
5
+#include <spa/utils/result.h>
6
 
7
 #include <sndfile.h>
8
 
9
@@ -184,14 +185,14 @@
10
    float outMAX_SAMPLES * channels;
11
    float ibufMAX_SAMPLES * channels;
12
    float obufMAX_SAMPLES * channels;
13
-   uint32_t in_len, out_len;
14
-        uint32_t pin_len, pout_len;
15
+   uint32_t in_len, out_len, queued;
16
+   uint32_t pin_len, pout_len;
17
    size_t read, written;
18
    const void *srcchannels;
19
    void *dstchannels;
20
    uint32_t i;
21
-   int j, k, queued;
22
-   bool flushing = false;
23
+   int res, j, k;
24
+   uint32_t flushing = UINT32_MAX;
25
 
26
    spa_zero(r);
27
    r.cpu_flags = d->cpu_flags;
28
@@ -200,7 +201,10 @@
29
    r.i_rate = d->iinfo.samplerate;
30
    r.o_rate = d->oinfo.samplerate;
31
    r.quality = d->quality < 0 ? DEFAULT_QUALITY : d->quality;
32
-   resample_native_init(&r);
33
+   if ((res = resample_native_init(&r)) < 0) {
34
+       fprintf(stderr, "can't init converter: %s\n", spa_strerror(res));
35
+       return res;
36
+   }
37
 
38
    for (j = 0; j < channels; j++)
39
        srcj = &inMAX_SAMPLES * j;
40
@@ -210,25 +214,29 @@
41
    read = written = queued = 0;
42
    while (true) {
43
        pout_len = out_len = MAX_SAMPLES;
44
-                in_len = SPA_MIN(MAX_SAMPLES, resample_in_len(&r, out_len)) - queued;
45
+       in_len = SPA_MIN(MAX_SAMPLES, resample_in_len(&r, out_len));
46
+       in_len -= SPA_MIN(queued, in_len);
47
 
48
-       pin_len = in_len = sf_readf_float(d->ifile, &ibufqueued * channels, in_len);
49
+       if (in_len > 0) {
50
+           pin_len = in_len = sf_readf_float(d->ifile, &ibufqueued * channels, in_len);
51
 
52
-       read += pin_len;
53
+           read += pin_len;
54
 
55
-       if (pin_len == 0) {
56
-           if (flushing)
57
-               break;
58
+           if (pin_len == 0) {
59
+               if (flushing == 0)
60
+                   break;
61
+               if (flushing == UINT32_MAX)
62
+                   flushing = resample_delay(&r);
63
 
64
-           flushing = true;
65
-           pin_len = in_len = resample_delay(&r);
66
+               pin_len = in_len = SPA_MIN(MAX_SAMPLES, flushing);
67
+               flushing -= in_len;
68
 
69
-           for (k = 0, i = 0; i < pin_len; i++) {
70
-               for (j = 0; j < channels; j++)
71
-                   ibufk++ = 0.0;
72
+               for (k = 0, i = 0; i < pin_len; i++) {
73
+                   for (j = 0; j < channels; j++)
74
+                       ibufk++ = 0.0;
75
+               }
76
            }
77
        }
78
-
79
        in_len += queued;
80
        pin_len = in_len;
81
 
82
@@ -243,18 +251,20 @@
83
        if (queued)
84
            memmove(ibuf, &ibufpin_len * channels, queued * channels * sizeof(float));
85
 
86
-       for (k = 0, i = 0; i < pout_len; i++) {
87
-           for (j = 0; j < channels; j++) {
88
-               obufk++ = outMAX_SAMPLES * j + i;
89
+       if (pout_len > 0) {
90
+           for (k = 0, i = 0; i < pout_len; i++) {
91
+               for (j = 0; j < channels; j++) {
92
+                   obufk++ = outMAX_SAMPLES * j + i;
93
+               }
94
            }
95
-       }
96
-       pout_len = sf_writef_float(d->ofile, obuf, pout_len);
97
+           pout_len = sf_writef_float(d->ofile, obuf, pout_len);
98
 
99
-       written += pout_len;
100
+           written += pout_len;
101
+       }
102
    }
103
-   if (d->verbose) {
104
+   if (d->verbose)
105
        fprintf(stdout, "read %zu samples, wrote %zu samples\n", read, written);
106
-   }
107
+
108
    return 0;
109
 }
110
 
111
pipewire-0.3.54.tar.gz/spa/plugins/audioconvert/test-audioconvert.c -> pipewire-0.3.56.tar.gz/spa/plugins/audioconvert/test-audioconvert.c Changed
127
 
1
@@ -703,11 +703,18 @@
2
 static const float data_f32p_4 = { 0.4f, 0.4f, 0.4f, 0.4f };
3
 static const float data_f32p_5 = { 0.5f, 0.5f, 0.5f, 0.5f };
4
 static const float data_f32p_6 = { 0.6f, 0.6f, 0.6f, 0.6f };
5
+static const float data_f32p_7 = { 0.7f, 0.7f, 0.7f, 0.7f };
6
+static const float data_f32p_8 = { 0.8f, 0.8f, 0.8f, 0.8f };
7
 
8
 static const float data_f32_5p1 = { 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f,
9
                      0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f,
10
                      0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f,
11
                      0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f };
12
+
13
+static const float data_f32_7p1_remapped = { 0.1f, 0.2f, 0.5f, 0.6f, 0.7f, 0.8f, 0.3f, 0.4f,
14
+                     0.1f, 0.2f, 0.5f, 0.6f, 0.7f, 0.8f, 0.3f, 0.4f,
15
+                     0.1f, 0.2f, 0.5f, 0.6f, 0.7f, 0.8f, 0.3f, 0.4f,
16
+                     0.1f, 0.2f, 0.5f, 0.6f, 0.7f, 0.8f, 0.3f, 0.4f };
17
 static const float data_f32_5p1_remapped = { 0.1f, 0.2f, 0.5f, 0.6f, 0.3f, 0.4f,
18
                      0.1f, 0.2f, 0.5f, 0.6f, 0.3f, 0.4f,
19
                      0.1f, 0.2f, 0.5f, 0.6f, 0.3f, 0.4f,
20
@@ -753,6 +760,48 @@
21
    .size = sizeof(float) * 4
22
 };
23
 
24
+struct data dsp_7p1_remapped = {
25
+   .mode = SPA_PARAM_PORT_CONFIG_MODE_dsp,
26
+   .info = SPA_AUDIO_INFO_RAW_INIT(
27
+       .format = SPA_AUDIO_FORMAT_F32,
28
+       .rate = 48000,
29
+       .channels = 8,
30
+       .position = {
31
+           SPA_AUDIO_CHANNEL_FL,
32
+           SPA_AUDIO_CHANNEL_FR,
33
+           SPA_AUDIO_CHANNEL_FC,
34
+           SPA_AUDIO_CHANNEL_LFE,
35
+           SPA_AUDIO_CHANNEL_RL,
36
+           SPA_AUDIO_CHANNEL_RR,
37
+           SPA_AUDIO_CHANNEL_SL,
38
+           SPA_AUDIO_CHANNEL_SR,
39
+       }),
40
+   .ports = 8,
41
+   .planes = 1,
42
+   .data = { data_f32p_1, data_f32p_2, data_f32p_3, data_f32p_4, data_f32p_7, data_f32p_8, data_f32p_5, data_f32p_6 },
43
+   .size = sizeof(data_f32p_1)
44
+};
45
+
46
+struct data dsp_5p1_remapped_2 = {
47
+   .mode = SPA_PARAM_PORT_CONFIG_MODE_dsp,
48
+   .info = SPA_AUDIO_INFO_RAW_INIT(
49
+       .format = SPA_AUDIO_FORMAT_F32,
50
+       .rate = 48000,
51
+       .channels = 6,
52
+       .position = {
53
+           SPA_AUDIO_CHANNEL_FC,
54
+           SPA_AUDIO_CHANNEL_LFE,
55
+           SPA_AUDIO_CHANNEL_RL,
56
+           SPA_AUDIO_CHANNEL_RR,
57
+           SPA_AUDIO_CHANNEL_FR,
58
+           SPA_AUDIO_CHANNEL_FL,
59
+       }),
60
+   .ports = 6,
61
+   .planes = 1,
62
+   .data = { data_f32p_3, data_f32p_4, data_f32p_5, data_f32p_6, data_f32p_2, data_f32p_1, },
63
+   .size = sizeof(float) * 4
64
+};
65
+
66
 struct data conv_f32_48000_5p1 = {
67
    .mode = SPA_PARAM_PORT_CONFIG_MODE_convert,
68
    .info = SPA_AUDIO_INFO_RAW_INIT(
69
@@ -833,6 +882,28 @@
70
    .size = sizeof(float) * 4
71
 };
72
 
73
+struct data conv_f32_48000_7p1_remapped = {
74
+   .mode = SPA_PARAM_PORT_CONFIG_MODE_convert,
75
+   .info = SPA_AUDIO_INFO_RAW_INIT(
76
+       .format = SPA_AUDIO_FORMAT_F32,
77
+       .rate = 48000,
78
+       .channels = 8,
79
+       .position = {
80
+           SPA_AUDIO_CHANNEL_FL,
81
+           SPA_AUDIO_CHANNEL_FR,
82
+           SPA_AUDIO_CHANNEL_SL,
83
+           SPA_AUDIO_CHANNEL_SR,
84
+           SPA_AUDIO_CHANNEL_RL,
85
+           SPA_AUDIO_CHANNEL_RR,
86
+           SPA_AUDIO_CHANNEL_FC,
87
+           SPA_AUDIO_CHANNEL_LFE,
88
+       }),
89
+   .ports = 1,
90
+   .planes = 1,
91
+   .data = { data_f32_7p1_remapped, },
92
+   .size = sizeof(data_f32_7p1_remapped)
93
+};
94
+
95
 static int test_convert_remap_dsp(struct context *ctx)
96
 {
97
    run_convert(ctx, &dsp_5p1, &conv_f32_48000_5p1);
98
@@ -843,6 +914,10 @@
99
    run_convert(ctx, &dsp_5p1_remapped, &conv_f32p_48000_5p1);
100
    run_convert(ctx, &dsp_5p1_remapped, &conv_f32_48000_5p1_remapped);
101
    run_convert(ctx, &dsp_5p1_remapped, &conv_f32p_48000_5p1_remapped);
102
+   run_convert(ctx, &dsp_5p1_remapped_2, &conv_f32_48000_5p1);
103
+   run_convert(ctx, &dsp_5p1_remapped_2, &conv_f32p_48000_5p1);
104
+   run_convert(ctx, &dsp_5p1_remapped_2, &conv_f32_48000_5p1_remapped);
105
+   run_convert(ctx, &dsp_5p1_remapped_2, &conv_f32p_48000_5p1_remapped);
106
    return 0;
107
 }
108
 
109
@@ -850,12 +925,17 @@
110
 {
111
    run_convert(ctx, &conv_f32_48000_5p1, &dsp_5p1);
112
    run_convert(ctx, &conv_f32_48000_5p1, &dsp_5p1_remapped);
113
+   run_convert(ctx, &conv_f32_48000_5p1, &dsp_5p1_remapped_2);
114
    run_convert(ctx, &conv_f32p_48000_5p1, &dsp_5p1);
115
    run_convert(ctx, &conv_f32p_48000_5p1, &dsp_5p1_remapped);
116
+   run_convert(ctx, &conv_f32p_48000_5p1, &dsp_5p1_remapped_2);
117
    run_convert(ctx, &conv_f32_48000_5p1_remapped, &dsp_5p1);
118
    run_convert(ctx, &conv_f32_48000_5p1_remapped, &dsp_5p1_remapped);
119
+   run_convert(ctx, &conv_f32_48000_5p1_remapped, &dsp_5p1_remapped_2);
120
    run_convert(ctx, &conv_f32p_48000_5p1_remapped, &dsp_5p1);
121
    run_convert(ctx, &conv_f32p_48000_5p1_remapped, &dsp_5p1_remapped);
122
+   run_convert(ctx, &conv_f32_48000_7p1_remapped, &dsp_7p1_remapped);
123
+   run_convert(ctx, &conv_f32p_48000_5p1_remapped, &dsp_5p1_remapped_2);
124
    return 0;
125
 }
126
 
127
pipewire-0.3.54.tar.gz/spa/plugins/audioconvert/test-fmt-ops.c -> pipewire-0.3.56.tar.gz/spa/plugins/audioconvert/test-fmt-ops.c Changed
201
 
1
@@ -54,7 +54,7 @@
2
        spa_debug_mem(0, m1, size);
3
        spa_debug_mem(0, m2, size);
4
    }
5
-// spa_assert_se(res == 0);
6
+   spa_assert_se(res == 0);
7
 }
8
 
9
 static void run_test(const char *name,
10
@@ -127,8 +127,9 @@
11
 
12
 static void test_f32_s8(void)
13
 {
14
-   static const float in = { 0.0f, 1.0f, -1.0f, 0.5f, -0.5f, 1.1f, -1.1f };
15
-   static const int8_t out = { 0, 127, -128, 64, 192, 127, -128 };
16
+   static const float in = { 0.0f, 1.0f, -1.0f, 0.5f, -0.5f, 1.1f, -1.1f,
17
+       1.0f/160.f, 1.0f/256.f, -1.0f/160.f, -1.0f/256.f };
18
+   static const int8_t out = { 0, 127, -128, 64, 192, 127, -128, 1, 0, -1, 0 };
19
 
20
    run_test("test_f32_s8", in, sizeof(in0), out, sizeof(out0), SPA_N_ELEMENTS(out),
21
            true, true, conv_f32_to_s8_c);
22
@@ -157,8 +158,9 @@
23
 
24
 static void test_f32_u8(void)
25
 {
26
-   static const float in = { 0.0f, 1.0f, -1.0f, 0.5f, -0.5f, 1.1f, -1.1f };
27
-   static const uint8_t out = { 128, 255, 0, 192, 64, 255, 0, };
28
+   static const float in = { 0.0f, 1.0f, -1.0f, 0.5f, -0.5f, 1.1f, -1.1f,
29
+       1.0f/160.f, 1.0f/256.f, -1.0f/160.f, -1.0f/256.f };
30
+   static const uint8_t out = { 128, 255, 0, 192, 64, 255, 0, 129, 128, 127, 128 };
31
 
32
    run_test("test_f32_u8", in, sizeof(in0), out, sizeof(out0), SPA_N_ELEMENTS(out),
33
            true, true, conv_f32_to_u8_c);
34
@@ -187,8 +189,10 @@
35
 
36
 static void test_f32_u16(void)
37
 {
38
-   static const float in = { 0.0f, 1.0f, -1.0f, 0.5f, -0.5f, 1.1f, -1.1f };
39
-   static const uint16_t out = { 32768, 65535, 0, 49152, 16384, 65535, 0 };
40
+   static const float in = { 0.0f, 1.0f, -1.0f, 0.5f, -0.5f, 1.1f, -1.1f,
41
+       1.0f/49152.f, 1.0f/65536.f, -1.0f/49152.f, -1.0f/65536.f };
42
+   static const uint16_t out = { 32768, 65535, 0, 49152, 16384, 65535, 0,
43
+       32769, 32768, 32767, 32768 };
44
 
45
    run_test("test_f32_u16", in, sizeof(in0), out, sizeof(out0), SPA_N_ELEMENTS(out),
46
            true, true, conv_f32_to_u16_c);
47
@@ -209,8 +213,10 @@
48
 
49
 static void test_f32_s16(void)
50
 {
51
-   static const float in = { 0.0f, 1.0f, -1.0f, 0.5f, -0.5f, 1.1f, -1.1f };
52
-   static const int16_t out = { 0, 32767, -32768, 16384, -16384, 32767, -32768 };
53
+   static const float in = { 0.0f, 1.0f, -1.0f, 0.5f, -0.5f, 1.1f, -1.1f,
54
+       1.0f/49152.f, 1.0f/65536.f, -1.0f/49152.f, -1.0f/65536.f };
55
+   static const int16_t out = { 0, 32767, -32768, 16384, -16384, 32767, -32768,
56
+       1, 0, -1, 0 };
57
 
58
    run_test("test_f32_s16", in, sizeof(in0), out, sizeof(out0), SPA_N_ELEMENTS(out),
59
            true, true, conv_f32_to_s16_c);
60
@@ -267,9 +273,11 @@
61
 
62
 static void test_f32_u32(void)
63
 {
64
-   static const float in = { 0.0f, 1.0f, -1.0f, 0.5f, -0.5f, 1.1f, -1.1f };
65
-   static const uint32_t out = { 0x80000000, 0xffffffff, 0x0, 0xc0000000, 0x40000000,
66
-                   0xffffffff, 0x0 };
67
+   static const float in = { 0.0f, 1.0f, -1.0f, 0.5f, -0.5f, 1.1f, -1.1f,
68
+       1.0f/0xa00000, 1.0f/0x1000000, -1.0f/0xa00000, -1.0f/0x1000000 };
69
+   static const uint32_t out = { 0x80000000, 0xffffff00, 0x0, 0xc0000000, 0x40000000,
70
+                   0xffffff00, 0x0,
71
+       0x80000100, 0x80000000, 0x7fffff00, 0x80000000 };
72
 
73
    run_test("test_f32_u32", in, sizeof(in0), out, sizeof(out0), SPA_N_ELEMENTS(out),
74
            true, true, conv_f32_to_u32_c);
75
@@ -279,8 +287,8 @@
76
 
77
 static void test_u32_f32(void)
78
 {
79
-   static const uint32_t in = { 0x80000000, 0xffffffff, 0x0, 0xc0000000, 0x40000000 };
80
-   static const float out = { 0.0f, 1.0f, -1.0f, 0.5f, -0.5f, };
81
+   static const uint32_t in = { 0x80000000, 0xffffff00, 0x0, 0xc0000000, 0x40000000 };
82
+   static const float out = { 0.0f, 0.999999880791f, -1.0f, 0.5f, -0.5f, };
83
 
84
    run_test("test_u32_f32d", in, sizeof(in0), out, sizeof(out0), SPA_N_ELEMENTS(out),
85
            true, false, conv_u32_to_f32d_c);
86
@@ -290,9 +298,11 @@
87
 
88
 static void test_f32_s32(void)
89
 {
90
-   static const float in = { 0.0f, 1.0f, -1.0f, 0.5f, -0.5f, 1.1f, -1.1f };
91
-   static const int32_t out = { 0, 0x7fffff80, 0x80000000, 0x40000000, 0xc0000000,
92
-                   0x7fffff80, 0x80000000 };
93
+   static const float in = { 0.0f, 1.0f, -1.0f, 0.5f, -0.5f, 1.1f, -1.1f,
94
+       1.0f/0xa00000, 1.0f/0x1000000, -1.0f/0xa00000, -1.0f/0x1000000 };
95
+   static const int32_t out = { 0, 0x7fffff00, 0x80000000, 0x40000000, 0xc0000000,
96
+                   0x7fffff00, 0x80000000,
97
+       0x00000100, 0x00000000, 0xffffff00, 0x00000000 };
98
 
99
    run_test("test_f32_s32", in, sizeof(in0), out, sizeof(out0), SPA_N_ELEMENTS(out),
100
            true, true, conv_f32_to_s32_c);
101
@@ -318,8 +328,8 @@
102
 
103
 static void test_s32_f32(void)
104
 {
105
-   static const int32_t in = { 0, 0x7fffff80, 0x80000000, 0x40000000, 0xc0000000 };
106
-   static const float out = { 0.0f, 0.999999940395f, -1.0f, 0.5, -0.5, };
107
+   static const int32_t in = { 0, 0x7fffff00, 0x80000000, 0x40000000, 0xc0000000 };
108
+   static const float out = { 0.0f, 0.999999880791, -1.0f, 0.5, -0.5, };
109
 
110
    run_test("test_s32_f32d", in, sizeof(in0), out, sizeof(out0), SPA_N_ELEMENTS(out),
111
            true, false, conv_s32_to_f32d_c);
112
@@ -345,10 +355,13 @@
113
 
114
 static void test_f32_u24(void)
115
 {
116
-   static const float in = { 0.0f, 1.0f, -1.0f, 0.5f, -0.5f, 1.1f, -1.1f };
117
+   static const float in = { 0.0f, 1.0f, -1.0f, 0.5f, -0.5f, 1.1f, -1.1f,
118
+       1.0f/0xa00000, 1.0f/0x1000000, -1.0f/0xa00000, -1.0f/0x1000000 };
119
    static const uint24_t out = { U32_TO_U24(0x00800000), U32_TO_U24(0xffffff),
120
        U32_TO_U24(0x000000), U32_TO_U24(0xc00000), U32_TO_U24(0x400000),
121
-       U32_TO_U24(0xffffff), U32_TO_U24(0x000000) };
122
+       U32_TO_U24(0xffffff), U32_TO_U24(0x000000),
123
+       U32_TO_U24(0x800001), U32_TO_U24(0x800000), U32_TO_U24(0x7fffff),
124
+       U32_TO_U24(0x800000) };
125
 
126
    run_test("test_f32_u24", in, sizeof(in0), out, 3, SPA_N_ELEMENTS(in),
127
            true, true, conv_f32_to_u24_c);
128
@@ -370,10 +383,13 @@
129
 
130
 static void test_f32_s24(void)
131
 {
132
-   static const float in = { 0.0f, 1.0f, -1.0f, 0.5f, -0.5f, 1.1f, -1.1f };
133
+   static const float in = { 0.0f, 1.0f, -1.0f, 0.5f, -0.5f, 1.1f, -1.1f,
134
+       1.0f/0xa00000, 1.0f/0x1000000, -1.0f/0xa00000, -1.0f/0x1000000 };
135
    static const int24_t out = { S32_TO_S24(0), S32_TO_S24(0x7fffff),
136
        S32_TO_S24(0xff800000), S32_TO_S24(0x400000), S32_TO_S24(0xc00000),
137
-       S32_TO_S24(0x7fffff), S32_TO_S24(0xff800000) };
138
+       S32_TO_S24(0x7fffff), S32_TO_S24(0xff800000),
139
+       S32_TO_S24(0x000001), S32_TO_S24(0x000000), S32_TO_S24(0xffffffff),
140
+       S32_TO_S24(0x000000) };
141
 
142
    run_test("test_f32_s24", in, sizeof(in0), out, 3, SPA_N_ELEMENTS(in),
143
            true, true, conv_f32_to_s24_c);
144
@@ -427,9 +443,11 @@
145
 
146
 static void test_f32_u24_32(void)
147
 {
148
-   static const float in = { 0.0f, 1.0f, -1.0f, 0.5f, -0.5f, 1.1f, -1.1f };
149
+   static const float in = { 0.0f, 1.0f, -1.0f, 0.5f, -0.5f, 1.1f, -1.1f,
150
+       1.0f/0xa00000, 1.0f/0x1000000, -1.0f/0xa00000, -1.0f/0x1000000 };
151
    static const uint32_t out = { 0x800000, 0xffffff, 0x0, 0xc00000, 0x400000,
152
-                   0xffffff, 0x000000 };
153
+                   0xffffff, 0x000000,
154
+       0x800001, 0x800000, 0x7fffff, 0x800000 };
155
 
156
    run_test("test_f32_u24_32", in, sizeof(in0), out, sizeof(out0), SPA_N_ELEMENTS(out),
157
            true, true, conv_f32_to_u24_32_c);
158
@@ -439,8 +457,8 @@
159
 
160
 static void test_u24_32_f32(void)
161
 {
162
-   static const uint32_t in = { 0x800000, 0xffffff, 0x0, 0xc00000, 0x400000 };
163
-   static const float out = { 0.0f, 0.999999880791f, -1.0f, 0.5f, -0.5f, };
164
+   static const uint32_t in = { 0x800000, 0xffffff, 0x0, 0xc00000, 0x400000, 0x11000000 };
165
+   static const float out = { 0.0f, 0.999999880791f, -1.0f, 0.5f, -0.5f, -1.0f };
166
 
167
    run_test("test_u24_32_f32d", in, sizeof(in0), out, sizeof(out0), SPA_N_ELEMENTS(out),
168
            true, false, conv_u24_32_to_f32d_c);
169
@@ -450,9 +468,11 @@
170
 
171
 static void test_f32_s24_32(void)
172
 {
173
-   static const float in = { 0.0f, 1.0f, -1.0f, 0.5f, -0.5f, 1.1f, -1.1f };
174
+   static const float in = { 0.0f, 1.0f, -1.0f, 0.5f, -0.5f, 1.1f, -1.1f,
175
+       1.0f/0xa00000, 1.0f/0x1000000, -1.0f/0xa00000, -1.0f/0x1000000 };
176
    static const int32_t out = { 0, 0x7fffff, 0xff800000, 0x400000, 0xffc00000,
177
-                   0x7fffff, 0xff800000 };
178
+                   0x7fffff, 0xff800000,
179
+       0x000001, 0x000000, 0xffffffff, 0x000000 };
180
 
181
    run_test("test_f32_s24_32", in, sizeof(in0), out, sizeof(out0), SPA_N_ELEMENTS(out),
182
            true, true, conv_f32_to_s24_32_c);
183
@@ -466,8 +486,8 @@
184
 
185
 static void test_s24_32_f32(void)
186
 {
187
-   static const int32_t in = { 0, 0x7fffff, 0xff800000, 0x400000, 0xffc00000 };
188
-   static const float out = { 0.0f, 0.999999880791f, -1.0f, 0.5f, -0.5f, };
189
+   static const int32_t in = { 0, 0x7fffff, 0xff800000, 0x400000, 0xffc00000, 0x66800000 };
190
+   static const float out = { 0.0f, 0.999999880791f, -1.0f, 0.5f, -0.5f, -1.0f };
191
 
192
    run_test("test_s24_32_f32d", in, sizeof(in0), out, sizeof(out0), SPA_N_ELEMENTS(out),
193
            true, false, conv_s24_32_to_f32d_c);
194
@@ -588,7 +608,7 @@
195
    for (i = S32_MIN; i < S32_MAX; i+=255) {
196
        float v = S32_TO_F32(i);
197
        int32_t t = F32_TO_S32(v);
198
-       spa_assert_se(SPA_ABS(i - t) <= 128);
199
+       spa_assert_se(SPA_ABS(i - t) <= 256);
200
    }
201
pipewire-0.3.56.tar.gz/spa/plugins/audiomixer/benchmark-mix-ops.c Added
201
 
1
@@ -0,0 +1,222 @@
2
+/* Spa
3
+ *
4
+ * Copyright © 2019 Wim Taymans
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a
7
+ * copy of this software and associated documentation files (the "Software"),
8
+ * to deal in the Software without restriction, including without limitation
9
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
+ * and/or sell copies of the Software, and to permit persons to whom the
11
+ * Software is furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice (including the next
14
+ * paragraph) shall be included in all copies or substantial portions of the
15
+ * Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23
+ * DEALINGS IN THE SOFTWARE.
24
+ */
25
+
26
+#include "config.h"
27
+
28
+#include <string.h>
29
+#include <stdio.h>
30
+#include <stdlib.h>
31
+#include <unistd.h>
32
+#include <errno.h>
33
+#include <time.h>
34
+
35
+#include "test-helper.h"
36
+#include "mix-ops.h"
37
+
38
+static uint32_t cpu_flags;
39
+
40
+typedef void (*mix_func_t) (struct mix_ops *ops, void * SPA_RESTRICT dst,
41
+       const void * SPA_RESTRICT src, uint32_t n_src, uint32_t n_samples);
42
+struct stats {
43
+   uint32_t n_samples;
44
+   uint32_t n_src;
45
+   uint64_t perf;
46
+   const char *name;
47
+   const char *impl;
48
+};
49
+
50
+#define MAX_SAMPLES    4096
51
+#define MAX_SRC        11
52
+
53
+#define MAX_COUNT 100
54
+
55
+static uint8_t samp_inMAX_SAMPLES * MAX_SRC * 8;
56
+static uint8_t samp_outMAX_SAMPLES * 8;
57
+
58
+static const int sample_sizes = { 0, 1, 128, 513, 4096 };
59
+static const int src_counts = { 1, 2, 4, 6, 8, 11 };
60
+
61
+#define MAX_RESULTS    SPA_N_ELEMENTS(sample_sizes) * SPA_N_ELEMENTS(src_counts) * 70
62
+
63
+static uint32_t n_results = 0;
64
+static struct stats resultsMAX_RESULTS;
65
+
66
+static void run_test1(const char *name, const char *impl, mix_func_t func, int n_src, int n_samples)
67
+{
68
+   int i, j;
69
+   const void *ipn_src;
70
+   void *op;
71
+   struct timespec ts;
72
+   uint64_t count, t1, t2;
73
+   struct mix_ops mix;
74
+
75
+   mix.n_channels = 1;
76
+
77
+   for (j = 0; j < n_src; j++)
78
+       ipj = SPA_PTR_ALIGN(&samp_inj * n_samples * 4, 32, void);
79
+   op = SPA_PTR_ALIGN(samp_out, 32, void);
80
+
81
+   clock_gettime(CLOCK_MONOTONIC, &ts);
82
+   t1 = SPA_TIMESPEC_TO_NSEC(&ts);
83
+
84
+   count = 0;
85
+   for (i = 0; i < MAX_COUNT; i++) {
86
+       func(&mix, op, ip, n_src, n_samples);
87
+       count++;
88
+   }
89
+   clock_gettime(CLOCK_MONOTONIC, &ts);
90
+   t2 = SPA_TIMESPEC_TO_NSEC(&ts);
91
+
92
+   spa_assert(n_results < MAX_RESULTS);
93
+
94
+   resultsn_results++ = (struct stats) {
95
+       .n_samples = n_samples,
96
+       .n_src = n_src,
97
+       .perf = count * (uint64_t)SPA_NSEC_PER_SEC / (t2 - t1),
98
+       .name = name,
99
+       .impl = impl
100
+   };
101
+}
102
+
103
+static void run_test(const char *name, const char *impl, mix_func_t func)
104
+{
105
+   size_t i, j;
106
+
107
+   for (i = 0; i < SPA_N_ELEMENTS(sample_sizes); i++) {
108
+       for (j = 0; j < SPA_N_ELEMENTS(src_counts); j++) {
109
+           run_test1(name, impl, func, src_countsj,
110
+               (sample_sizesi + (src_countsj -1)) / src_countsj);
111
+       }
112
+   }
113
+}
114
+
115
+static void test_s8(void)
116
+{
117
+   run_test("test_s8", "c", mix_s8_c);
118
+}
119
+static void test_u8(void)
120
+{
121
+   run_test("test_u8", "c", mix_u8_c);
122
+}
123
+
124
+static void test_s16(void)
125
+{
126
+   run_test("test_s16", "c", mix_s16_c);
127
+}
128
+static void test_u16(void)
129
+{
130
+   run_test("test_u8", "c", mix_u16_c);
131
+}
132
+
133
+static void test_s24(void)
134
+{
135
+   run_test("test_s24", "c", mix_s24_c);
136
+}
137
+static void test_u24(void)
138
+{
139
+   run_test("test_u24", "c", mix_u24_c);
140
+}
141
+static void test_s24_32(void)
142
+{
143
+   run_test("test_s24_32", "c", mix_s24_32_c);
144
+}
145
+static void test_u24_32(void)
146
+{
147
+   run_test("test_u24_32", "c", mix_u24_32_c);
148
+}
149
+
150
+static void test_s32(void)
151
+{
152
+   run_test("test_s32", "c", mix_s32_c);
153
+}
154
+static void test_u32(void)
155
+{
156
+   run_test("test_u32", "c", mix_u32_c);
157
+}
158
+
159
+static void test_f32(void)
160
+{
161
+   run_test("test_f32", "c", mix_f32_c);
162
+#if defined (HAVE_SSE)
163
+   if (cpu_flags & SPA_CPU_FLAG_SSE) {
164
+       run_test("test_f32", "sse", mix_f32_sse);
165
+   }
166
+#endif
167
+#if defined (HAVE_AVX)
168
+   if (cpu_flags & SPA_CPU_FLAG_AVX) {
169
+       run_test("test_f32", "avx", mix_f32_avx);
170
+   }
171
+#endif
172
+}
173
+
174
+static void test_f64(void)
175
+{
176
+   run_test("test_f64", "c", mix_f64_c);
177
+#if defined (HAVE_SSE2)
178
+   if (cpu_flags & SPA_CPU_FLAG_SSE2) {
179
+       run_test("test_f64", "sse2", mix_f64_sse2);
180
+   }
181
+#endif
182
+}
183
+
184
+static int compare_func(const void *_a, const void *_b)
185
+{
186
+   const struct stats *a = _a, *b = _b;
187
+   int diff;
188
+   if ((diff = strcmp(a->name, b->name)) != 0) return diff;
189
+   if ((diff = a->n_samples - b->n_samples) != 0) return diff;
190
+   if ((diff = a->n_src - b->n_src) != 0) return diff;
191
+   if ((diff = b->perf - a->perf) != 0) return diff;
192
+   return 0;
193
+}
194
+
195
+int main(int argc, char *argv)
196
+{
197
+   uint32_t i;
198
+
199
+   cpu_flags = get_cpu_flags();
200
+   printf("got get CPU flags %d\n", cpu_flags);
201
pipewire-0.3.54.tar.gz/spa/plugins/audiomixer/meson.build -> pipewire-0.3.56.tar.gz/spa/plugins/audiomixer/meson.build Changed
92
 
1
@@ -1,6 +1,5 @@
2
 audiomixer_sources = 
3
   'audiomixer.c',
4
-  'mix-ops.c',
5
   'mixer-dsp.c',
6
   'plugin.c'
7
 
8
@@ -47,11 +46,81 @@
9
   simd_dependencies += audiomixer_avx
10
 endif
11
 
12
-audiomixerlib = shared_library('spa-audiomixer',
13
+audiomixer_lib = static_library('audiomixer',
14
+  'mix-ops.c' ,
15
+  c_args :  simd_cargs, '-O3',
16
+  link_with : simd_dependencies,
17
+  include_directories : configinc,
18
+  dependencies :  spa_dep ,
19
+  install : false
20
+  )
21
+audiomixer_dep = declare_dependency(link_with: audiomixer_lib)
22
+
23
+spa_audiomixer_lib = shared_library('spa-audiomixer',
24
   audiomixer_sources,
25
   c_args : simd_cargs,
26
   link_with : simd_dependencies,
27
-  dependencies :  spa_dep, mathlib ,
28
+  dependencies :  spa_dep, mathlib, audiomixer_dep ,
29
   install : true,
30
   install_dir : spa_plugindir / 'audiomixer'
31
 )
32
+spa_audiomixer_dep = declare_dependency(link_with: spa_audiomixer_lib)
33
+
34
+test_apps = 
35
+  'test-mix-ops',
36
+  
37
+
38
+foreach a : test_apps
39
+  test(a,
40
+    executable(a, a + '.c',
41
+      dependencies :  spa_dep, dl_lib, pthread_lib, mathlib, audiomixer_dep ,
42
+      include_directories :  configinc ,
43
+      link_with :  test_lib ,
44
+      install_rpath : spa_plugindir / 'audiomixer',
45
+      c_args :  simd_cargs ,
46
+      install : installed_tests_enabled,
47
+      install_dir : installed_tests_execdir / 'audiomixer'),
48
+      env : 
49
+        'SPA_PLUGIN_DIR=@0@'.format(spa_dep.get_variable('plugindir')),
50
+        )
51
+
52
+    if installed_tests_enabled
53
+      test_conf = configuration_data()
54
+      test_conf.set('exec', installed_tests_execdir / 'audiomixer' / a)
55
+      configure_file(
56
+        input: installed_tests_template,
57
+        output: a + '.test',
58
+        install_dir: installed_tests_metadir / 'audiomixer',
59
+        configuration: test_conf
60
+        )
61
+  endif
62
+endforeach
63
+
64
+benchmark_apps = 
65
+  'benchmark-mix-ops',
66
+  
67
+
68
+foreach a : benchmark_apps
69
+  benchmark(a,
70
+    executable(a, a + '.c',
71
+      dependencies :  spa_dep, dl_lib, pthread_lib, mathlib, audiomixer_dep ,
72
+      include_directories :  configinc ,
73
+      c_args :  simd_cargs ,
74
+      install_rpath : spa_plugindir / 'audiomixer',
75
+      install : installed_tests_enabled,
76
+      install_dir : installed_tests_execdir / 'audiomixer'),
77
+      env : 
78
+        'SPA_PLUGIN_DIR=@0@'.format(spa_dep.get_variable('plugindir')),
79
+        )
80
+
81
+    if installed_tests_enabled
82
+      test_conf = configuration_data()
83
+      test_conf.set('exec', installed_tests_execdir / 'audiomixer' / a)
84
+      configure_file(
85
+        input: installed_tests_template,
86
+        output: a + '.test',
87
+        install_dir: installed_tests_metadir / 'audiomixer',
88
+        configuration: test_conf
89
+        )
90
+  endif
91
+endforeach
92
pipewire-0.3.54.tar.gz/spa/plugins/audiomixer/mix-ops-avx.c -> pipewire-0.3.56.tar.gz/spa/plugins/audiomixer/mix-ops-avx.c Changed
98
 
1
@@ -86,50 +86,59 @@
2
 
3
 static inline void mix_2(float * dst, const float * SPA_RESTRICT src, uint32_t n_samples)
4
 {
5
-   uint32_t n, unrolled;
6
-
7
-   if (SPA_IS_ALIGNED(src, 32) &&
8
-       SPA_IS_ALIGNED(dst, 32))
9
-       unrolled = n_samples & ~15;
10
-   else
11
-       unrolled = 0;
12
-
13
-   for (n = 0; n < unrolled; n += 16) {
14
-       __m256 in12, in22;
15
-
16
-       in10 = _mm256_load_ps(&dstn + 0);
17
-       in11 = _mm256_load_ps(&dstn + 8);
18
-       in20 = _mm256_load_ps(&srcn + 0);
19
-       in21 = _mm256_load_ps(&srcn + 8);
20
-
21
-       in10 = _mm256_add_ps(in10, in20);
22
-       in11 = _mm256_add_ps(in11, in21);
23
-
24
-       _mm256_store_ps(&dstn + 0, in10);
25
-       _mm256_store_ps(&dstn + 8, in11);
26
-   }
27
-   for (; n < n_samples; n++) {
28
-       __m128 in11, in21;
29
-       in10 = _mm_load_ss(&dstn),
30
-       in20 = _mm_load_ss(&srcn),
31
-       in10 = _mm_add_ss(in10, in20);
32
-       _mm_store_ss(&dstn, in10);
33
-   }
34
 }
35
 
36
 void
37
 mix_f32_avx(struct mix_ops *ops, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src,
38
        uint32_t n_src, uint32_t n_samples)
39
 {
40
-   uint32_t i;
41
+   n_samples *= ops->n_channels;
42
 
43
    if (n_src == 0)
44
        memset(dst, 0, n_samples * ops->n_channels * sizeof(float));
45
-   else if (dst != src0)
46
-       spa_memcpy(dst, src0, n_samples * ops->n_channels * sizeof(float));
47
-
48
-   for (i = 1; i + 2 < n_src; i += 3)
49
-       mix_4(dst, srci, srci + 1, srci + 2, n_samples);
50
-   for (; i < n_src; i++)
51
-       mix_2(dst, srci, n_samples * ops->n_channels);
52
+   else if (n_src == 1) {
53
+       if (dst != src0)
54
+           spa_memcpy(dst, src0, n_samples * sizeof(float));
55
+   } else {
56
+       uint32_t i, n, unrolled;
57
+       const float **s = (const float **)src;
58
+       float *d = dst;
59
+
60
+       if (SPA_LIKELY(SPA_IS_ALIGNED(dst, 32))) {
61
+           unrolled = n_samples & ~31;
62
+           for (i = 0; i < n_src; i++) {
63
+               if (SPA_UNLIKELY(!SPA_IS_ALIGNED(srci, 32))) {
64
+                   unrolled = 0;
65
+                   break;
66
+               }
67
+           }
68
+       } else
69
+           unrolled = 0;
70
+
71
+       for (n = 0; n < unrolled; n += 32) {
72
+           __m256 in4;
73
+
74
+           in0 = _mm256_load_ps(&s0n +  0);
75
+           in1 = _mm256_load_ps(&s0n +  8);
76
+           in2 = _mm256_load_ps(&s0n + 16);
77
+           in3 = _mm256_load_ps(&s0n + 24);
78
+           for (i = 1; i < n_src; i++) {
79
+               in0 = _mm256_add_ps(in0, _mm256_load_ps(&sin +  0));
80
+               in1 = _mm256_add_ps(in1, _mm256_load_ps(&sin +  8));
81
+               in2 = _mm256_add_ps(in2, _mm256_load_ps(&sin + 16));
82
+               in3 = _mm256_add_ps(in3, _mm256_load_ps(&sin + 24));
83
+           }
84
+           _mm256_store_ps(&dn +  0, in0);
85
+           _mm256_store_ps(&dn +  8, in1);
86
+           _mm256_store_ps(&dn + 16, in2);
87
+           _mm256_store_ps(&dn + 24, in3);
88
+       }
89
+       for (; n < n_samples; n++) {
90
+           __m128 in1;
91
+           in0 = _mm_load_ss(&s0n);
92
+           for (i = 1; i < n_src; i++)
93
+               in0 = _mm_add_ss(in0, _mm_load_ss(&sin));
94
+           _mm_store_ss(&dn, in0);
95
+       }
96
+   }
97
 }
98
pipewire-0.3.54.tar.gz/spa/plugins/audiomixer/mix-ops-c.c -> pipewire-0.3.56.tar.gz/spa/plugins/audiomixer/mix-ops-c.c Changed
201
 
1
@@ -30,236 +30,39 @@
2
 
3
 #include "mix-ops.h"
4
 
5
-void
6
-mix_s8_c(struct mix_ops *ops, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src,
7
-       uint32_t n_src, uint32_t n_samples)
8
-{
9
-   uint32_t i, n;
10
-   int8_t *d = dst;
11
-
12
-   if (n_src == 0)
13
-       memset(dst, 0, n_samples * ops->n_channels * sizeof(int8_t));
14
-   else if (dst != src0)
15
-       spa_memcpy(dst, src0, n_samples * ops->n_channels * sizeof(int8_t));
16
-
17
-   for (i = 1; i < n_src; i++) {
18
-       const int8_t *s = srci;
19
-       for (n = 0; n < n_samples * ops->n_channels; n++)
20
-           dn = S8_MIX(dn, sn);
21
-   }
22
-}
23
-
24
-void
25
-mix_u8_c(struct mix_ops *ops, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src,
26
-       uint32_t n_src, uint32_t n_samples)
27
-{
28
-   uint32_t i, n;
29
-   uint8_t *d = dst;
30
-
31
-   if (n_src == 0)
32
-       memset(dst, 0, n_samples * ops->n_channels * sizeof(uint8_t));
33
-   else if (dst != src0)
34
-       spa_memcpy(dst, src0, n_samples * ops->n_channels * sizeof(uint8_t));
35
-
36
-   for (i = 1; i < n_src; i++) {
37
-       const uint8_t *s = srci;
38
-       for (n = 0; n < n_samples * ops->n_channels; n++)
39
-           dn = U8_MIX(dn, sn);
40
-   }
41
+#define MAKE_FUNC(name,type,atype,accum,clamp,zero)                \
42
+void mix_ ##name## _c(struct mix_ops *ops,                 \
43
+       void * SPA_RESTRICT dst, const void * SPA_RESTRICT src, \
44
+                uint32_t n_src, uint32_t n_samples)                \
45
+{                                      \
46
+   uint32_t i, n;                              \
47
+   type *d = dst;                              \
48
+   const type **s = (const type **)src;                    \
49
+   n_samples *= ops->n_channels;                       \
50
+   if (n_src == 0 && zero)                         \
51
+       memset(dst, 0, n_samples * sizeof(type));           \
52
+   else if (n_src == 1) {                          \
53
+       if (dst != src0)                        \
54
+           spa_memcpy(dst, src0, n_samples * sizeof(type));    \
55
+   } else {                                \
56
+       for (n = 0; n < n_samples; n++) {               \
57
+           atype ac = 0;                       \
58
+           for (i = 0; i < n_src; i++)             \
59
+               ac = accum (ac, sin);           \
60
+           dn = clamp (ac);                    \
61
+       }                               \
62
+   }                                   \
63
 }
64
 
65
-void
66
-mix_s16_c(struct mix_ops *ops, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src,
67
-       uint32_t n_src, uint32_t n_samples)
68
-{
69
-   uint32_t i, n;
70
-   int16_t *d = dst;
71
-
72
-   if (n_src == 0)
73
-       memset(dst, 0, n_samples * ops->n_channels * sizeof(int16_t));
74
-   else if (dst != src0)
75
-       spa_memcpy(dst, src0, n_samples * ops->n_channels * sizeof(int16_t));
76
-
77
-   for (i = 1; i < n_src; i++) {
78
-       const int16_t *s = srci;
79
-       for (n = 0; n < n_samples * ops->n_channels; n++)
80
-           dn = S16_MIX(dn, sn);
81
-   }
82
-}
83
-
84
-void
85
-mix_u16_c(struct mix_ops *ops, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src,
86
-       uint32_t n_src, uint32_t n_samples)
87
-{
88
-   uint32_t i, n;
89
-   uint16_t *d = dst;
90
-
91
-   if (n_src == 0)
92
-       memset(dst, 0, n_samples * ops->n_channels * sizeof(uint16_t));
93
-   else if (dst != src0)
94
-       spa_memcpy(dst, src0, n_samples * ops->n_channels * sizeof(uint16_t));
95
-
96
-   for (i = 1; i < n_src; i++) {
97
-       const uint16_t *s = srci;
98
-       for (n = 0; n < n_samples * ops->n_channels; n++)
99
-           dn = U16_MIX(dn, sn);
100
-   }
101
-}
102
-
103
-void
104
-mix_s24_c(struct mix_ops *ops, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src,
105
-       uint32_t n_src, uint32_t n_samples)
106
-{
107
-   uint32_t i, n;
108
-   uint8_t *d = dst;
109
-
110
-   if (n_src == 0)
111
-       memset(dst, 0, n_samples * ops->n_channels * sizeof(uint8_t) * 3);
112
-   else if (dst != src0)
113
-       spa_memcpy(dst, src0, n_samples * ops->n_channels * sizeof(uint8_t) * 3);
114
-
115
-   for (i = 1; i < n_src; i++) {
116
-       const uint8_t *s = srci;
117
-       for (n = 0; n < n_samples * ops->n_channels; n++) {
118
-           write_s24(d, S24_MIX(read_s24(d), read_s24(s)));
119
-           d += 3;
120
-           s += 3;
121
-       }
122
-   }
123
-}
124
-
125
-void
126
-mix_u24_c(struct mix_ops *ops, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src,
127
-       uint32_t n_src, uint32_t n_samples)
128
-{
129
-   uint32_t i, n;
130
-   uint8_t *d = dst;
131
-
132
-   if (n_src == 0)
133
-       memset(dst, 0, n_samples * ops->n_channels * sizeof(uint8_t) * 3);
134
-   else if (dst != src0)
135
-       spa_memcpy(dst, src0, n_samples * ops->n_channels * sizeof(uint8_t) * 3);
136
-
137
-   for (i = 1; i < n_src; i++) {
138
-       const uint8_t *s = srci;
139
-       for (n = 0; n < n_samples * ops->n_channels; n++) {
140
-           write_u24(d, U24_MIX(read_u24(d), read_u24(s)));
141
-           d += 3;
142
-           s += 3;
143
-       }
144
-   }
145
-}
146
-
147
-void
148
-mix_s32_c(struct mix_ops *ops, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src,
149
-       uint32_t n_src, uint32_t n_samples)
150
-{
151
-   uint32_t i, n;
152
-   int32_t *d = dst;
153
-
154
-   if (n_src == 0)
155
-       memset(dst, 0, n_samples * ops->n_channels * sizeof(int32_t));
156
-   else if (dst != src0)
157
-       spa_memcpy(dst, src0, n_samples * ops->n_channels * sizeof(int32_t));
158
-
159
-   for (i = 1; i < n_src; i++) {
160
-       const int32_t *s = srci;
161
-       for (n = 0; n < n_samples * ops->n_channels; n++)
162
-           dn = S32_MIX(dn, sn);
163
-   }
164
-}
165
-
166
-void
167
-mix_u32_c(struct mix_ops *ops, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src,
168
-       uint32_t n_src, uint32_t n_samples)
169
-{
170
-   uint32_t i, n;
171
-   uint32_t *d = dst;
172
-
173
-   if (n_src == 0)
174
-       memset(dst, 0, n_samples * ops->n_channels * sizeof(uint32_t));
175
-   else if (dst != src0)
176
-       spa_memcpy(dst, src0, n_samples * ops->n_channels * sizeof(uint32_t));
177
-
178
-   for (i = 1; i < n_src; i++) {
179
-       const uint32_t *s = srci;
180
-       for (n = 0; n < n_samples * ops->n_channels; n++)
181
-           dn = U32_MIX(dn, sn);
182
-   }
183
-}
184
-
185
-void
186
-mix_s24_32_c(struct mix_ops *ops, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src,
187
-       uint32_t n_src, uint32_t n_samples)
188
-{
189
-   uint32_t i, n;
190
-   int32_t *d = dst;
191
-
192
-   if (n_src == 0)
193
-       memset(dst, 0, n_samples * ops->n_channels * sizeof(int32_t));
194
-   else if (dst != src0)
195
-       spa_memcpy(dst, src0, n_samples * ops->n_channels * sizeof(int32_t));
196
-
197
-   for (i = 1; i < n_src; i++) {
198
-       const int32_t *s = srci;
199
-       for (n = 0; n < n_samples * ops->n_channels; n++)
200
-           dn = S24_32_MIX(dn, sn);
201
pipewire-0.3.54.tar.gz/spa/plugins/audiomixer/mix-ops-sse.c -> pipewire-0.3.56.tar.gz/spa/plugins/audiomixer/mix-ops-sse.c Changed
105
 
1
@@ -32,58 +32,56 @@
2
 
3
 #include <xmmintrin.h>
4
 
5
-static inline void mix_2(float * dst, const float * SPA_RESTRICT src, uint32_t n_samples)
6
-{
7
-   uint32_t n, unrolled;
8
-   __m128 in14, in24;
9
-
10
-   if (SPA_LIKELY(SPA_IS_ALIGNED(src, 16) &&
11
-       SPA_IS_ALIGNED(dst, 16)))
12
-       unrolled = n_samples & ~15;
13
-   else
14
-       unrolled = 0;
15
-
16
-   for (n = 0; n < unrolled; n += 16) {
17
-       in10 = _mm_load_ps(&dstn+ 0);
18
-       in11 = _mm_load_ps(&dstn+ 4);
19
-       in12 = _mm_load_ps(&dstn+ 8);
20
-       in13 = _mm_load_ps(&dstn+12);
21
-
22
-       in20 = _mm_load_ps(&srcn+ 0);
23
-       in21 = _mm_load_ps(&srcn+ 4);
24
-       in22 = _mm_load_ps(&srcn+ 8);
25
-       in23 = _mm_load_ps(&srcn+12);
26
-
27
-       in10 = _mm_add_ps(in10, in20);
28
-       in11 = _mm_add_ps(in11, in21);
29
-       in12 = _mm_add_ps(in12, in22);
30
-       in13 = _mm_add_ps(in13, in23);
31
-
32
-       _mm_store_ps(&dstn+ 0, in10);
33
-       _mm_store_ps(&dstn+ 4, in11);
34
-       _mm_store_ps(&dstn+ 8, in12);
35
-       _mm_store_ps(&dstn+12, in13);
36
-   }
37
-   for (; n < n_samples; n++) {
38
-       in10 = _mm_load_ss(&dstn),
39
-       in20 = _mm_load_ss(&srcn),
40
-       in10 = _mm_add_ss(in10, in20);
41
-       _mm_store_ss(&dstn, in10);
42
-   }
43
-}
44
-
45
 void
46
 mix_f32_sse(struct mix_ops *ops, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src,
47
        uint32_t n_src, uint32_t n_samples)
48
 {
49
-   uint32_t i;
50
+   n_samples *= ops->n_channels;
51
+
52
+   if (n_src == 0) {
53
+       memset(dst, 0, n_samples * sizeof(float));
54
+   } else if (n_src == 1) {
55
+       if (dst != src0)
56
+           spa_memcpy(dst, src0, n_samples * sizeof(float));
57
+   } else {
58
+       uint32_t n, i, unrolled;
59
+       __m128 in4;
60
+       const float **s = (const float **)src;
61
+       float *d = dst;
62
+
63
+       if (SPA_LIKELY(SPA_IS_ALIGNED(dst, 16))) {
64
+           unrolled = n_samples & ~15;
65
+           for (i = 0; i < n_src; i++) {
66
+               if (SPA_UNLIKELY(!SPA_IS_ALIGNED(srci, 16))) {
67
+                   unrolled = 0;
68
+                   break;
69
+               }
70
+           }
71
+       } else
72
+           unrolled = 0;
73
 
74
-   if (n_src == 0)
75
-       memset(dst, 0, n_samples * ops->n_channels * sizeof(float));
76
-   else if (dst != src0)
77
-       spa_memcpy(dst, src0, n_samples * ops->n_channels * sizeof(float));
78
+       for (n = 0; n < unrolled; n += 16) {
79
+           in0 = _mm_load_ps(&s0n+ 0);
80
+           in1 = _mm_load_ps(&s0n+ 4);
81
+           in2 = _mm_load_ps(&s0n+ 8);
82
+           in3 = _mm_load_ps(&s0n+12);
83
 
84
-   for (i = 1; i < n_src; i++) {
85
-       mix_2(dst, srci, n_samples * ops->n_channels);
86
+           for (i = 1; i < n_src; i++) {
87
+               in0 = _mm_add_ps(in0, _mm_load_ps(&sin+ 0));
88
+               in1 = _mm_add_ps(in1, _mm_load_ps(&sin+ 4));
89
+               in2 = _mm_add_ps(in2, _mm_load_ps(&sin+ 8));
90
+               in3 = _mm_add_ps(in3, _mm_load_ps(&sin+12));
91
+           }
92
+           _mm_store_ps(&dn+ 0, in0);
93
+           _mm_store_ps(&dn+ 4, in1);
94
+           _mm_store_ps(&dn+ 8, in2);
95
+           _mm_store_ps(&dn+12, in3);
96
+       }
97
+       for (; n < n_samples; n++) {
98
+           in0 = _mm_load_ss(&s0n);
99
+           for (i = 1; i < n_src; i++)
100
+               in0 = _mm_add_ss(in0, _mm_load_ss(&sin));
101
+           _mm_store_ss(&dn, in0);
102
+       }
103
    }
104
 }
105
pipewire-0.3.54.tar.gz/spa/plugins/audiomixer/mix-ops-sse2.c -> pipewire-0.3.56.tar.gz/spa/plugins/audiomixer/mix-ops-sse2.c Changed
105
 
1
@@ -32,58 +32,56 @@
2
 
3
 #include <emmintrin.h>
4
 
5
-static inline void mix_2(double * dst, const double * SPA_RESTRICT src, uint32_t n_samples)
6
-{
7
-   uint32_t n, unrolled;
8
-   __m128d in14, in24;
9
-
10
-   if (SPA_IS_ALIGNED(src, 16) &&
11
-       SPA_IS_ALIGNED(dst, 16))
12
-       unrolled = n_samples & ~7;
13
-   else
14
-       unrolled = 0;
15
-
16
-   for (n = 0; n < unrolled; n += 8) {
17
-       in10 = _mm_load_pd(&dstn+ 0);
18
-       in11 = _mm_load_pd(&dstn+ 2);
19
-       in12 = _mm_load_pd(&dstn+ 4);
20
-       in13 = _mm_load_pd(&dstn+ 6);
21
-
22
-       in20 = _mm_load_pd(&srcn+ 0);
23
-       in21 = _mm_load_pd(&srcn+ 2);
24
-       in22 = _mm_load_pd(&srcn+ 4);
25
-       in23 = _mm_load_pd(&srcn+ 6);
26
-
27
-       in10 = _mm_add_pd(in10, in20);
28
-       in11 = _mm_add_pd(in11, in21);
29
-       in12 = _mm_add_pd(in12, in22);
30
-       in13 = _mm_add_pd(in13, in23);
31
-
32
-       _mm_store_pd(&dstn+ 0, in10);
33
-       _mm_store_pd(&dstn+ 2, in11);
34
-       _mm_store_pd(&dstn+ 4, in12);
35
-       _mm_store_pd(&dstn+ 6, in13);
36
-   }
37
-   for (; n < n_samples; n++) {
38
-       in10 = _mm_load_sd(&dstn),
39
-       in20 = _mm_load_sd(&srcn),
40
-       in10 = _mm_add_sd(in10, in20);
41
-       _mm_store_sd(&dstn, in10);
42
-   }
43
-}
44
-
45
 void
46
 mix_f64_sse2(struct mix_ops *ops, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src,
47
        uint32_t n_src, uint32_t n_samples)
48
 {
49
-   uint32_t i;
50
+   n_samples *= ops->n_channels;
51
+
52
+   if (n_src == 0) {
53
+       memset(dst, 0, n_samples * sizeof(double));
54
+   } else if (n_src == 1) {
55
+       if (dst != src0)
56
+           spa_memcpy(dst, src0, n_samples * sizeof(double));
57
+   } else {
58
+       uint32_t n, i, unrolled;
59
+       __m128d in4;
60
+       const double **s = (const double **)src;
61
+       double *d = dst;
62
+
63
+       if (SPA_LIKELY(SPA_IS_ALIGNED(dst, 16))) {
64
+           unrolled = n_samples & ~15;
65
+           for (i = 0; i < n_src; i++) {
66
+               if (SPA_UNLIKELY(!SPA_IS_ALIGNED(srci, 16))) {
67
+                   unrolled = 0;
68
+                   break;
69
+               }
70
+           }
71
+       } else
72
+           unrolled = 0;
73
 
74
-   if (n_src == 0)
75
-       memset(dst, 0, n_samples * ops->n_channels * sizeof(double));
76
-   else if (dst != src0)
77
-       spa_memcpy(dst, src0, n_samples * ops->n_channels * sizeof(double));
78
+       for (n = 0; n < unrolled; n += 8) {
79
+           in0 = _mm_load_pd(&s0n+0);
80
+           in1 = _mm_load_pd(&s0n+2);
81
+           in2 = _mm_load_pd(&s0n+4);
82
+           in3 = _mm_load_pd(&s0n+6);
83
 
84
-   for (i = 1; i < n_src; i++) {
85
-       mix_2(dst, srci, n_samples * ops->n_channels);
86
+           for (i = 1; i < n_src; i++) {
87
+               in0 = _mm_add_pd(in0, _mm_load_pd(&sin+0));
88
+               in1 = _mm_add_pd(in1, _mm_load_pd(&sin+2));
89
+               in2 = _mm_add_pd(in2, _mm_load_pd(&sin+4));
90
+               in3 = _mm_add_pd(in3, _mm_load_pd(&sin+6));
91
+           }
92
+           _mm_store_pd(&dn+0, in0);
93
+           _mm_store_pd(&dn+2, in1);
94
+           _mm_store_pd(&dn+4, in2);
95
+           _mm_store_pd(&dn+6, in3);
96
+       }
97
+       for (; n < n_samples; n++) {
98
+           in0 = _mm_load_sd(&s0n);
99
+           for (i = 1; i < n_src; i++)
100
+               in0 = _mm_add_sd(in0, _mm_load_sd(&sin));
101
+           _mm_store_sd(&dn, in0);
102
+       }
103
    }
104
 }
105
pipewire-0.3.54.tar.gz/spa/plugins/audiomixer/mix-ops.h -> pipewire-0.3.56.tar.gz/spa/plugins/audiomixer/mix-ops.h Changed
156
 
1
@@ -24,80 +24,98 @@
2
 
3
 #include <spa/utils/defs.h>
4
 
5
-static inline uint32_t read_u24(const void *src)
6
-{
7
-   const uint8_t *s = src;
8
+typedef struct {
9
 #if __BYTE_ORDER == __LITTLE_ENDIAN
10
-   return (((uint32_t)s2 << 16) | ((uint32_t)(uint8_t)s1 << 8) | (uint32_t)(uint8_t)s0);
11
+   uint8_t v3;
12
+   uint8_t v2;
13
+   uint8_t v1;
14
 #else
15
-   return (((uint32_t)s0 << 16) | ((uint32_t)(uint8_t)s1 << 8) | (uint32_t)(uint8_t)s2);
16
+   uint8_t v1;
17
+   uint8_t v2;
18
+   uint8_t v3;
19
 #endif
20
-}
21
+} __attribute__ ((packed)) uint24_t;
22
 
23
-static inline int32_t read_s24(const void *src)
24
-{
25
-   const int8_t *s = src;
26
+typedef struct {
27
 #if __BYTE_ORDER == __LITTLE_ENDIAN
28
-   return (((int32_t)s2 << 16) | ((uint32_t)(uint8_t)s1 << 8) | (uint32_t)(uint8_t)s0);
29
+   uint8_t v3;
30
+   uint8_t v2;
31
+   int8_t v1;
32
 #else
33
-   return (((int32_t)s0 << 16) | ((uint32_t)(uint8_t)s1 << 8) | (uint32_t)(uint8_t)s2);
34
+   int8_t v1;
35
+   uint8_t v2;
36
+   uint8_t v3;
37
 #endif
38
-}
39
+} __attribute__ ((packed)) int24_t;
40
 
41
-static inline void write_u24(void *dst, uint32_t val)
42
+static inline uint32_t u24_to_u32(uint24_t src)
43
 {
44
-   uint8_t *d = dst;
45
-#if __BYTE_ORDER == __LITTLE_ENDIAN
46
-   d0 = (uint8_t) (val);
47
-   d1 = (uint8_t) (val >> 8);
48
-   d2 = (uint8_t) (val >> 16);
49
-#else
50
-   d0 = (uint8_t) (val >> 16);
51
-   d1 = (uint8_t) (val >> 8);
52
-   d2 = (uint8_t) (val);
53
-#endif
54
+   return ((uint32_t)src.v1 << 16) | ((uint32_t)src.v2 << 8) | (uint32_t)src.v3;
55
 }
56
 
57
-static inline void write_s24(void *dst, int32_t val)
58
+#define U32_TO_U24(s) (uint24_t) { .v1 = (uint8_t)(((uint32_t)s) >> 16), \
59
+   .v2 = (uint8_t)(((uint32_t)s) >> 8), .v3 = (uint8_t)((uint32_t)s) }
60
+
61
+static inline uint24_t u32_to_u24(uint32_t src)
62
 {
63
-   uint8_t *d = dst;
64
-#if __BYTE_ORDER == __LITTLE_ENDIAN
65
-   d0 = (uint8_t) (val);
66
-   d1 = (uint8_t) (val >> 8);
67
-   d2 = (uint8_t) (val >> 16);
68
-#else
69
-   d0 = (uint8_t) (val >> 16);
70
-   d1 = (uint8_t) (val >> 8);
71
-   d2 = (uint8_t) (val);
72
-#endif
73
+   return U32_TO_U24(src);
74
 }
75
 
76
-#define S8_MIN     -127
77
-#define S8_MAX     127
78
-#define S8_MIX(a, b)    (int8_t)(SPA_CLAMP((int16_t)(a) + (int16_t)(b), S8_MIN, S8_MAX))
79
-#define U8_MIX(a, b)    (uint8_t)((int16_t)S8_MIX((int16_t)(a) - S8_MAX, (int16_t)(b) - S8_MAX) + S8_MAX)
80
-
81
-#define S16_MIN        -32767
82
-#define S16_MAX        32767
83
-#define S16_MIX(a, b)   (int16_t)(SPA_CLAMP((int32_t)(a) + (int32_t)(b), S16_MIN, S16_MAX))
84
-#define U16_MIX(a, b)   (uint16_t)((int32_t)S16_MIX((int32_t)(a) - S16_MAX, (int32_t)(b) - S16_MAX) + S16_MAX)
85
-
86
-#define S24_MIN        -8388607
87
-#define S24_MAX        8388607
88
-#define S24_MIX(a, b)   (int32_t)(SPA_CLAMP((int32_t)(a) + (int32_t)(b), S24_MIN, S24_MAX))
89
-#define U24_MIX(a, b)   (uint32_t)((int32_t)S24_MIX((int32_t)(a) - S24_MAX, (int32_t)(b) - S24_MAX) + S24_MAX)
90
+static inline int32_t s24_to_s32(int24_t src)
91
+{
92
+   return ((int32_t)src.v1 << 16) | ((uint32_t)src.v2 << 8) | (uint32_t)src.v3;
93
+}
94
 
95
-#define S32_MIN        -2147483647
96
-#define S32_MAX        2147483647
97
-#define S32_MIX(a, b)   (int32_t)(SPA_CLAMP((int64_t)(a) + (int64_t)(b), S32_MIN, S32_MAX))
98
-#define U32_MIX(a, b)   (uint32_t)((int64_t)S32_MIX((int64_t)(a) - S32_MAX, (int64_t)(b) - S32_MAX) + S32_MAX)
99
+#define S32_TO_S24(s) (int24_t) { .v1 = (int8_t)(((int32_t)s) >> 16), \
100
+   .v2 = (uint8_t)(((uint32_t)s) >> 8), .v3 = (uint8_t)((uint32_t)s) }
101
 
102
-#define S24_32_MIX(a, b) S24_MIX (a, b)
103
-#define U24_32_MIX(a, b) U24_MIX (a, b)
104
+static inline int24_t s32_to_s24(int32_t src)
105
+{
106
+   return S32_TO_S24(src);
107
+}
108
 
109
-#define F32_MIX(a, b)   (float)((float)(a) + (float)(b))
110
 
111
-#define F64_MIX(a, b)   (double)((double)(a) + (double)(b))
112
+#define S8_MIN         -128
113
+#define S8_MAX         127
114
+#define S8_ACCUM(a,b)      ((a) + (int16_t)(b))
115
+#define S8_CLAMP(a)        (int8_t)(SPA_CLAMP((a), S8_MIN, S8_MAX))
116
+#define U8_OFFS            128
117
+#define U8_ACCUM(a,b)      ((a) + ((int16_t)(b) - U8_OFFS))
118
+#define U8_CLAMP(a)        (uint8_t)(SPA_CLAMP((a), S8_MIN, S8_MAX) + U8_OFFS)
119
+
120
+#define S16_MIN            -32768
121
+#define S16_MAX            32767
122
+#define S16_ACCUM(a,b)     ((a) + (int32_t)(b))
123
+#define S16_CLAMP(a)       (int16_t)(SPA_CLAMP((a), S16_MIN, S16_MAX))
124
+#define U16_OFFS       32768
125
+#define U16_ACCUM(a,b)     ((a) + ((int32_t)(b) - U16_OFFS))
126
+#define U16_CLAMP(a)       (uint16_t)(SPA_CLAMP((a), S16_MIN, S16_MAX) + U16_OFFS)
127
+
128
+#define S24_32_MIN     -8388608
129
+#define S24_32_MAX     8388607
130
+#define S24_32_ACCUM(a,b)  ((a) + (int32_t)(b))
131
+#define S24_32_CLAMP(a)        (int32_t)(SPA_CLAMP((a), S24_32_MIN, S24_32_MAX))
132
+#define U24_32_OFFS        8388608
133
+#define U24_32_ACCUM(a,b)  ((a) + ((int32_t)(b) - U24_32_OFFS))
134
+#define U24_32_CLAMP(a)        (uint32_t)(SPA_CLAMP((a), S24_32_MIN, S24_32_MAX) + U24_32_OFFS)
135
+
136
+#define S24_ACCUM(a,b)     S24_32_ACCUM(a, s24_to_s32(b))
137
+#define S24_CLAMP(a)       s32_to_s24(S24_32_CLAMP(a))
138
+#define U24_ACCUM(a,b)     U24_32_ACCUM(a, u24_to_u32(b))
139
+#define U24_CLAMP(a)       u32_to_u24(U24_32_CLAMP(a))
140
+
141
+#define S32_MIN            -2147483648
142
+#define S32_MAX            2147483647
143
+#define S32_ACCUM(a,b)     ((a) + (int64_t)(b))
144
+#define S32_CLAMP(a)       (int32_t)(SPA_CLAMP((a), S32_MIN, S32_MAX))
145
+#define U32_OFFS       2147483648
146
+#define U32_ACCUM(a,b)     ((a) + ((int64_t)(b) - U32_OFFS))
147
+#define U32_CLAMP(a)       (uint32_t)(SPA_CLAMP((a), S32_MIN, S32_MAX) + U32_OFFS)
148
+
149
+#define F32_ACCUM(a,b)     ((a) + (b))
150
+#define F32_CLAMP(a)       (a)
151
+#define F64_ACCUM(a,b)     ((a) + (b))
152
+#define F64_CLAMP(a)       (a)
153
 
154
 struct mix_ops {
155
    uint32_t fmt;
156
pipewire-0.3.54.tar.gz/spa/plugins/audiomixer/mixer-dsp.c -> pipewire-0.3.56.tar.gz/spa/plugins/audiomixer/mixer-dsp.c Changed
51
 
1
@@ -105,7 +105,6 @@
2
    uint32_t cpu_flags;
3
    uint32_t max_align;
4
 
5
-   struct spa_io_position *io_position;
6
    uint32_t quantum_limit;
7
 
8
    struct mix_ops ops;
9
@@ -153,20 +152,7 @@
10
 
11
 static int impl_node_set_io(void *object, uint32_t id, void *data, size_t size)
12
 {
13
-   struct impl *this = object;
14
-
15
-   spa_return_val_if_fail(this != NULL, -EINVAL);
16
-
17
-   spa_log_debug(this->log, "%p: io %d %p/%zd", this, id, data, size);
18
-
19
-   switch (id) {
20
-   case SPA_IO_Position:
21
-       this->io_position = data;
22
-       break;
23
-   default:
24
-       return -ENOENT;
25
-   }
26
-   return 0;
27
+   return -ENOTSUP;
28
 }
29
 
30
 static int impl_node_send_command(void *object, const struct spa_command *command)
31
@@ -708,10 +694,7 @@
32
    datas = alloca(MAX_PORTS * sizeof(void *));
33
    n_buffers = 0;
34
 
35
-   if (SPA_LIKELY(this->io_position))
36
-       maxsize = this->io_position->clock.duration * sizeof(float);
37
-   else
38
-       maxsize = this->quantum_limit;
39
+   maxsize = UINT32_MAX;
40
 
41
    for (i = 0; i < this->last_port; i++) {
42
        struct port *inport = GET_IN_PORT(this, i);
43
@@ -867,7 +850,6 @@
44
        this->max_align = SPA_MIN(MAX_ALIGN, spa_cpu_get_max_align(this->cpu));
45
    }
46
 
47
-   this->quantum_limit = 8192;
48
    for (i = 0; info && i < info->n_items; i++) {
49
        const char *k = info->itemsi.key;
50
        const char *s = info->itemsi.value;
51
pipewire-0.3.56.tar.gz/spa/plugins/audiomixer/test-helper.h Added
99
 
1
@@ -0,0 +1,97 @@
2
+#include <dlfcn.h>
3
+
4
+#include <spa/support/plugin.h>
5
+#include <spa/utils/type.h>
6
+#include <spa/utils/result.h>
7
+#include <spa/support/cpu.h>
8
+#include <spa/utils/names.h>
9
+
10
+static inline const struct spa_handle_factory *get_factory(spa_handle_factory_enum_func_t enum_func,
11
+       const char *name, uint32_t version)
12
+{
13
+   uint32_t i;
14
+   int res;
15
+   const struct spa_handle_factory *factory;
16
+
17
+   for (i = 0;;) {
18
+       if ((res = enum_func(&factory, &i)) <= 0) {
19
+           if (res < 0)
20
+               errno = -res;
21
+           break;
22
+       }
23
+       if (factory->version >= version &&
24
+           !strcmp(factory->name, name))
25
+           return factory;
26
+   }
27
+   return NULL;
28
+}
29
+
30
+static inline struct spa_handle *load_handle(const struct spa_support *support,
31
+       uint32_t n_support, const char *lib, const char *name)
32
+{
33
+   int res, len;
34
+   void *hnd;
35
+   spa_handle_factory_enum_func_t enum_func;
36
+   const struct spa_handle_factory *factory;
37
+   struct spa_handle *handle;
38
+   const char *str;
39
+   char *path;
40
+
41
+   if ((str = getenv("SPA_PLUGIN_DIR")) == NULL)
42
+       str = PLUGINDIR;
43
+
44
+   len = strlen(str) + strlen(lib) + 2;
45
+   path = alloca(len);
46
+   snprintf(path, len, "%s/%s", str, lib);
47
+
48
+   if ((hnd = dlopen(path, RTLD_NOW)) == NULL) {
49
+       fprintf(stderr, "can't load %s: %s\n", lib, dlerror());
50
+       res = -ENOENT;
51
+       goto error;
52
+   }
53
+   if ((enum_func = dlsym(hnd, SPA_HANDLE_FACTORY_ENUM_FUNC_NAME)) == NULL) {
54
+       fprintf(stderr, "can't find enum function\n");
55
+       res = -ENXIO;
56
+       goto error_close;
57
+   }
58
+
59
+   if ((factory = get_factory(enum_func, name, SPA_VERSION_HANDLE_FACTORY)) == NULL) {
60
+       fprintf(stderr, "can't find factory\n");
61
+       res = -ENOENT;
62
+       goto error_close;
63
+   }
64
+   handle = calloc(1, spa_handle_factory_get_size(factory, NULL));
65
+   if ((res = spa_handle_factory_init(factory, handle,
66
+                   NULL, support, n_support)) < 0) {
67
+       fprintf(stderr, "can't make factory instance: %d\n", res);
68
+       goto error_close;
69
+   }
70
+   return handle;
71
+
72
+error_close:
73
+   dlclose(hnd);
74
+error:
75
+   errno = -res;
76
+   return NULL;
77
+}
78
+
79
+static inline uint32_t get_cpu_flags(void)
80
+{
81
+   struct spa_handle *handle;
82
+   uint32_t flags;
83
+   void *iface;
84
+   int res;
85
+
86
+   handle = load_handle(NULL, 0, "support/libspa-support.so", SPA_NAME_SUPPORT_CPU);
87
+   if (handle == NULL)
88
+       return 0;
89
+   if ((res = spa_handle_get_interface(handle, SPA_TYPE_INTERFACE_CPU, &iface)) < 0) {
90
+       fprintf(stderr, "can't get CPU interface %s\n", spa_strerror(res));
91
+       return 0;
92
+   }
93
+   flags = spa_cpu_get_flags((struct spa_cpu*)iface);
94
+
95
+   free(handle);
96
+
97
+   return flags;
98
+}
99
pipewire-0.3.56.tar.gz/spa/plugins/audiomixer/test-mix-ops.c Added
201
 
1
@@ -0,0 +1,293 @@
2
+/* Spa
3
+ *
4
+ * Copyright © 2022 Wim Taymans
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a
7
+ * copy of this software and associated documentation files (the "Software"),
8
+ * to deal in the Software without restriction, including without limitation
9
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
+ * and/or sell copies of the Software, and to permit persons to whom the
11
+ * Software is furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice (including the next
14
+ * paragraph) shall be included in all copies or substantial portions of the
15
+ * Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23
+ * DEALINGS IN THE SOFTWARE.
24
+ */
25
+
26
+#include "config.h"
27
+
28
+#include <string.h>
29
+#include <stdio.h>
30
+#include <stdlib.h>
31
+#include <unistd.h>
32
+#include <errno.h>
33
+#include <time.h>
34
+
35
+#include <spa/debug/mem.h>
36
+
37
+#include "test-helper.h"
38
+#include "mix-ops.c"
39
+
40
+static uint32_t cpu_flags;
41
+
42
+#define N_SAMPLES 1024
43
+
44
+static uint8_t samp_outN_SAMPLES * 8;
45
+
46
+static void compare_mem(int i, int j, const void *m1, const void *m2, size_t size)
47
+{
48
+   int res = memcmp(m1, m2, size);
49
+   if (res != 0) {
50
+       fprintf(stderr, "%d %d %zd:\n", i, j, size);
51
+       spa_debug_mem(0, m1, size);
52
+       spa_debug_mem(0, m2, size);
53
+   }
54
+   spa_assert_se(res == 0);
55
+}
56
+
57
+static int run_test(const char *name, const void *src, uint32_t n_src, const void *dst,
58
+       size_t dst_size, uint32_t n_samples, mix_func_t mix)
59
+{
60
+   struct mix_ops ops;
61
+
62
+   ops.fmt = SPA_AUDIO_FORMAT_F32;
63
+   ops.n_channels = 1;
64
+   ops.cpu_flags = cpu_flags;
65
+   mix_ops_init(&ops);
66
+
67
+   fprintf(stderr, "%s\n", name);
68
+
69
+   mix(&ops, (void *)samp_out, src, n_src, n_samples);
70
+   compare_mem(0, 0, samp_out, dst, dst_size);
71
+   return 0;
72
+}
73
+
74
+static void test_s8(void)
75
+{
76
+   int8_t out = { 0x00, 0x00, 0x00, 0x00 };
77
+   int8_t in_1 = { 0x00, 0x00, 0x00, 0x00 };
78
+   int8_t in_2 = { 0x7f, 0x80, 0x40, 0xc0 };
79
+   int8_t in_3 = { 0x40, 0xc0, 0xc0, 0x40 };
80
+   int8_t in_4 = { 0xc0, 0x40, 0x40, 0xc0 };
81
+   int8_t out_4 = { 0x7f, 0x80, 0x40, 0xc0 };
82
+   const void *src6 = { in_1, in_2, in_3, in_4 };
83
+
84
+   run_test("test_s8_0", NULL, 0, out, sizeof(out), SPA_N_ELEMENTS(out), mix_s8_c);
85
+   run_test("test_s8_1", src, 1, in_1, sizeof(in_1), SPA_N_ELEMENTS(in_1), mix_s8_c);
86
+   run_test("test_s8_4", src, 4, out_4, sizeof(out_4), SPA_N_ELEMENTS(out_4), mix_s8_c);
87
+}
88
+
89
+static void test_u8(void)
90
+{
91
+   uint8_t out = { 0x80, 0x80, 0x80, 0x80 };
92
+   uint8_t in_1 = { 0x80, 0x80, 0x80, 0x80 };
93
+   uint8_t in_2 = { 0xff, 0x00, 0xc0, 0x40 };
94
+   uint8_t in_3 = { 0xc0, 0x40, 0x40, 0xc0 };
95
+   uint8_t in_4 = { 0x40, 0xc0, 0xc0, 0x40 };
96
+   uint8_t out_4 = { 0xff, 0x00, 0xc0, 0x40 };
97
+   const void *src6 = { in_1, in_2, in_3, in_4 };
98
+
99
+   run_test("test_u8_0", NULL, 0, out, sizeof(out), SPA_N_ELEMENTS(out), mix_u8_c);
100
+   run_test("test_u8_1", src, 1, in_1, sizeof(in_1), SPA_N_ELEMENTS(in_1), mix_u8_c);
101
+   run_test("test_u8_4", src, 4, out_4, sizeof(out_4), SPA_N_ELEMENTS(out_4), mix_u8_c);
102
+}
103
+
104
+static void test_s16(void)
105
+{
106
+   int16_t out = { 0x0000, 0x0000, 0x0000, 0x0000 };
107
+   int16_t in_1 = { 0x0000, 0x0000, 0x0000, 0x0000 };
108
+   int16_t in_2 = { 0x7fff, 0x8000, 0x4000, 0xc000 };
109
+   int16_t in_3 = { 0x4000, 0xc000, 0xc000, 0x4000 };
110
+   int16_t in_4 = { 0xc000, 0x4000, 0x4000, 0xc000 };
111
+   int16_t out_4 = { 0x7fff, 0x8000, 0x4000, 0xc000 };
112
+   const void *src6 = { in_1, in_2, in_3, in_4 };
113
+
114
+   run_test("test_s16_0", NULL, 0, out, sizeof(out), SPA_N_ELEMENTS(out), mix_s16_c);
115
+   run_test("test_s16_1", src, 1, in_1, sizeof(in_1), SPA_N_ELEMENTS(in_1), mix_s16_c);
116
+   run_test("test_s16_4", src, 4, out_4, sizeof(out_4), SPA_N_ELEMENTS(out_4), mix_s16_c);
117
+}
118
+
119
+static void test_u16(void)
120
+{
121
+   uint16_t out = { 0x8000, 0x8000, 0x8000, 0x8000 };
122
+   uint16_t in_1 = { 0x8000, 0x8000, 0x8000 , 0x8000};
123
+   uint16_t in_2 = { 0xffff, 0x0000, 0xc000, 0x4000 };
124
+   uint16_t in_3 = { 0xc000, 0x4000, 0x4000, 0xc000 };
125
+   uint16_t in_4 = { 0x4000, 0xc000, 0xc000, 0x4000 };
126
+   uint16_t out_4 = { 0xffff, 0x0000, 0xc000, 0x4000 };
127
+   const void *src6 = { in_1, in_2, in_3, in_4 };
128
+
129
+   run_test("test_u16_0", NULL, 0, out, sizeof(out), SPA_N_ELEMENTS(out), mix_u16_c);
130
+   run_test("test_u16_1", src, 1, in_1, sizeof(in_1), SPA_N_ELEMENTS(in_1), mix_u16_c);
131
+   run_test("test_u16_4", src, 4, out_4, sizeof(out_4), SPA_N_ELEMENTS(out_4), mix_u16_c);
132
+}
133
+
134
+static void test_s24(void)
135
+{
136
+   int24_t out = { S32_TO_S24(0x000000), S32_TO_S24(0x000000), S32_TO_S24(0x000000) };
137
+   int24_t in_1 = { S32_TO_S24(0x000000), S32_TO_S24(0x000000), S32_TO_S24(0x000000) };
138
+   int24_t in_2 = { S32_TO_S24(0x7fffff), S32_TO_S24(0xff800000), S32_TO_S24(0x400000) };
139
+   int24_t in_3 = { S32_TO_S24(0x400000), S32_TO_S24(0xffc00000), S32_TO_S24(0xffc00000) };
140
+   int24_t in_4 = { S32_TO_S24(0xffc00000), S32_TO_S24(0x400000), S32_TO_S24(0x400000) };
141
+   int24_t out_4 = { S32_TO_S24(0x7fffff), S32_TO_S24(0xff800000), S32_TO_S24(0x400000) };
142
+   const void *src6 = { in_1, in_2, in_3, in_4 };
143
+
144
+   run_test("test_s24_0", NULL, 0, out, sizeof(out), SPA_N_ELEMENTS(out), mix_s24_c);
145
+   run_test("test_s24_1", src, 1, in_1, sizeof(in_1), SPA_N_ELEMENTS(in_1), mix_s24_c);
146
+   run_test("test_s24_4", src, 4, out_4, sizeof(out_4), SPA_N_ELEMENTS(out_4), mix_s24_c);
147
+}
148
+
149
+static void test_u24(void)
150
+{
151
+   uint24_t out = { U32_TO_U24(0x800000), U32_TO_U24(0x800000), U32_TO_U24(0x800000) };
152
+   uint24_t in_1 = { U32_TO_U24(0x800000), U32_TO_U24(0x800000), U32_TO_U24(0x800000) };
153
+   uint24_t in_2 = { U32_TO_U24(0xffffffff), U32_TO_U24(0x000000), U32_TO_U24(0xffc00000) };
154
+   uint24_t in_3 = { U32_TO_U24(0xffc00000), U32_TO_U24(0x400000), U32_TO_U24(0x400000) };
155
+   uint24_t in_4 = { U32_TO_U24(0x400000), U32_TO_U24(0xffc00000), U32_TO_U24(0xffc00000) };
156
+   uint24_t out_4 = { U32_TO_U24(0xffffffff), U32_TO_U24(0x000000), U32_TO_U24(0xffc00000) };
157
+   const void *src6 = { in_1, in_2, in_3, in_4 };
158
+
159
+   run_test("test_u24_0", NULL, 0, out, sizeof(out), SPA_N_ELEMENTS(out), mix_u24_c);
160
+   run_test("test_u24_1", src, 1, in_1, sizeof(in_1), SPA_N_ELEMENTS(in_1), mix_u24_c);
161
+   run_test("test_u24_4", src, 4, out_4, sizeof(out_4), SPA_N_ELEMENTS(out_4), mix_u24_c);
162
+}
163
+
164
+static void test_s32(void)
165
+{
166
+   int32_t out = { 0x00000000, 0x00000000, 0x00000000, 0x00000000 };
167
+   int32_t in_1 = { 0x00000000, 0x00000000, 0x00000000, 0x00000000 };
168
+   int32_t in_2 = { 0x7fffffff, 0x80000000, 0x40000000, 0xc0000000 };
169
+   int32_t in_3 = { 0x40000000, 0xc0000000, 0xc0000000, 0x40000000 };
170
+   int32_t in_4 = { 0xc0000000, 0x40000000, 0x40000000, 0xc0000000 };
171
+   int32_t out_4 = { 0x7fffffff, 0x80000000, 0x40000000, 0xc0000000 };
172
+   const void *src6 = { in_1, in_2, in_3, in_4 };
173
+
174
+   run_test("test_s32_0", NULL, 0, out, sizeof(out), SPA_N_ELEMENTS(out), mix_s32_c);
175
+   run_test("test_s32_1", src, 1, in_1, sizeof(in_1), SPA_N_ELEMENTS(in_1), mix_s32_c);
176
+   run_test("test_s32_4", src, 4, out_4, sizeof(out_4), SPA_N_ELEMENTS(out_4), mix_s32_c);
177
+}
178
+
179
+static void test_u32(void)
180
+{
181
+   uint32_t out = { 0x80000000, 0x80000000, 0x80000000, 0x80000000 };
182
+   uint32_t in_1 = { 0x80000000, 0x80000000, 0x80000000, 0x80000000 };
183
+   uint32_t in_2 = { 0xffffffff, 0x00000000, 0xc0000000, 0x40000000 };
184
+   uint32_t in_3 = { 0xc0000000, 0x40000000, 0x40000000, 0xc0000000 };
185
+   uint32_t in_4 = { 0x40000000, 0xc0000000, 0xc0000000, 0x40000000 };
186
+   uint32_t out_4 = { 0xffffffff, 0x00000000, 0xc0000000, 0x40000000 };
187
+   const void *src6 = { in_1, in_2, in_3, in_4 };
188
+
189
+   run_test("test_u32_0", NULL, 0, out, sizeof(out), SPA_N_ELEMENTS(out), mix_u32_c);
190
+   run_test("test_u32_1", src, 1, in_1, sizeof(in_1), SPA_N_ELEMENTS(in_1), mix_u32_c);
191
+   run_test("test_u32_4", src, 4, out_4, sizeof(out_4), SPA_N_ELEMENTS(out_4), mix_u32_c);
192
+}
193
+
194
+static void test_s24_32(void)
195
+{
196
+   int32_t out = { 0x000000, 0x000000, 0x000000, 0x000000 };
197
+   int32_t in_1 = { 0x000000, 0x000000, 0x000000, 0x000000 };
198
+   int32_t in_2 = { 0x7fffff, 0xff800000, 0x400000, 0xffc00000 };
199
+   int32_t in_3 = { 0x400000, 0xffc00000, 0xffc00000, 0x400000 };
200
+   int32_t in_4 = { 0xffc00000, 0x400000, 0x400000, 0xffc00000 };
201
pipewire-0.3.56.tar.gz/spa/plugins/avb Added
2
 
1
+(directory)
2
pipewire-0.3.56.tar.gz/spa/plugins/avb/avb-pcm-sink.c Added
201
 
1
@@ -0,0 +1,912 @@
2
+/* Spa AVB PCM Sink
3
+ *
4
+ * Copyright © 2022 Wim Taymans
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a
7
+ * copy of this software and associated documentation files (the "Software"),
8
+ * to deal in the Software without restriction, including without limitation
9
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
+ * and/or sell copies of the Software, and to permit persons to whom the
11
+ * Software is furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice (including the next
14
+ * paragraph) shall be included in all copies or substantial portions of the
15
+ * Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23
+ * DEALINGS IN THE SOFTWARE.
24
+ */
25
+
26
+#include <stddef.h>
27
+
28
+#include <spa/node/node.h>
29
+#include <spa/node/utils.h>
30
+#include <spa/node/keys.h>
31
+#include <spa/monitor/device.h>
32
+#include <spa/utils/keys.h>
33
+#include <spa/utils/names.h>
34
+#include <spa/utils/string.h>
35
+#include <spa/param/audio/format.h>
36
+#include <spa/pod/filter.h>
37
+#include <spa/debug/pod.h>
38
+
39
+#include "avb-pcm.h"
40
+
41
+#define CHECK_PORT(this,d,p)    ((d) == SPA_DIRECTION_INPUT && (p) == 0)
42
+#define GET_PORT(this,d,p) (&this->portsp)
43
+
44
+static void reset_props(struct props *props)
45
+{
46
+   snprintf(props->ifname, sizeof(props->ifname), "%s", DEFAULT_IFNAME);
47
+   parse_addr(props->addr, DEFAULT_ADDR);
48
+   props->prio = DEFAULT_PRIO;
49
+   parse_streamid(&props->streamid, DEFAULT_STREAMID);
50
+   props->mtt = DEFAULT_MTT;
51
+   props->t_uncertainty = DEFAULT_TU;
52
+   props->frames_per_pdu = DEFAULT_FRAMES_PER_PDU;
53
+}
54
+
55
+static void emit_node_info(struct state *this, bool full)
56
+{
57
+   uint64_t old = full ? this->info.change_mask : 0;
58
+
59
+   if (full)
60
+       this->info.change_mask = this->info_all;
61
+   if (this->info.change_mask) {
62
+       struct spa_dict_item items4;
63
+       uint32_t i, n_items = 0;
64
+
65
+       itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_API, "avb");
66
+       itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_MEDIA_CLASS, "Audio/Sink");
67
+       itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_NODE_DRIVER, "true");
68
+       this->info.props = &SPA_DICT_INIT(items, n_items);
69
+
70
+       if (this->info.change_mask & SPA_NODE_CHANGE_MASK_PARAMS) {
71
+           for (i = 0; i < this->info.n_params; i++) {
72
+               if (this->paramsi.user > 0) {
73
+                   this->paramsi.flags ^= SPA_PARAM_INFO_SERIAL;
74
+                   this->paramsi.user = 0;
75
+               }
76
+           }
77
+       }
78
+       spa_node_emit_info(&this->hooks, &this->info);
79
+
80
+       this->info.change_mask = old;
81
+   }
82
+}
83
+
84
+static void emit_port_info(struct state *this, struct port *port, bool full)
85
+{
86
+   uint64_t old = full ? port->info.change_mask : 0;
87
+
88
+   if (full)
89
+       port->info.change_mask = port->info_all;
90
+   if (port->info.change_mask) {
91
+       uint32_t i;
92
+
93
+       if (port->info.change_mask & SPA_PORT_CHANGE_MASK_PARAMS) {
94
+           for (i = 0; i < port->info.n_params; i++) {
95
+               if (port->paramsi.user > 0) {
96
+                   port->paramsi.flags ^= SPA_PARAM_INFO_SERIAL;
97
+                   port->paramsi.user = 0;
98
+               }
99
+           }
100
+       }
101
+       spa_node_emit_port_info(&this->hooks,
102
+               port->direction, port->id, &port->info);
103
+       port->info.change_mask = old;
104
+   }
105
+}
106
+
107
+static int impl_node_enum_params(void *object, int seq,
108
+                uint32_t id, uint32_t start, uint32_t num,
109
+                const struct spa_pod *filter)
110
+{
111
+   struct state *this = object;
112
+   struct spa_pod *param;
113
+   struct spa_pod_builder b = { 0 };
114
+   uint8_t buffer4096;
115
+   struct spa_result_node_params result;
116
+   uint32_t count = 0;
117
+
118
+   spa_return_val_if_fail(this != NULL, -EINVAL);
119
+   spa_return_val_if_fail(num != 0, -EINVAL);
120
+
121
+   result.id = id;
122
+   result.next = start;
123
+      next:
124
+   result.index = result.next++;
125
+
126
+   spa_pod_builder_init(&b, buffer, sizeof(buffer));
127
+
128
+   switch (id) {
129
+   case SPA_PARAM_PropInfo:
130
+   {
131
+       switch (result.index) {
132
+       default:
133
+           param = spa_avb_enum_propinfo(this, result.index, &b);
134
+           if (param == NULL)
135
+               return 0;
136
+       }
137
+       break;
138
+   }
139
+   case SPA_PARAM_Props:
140
+   {
141
+       struct spa_pod_frame f;
142
+
143
+       switch (result.index) {
144
+       case 0:
145
+           spa_pod_builder_push_object(&b, &f,
146
+                                SPA_TYPE_OBJECT_Props, id);
147
+           spa_pod_builder_add(&b,
148
+               SPA_PROP_latencyOffsetNsec,   SPA_POD_Long(this->process_latency.ns),
149
+               0);
150
+           spa_avb_add_prop_params(this, &b);
151
+           param = spa_pod_builder_pop(&b, &f);
152
+           break;
153
+       default:
154
+           return 0;
155
+       }
156
+       break;
157
+   }
158
+   case SPA_PARAM_IO:
159
+       switch (result.index) {
160
+       case 0:
161
+           param = spa_pod_builder_add_object(&b,
162
+               SPA_TYPE_OBJECT_ParamIO, id,
163
+               SPA_PARAM_IO_id,   SPA_POD_Id(SPA_IO_Clock),
164
+               SPA_PARAM_IO_size, SPA_POD_Int(sizeof(struct spa_io_clock)));
165
+           break;
166
+       case 1:
167
+           param = spa_pod_builder_add_object(&b,
168
+               SPA_TYPE_OBJECT_ParamIO, id,
169
+               SPA_PARAM_IO_id,   SPA_POD_Id(SPA_IO_Position),
170
+               SPA_PARAM_IO_size, SPA_POD_Int(sizeof(struct spa_io_position)));
171
+           break;
172
+       default:
173
+           return 0;
174
+       }
175
+       break;
176
+
177
+   case SPA_PARAM_ProcessLatency:
178
+       switch (result.index) {
179
+       case 0:
180
+           param = spa_process_latency_build(&b, id, &this->process_latency);
181
+           break;
182
+       default:
183
+           return 0;
184
+       }
185
+       break;
186
+
187
+   default:
188
+       return -ENOENT;
189
+   }
190
+
191
+   if (spa_pod_filter(&b, &result.param, param, filter) < 0)
192
+       goto next;
193
+
194
+   spa_node_emit_result(&this->hooks, seq, 0, SPA_RESULT_TYPE_NODE_PARAMS, &result);
195
+
196
+   if (++count != num)
197
+       goto next;
198
+
199
+   return 0;
200
+}
201
pipewire-0.3.56.tar.gz/spa/plugins/avb/avb-pcm-source.c Added
201
 
1
@@ -0,0 +1,912 @@
2
+/* Spa AVB PCM Source
3
+ *
4
+ * Copyright © 2022 Wim Taymans
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a
7
+ * copy of this software and associated documentation files (the "Software"),
8
+ * to deal in the Software without restriction, including without limitation
9
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
+ * and/or sell copies of the Software, and to permit persons to whom the
11
+ * Software is furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice (including the next
14
+ * paragraph) shall be included in all copies or substantial portions of the
15
+ * Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23
+ * DEALINGS IN THE SOFTWARE.
24
+ */
25
+
26
+#include <stddef.h>
27
+
28
+#include <spa/node/node.h>
29
+#include <spa/node/utils.h>
30
+#include <spa/node/keys.h>
31
+#include <spa/monitor/device.h>
32
+#include <spa/utils/keys.h>
33
+#include <spa/utils/names.h>
34
+#include <spa/utils/string.h>
35
+#include <spa/param/audio/format.h>
36
+#include <spa/pod/filter.h>
37
+#include <spa/debug/pod.h>
38
+
39
+#include "avb-pcm.h"
40
+
41
+#define CHECK_PORT(this,d,p)    ((d) == SPA_DIRECTION_OUTPUT && (p) == 0)
42
+#define GET_PORT(this,d,p) (&this->portsp)
43
+
44
+static void reset_props(struct props *props)
45
+{
46
+   snprintf(props->ifname, sizeof(props->ifname), "%s", DEFAULT_IFNAME);
47
+   parse_addr(props->addr, DEFAULT_ADDR);
48
+   props->prio = DEFAULT_PRIO;
49
+   parse_streamid(&props->streamid, DEFAULT_STREAMID);
50
+   props->mtt = DEFAULT_MTT;
51
+   props->t_uncertainty = DEFAULT_TU;
52
+   props->frames_per_pdu = DEFAULT_FRAMES_PER_PDU;
53
+}
54
+
55
+static void emit_node_info(struct state *this, bool full)
56
+{
57
+   uint64_t old = full ? this->info.change_mask : 0;
58
+
59
+   if (full)
60
+       this->info.change_mask = this->info_all;
61
+   if (this->info.change_mask) {
62
+       struct spa_dict_item items4;
63
+       uint32_t i, n_items = 0;
64
+
65
+       itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_API, "avb");
66
+       itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_MEDIA_CLASS, "Audio/Source");
67
+       itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_NODE_DRIVER, "true");
68
+       this->info.props = &SPA_DICT_INIT(items, n_items);
69
+
70
+       if (this->info.change_mask & SPA_NODE_CHANGE_MASK_PARAMS) {
71
+           for (i = 0; i < this->info.n_params; i++) {
72
+               if (this->paramsi.user > 0) {
73
+                   this->paramsi.flags ^= SPA_PARAM_INFO_SERIAL;
74
+                   this->paramsi.user = 0;
75
+               }
76
+           }
77
+       }
78
+       spa_node_emit_info(&this->hooks, &this->info);
79
+
80
+       this->info.change_mask = old;
81
+   }
82
+}
83
+
84
+static void emit_port_info(struct state *this, struct port *port, bool full)
85
+{
86
+   uint64_t old = full ? port->info.change_mask : 0;
87
+
88
+   if (full)
89
+       port->info.change_mask = port->info_all;
90
+   if (port->info.change_mask) {
91
+       uint32_t i;
92
+
93
+       if (port->info.change_mask & SPA_PORT_CHANGE_MASK_PARAMS) {
94
+           for (i = 0; i < port->info.n_params; i++) {
95
+               if (port->paramsi.user > 0) {
96
+                   port->paramsi.flags ^= SPA_PARAM_INFO_SERIAL;
97
+                   port->paramsi.user = 0;
98
+               }
99
+           }
100
+       }
101
+       spa_node_emit_port_info(&this->hooks,
102
+               port->direction, port->id, &port->info);
103
+       port->info.change_mask = old;
104
+   }
105
+}
106
+
107
+static int impl_node_enum_params(void *object, int seq,
108
+                uint32_t id, uint32_t start, uint32_t num,
109
+                const struct spa_pod *filter)
110
+{
111
+   struct state *this = object;
112
+   struct spa_pod *param;
113
+   struct spa_pod_builder b = { 0 };
114
+   uint8_t buffer4096;
115
+   struct spa_result_node_params result;
116
+   uint32_t count = 0;
117
+
118
+   spa_return_val_if_fail(this != NULL, -EINVAL);
119
+   spa_return_val_if_fail(num != 0, -EINVAL);
120
+
121
+   result.id = id;
122
+   result.next = start;
123
+      next:
124
+   result.index = result.next++;
125
+
126
+   spa_pod_builder_init(&b, buffer, sizeof(buffer));
127
+
128
+   switch (id) {
129
+   case SPA_PARAM_PropInfo:
130
+   {
131
+       switch (result.index) {
132
+       default:
133
+           param = spa_avb_enum_propinfo(this, result.index, &b);
134
+           if (param == NULL)
135
+               return 0;
136
+       }
137
+       break;
138
+   }
139
+   case SPA_PARAM_Props:
140
+   {
141
+       struct spa_pod_frame f;
142
+
143
+       switch (result.index) {
144
+       case 0:
145
+           spa_pod_builder_push_object(&b, &f,
146
+                                SPA_TYPE_OBJECT_Props, id);
147
+           spa_pod_builder_add(&b,
148
+               SPA_PROP_latencyOffsetNsec,   SPA_POD_Long(this->process_latency.ns),
149
+               0);
150
+           spa_avb_add_prop_params(this, &b);
151
+           param = spa_pod_builder_pop(&b, &f);
152
+           break;
153
+       default:
154
+           return 0;
155
+       }
156
+       break;
157
+   }
158
+   case SPA_PARAM_IO:
159
+       switch (result.index) {
160
+       case 0:
161
+           param = spa_pod_builder_add_object(&b,
162
+               SPA_TYPE_OBJECT_ParamIO, id,
163
+               SPA_PARAM_IO_id,   SPA_POD_Id(SPA_IO_Clock),
164
+               SPA_PARAM_IO_size, SPA_POD_Int(sizeof(struct spa_io_clock)));
165
+           break;
166
+       case 1:
167
+           param = spa_pod_builder_add_object(&b,
168
+               SPA_TYPE_OBJECT_ParamIO, id,
169
+               SPA_PARAM_IO_id,   SPA_POD_Id(SPA_IO_Position),
170
+               SPA_PARAM_IO_size, SPA_POD_Int(sizeof(struct spa_io_position)));
171
+           break;
172
+       default:
173
+           return 0;
174
+       }
175
+       break;
176
+
177
+   case SPA_PARAM_ProcessLatency:
178
+       switch (result.index) {
179
+       case 0:
180
+           param = spa_process_latency_build(&b, id, &this->process_latency);
181
+           break;
182
+       default:
183
+           return 0;
184
+       }
185
+       break;
186
+
187
+   default:
188
+       return -ENOENT;
189
+   }
190
+
191
+   if (spa_pod_filter(&b, &result.param, param, filter) < 0)
192
+       goto next;
193
+
194
+   spa_node_emit_result(&this->hooks, seq, 0, SPA_RESULT_TYPE_NODE_PARAMS, &result);
195
+
196
+   if (++count != num)
197
+       goto next;
198
+
199
+   return 0;
200
+}
201
pipewire-0.3.56.tar.gz/spa/plugins/avb/avb-pcm.c Added
201
 
1
@@ -0,0 +1,1217 @@
2
+/* Spa AVB PCM
3
+ *
4
+ * Copyright © 2022 Wim Taymans
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a
7
+ * copy of this software and associated documentation files (the "Software"),
8
+ * to deal in the Software without restriction, including without limitation
9
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
+ * and/or sell copies of the Software, and to permit persons to whom the
11
+ * Software is furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice (including the next
14
+ * paragraph) shall be included in all copies or substantial portions of the
15
+ * Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23
+ * DEALINGS IN THE SOFTWARE.
24
+ */
25
+
26
+#include <stdio.h>
27
+#include <stdlib.h>
28
+#include <string.h>
29
+#include <sched.h>
30
+#include <errno.h>
31
+#include <getopt.h>
32
+#include <sys/time.h>
33
+#include <math.h>
34
+#include <limits.h>
35
+#include <unistd.h>
36
+#include <sys/ioctl.h>
37
+#include <arpa/inet.h>
38
+
39
+#include <spa/pod/filter.h>
40
+#include <spa/utils/string.h>
41
+#include <spa/support/system.h>
42
+#include <spa/utils/keys.h>
43
+
44
+#include "avb-pcm.h"
45
+
46
+#define TAI_OFFSET    (37ULL * SPA_NSEC_PER_SEC)
47
+#define TAI_TO_UTC(t) (t - TAI_OFFSET)
48
+
49
+static int avb_set_param(struct state *state, const char *k, const char *s)
50
+{
51
+   struct props *p = &state->props;
52
+   int fmt_change = 0;
53
+   if (spa_streq(k, SPA_KEY_AUDIO_CHANNELS)) {
54
+       state->default_channels = atoi(s);
55
+       fmt_change++;
56
+   } else if (spa_streq(k, SPA_KEY_AUDIO_RATE)) {
57
+       state->default_rate = atoi(s);
58
+       fmt_change++;
59
+   } else if (spa_streq(k, SPA_KEY_AUDIO_FORMAT)) {
60
+       state->default_format = spa_avb_format_from_name(s, strlen(s));
61
+       fmt_change++;
62
+   } else if (spa_streq(k, SPA_KEY_AUDIO_POSITION)) {
63
+       spa_avb_parse_position(&state->default_pos, s, strlen(s));
64
+       fmt_change++;
65
+   } else if (spa_streq(k, SPA_KEY_AUDIO_ALLOWED_RATES)) {
66
+       state->n_allowed_rates = spa_avb_parse_rates(state->allowed_rates,
67
+               MAX_RATES, s, strlen(s));
68
+       fmt_change++;
69
+   } else if (spa_streq(k, "avb.ifname")) {
70
+       snprintf(p->ifname, sizeof(p->ifname), "%s", s);
71
+   } else if (spa_streq(k, "avb.macaddr")) {
72
+       parse_addr(p->addr, s);
73
+   } else if (spa_streq(k, "avb.prio")) {
74
+       p->prio = atoi(s);
75
+   } else if (spa_streq(k, "avb.streamid")) {
76
+       parse_streamid(&p->streamid, s);
77
+   } else if (spa_streq(k, "avb.mtt")) {
78
+       p->mtt = atoi(s);
79
+   } else if (spa_streq(k, "avb.time-uncertainty")) {
80
+       p->t_uncertainty = atoi(s);
81
+   } else if (spa_streq(k, "avb.frames-per-pdu")) {
82
+       p->frames_per_pdu = atoi(s);
83
+   } else if (spa_streq(k, "avb.ptime-tolerance")) {
84
+       p->ptime_tolerance = atoi(s);
85
+   } else if (spa_streq(k, "latency.internal.rate")) {
86
+       state->process_latency.rate = atoi(s);
87
+   } else if (spa_streq(k, "latency.internal.ns")) {
88
+       state->process_latency.ns = atoi(s);
89
+   } else if (spa_streq(k, "clock.name")) {
90
+       spa_scnprintf(state->clock_name,
91
+               sizeof(state->clock_name), "%s", s);
92
+   } else
93
+       return 0;
94
+
95
+   if (fmt_change > 0) {
96
+       struct port *port = &state->ports0;
97
+       port->info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS;
98
+       port->paramsPORT_EnumFormat.user++;
99
+   }
100
+   return 1;
101
+}
102
+
103
+static int position_to_string(struct channel_map *map, char *val, size_t len)
104
+{
105
+   uint32_t i, o = 0;
106
+   int r;
107
+   o += snprintf(val, len, " ");
108
+   for (i = 0; i < map->channels; i++) {
109
+       r = snprintf(val+o, len-o, "%s%s", i == 0 ? "" : ", ",
110
+               spa_debug_type_find_short_name(spa_type_audio_channel,
111
+                   map->posi));
112
+       if (r < 0 || o + r >= len)
113
+           return -ENOSPC;
114
+       o += r;
115
+   }
116
+   if (len > o)
117
+       o += snprintf(val+o, len-o, " ");
118
+   return 0;
119
+}
120
+
121
+static int uint32_array_to_string(uint32_t *vals, uint32_t n_vals, char *val, size_t len)
122
+{
123
+   uint32_t i, o = 0;
124
+   int r;
125
+   o += snprintf(val, len, " ");
126
+   for (i = 0; i < n_vals; i++) {
127
+       r = snprintf(val+o, len-o, "%s%d", i == 0 ? "" : ", ", valsi);
128
+       if (r < 0 || o + r >= len)
129
+           return -ENOSPC;
130
+       o += r;
131
+   }
132
+   if (len > o)
133
+       o += snprintf(val+o, len-o, " ");
134
+   return 0;
135
+}
136
+
137
+struct spa_pod *spa_avb_enum_propinfo(struct state *state,
138
+       uint32_t idx, struct spa_pod_builder *b)
139
+{
140
+   struct spa_pod *param;
141
+   struct props *p = &state->props;
142
+   char tmp128;
143
+
144
+   switch (idx) {
145
+   case 0:
146
+       param = spa_pod_builder_add_object(b,
147
+           SPA_TYPE_OBJECT_PropInfo, SPA_PARAM_PropInfo,
148
+           SPA_PROP_INFO_name, SPA_POD_String(SPA_KEY_AUDIO_CHANNELS),
149
+           SPA_PROP_INFO_description, SPA_POD_String("Audio Channels"),
150
+           SPA_PROP_INFO_type, SPA_POD_Int(state->default_channels),
151
+           SPA_PROP_INFO_params, SPA_POD_Bool(true));
152
+       break;
153
+   case 1:
154
+       param = spa_pod_builder_add_object(b,
155
+           SPA_TYPE_OBJECT_PropInfo, SPA_PARAM_PropInfo,
156
+           SPA_PROP_INFO_name, SPA_POD_String(SPA_KEY_AUDIO_RATE),
157
+           SPA_PROP_INFO_description, SPA_POD_String("Audio Rate"),
158
+           SPA_PROP_INFO_type, SPA_POD_Int(state->default_rate),
159
+           SPA_PROP_INFO_params, SPA_POD_Bool(true));
160
+       break;
161
+   case 2:
162
+       param = spa_pod_builder_add_object(b,
163
+           SPA_TYPE_OBJECT_PropInfo, SPA_PARAM_PropInfo,
164
+           SPA_PROP_INFO_name, SPA_POD_String(SPA_KEY_AUDIO_FORMAT),
165
+           SPA_PROP_INFO_description, SPA_POD_String("Audio Format"),
166
+           SPA_PROP_INFO_type, SPA_POD_String(
167
+               spa_debug_type_find_short_name(spa_type_audio_format,
168
+                   state->default_format)),
169
+           SPA_PROP_INFO_params, SPA_POD_Bool(true));
170
+       break;
171
+   case 3:
172
+   {
173
+       char buf1024;
174
+       position_to_string(&state->default_pos, buf, sizeof(buf));
175
+       param = spa_pod_builder_add_object(b,
176
+           SPA_TYPE_OBJECT_PropInfo, SPA_PARAM_PropInfo,
177
+           SPA_PROP_INFO_name, SPA_POD_String(SPA_KEY_AUDIO_POSITION),
178
+           SPA_PROP_INFO_description, SPA_POD_String("Audio Position"),
179
+           SPA_PROP_INFO_type, SPA_POD_String(buf),
180
+           SPA_PROP_INFO_params, SPA_POD_Bool(true));
181
+       break;
182
+   }
183
+   case 4:
184
+   {
185
+       char buf1024;
186
+       uint32_array_to_string(state->allowed_rates, state->n_allowed_rates, buf, sizeof(buf));
187
+       param = spa_pod_builder_add_object(b,
188
+           SPA_TYPE_OBJECT_PropInfo, SPA_PARAM_PropInfo,
189
+           SPA_PROP_INFO_name, SPA_POD_String(SPA_KEY_AUDIO_ALLOWED_RATES),
190
+           SPA_PROP_INFO_description, SPA_POD_String("Audio Allowed Rates"),
191
+           SPA_PROP_INFO_type, SPA_POD_String(buf),
192
+           SPA_PROP_INFO_params, SPA_POD_Bool(true));
193
+       break;
194
+   }
195
+   case 5:
196
+       param = spa_pod_builder_add_object(b,
197
+           SPA_TYPE_OBJECT_PropInfo, SPA_PARAM_PropInfo,
198
+           SPA_PROP_INFO_name, SPA_POD_String("avb.ifname"),
199
+           SPA_PROP_INFO_description, SPA_POD_String("The AVB interface name"),
200
+           SPA_PROP_INFO_type, SPA_POD_Stringn(p->ifname, sizeof(p->ifname)),
201
pipewire-0.3.56.tar.gz/spa/plugins/avb/avb-pcm.h Added
201
 
1
@@ -0,0 +1,343 @@
2
+/* Spa AVB PCM
3
+ *
4
+ * Copyright © 2022 Wim Taymans
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a
7
+ * copy of this software and associated documentation files (the "Software"),
8
+ * to deal in the Software without restriction, including without limitation
9
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
+ * and/or sell copies of the Software, and to permit persons to whom the
11
+ * Software is furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice (including the next
14
+ * paragraph) shall be included in all copies or substantial portions of the
15
+ * Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23
+ * DEALINGS IN THE SOFTWARE.
24
+ */
25
+
26
+#ifndef SPA_AVB_PCM_H
27
+#define SPA_AVB_PCM_H
28
+
29
+#ifdef __cplusplus
30
+extern "C" {
31
+#endif
32
+
33
+#include <stddef.h>
34
+#include <math.h>
35
+#include <linux/if_ether.h>
36
+#include <linux/if_packet.h>
37
+#include <linux/net_tstamp.h>
38
+#include <limits.h>
39
+#include <net/if.h>
40
+
41
+#include <avbtp/packets.h>
42
+
43
+#include <spa/support/plugin.h>
44
+#include <spa/support/loop.h>
45
+#include <spa/utils/list.h>
46
+#include <spa/utils/json.h>
47
+#include <spa/utils/dll.h>
48
+
49
+#include <spa/node/node.h>
50
+#include <spa/node/utils.h>
51
+#include <spa/node/io.h>
52
+#include <spa/debug/types.h>
53
+#include <spa/utils/ringbuffer.h>
54
+#include <spa/param/param.h>
55
+#include <spa/param/latency-utils.h>
56
+#include <spa/param/audio/format-utils.h>
57
+
58
+#include "avb.h"
59
+
60
+#define MAX_RATES  16
61
+
62
+#define DEFAULT_IFNAME     "eth0"
63
+#define DEFAULT_ADDR       "01:AA:AA:AA:AA:AA"
64
+#define DEFAULT_PRIO       0
65
+#define DEFAULT_STREAMID   "AA:BB:CC:DD:EE:FF:0000"
66
+#define DEFAULT_MTT        5000000
67
+#define DEFAULT_TU     1000000
68
+#define DEFAULT_FRAMES_PER_PDU 8
69
+
70
+#define DEFAULT_PERIOD     1024u
71
+#define DEFAULT_RATE       48000u
72
+#define DEFAULT_CHANNELS   8u
73
+
74
+struct props {
75
+   char ifnameIFNAMSIZ;
76
+   unsigned char addrETH_ALEN;
77
+   int prio;
78
+   uint64_t streamid;
79
+   int mtt;
80
+   int t_uncertainty;
81
+   uint32_t frames_per_pdu;
82
+   int ptime_tolerance;
83
+};
84
+
85
+static inline int parse_addr(unsigned char addrETH_ALEN, const char *str)
86
+{
87
+   unsigned char adETH_ALEN;
88
+   if (sscanf(str, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
89
+           &ad0, &ad1, &ad2, &ad3, &ad4, &ad5) != 6)
90
+       return -EINVAL;
91
+   memcpy(addr, ad, sizeof(ad));
92
+   return 0;
93
+}
94
+static inline char *format_addr(char *str, size_t size, const unsigned char addrETH_ALEN)
95
+{
96
+   snprintf(str, size, "%02x:%02x:%02x:%02x:%02x:%02x",
97
+           addr0, addr1, addr2,
98
+           addr3, addr4, addr5);
99
+   return str;
100
+}
101
+
102
+static inline int parse_streamid(uint64_t *streamid, const char *str)
103
+{
104
+   unsigned char addr6;
105
+   unsigned short unique_id;
106
+   if (sscanf(str, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hx",
107
+           &addr0, &addr1, &addr2, &addr3,
108
+           &addr4, &addr5, &unique_id) != 7)
109
+       return -EINVAL;
110
+   *streamid = (uint64_t) addr0 << 56 |
111
+           (uint64_t) addr1 << 48 |
112
+           (uint64_t) addr2 << 40 |
113
+           (uint64_t) addr3 << 32 |
114
+           (uint64_t) addr4 << 24 |
115
+           (uint64_t) addr5 << 16 |
116
+           unique_id;
117
+   return 0;
118
+}
119
+static inline char *format_streamid(char *str, size_t size, const uint64_t streamid)
120
+{
121
+   snprintf(str, size, "%02x:%02x:%02x:%02x:%02x:%02x:%04x",
122
+           (uint8_t)(streamid >> 56),
123
+           (uint8_t)(streamid >> 48),
124
+           (uint8_t)(streamid >> 40),
125
+           (uint8_t)(streamid >> 32),
126
+           (uint8_t)(streamid >> 24),
127
+           (uint8_t)(streamid >> 16),
128
+           (uint16_t)(streamid));
129
+   return str;
130
+}
131
+
132
+#define MAX_BUFFERS 32
133
+
134
+struct buffer {
135
+   uint32_t id;
136
+#define BUFFER_FLAG_OUT    (1<<0)
137
+   uint32_t flags;
138
+   struct spa_buffer *buf;
139
+   struct spa_meta_header *h;
140
+   struct spa_list link;
141
+};
142
+
143
+#define BW_MAX     0.128
144
+#define BW_MED     0.064
145
+#define BW_MIN     0.016
146
+#define BW_PERIOD  (3 * SPA_NSEC_PER_SEC)
147
+
148
+struct channel_map {
149
+   uint32_t channels;
150
+   uint32_t posSPA_AUDIO_MAX_CHANNELS;
151
+};
152
+
153
+struct port {
154
+   enum spa_direction direction;
155
+   uint32_t id;
156
+
157
+   uint64_t info_all;
158
+   struct spa_port_info info;
159
+#define PORT_EnumFormat        0
160
+#define PORT_Meta      1
161
+#define PORT_IO            2
162
+#define PORT_Format        3
163
+#define PORT_Buffers       4
164
+#define PORT_Latency       5
165
+#define N_PORT_PARAMS      6
166
+   struct spa_param_info paramsN_PORT_PARAMS;
167
+
168
+   bool have_format;
169
+   struct spa_audio_info current_format;
170
+
171
+   struct spa_io_buffers *io;
172
+   struct spa_io_rate_match *rate_match;
173
+   struct buffer buffersMAX_BUFFERS;
174
+   unsigned int n_buffers;
175
+
176
+   struct spa_list free;
177
+   struct spa_list ready;
178
+   uint32_t ready_offset;
179
+};
180
+
181
+struct state {
182
+   struct spa_handle handle;
183
+   struct spa_node node;
184
+
185
+   struct spa_log *log;
186
+   struct spa_system *data_system;
187
+   struct spa_loop *data_loop;
188
+
189
+   struct spa_hook_list hooks;
190
+   struct spa_callbacks callbacks;
191
+
192
+   uint64_t info_all;
193
+   struct spa_node_info info;
194
+#define NODE_PropInfo      0
195
+#define NODE_Props     1
196
+#define NODE_IO            2
197
+#define NODE_ProcessLatency    3
198
+#define N_NODE_PARAMS      4
199
+   struct spa_param_info paramsN_NODE_PARAMS;
200
+   struct props props;
201
pipewire-0.3.56.tar.gz/spa/plugins/avb/avb.c Added
56
 
1
@@ -0,0 +1,54 @@
2
+/* Spa AVB support
3
+ *
4
+ * Copyright © 2022 Wim Taymans
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a
7
+ * copy of this software and associated documentation files (the "Software"),
8
+ * to deal in the Software without restriction, including without limitation
9
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
+ * and/or sell copies of the Software, and to permit persons to whom the
11
+ * Software is furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice (including the next
14
+ * paragraph) shall be included in all copies or substantial portions of the
15
+ * Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23
+ * DEALINGS IN THE SOFTWARE.
24
+ */
25
+
26
+#include <errno.h>
27
+
28
+#include <spa/support/plugin.h>
29
+#include <spa/support/log.h>
30
+
31
+extern const struct spa_handle_factory spa_avb_sink_factory;
32
+extern const struct spa_handle_factory spa_avb_source_factory;
33
+
34
+struct spa_log_topic log_topic = SPA_LOG_TOPIC(0, "spa.avb");
35
+struct spa_log_topic *avb_log_topic = &log_topic;
36
+
37
+SPA_EXPORT
38
+int spa_handle_factory_enum(const struct spa_handle_factory **factory, uint32_t *index)
39
+{
40
+   spa_return_val_if_fail(factory != NULL, -EINVAL);
41
+   spa_return_val_if_fail(index != NULL, -EINVAL);
42
+
43
+   switch (*index) {
44
+   case 0:
45
+       *factory = &spa_avb_sink_factory;
46
+       break;
47
+   case 1:
48
+       *factory = &spa_avb_source_factory;
49
+       break;
50
+   default:
51
+       return 0;
52
+   }
53
+   (*index)++;
54
+   return 1;
55
+}
56
pipewire-0.3.56.tar.gz/spa/plugins/avb/avb.h Added
41
 
1
@@ -0,0 +1,39 @@
2
+/* Spa AVB
3
+ *
4
+ * Copyright © 2022 Wim Taymans
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a
7
+ * copy of this software and associated documentation files (the "Software"),
8
+ * to deal in the Software without restriction, including without limitation
9
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
+ * and/or sell copies of the Software, and to permit persons to whom the
11
+ * Software is furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice (including the next
14
+ * paragraph) shall be included in all copies or substantial portions of the
15
+ * Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23
+ * DEALINGS IN THE SOFTWARE.
24
+ */
25
+
26
+#ifndef SPA_AVB_H
27
+#define SPA_AVB_H
28
+
29
+#include <spa/support/log.h>
30
+
31
+#undef SPA_LOG_TOPIC_DEFAULT
32
+#define SPA_LOG_TOPIC_DEFAULT avb_log_topic
33
+extern struct spa_log_topic *avb_log_topic;
34
+
35
+static inline void avb_log_topic_init(struct spa_log *log)
36
+{
37
+   spa_log_topic_init(log, avb_log_topic);
38
+}
39
+
40
+#endif /* SPA_AVB_H */
41
pipewire-0.3.56.tar.gz/spa/plugins/avb/avbtp Added
2
 
1
+(directory)
2
pipewire-0.3.56.tar.gz/spa/plugins/avb/avbtp/packets.h Added
201
 
1
@@ -0,0 +1,220 @@
2
+/* Spa AVB support
3
+ *
4
+ * Copyright © 2022 Wim Taymans
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a
7
+ * copy of this software and associated documentation files (the "Software"),
8
+ * to deal in the Software without restriction, including without limitation
9
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
+ * and/or sell copies of the Software, and to permit persons to whom the
11
+ * Software is furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice (including the next
14
+ * paragraph) shall be included in all copies or substantial portions of the
15
+ * Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23
+ * DEALINGS IN THE SOFTWARE.
24
+ */
25
+
26
+#ifndef SPA_AVB_PACKETS_H
27
+#define SPA_AVB_PACKETS_H
28
+
29
+#define SPA_AVBTP_SUBTYPE_61883_IIDC       0x00
30
+#define SPA_AVBTP_SUBTYPE_MMA_STREAM       0x01
31
+#define SPA_AVBTP_SUBTYPE_AAF          0x02
32
+#define SPA_AVBTP_SUBTYPE_CVF          0x03
33
+#define SPA_AVBTP_SUBTYPE_CRF          0x04
34
+#define SPA_AVBTP_SUBTYPE_TSCF         0x05
35
+#define SPA_AVBTP_SUBTYPE_SVF          0x06
36
+#define SPA_AVBTP_SUBTYPE_RVF          0x07
37
+#define SPA_AVBTP_SUBTYPE_AEF_CONTINUOUS   0x6E
38
+#define SPA_AVBTP_SUBTYPE_VSF_STREAM       0x6F
39
+#define SPA_AVBTP_SUBTYPE_EF_STREAM        0x7F
40
+#define SPA_AVBTP_SUBTYPE_NTSCF            0x82
41
+#define SPA_AVBTP_SUBTYPE_ESCF         0xEC
42
+#define SPA_AVBTP_SUBTYPE_EECF         0xED
43
+#define SPA_AVBTP_SUBTYPE_AEF_DISCRETE     0xEE
44
+#define SPA_AVBTP_SUBTYPE_ADP          0xFA
45
+#define SPA_AVBTP_SUBTYPE_AECP         0xFB
46
+#define SPA_AVBTP_SUBTYPE_ACMP         0xFC
47
+#define SPA_AVBTP_SUBTYPE_MAAP         0xFE
48
+#define SPA_AVBTP_SUBTYPE_EF_CONTROL       0xFF
49
+
50
+struct spa_avbtp_packet_common {
51
+   uint8_t subtype;
52
+#if __BYTE_ORDER == __BIG_ENDIAN
53
+   unsigned sv:1;          /* stream_id valid */
54
+   unsigned version:3;
55
+   unsigned subtype_data1:4;
56
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
57
+   unsigned subtype_data1:4;
58
+   unsigned version:3;
59
+   unsigned sv:1;
60
+#elif
61
+#error "Unknown byte order"
62
+#endif
63
+   uint16_t subtype_data2;
64
+   uint64_t stream_id;
65
+   uint8_t payload0;
66
+} __attribute__ ((__packed__));
67
+
68
+#define SPA_AVBTP_PACKET_SET_SUBTYPE(p,v)  ((p)->subtype = (v))
69
+#define SPA_AVBTP_PACKET_SET_SV(p,v)       ((p)->sv = (v))
70
+#define SPA_AVBTP_PACKET_SET_VERSION(p,v)  ((p)->version = (v))
71
+#define SPA_AVBTP_PACKET_SET_STREAM_ID(p,v)    ((p)->stream_id = htobe64(v))
72
+
73
+#define SPA_AVBTP_PACKET_GET_SUBTYPE(p)        ((p)->subtype)
74
+#define SPA_AVBTP_PACKET_GET_SV(p)     ((p)->sv)
75
+#define SPA_AVBTP_PACKET_GET_VERSION(p)        ((p)->version)
76
+#define SPA_AVBTP_PACKET_GET_STREAM_ID(p)  be64toh((p)->stream_id)
77
+
78
+struct spa_avbtp_packet_cc {
79
+   uint8_t subtype;
80
+#if __BYTE_ORDER == __BIG_ENDIAN
81
+   unsigned sv:1;
82
+   unsigned version:3;
83
+   unsigned control_data1:4;
84
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
85
+   unsigned control_data1:4;
86
+   unsigned version:3;
87
+   unsigned sv:1;
88
+#endif
89
+   uint8_t status;
90
+   uint16_t control_frame_length;
91
+   uint64_t stream_id;
92
+   uint8_t payload0;
93
+} __attribute__ ((__packed__));
94
+
95
+#define SPA_AVBTP_PACKET_CC_SET_SUBTYPE(p,v)       ((p)->subtype = (v))
96
+#define SPA_AVBTP_PACKET_CC_SET_SV(p,v)            ((p)->sv = (v))
97
+#define SPA_AVBTP_PACKET_CC_SET_VERSION(p,v)       ((p)->version = (v))
98
+#define SPA_AVBTP_PACKET_CC_SET_STREAM_ID(p,v)     ((p)->stream_id = htobe64(v))
99
+#define SPA_AVBTP_PACKET_CC_SET_STATUS(p,v)        ((p)->status = (v))
100
+#define SPA_AVBTP_PACKET_CC_SET_LENGTH(p,v)        ((p)->control_frame_length = htons(v))
101
+
102
+#define SPA_AVBTP_PACKET_CC_GET_SUBTYPE(p)     ((p)->subtype)
103
+#define SPA_AVBTP_PACKET_CC_GET_SV(p)          ((p)->sv)
104
+#define SPA_AVBTP_PACKET_CC_GET_VERSION(p)     ((p)->version)
105
+#define SPA_AVBTP_PACKET_CC_GET_STREAM_ID(p)       be64toh((p)->stream_id)
106
+#define SPA_AVBTP_PACKET_CC_GET_STATUS(p)      ((p)->status)
107
+#define SPA_AVBTP_PACKET_CC_GET_LENGTH(p)      ntohs((p)->control_frame_length)
108
+
109
+/* AAF */
110
+struct spa_avbtp_packet_aaf {
111
+   uint8_t subtype;
112
+#if __BYTE_ORDER == __BIG_ENDIAN
113
+   unsigned sv:1;
114
+   unsigned version:3;
115
+   unsigned mr:1;
116
+   unsigned _r1:1;
117
+   unsigned gv:1;
118
+   unsigned tv:1;
119
+
120
+   uint8_t seq_number;
121
+
122
+   unsigned _r2:7;
123
+   unsigned tu:1;
124
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
125
+   unsigned tv:1;
126
+   unsigned gv:1;
127
+   unsigned _r1:1;
128
+   unsigned mr:1;
129
+   unsigned version:3;
130
+   unsigned sv:1;
131
+
132
+   uint8_t seq_num;
133
+
134
+   unsigned tu:1;
135
+   unsigned _r2:7;
136
+#endif
137
+   uint64_t stream_id;
138
+   uint32_t timestamp;
139
+#define SPA_AVBTP_AAF_FORMAT_USER      0x00
140
+#define SPA_AVBTP_AAF_FORMAT_FLOAT_32BIT   0x01
141
+#define SPA_AVBTP_AAF_FORMAT_INT_32BIT     0x02
142
+#define SPA_AVBTP_AAF_FORMAT_INT_24BIT     0x03
143
+#define SPA_AVBTP_AAF_FORMAT_INT_16BIT     0x04
144
+#define SPA_AVBTP_AAF_FORMAT_AES3_32BIT        0x05
145
+   uint8_t format;
146
+
147
+#define SPA_AVBTP_AAF_PCM_NSR_USER     0x00
148
+#define SPA_AVBTP_AAF_PCM_NSR_8KHZ     0x01
149
+#define SPA_AVBTP_AAF_PCM_NSR_16KHZ        0x02
150
+#define SPA_AVBTP_AAF_PCM_NSR_32KHZ        0x03
151
+#define SPA_AVBTP_AAF_PCM_NSR_44_1KHZ      0x04
152
+#define SPA_AVBTP_AAF_PCM_NSR_48KHZ        0x05
153
+#define SPA_AVBTP_AAF_PCM_NSR_88_2KHZ      0x06
154
+#define SPA_AVBTP_AAF_PCM_NSR_96KHZ        0x07
155
+#define SPA_AVBTP_AAF_PCM_NSR_176_4KHZ     0x08
156
+#define SPA_AVBTP_AAF_PCM_NSR_192KHZ       0x09
157
+#define SPA_AVBTP_AAF_PCM_NSR_24KHZ        0x0A
158
+#if __BYTE_ORDER == __BIG_ENDIAN
159
+   unsigned nsr:4;
160
+   unsigned _r3:4;
161
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
162
+   unsigned _r3:4;
163
+   unsigned nsr:4;
164
+#endif
165
+   uint8_t chan_per_frame;
166
+   uint8_t bit_depth;
167
+   uint16_t data_len;
168
+
169
+#define SPA_AVBTP_AAF_PCM_SP_NORMAL        0x00
170
+#define SPA_AVBTP_AAF_PCM_SP_SPARSE        0x01
171
+#if __BYTE_ORDER == __BIG_ENDIAN
172
+   unsigned _r4:3;
173
+   unsigned sp:1;
174
+   unsigned event:4;
175
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
176
+   unsigned event:4;
177
+   unsigned sp:1;
178
+   unsigned _r4:3;
179
+#endif
180
+   uint8_t _r5;
181
+   uint8_t payload0;
182
+} __attribute__ ((__packed__));
183
+
184
+#define SPA_AVBTP_PACKET_AAF_SET_SUBTYPE(p,v)      ((p)->subtype = (v))
185
+#define SPA_AVBTP_PACKET_AAF_SET_SV(p,v)       ((p)->sv = (v))
186
+#define SPA_AVBTP_PACKET_AAF_SET_VERSION(p,v)      ((p)->version = (v))
187
+#define SPA_AVBTP_PACKET_AAF_SET_MR(p,v)       ((p)->mr = (v))
188
+#define SPA_AVBTP_PACKET_AAF_SET_GV(p,v)       ((p)->gv = (v))
189
+#define SPA_AVBTP_PACKET_AAF_SET_TV(p,v)       ((p)->tv = (v))
190
+#define SPA_AVBTP_PACKET_AAF_SET_SEQ_NUM(p,v)      ((p)->seq_num = (v))
191
+#define SPA_AVBTP_PACKET_AAF_SET_TU(p,v)       ((p)->tu = (v))
192
+#define SPA_AVBTP_PACKET_AAF_SET_STREAM_ID(p,v)        ((p)->stream_id = htobe64(v))
193
+#define SPA_AVBTP_PACKET_AAF_SET_TIMESTAMP(p,v)        ((p)->timestamp = htonl(v))
194
+#define SPA_AVBTP_PACKET_AAF_SET_DATA_LEN(p,v)     ((p)->data_len = htons(v))
195
+#define SPA_AVBTP_PACKET_AAF_SET_FORMAT(p,v)       ((p)->format = (v))
196
+#define SPA_AVBTP_PACKET_AAF_SET_NSR(p,v)      ((p)->nsr = (v))
197
+#define SPA_AVBTP_PACKET_AAF_SET_CHAN_PER_FRAME(p,v)   ((p)->chan_per_frame = (v))
198
+#define SPA_AVBTP_PACKET_AAF_SET_BIT_DEPTH(p,v)        ((p)->bit_depth = (v))
199
+#define SPA_AVBTP_PACKET_AAF_SET_SP(p,v)       ((p)->sp = (v))
200
+#define SPA_AVBTP_PACKET_AAF_SET_EVENT(p,v)        ((p)->event = (v))
201
pipewire-0.3.56.tar.gz/spa/plugins/avb/meson.build Added
16
 
1
@@ -0,0 +1,14 @@
2
+spa_avb_sources = 'avb.c',
3
+                'avb.h',
4
+                'avb-pcm-sink.c',
5
+                'avb-pcm-source.c',
6
+                'avb-pcm.c' 
7
+
8
+spa_avb = shared_library(
9
+  'spa-avb',
10
+   spa_avb_sources ,
11
+  include_directories : configinc,
12
+  dependencies :  spa_dep, mathlib, epoll_shim_dep ,
13
+  install : true,
14
+  install_dir : spa_plugindir / 'avb'
15
+)
16
pipewire-0.3.54.tar.gz/spa/plugins/bluez5/backend-native.c -> pipewire-0.3.56.tar.gz/spa/plugins/bluez5/backend-native.c Changed
201
 
1
@@ -29,6 +29,7 @@
2
 #include <sys/types.h>
3
 #include <sys/stat.h>
4
 #include <fcntl.h>
5
+#include <poll.h>
6
 
7
 #include <bluetooth/bluetooth.h>
8
 #include <bluetooth/sco.h>
9
@@ -73,6 +74,7 @@
10
    struct spa_log *log;
11
    struct spa_loop *main_loop;
12
    struct spa_system *main_system;
13
+   struct spa_loop_utils *loop_utils;
14
    struct spa_dbus *dbus;
15
    DBusConnection *conn;
16
 
17
@@ -127,6 +129,7 @@
18
    struct spa_hook transport_listener;
19
    enum spa_bt_profile profile;
20
    struct spa_source timer;
21
+   struct spa_source *volume_sync_timer;
22
    char* path;
23
    bool has_volume;
24
    struct rfcomm_volume volumesSPA_BT_VOLUME_ID_TERM;
25
@@ -225,6 +228,8 @@
26
 
27
 static int codec_switch_stop_timer(struct rfcomm *rfcomm);
28
 
29
+static void volume_sync_stop_timer(struct rfcomm *rfcomm);
30
+
31
 static void rfcomm_free(struct rfcomm *rfcomm)
32
 {
33
    codec_switch_stop_timer(rfcomm);
34
@@ -247,6 +252,8 @@
35
        close (rfcomm->source.fd);
36
        rfcomm->source.fd = -1;
37
    }
38
+   if (rfcomm->volume_sync_timer)
39
+       spa_loop_utils_destroy_source(rfcomm->backend->loop_utils, rfcomm->volume_sync_timer);
40
    free(rfcomm);
41
 }
42
 
43
@@ -809,6 +816,7 @@
44
        rfcomm->hfp_ag_switching_codec = false;
45
        rfcomm->hfp_ag_initial_codec_setup = HFP_AG_INITIAL_CODEC_SETUP_NONE;
46
        codec_switch_stop_timer(rfcomm);
47
+       volume_sync_stop_timer(rfcomm);
48
 
49
        if (selected_codec != HFP_AUDIO_CODEC_CVSD && selected_codec != HFP_AUDIO_CODEC_MSBC) {
50
            spa_log_warn(backend->log, "unsupported codec negotiation: %d", selected_codec);
51
@@ -1203,6 +1211,18 @@
52
    return -1;
53
 }
54
 
55
+static int rfcomm_ag_sync_volume(struct rfcomm *rfcomm, bool later);
56
+
57
+static void wait_for_socket(int fd)
58
+{
59
+   struct pollfd fds1;
60
+   const int timeout_ms = 500;
61
+
62
+   fds0.fd = fd;
63
+   fds0.events = POLLIN | POLLERR | POLLHUP;
64
+   poll(fds, 1, timeout_ms);
65
+}
66
+
67
 static int sco_acquire_cb(void *data, bool optional)
68
 {
69
    struct spa_bt_transport *t = data;
70
@@ -1225,6 +1245,25 @@
71
    rfcomm_hfp_ag_set_cind(td->rfcomm, true);
72
 #endif
73
 
74
+   /*
75
+    * Send RFCOMM volume after connection is ready, and also after
76
+    * a timeout.
77
+    *
78
+    * Some headsets adjust their HFP volume when in A2DP mode
79
+    * without reporting via RFCOMM to us, so the volume level can
80
+    * be out of sync, and we can't know what it is. Moreover, they may
81
+    * take the first +VGS command after connection only partially
82
+    * into account, and need a long enough timeout.
83
+    *
84
+    * E.g. with Sennheiser HD-250BT, the first +VGS changes the
85
+    * actual volume, but does not update the level in the hardware
86
+    * volume buttons, which is updated by an +VGS event only after
87
+    * sufficient time is elapsed from the connection.
88
+    */
89
+   wait_for_socket(sock);
90
+   rfcomm_ag_sync_volume(td->rfcomm, false);
91
+   rfcomm_ag_sync_volume(td->rfcomm, true);
92
+
93
    t->fd = sock;
94
 
95
    /* Fallback value */
96
@@ -1471,10 +1510,8 @@
97
    return -1;
98
 }
99
 
100
-static int sco_set_volume_cb(void *data, int id, float volume)
101
+static int rfcomm_ag_set_volume(struct spa_bt_transport *t, int id)
102
 {
103
-   struct spa_bt_transport *t = data;
104
-   struct spa_bt_transport_volume *t_volume = &t->volumesid;
105
    struct transport_data *td = t->user_data;
106
    struct rfcomm *rfcomm = td->rfcomm;
107
    const char *format;
108
@@ -1485,12 +1522,7 @@
109
        || !(rfcomm->has_volume && rfcomm->volumesid.active))
110
        return -ENOTSUP;
111
 
112
-   value = spa_bt_volume_linear_to_hw(volume, t_volume->hw_volume_max);
113
-   t_volume->volume = volume;
114
-
115
-   if (rfcomm->volumesid.hw_volume == value)
116
-       return 0;
117
-   rfcomm->volumesid.hw_volume = value;
118
+   value = rfcomm->volumesid.hw_volume;
119
 
120
    if (id == SPA_BT_VOLUME_ID_RX)
121
        if (rfcomm->profile & SPA_BT_PROFILE_HFP_HF)
122
@@ -1511,6 +1543,29 @@
123
    return 0;
124
 }
125
 
126
+static int sco_set_volume_cb(void *data, int id, float volume)
127
+{
128
+   struct spa_bt_transport *t = data;
129
+   struct spa_bt_transport_volume *t_volume = &t->volumesid;
130
+   struct transport_data *td = t->user_data;
131
+   struct rfcomm *rfcomm = td->rfcomm;
132
+   int value;
133
+
134
+   if (!rfcomm_volume_enabled(rfcomm)
135
+       || !(rfcomm->profile & SPA_BT_PROFILE_HEADSET_HEAD_UNIT)
136
+       || !(rfcomm->has_volume && rfcomm->volumesid.active))
137
+       return -ENOTSUP;
138
+
139
+   value = spa_bt_volume_linear_to_hw(volume, t_volume->hw_volume_max);
140
+   t_volume->volume = volume;
141
+
142
+   if (rfcomm->volumesid.hw_volume == value)
143
+       return 0;
144
+   rfcomm->volumesid.hw_volume = value;
145
+
146
+   return rfcomm_ag_set_volume(t, id);
147
+}
148
+
149
 static const struct spa_bt_transport_implementation sco_transport_impl = {
150
    SPA_VERSION_BT_TRANSPORT_IMPLEMENTATION,
151
    .acquire = sco_acquire_cb,
152
@@ -1570,6 +1625,60 @@
153
    return 0;
154
 }
155
 
156
+static void volume_sync_stop_timer(struct rfcomm *rfcomm)
157
+{
158
+   if (rfcomm->volume_sync_timer)
159
+       spa_loop_utils_update_timer(rfcomm->backend->loop_utils, rfcomm->volume_sync_timer,
160
+               NULL, NULL, false);
161
+}
162
+
163
+static void volume_sync_timer_event(void *data, uint64_t expirations)
164
+{
165
+   struct rfcomm *rfcomm = data;
166
+
167
+   volume_sync_stop_timer(rfcomm);
168
+
169
+   if (rfcomm->transport) {
170
+       rfcomm_ag_set_volume(rfcomm->transport, SPA_BT_VOLUME_ID_TX);
171
+       rfcomm_ag_set_volume(rfcomm->transport, SPA_BT_VOLUME_ID_RX);
172
+   }
173
+}
174
+
175
+static int volume_sync_start_timer(struct rfcomm *rfcomm)
176
+{
177
+   struct timespec ts;
178
+   const uint64_t timeout = 1500 * SPA_NSEC_PER_MSEC;
179
+
180
+   if (rfcomm->volume_sync_timer == NULL)
181
+       rfcomm->volume_sync_timer = spa_loop_utils_add_timer(rfcomm->backend->loop_utils,
182
+               volume_sync_timer_event, rfcomm);
183
+
184
+   if (rfcomm->volume_sync_timer == NULL)
185
+       return -EIO;
186
+
187
+   ts.tv_sec = timeout / SPA_NSEC_PER_SEC;
188
+   ts.tv_nsec = timeout % SPA_NSEC_PER_SEC;
189
+   spa_loop_utils_update_timer(rfcomm->backend->loop_utils, rfcomm->volume_sync_timer,
190
+           &ts, NULL, false);
191
+
192
+   return 0;
193
+}
194
+
195
+static int rfcomm_ag_sync_volume(struct rfcomm *rfcomm, bool later)
196
+{
197
+   if (rfcomm->transport == NULL)
198
+       return -ENOENT;
199
+
200
+   if (!later) {
201
pipewire-0.3.54.tar.gz/spa/plugins/bluez5/bluez5-device.c -> pipewire-0.3.56.tar.gz/spa/plugins/bluez5/bluez5-device.c Changed
201
 
1
@@ -337,35 +337,57 @@
2
    }
3
 }
4
 
5
-static void volume_changed(void *userdata)
6
+static bool node_update_volume_from_transport(struct node *node, bool reset)
7
 {
8
-   struct node *node = userdata;
9
    struct impl *impl = node->impl;
10
    struct spa_bt_transport_volume *t_volume;
11
    float prev_hw_volume;
12
 
13
    if (!node->transport || !spa_bt_transport_volume_enabled(node->transport))
14
-       return;
15
+       return false;
16
 
17
    /* PW is the controller for remote device. */
18
    if (impl->profile != DEVICE_PROFILE_A2DP
19
        && impl->profile !=  DEVICE_PROFILE_HSP_HFP)
20
-       return;
21
+       return false;
22
 
23
    t_volume = &node->transport->volumesnode->id;
24
 
25
    if (!t_volume->active)
26
-       return;
27
+       return false;
28
 
29
    prev_hw_volume = node_get_hw_volume(node);
30
-   for (uint32_t i = 0; i < node->n_channels; ++i) {
31
-       node->volumesi = prev_hw_volume > 0.0f
32
-           ? node->volumesi * t_volume->volume / prev_hw_volume
33
-           : t_volume->volume;
34
+
35
+   if (!reset) {
36
+       for (uint32_t i = 0; i < node->n_channels; ++i) {
37
+           node->volumesi = prev_hw_volume > 0.0f
38
+               ? node->volumesi * t_volume->volume / prev_hw_volume
39
+               : t_volume->volume;
40
+       }
41
+   } else {
42
+       for (uint32_t i = 0; i < node->n_channels; ++i)
43
+           node->volumesi = t_volume->volume;
44
    }
45
 
46
    node_update_soft_volumes(node, t_volume->volume);
47
 
48
+   /*
49
+    * Consider volume changes from the headset as requested
50
+    * by the user, and to be saved by the SM.
51
+    */
52
+   node->save = true;
53
+
54
+   return true;
55
+}
56
+
57
+static void volume_changed(void *userdata)
58
+{
59
+   struct node *node = userdata;
60
+   struct impl *impl = node->impl;
61
+
62
+   if (!node_update_volume_from_transport(node, false))
63
+       return;
64
+
65
    emit_volume(impl, node);
66
 
67
    impl->info.change_mask |= SPA_DEVICE_CHANGE_MASK_PARAMS;
68
@@ -469,6 +491,8 @@
69
                this->nodesid.volumesi = this->nodesid.volumesi % prev_channels;
70
        }
71
 
72
+       node_update_volume_from_transport(&this->nodesid, true);
73
+
74
        boost = get_soft_volume_boost(&this->nodesid);
75
        if (boost != 1.0f) {
76
            size_t i;
77
@@ -1301,16 +1325,17 @@
78
 }
79
 
80
 static struct spa_pod *build_route(struct impl *this, struct spa_pod_builder *b,
81
-       uint32_t id, uint32_t port, uint32_t dev, uint32_t profile)
82
+       uint32_t id, uint32_t port, uint32_t profile)
83
 {
84
    struct spa_bt_device *device = this->bt_dev;
85
    struct spa_pod_frame f2;
86
    enum spa_direction direction;
87
-   const char *name_prefix, *description, *port_type;
88
+   const char *name_prefix, *description, *hfp_description, *port_type;
89
    enum spa_bt_form_factor ff;
90
    enum spa_bluetooth_audio_codec codec;
91
    char name128;
92
    uint32_t i, j, mask, next;
93
+   uint32_t dev = SPA_ID_INVALID, enum_dev;
94
 
95
    ff = spa_bt_form_factor_from_class(device->bluetooth_class);
96
 
97
@@ -1318,52 +1343,62 @@
98
    case SPA_BT_FORM_FACTOR_HEADSET:
99
        name_prefix = "headset";
100
        description = _("Headset");
101
+       hfp_description = _("Handsfree");
102
        port_type = "headset";
103
        break;
104
    case SPA_BT_FORM_FACTOR_HANDSFREE:
105
        name_prefix = "handsfree";
106
        description = _("Handsfree");
107
+       hfp_description = _("Handsfree (HFP)");
108
        port_type = "handsfree";
109
        break;
110
    case SPA_BT_FORM_FACTOR_MICROPHONE:
111
        name_prefix = "microphone";
112
        description = _("Microphone");
113
+       hfp_description = _("Handsfree");
114
        port_type = "mic";
115
        break;
116
    case SPA_BT_FORM_FACTOR_SPEAKER:
117
        name_prefix = "speaker";
118
        description = _("Speaker");
119
+       hfp_description = _("Handsfree");
120
        port_type = "speaker";
121
        break;
122
    case SPA_BT_FORM_FACTOR_HEADPHONE:
123
        name_prefix = "headphone";
124
        description = _("Headphone");
125
+       hfp_description = _("Handsfree");
126
        port_type = "headphones";
127
        break;
128
    case SPA_BT_FORM_FACTOR_PORTABLE:
129
        name_prefix = "portable";
130
        description = _("Portable");
131
+       hfp_description = _("Handsfree");
132
        port_type = "portable";
133
        break;
134
    case SPA_BT_FORM_FACTOR_CAR:
135
        name_prefix = "car";
136
        description = _("Car");
137
+       hfp_description = _("Handsfree");
138
        port_type = "car";
139
        break;
140
    case SPA_BT_FORM_FACTOR_HIFI:
141
        name_prefix = "hifi";
142
        description = _("HiFi");
143
+       hfp_description = _("Handsfree");
144
        port_type = "hifi";
145
        break;
146
    case SPA_BT_FORM_FACTOR_PHONE:
147
        name_prefix = "phone";
148
        description = _("Phone");
149
+       hfp_description = _("Handsfree");
150
        port_type = "phone";
151
        break;
152
    case SPA_BT_FORM_FACTOR_UNKNOWN:
153
    default:
154
        name_prefix = "bluetooth";
155
        description = _("Bluetooth");
156
+       hfp_description = _("Bluetooth (HFP)");
157
        port_type = "bluetooth";
158
        break;
159
    }
160
@@ -1372,16 +1407,51 @@
161
    case 0:
162
        direction = SPA_DIRECTION_INPUT;
163
        snprintf(name, sizeof(name), "%s-input", name_prefix);
164
+       enum_dev = DEVICE_ID_SOURCE;
165
+       if (profile == DEVICE_PROFILE_A2DP)
166
+           dev = enum_dev;
167
+       else if (profile != SPA_ID_INVALID)
168
+           enum_dev = SPA_ID_INVALID;
169
        break;
170
    case 1:
171
        direction = SPA_DIRECTION_OUTPUT;
172
        snprintf(name, sizeof(name), "%s-output", name_prefix);
173
+       enum_dev = DEVICE_ID_SINK;
174
+       if (profile == DEVICE_PROFILE_A2DP)
175
+           dev = enum_dev;
176
+       else if (profile != SPA_ID_INVALID)
177
+           enum_dev = SPA_ID_INVALID;
178
+       break;
179
+   case 2:
180
+       direction = SPA_DIRECTION_INPUT;
181
+       snprintf(name, sizeof(name), "%s-hf-input", name_prefix);
182
+       description = hfp_description;
183
+       enum_dev = DEVICE_ID_SOURCE;
184
+       if (profile == DEVICE_PROFILE_HSP_HFP)
185
+           dev = enum_dev;
186
+       else if (profile != SPA_ID_INVALID)
187
+           enum_dev = SPA_ID_INVALID;
188
+       break;
189
+   case 3:
190
+       direction = SPA_DIRECTION_OUTPUT;
191
+       snprintf(name, sizeof(name), "%s-hf-output", name_prefix);
192
+       description = hfp_description;
193
+       enum_dev = DEVICE_ID_SINK;
194
+       if (profile == DEVICE_PROFILE_HSP_HFP)
195
+           dev = enum_dev;
196
+       else if (profile != SPA_ID_INVALID)
197
+           enum_dev = SPA_ID_INVALID;
198
        break;
199
    default:
200
        errno = EINVAL;
201
pipewire-0.3.54.tar.gz/spa/plugins/bluez5/decode-buffer.h -> pipewire-0.3.56.tar.gz/spa/plugins/bluez5/decode-buffer.h Changed
201
 
1
@@ -56,12 +56,10 @@
2
 
3
 #include <stdlib.h>
4
 #include <spa/utils/defs.h>
5
-#include <spa/utils/dll.h>
6
 #include <spa/support/log.h>
7
 
8
-#define BUFFERING_LONG_MSEC        60000
9
+#define BUFFERING_LONG_MSEC        (2*60000)
10
 #define BUFFERING_SHORT_MSEC       1000
11
-#define BUFFERING_DLL_BW       0.03
12
 #define BUFFERING_RATE_DIFF_MAX        0.005
13
 
14
 /**
15
@@ -73,6 +71,132 @@
16
 #define BUFFERING_TARGET(spike,packet_size)                \
17
    SPA_CLAMP((spike)*3/2, (packet_size), 6*(packet_size))
18
 
19
+/**
20
+ * Rate controller.
21
+ *
22
+ * It's here in a form, where it operates on the running average
23
+ * so it's compatible with the level spike determination, and
24
+ * clamping the rate to a range is easy. The impulse response
25
+ * is similar to spa_dll, and step response does not have sign changes.
26
+ *
27
+ * The controller iterates as
28
+ *
29
+ *    avg(j+1) = (1 - beta) avg(j) + beta level(j)
30
+ *    corr(j+1) = corr(j) + a avg(j+1) - avg(j) / duration
31
+ *           + b avg(j) - target / duration
32
+ *
33
+ * with beta = duration/avg_period < 0.5 is the moving average parameter,
34
+ * and a = beta/3 + ..., b = beta^2/27 + ....
35
+ *
36
+ * This choice results to c(j) being low-pass filtered, and buffer level(j)
37
+ * converging towards target with stable damped evolution with eigenvalues
38
+ * real and close to each other around (1 - beta)^(1/3).
39
+ *
40
+ * Derivation:
41
+ *
42
+ * The deviation from the buffer level target evolves as
43
+ *
44
+ *     delta(j) = level(j) - target
45
+ *     delta(j+1) = delta(j) + r(j) - c(j+1)
46
+ *
47
+ * where r is samples received in one duration, and c corrected rate
48
+ * (samples per duration).
49
+ *
50
+ * The rate correction is in general determined by linear filter f
51
+ *
52
+ *     c(j+1) = c(j) + \sum_{k=0}^\infty delta(j - k) f(k)
53
+ *
54
+ * If \sum_k f(k) is not zero, the only fixed point is c=r, delta=0,
55
+ * so this structure (if the filter is stable) rate matches and
56
+ * drives buffer level to target.
57
+ *
58
+ * The z-transform then is
59
+ *
60
+ *     delta(z) = G(z) r(z)
61
+ *     c(z) = F(z) delta(z)
62
+ *     G(z) = (z - 1) / (z - 1)^2 + z f(z)
63
+ *     F(z) = f(z) / (z - 1)
64
+ *
65
+ * We now want: poles of G(z) must be in |z|<1 for stability, F(z)
66
+ * should damp high frequencies, and f(z) is causal.
67
+ *
68
+ * To satisfy the conditions, take
69
+ *
70
+ *     (z - 1)^2 + z f(z) = p(z) / q(z)
71
+ *
72
+ * where p(z) is polynomial with leading term z^n with wanted root
73
+ * structure, and q(z) is any polynomial with leading term z^{n-2}.
74
+ * This guarantees f(z) is causal, and G(z) = (z-1) q(z) / p(z).
75
+ * We can choose p(z) and q(z) to improve low-pass properties of F(z).
76
+ *
77
+ * Simplest choice is p(z)=(z-x)^2 and q(z)=1, but that gives flat
78
+ * high frequency response in F(z). Better choice is p(z) = (z-u)*(z-v)*(z-w)
79
+ * and q(z) = z - r. To make F(z) better lowpass, one can cancel
80
+ * a resulting 1/z pole in F(z) by setting r=u*v*w. Then,
81
+ *
82
+ *     G(z) = (z - u*v*w)*(z - 1) / (z - u)*(z - v)*(z - w)
83
+ *     F(z) = (a z + b - a) / (z - 1) *     H(z)
84
+ *     H(z) = beta / (z - 1 + beta)
85
+ *     beta = 1 - u*v*w
86
+ *     a = (1-u) + (1-v) + (1-w) - beta / beta
87
+ *     b = (1-u)*(1-v)*(1-w) / beta
88
+ *
89
+ * which corresponds to iteration for c(j):
90
+ *
91
+ *    avg(j+1) = (1 - beta) avg(j) + beta delta(j)
92
+ *    c(j+1) = c(j) + a avg(j+1) - avg(j) + b avg(j)
93
+ *
94
+ * So the controller operates on the running average,
95
+ * which gives the low-pass property for c(j).
96
+ *
97
+ * The simplest filter is obtained by putting the poles at
98
+ * u=v=w=(1-beta)**(1/3). Since beta << 1, computing the root
99
+ * can be avoided by expanding in series.
100
+ *
101
+ * Overshoot in impulse response could be reduced by moving one of the
102
+ * poles closer to z=1, but this increases the step response time.
103
+ */
104
+struct spa_bt_rate_control
105
+{
106
+   double avg;
107
+   double corr;
108
+};
109
+
110
+static void spa_bt_rate_control_init(struct spa_bt_rate_control *this, double level)
111
+{
112
+   this->avg = level;
113
+   this->corr = 1.0;
114
+}
115
+
116
+static double spa_bt_rate_control_update(struct spa_bt_rate_control *this, double level,
117
+       double target, double duration, double period)
118
+{
119
+   /*
120
+    * u = (1 - beta)^(1/3)
121
+    * x = a / beta
122
+    * y = b / beta
123
+    * a = (2 + u) * (1 - u)^2 / beta
124
+    * b = (1 - u)^3 / beta
125
+    * beta -> 0
126
+    */
127
+   const double beta = SPA_CLAMP(duration / period, 0, 0.5);
128
+   const double x = 1.0/3;
129
+   const double y = beta/27;
130
+   double avg;
131
+
132
+   avg = beta * level + (1 - beta) * this->avg;
133
+   this->corr += x * (avg - this->avg) / period
134
+       + y * (this->avg - target) / period;
135
+   this->avg = avg;
136
+
137
+   this->corr = SPA_CLAMP(this->corr,
138
+           1 - BUFFERING_RATE_DIFF_MAX,
139
+           1 + BUFFERING_RATE_DIFF_MAX);
140
+
141
+   return this->corr;
142
+}
143
+
144
+
145
 /** Windowed min/max */
146
 struct spa_bt_ptp
147
 {
148
@@ -104,11 +228,7 @@
149
    struct spa_bt_ptp spike;    /**< spikes (long window) */
150
    struct spa_bt_ptp packet_size;  /**< packet size (short window) */
151
 
152
-   int32_t target;
153
-   int32_t level;
154
-   double level_avg;
155
-
156
-   struct spa_dll dll;
157
+   struct spa_bt_rate_control ctl;
158
    double corr;
159
 
160
    uint32_t prev_consumed;
161
@@ -168,7 +288,7 @@
162
    this->corr = 1.0;
163
    this->buffering = true;
164
 
165
-   spa_dll_init(&this->dll);
166
+   spa_bt_rate_control_init(&this->ctl, 0);
167
 
168
    spa_bt_ptp_init(&this->spike, (uint64_t)this->rate * BUFFERING_LONG_MSEC / 1000);
169
    spa_bt_ptp_init(&this->packet_size, (uint64_t)this->rate * BUFFERING_SHORT_MSEC / 1000);
170
@@ -254,16 +374,16 @@
171
 static void spa_bt_decode_buffer_recover(struct spa_bt_decode_buffer *this)
172
 {
173
    int32_t size = (this->write_index - this->read_index) / this->frame_size;
174
+   int32_t level;
175
 
176
    this->prev_avail = size * this->frame_size;
177
    this->prev_consumed = this->prev_duration;
178
-   this->level = (int32_t)this->prev_avail/this->frame_size
179
+
180
+   level = (int32_t)this->prev_avail/this->frame_size
181
        - (int32_t)this->prev_duration;
182
-   this->level_avg = this->level;
183
-   this->target = this->level;
184
    this->corr = 1.0;
185
 
186
-   spa_dll_init(&this->dll);
187
+   spa_bt_rate_control_init(&this->ctl, level);
188
 }
189
 
190
 static void spa_bt_decode_buffer_process(struct spa_bt_decode_buffer *this, uint32_t samples, uint32_t duration)
191
@@ -294,12 +414,6 @@
192
        spa_bt_decode_buffer_recover(this);
193
    }
194
 
195
-   if (SPA_UNLIKELY(this->dll.bw == 0.0)) {
196
-       spa_log_trace(this->log, "%p dll reset duration:%d rate:%d", this,
197
-               (int)duration, (int)this->rate);
198
-       spa_dll_set_bw(&this->dll, BUFFERING_DLL_BW, duration, (uint64_t)this->rate);
199
-   }
200
-
201
pipewire-0.3.54.tar.gz/spa/plugins/bluez5/sco-sink.c -> pipewire-0.3.56.tar.gz/spa/plugins/bluez5/sco-sink.c Changed
9
 
1
@@ -759,6 +759,7 @@
2
        { SPA_KEY_MEDIA_CLASS, "Stream/Input/Audio" },
3
        { "media.name", ((this->transport && this->transport->device->name) ?
4
                         this->transport->device->name : "HSP/HFP") },
5
+       { SPA_KEY_MEDIA_ROLE, "Communication" },
6
    };
7
    bool is_ag = this->transport &&
8
        (this->transport->profile & SPA_BT_PROFILE_HEADSET_AUDIO_GATEWAY);
9
pipewire-0.3.54.tar.gz/spa/plugins/bluez5/sco-source.c -> pipewire-0.3.56.tar.gz/spa/plugins/bluez5/sco-source.c Changed
9
 
1
@@ -805,6 +805,7 @@
2
        { SPA_KEY_MEDIA_CLASS, "Stream/Output/Audio" },
3
        { "media.name", ((this->transport && this->transport->device->name) ?
4
                    this->transport->device->name : "HSP/HFP") },
5
+       { SPA_KEY_MEDIA_ROLE, "Communication" },
6
    };
7
    bool is_ag = this->transport && (this->transport->profile & SPA_BT_PROFILE_HEADSET_AUDIO_GATEWAY);
8
    uint64_t old = full ? this->info.change_mask : 0;
9
pipewire-0.3.54.tar.gz/spa/plugins/meson.build -> pipewire-0.3.56.tar.gz/spa/plugins/meson.build Changed
11
 
1
@@ -1,6 +1,9 @@
2
 if alsa_dep.found()
3
   subdir('alsa')
4
 endif
5
+if get_option('avb').allowed()
6
+  subdir('avb')
7
+endif
8
 if get_option('audioconvert').allowed()
9
   subdir('audioconvert')
10
 endif
11
pipewire-0.3.54.tar.gz/spa/plugins/v4l2/v4l2-udev.c -> pipewire-0.3.56.tar.gz/spa/plugins/v4l2/v4l2-udev.c Changed
36
 
1
@@ -278,9 +278,14 @@
2
    if ((str = udev_device_get_property_value(dev, "SUBSYSTEM")) && *str) {
3
        itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_SUBSYSTEM, str);
4
    }
5
-   if ((str = udev_device_get_property_value(dev, "ID_VENDOR_ID")) && *str)
6
-       itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_VENDOR_ID, str);
7
-
8
+   if ((str = udev_device_get_property_value(dev, "ID_VENDOR_ID")) && *str) {
9
+       int32_t val;
10
+       if (spa_atoi32(str, &val, 16)) {
11
+           char *dec = alloca(12); /* 0xffff is max */
12
+           snprintf(dec, 12, "0x%04x", val);
13
+           itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_VENDOR_ID, dec);
14
+       }
15
+   }
16
    str = udev_device_get_property_value(dev, "ID_VENDOR_FROM_DATABASE");
17
    if (!(str && *str)) {
18
        str = udev_device_get_property_value(dev, "ID_VENDOR_ENC");
19
@@ -295,8 +300,14 @@
20
    if (str && *str) {
21
        itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_VENDOR_NAME, str);
22
    }
23
-   if ((str = udev_device_get_property_value(dev, "ID_MODEL_ID")) && *str)
24
-       itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_PRODUCT_ID, str);
25
+   if ((str = udev_device_get_property_value(dev, "ID_MODEL_ID")) && *str) {
26
+       int32_t val;
27
+       if (spa_atoi32(str, &val, 16)) {
28
+           char *dec = alloca(12); /* 0xffff is max */
29
+           snprintf(dec, 12, "0x%04x", val);
30
+           itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_PRODUCT_ID, dec);
31
+       }
32
+   }
33
 
34
    str = udev_device_get_property_value(dev, "ID_MODEL_FROM_DATABASE");
35
    if (!(str && *str)) {
36
pipewire-0.3.54.tar.gz/spa/plugins/vulkan/vulkan-utils.c -> pipewire-0.3.56.tar.gz/spa/plugins/vulkan/vulkan-utils.c Changed
10
 
1
@@ -6,7 +6,7 @@
2
 #include <sys/mman.h>
3
 #include <fcntl.h>
4
 #include <string.h>
5
-#if defined(__FreeBSD__) || defined(__MidnightBSD__)
6
+#if !defined(__FreeBSD__) && !defined(__MidnightBSD__)
7
 #include <alloca.h>
8
 #endif
9
 #include <errno.h>
10
pipewire-0.3.54.tar.gz/src/daemon/client.conf.in -> pipewire-0.3.56.tar.gz/src/daemon/client.conf.in Changed
9
 
1
@@ -7,6 +7,7 @@
2
 # @PIPEWIRE_CONFIG_DIR@/client.conf.d/ for system-wide changes or in
3
 # ~/.config/pipewire/client.conf.d/ for local changes.
4
 #
5
+
6
 context.properties = {
7
     ## Configure properties in the system.
8
     #mem.warn-mlock  = false
9
pipewire-0.3.56.tar.gz/src/daemon/filter-chain.conf.in Added
64
 
1
@@ -0,0 +1,62 @@
2
+# Filter-chain config file for PipeWire version @VERSION@ #
3
+#
4
+# This is a base config file for running filters.
5
+#
6
+# Place filter fragments in @PIPEWIRE_CONFIG_DIR@/filter-chain.conf.d/
7
+# for system-wide changes or in ~/.config/pipewire/filter-chain.conf.d/
8
+# for local changes.
9
+#
10
+# Run the filters with pipewire -c filter-chain.conf
11
+#
12
+
13
+context.properties = {
14
+    ## Configure properties in the system.
15
+    #mem.warn-mlock  = false
16
+    #mem.allow-mlock = true
17
+    #mem.mlock-all   = false
18
+    log.level        = 0
19
+}
20
+
21
+context.spa-libs = {
22
+    #<factory-name regex> = <library-name>
23
+    #
24
+    # Used to find spa factory names. It maps an spa factory name
25
+    # regular expression to a library name that should contain
26
+    # that factory.
27
+    #
28
+    audio.convert.* = audioconvert/libspa-audioconvert
29
+    support.*       = support/libspa-support
30
+}
31
+
32
+context.modules = 
33
+    #{ name = <module-name>
34
+    #     args  = { <key> = <value> ... } 
35
+    #     flags =   ifexists   nofail  
36
+    #}
37
+    #
38
+    # Loads a module with the given parameters.
39
+    # If ifexists is given, the module is ignored when it is not found.
40
+    # If nofail is given, module initialization failures are ignored.
41
+    #
42
+    # Uses realtime scheduling to boost the audio thread priorities
43
+    { name = libpipewire-module-rt
44
+        args = {
45
+            #rt.prio      = 88
46
+            #rt.time.soft = -1
47
+            #rt.time.hard = -1
48
+        }
49
+        flags =  ifexists nofail 
50
+    }
51
+
52
+    # The native communication protocol.
53
+    { name = libpipewire-module-protocol-native }
54
+
55
+    # Allows creating nodes that run in the context of the
56
+    # client. Is used by all clients that want to provide
57
+    # data to PipeWire.
58
+    { name = libpipewire-module-client-node }
59
+
60
+    # Makes a factory for wrapping nodes in an adapter with a
61
+    # converter and resampler.
62
+    { name = libpipewire-module-adapter }
63
+
64
pipewire-0.3.54.tar.gz/src/daemon/filter-chain/demonic.conf -> pipewire-0.3.56.tar.gz/src/daemon/filter-chain/demonic.conf Changed
52
 
1
@@ -1,46 +1,9 @@
2
 # filter-chain example config file for PipeWire version @VERSION@ #
3
-context.properties = {
4
-    ## Configure properties in the system.
5
-    #mem.warn-mlock  = false
6
-    #mem.allow-mlock = true
7
-    #mem.mlock-all   = false
8
-    log.level        = 0
9
-}
10
-
11
-context.spa-libs = {
12
-    #<factory-name regex> = <library-name>
13
-    #
14
-    # Used to find spa factory names. It maps an spa factory name
15
-    # regular expression to a library name that should contain
16
-    # that factory.
17
-    #
18
-    audio.convert.* = audioconvert/libspa-audioconvert
19
-    support.*       = support/libspa-support
20
-}
21
-
22
+#
23
+# Copy this file into a conf.d/ directory such as
24
+# ~/.config/pipewire/filter-chain.conf.d/
25
+#
26
 context.modules = 
27
-    # Uses realtime scheduling to boost the audio thread priorities
28
-    { name = libpipewire-module-rt
29
-        args = {
30
-            #rt.prio      = 88
31
-            #rt.time.soft = -1
32
-            #rt.time.hard = -1
33
-        }
34
-        flags =  ifexists nofail 
35
-    }
36
-
37
-    # The native communication protocol.
38
-    { name = libpipewire-module-protocol-native }
39
-
40
-    # Allows creating nodes that run in the context of the
41
-    # client. Is used by all clients that want to provide
42
-    # data to PipeWire.
43
-    { name = libpipewire-module-client-node }
44
-
45
-    # Makes a factory for wrapping nodes in an adapter with a
46
-    # converter and resampler.
47
-    { name = libpipewire-module-adapter }
48
-
49
     { name = libpipewire-module-filter-chain
50
         args = {
51
             #audio.format    = F32
52
pipewire-0.3.54.tar.gz/src/daemon/filter-chain/meson.build -> pipewire-0.3.56.tar.gz/src/daemon/filter-chain/meson.build Changed
11
 
1
@@ -1,6 +1,8 @@
2
 conf_files = 
3
    'demonic.conf', 'demonic.conf' ,
4
-   'duplicate-FL.conf', 'duplicate-FL.conf' ,
5
+   'source-duplicate-FL.conf', 'source-duplicate-FL.conf' ,
6
+   'sink-mix-FL-FR.conf', 'sink-mix-FL-FR.conf' ,
7
+   'sink-make-LFE.conf', 'sink-make-LFE.conf' ,
8
    'sink-virtual-surround-5.1-kemar.conf', 'sink-virtual-surround-5.1-kemar.conf' ,
9
    'sink-virtual-surround-7.1-hesuvi.conf', 'sink-virtual-surround-7.1-hesuvi.conf' ,
10
    'sink-dolby-surround.conf', 'sink-dolby-surround.conf' ,
11
pipewire-0.3.54.tar.gz/src/daemon/filter-chain/sink-dolby-surround.conf -> pipewire-0.3.56.tar.gz/src/daemon/filter-chain/sink-dolby-surround.conf Changed
33
 
1
@@ -1,29 +1,9 @@
2
 # Dolby Surround encoder sink
3
 #
4
-# start with pipewire -c filter-chain/sink-dolby-surround.conf
5
+# Copy this file into a conf.d/ directory such as
6
+# ~/.config/pipewire/filter-chain.conf.d/
7
 #
8
-context.properties = {
9
-    log.level = 0
10
-}
11
-
12
-context.spa-libs = {
13
-    audio.convert.* = audioconvert/libspa-audioconvert
14
-    support.*       = support/libspa-support
15
-}
16
-
17
 context.modules = 
18
-    { name = libpipewire-module-rt
19
-        args = {
20
-            #rt.prio      = 88
21
-            #rt.time.soft = -1
22
-            #rt.time.hard = -1
23
-        }
24
-        flags =  ifexists nofail 
25
-    }
26
-    { name = libpipewire-module-protocol-native }
27
-    { name = libpipewire-module-client-node }
28
-    { name = libpipewire-module-adapter }
29
-
30
     { name = libpipewire-module-filter-chain
31
         args = {
32
             node.description = "Dolby Surround Sink"
33
pipewire-0.3.54.tar.gz/src/daemon/filter-chain/sink-eq6.conf -> pipewire-0.3.56.tar.gz/src/daemon/filter-chain/sink-eq6.conf Changed
33
 
1
@@ -1,29 +1,9 @@
2
 # 6 band sink equalizer
3
 #
4
-# start with pipewire -c filter-chain/sink-eq6.conf
5
+# Copy this file into a conf.d/ directory such as
6
+# ~/.config/pipewire/filter-chain.conf.d/
7
 #
8
-context.properties = {
9
-    log.level = 0
10
-}
11
-
12
-context.spa-libs = {
13
-    audio.convert.* = audioconvert/libspa-audioconvert
14
-    support.*       = support/libspa-support
15
-}
16
-
17
 context.modules = 
18
-    { name = libpipewire-module-rt
19
-        args = {
20
-            #rt.prio      = 88
21
-            #rt.time.soft = -1
22
-            #rt.time.hard = -1
23
-        }
24
-        flags =  ifexists nofail 
25
-    }
26
-    { name = libpipewire-module-protocol-native }
27
-    { name = libpipewire-module-client-node }
28
-    { name = libpipewire-module-adapter }
29
-
30
     { name = libpipewire-module-filter-chain
31
         args = {
32
             node.description = "Equalizer Sink"
33
pipewire-0.3.56.tar.gz/src/daemon/filter-chain/sink-make-LFE.conf Added
58
 
1
@@ -0,0 +1,56 @@
2
+# An example filter chain that makes a stereo sink that mixes
3
+# the FL and FR channels to FL, FR, LFE
4
+#
5
+# Copy this file into a conf.d/ directory
6
+#
7
+context.modules = 
8
+    { name = libpipewire-module-filter-chain
9
+        args = {
10
+            node.description = "LFE example"
11
+            media.name       = "LFE example"
12
+            filter.graph = {
13
+                nodes = 
14
+                    { name = copyIL type = builtin label = copy }
15
+                    { name = copyOL type = builtin label = copy }
16
+                    { name = copyIR type = builtin label = copy }
17
+                    { name = copyOR type = builtin label = copy }
18
+                    {
19
+                        name   = mix
20
+                        type   = builtin
21
+                        label  = mixer
22
+                        control = {
23
+                          "Gain 1" = 0.5
24
+                          "Gain 2" = 0.5
25
+                        }
26
+                    }
27
+                    {
28
+                        type  = builtin
29
+                        name  = lpLFE
30
+                        label = bq_lowpass
31
+                        control = { "Freq" = 150.0 }
32
+                    }
33
+                
34
+                links = 
35
+                    { output = "copyIL:Out" input = "copyOL:In" }
36
+                    { output = "copyIR:Out" input = "copyOR:In" }
37
+                    { output = "copyIL:Out" input = "mix:In 1" }
38
+                    { output = "copyIR:Out" input = "mix:In 2" }
39
+                    { output = "mix:Out" input = "lpLFE:In" }
40
+                
41
+                inputs  =  "copyIL:In" "copyIR:In" 
42
+                outputs =  "copyOL:Out" "copyOR:Out" "lpLFE:Out"
43
+            }
44
+            capture.props = {
45
+                node.name         = "input_lfe"
46
+                audio.position    =  FL FR 
47
+                media.class       = "Audio/Sink"
48
+            }
49
+            playback.props = {
50
+                node.name         = "output_lfe"
51
+                audio.position    =  FL FR LFE 
52
+                stream.dont-remix = true
53
+                node.passive      = true
54
+            }
55
+        }
56
+    }
57
+
58
pipewire-0.3.54.tar.gz/src/daemon/filter-chain/sink-matrix-spatialiser.conf -> pipewire-0.3.56.tar.gz/src/daemon/filter-chain/sink-matrix-spatialiser.conf Changed
36
 
1
@@ -1,30 +1,12 @@
2
 # Matrix Spatialiser sink
3
 #
4
-# start with pipewire -c filter-chain/sink-matrix-spatialiser.conf
5
+# Copy this file into a conf.d/ directory such as
6
+# ~/.config/pipewire/filter-chain.conf.d/
7
+#
8
 # ( Jean-Philippe Guillemin <hyp3ri0n@sfr.fr> )
9
-
10
-context.properties = {
11
-    log.level = 0
12
-}
13
-
14
-context.spa-libs = {
15
-    audio.convert.* = audioconvert/libspa-audioconvert
16
-    support.*       = support/libspa-support
17
-}
18
+#
19
 
20
 context.modules = 
21
-    { name = libpipewire-module-rt
22
-        args = {
23
-            #rt.prio      = 88
24
-            #rt.time.soft = -1
25
-            #rt.time.hard = -1
26
-        }
27
-        flags =  ifexists nofail 
28
-    }
29
-    { name = libpipewire-module-protocol-native }
30
-    { name = libpipewire-module-client-node }
31
-    { name = libpipewire-module-adapter }
32
-
33
     { name = libpipewire-module-filter-chain
34
         args = {
35
             node.description = "Matrix Spatialiser"
36
pipewire-0.3.56.tar.gz/src/daemon/filter-chain/sink-mix-FL-FR.conf Added
42
 
1
@@ -0,0 +1,40 @@
2
+# An example filter chain that makes a stereo sink that mixes
3
+# the FL and FR channels to a single FL channel
4
+#
5
+# Copy this file into a conf.d/ directory such as
6
+# ~/.config/pipewire/filter-chain.conf.d/
7
+#
8
+context.modules = 
9
+    { name = libpipewire-module-filter-chain
10
+        args = {
11
+            node.description = "Mix example"
12
+            media.name       = "Mix example"
13
+            filter.graph = {
14
+                nodes = 
15
+                    {
16
+                        name   = mix
17
+                        type   = builtin
18
+                        label  = mixer
19
+                        control = {
20
+                          "Gain 1" = 0.5
21
+                          "Gain 2" = 0.5
22
+                        }
23
+                    }
24
+                
25
+                inputs  =  "mix:In 1" "mix:In 2" 
26
+                outputs =  "mix:Out" 
27
+            }
28
+            capture.props = {
29
+                node.name         = "mix_input.mix-FL-FR-to-FL"
30
+                audio.position    =  FL FR 
31
+                media.class       = "Audio/Sink"
32
+            }
33
+            playback.props = {
34
+                node.name         = "mix_output.mix-FL-FR-to-FL"
35
+                audio.position    =  FL 
36
+                stream.dont-remix = true
37
+                node.passive      = true
38
+            }
39
+        }
40
+    }
41
+
42
pipewire-0.3.54.tar.gz/src/daemon/filter-chain/sink-virtual-surround-5.1-kemar.conf -> pipewire-0.3.56.tar.gz/src/daemon/filter-chain/sink-virtual-surround-5.1-kemar.conf Changed
33
 
1
@@ -1,29 +1,9 @@
2
 # Convolver sink
3
 #
4
-# start with pipewire -c filter-chain/sink-virtual-surround-5.1-kemar.conf
5
+# Copy this file into a conf.d/ directory such as
6
+# ~/.config/pipewire/filter-chain.conf.d/
7
 #
8
-context.properties = {
9
-    log.level = 0
10
-}
11
-
12
-context.spa-libs = {
13
-    audio.convert.* = audioconvert/libspa-audioconvert
14
-    support.*       = support/libspa-support
15
-}
16
-
17
 context.modules = 
18
-    { name = libpipewire-module-rt
19
-        args = {
20
-            #rt.prio      = 88
21
-            #rt.time.soft = -1
22
-            #rt.time.hard = -1
23
-        }
24
-        flags =  ifexists nofail 
25
-    }
26
-    { name = libpipewire-module-protocol-native }
27
-    { name = libpipewire-module-client-node }
28
-    { name = libpipewire-module-adapter }
29
-
30
     { name = libpipewire-module-filter-chain
31
         args = {
32
             node.description = "Virtual Surround Sink"
33
pipewire-0.3.54.tar.gz/src/daemon/filter-chain/sink-virtual-surround-7.1-hesuvi.conf -> pipewire-0.3.56.tar.gz/src/daemon/filter-chain/sink-virtual-surround-7.1-hesuvi.conf Changed
33
 
1
@@ -1,29 +1,9 @@
2
 # Convolver sink
3
 #
4
-# start with pipewire -c filter-chain/sink-virtual-surround-7.1-hesuvi.conf
5
+# Copy this file into a conf.d/ directory such as
6
+# ~/.config/pipewire/filter-chain.conf.d/
7
 #
8
-context.properties = {
9
-    log.level = 0
10
-}
11
-
12
-context.spa-libs = {
13
-    audio.convert.* = audioconvert/libspa-audioconvert
14
-    support.*       = support/libspa-support
15
-}
16
-
17
 context.modules = 
18
-    { name = libpipewire-module-rt
19
-        args = {
20
-            #rt.prio      = 88
21
-            #rt.time.soft = -1
22
-            #rt.time.hard = -1
23
-        }
24
-        flags =  ifexists nofail 
25
-    }
26
-    { name = libpipewire-module-protocol-native }
27
-    { name = libpipewire-module-client-node }
28
-    { name = libpipewire-module-adapter }
29
-
30
     { name = libpipewire-module-filter-chain
31
         args = {
32
             node.description = "Virtual Surround Sink"
33
pipewire-0.3.56.tar.gz/src/daemon/filter-chain/source-duplicate-FL.conf Added
54
 
1
@@ -0,0 +1,52 @@
2
+# An example filter chain that makes a source that duplicates the FL channel
3
+# to FL and FR.
4
+#
5
+# Copy this file into a conf.d/ directory such as
6
+# ~/.config/pipewire/filter-chain.conf.d/
7
+#
8
+context.modules = 
9
+    { name = libpipewire-module-filter-chain
10
+        args = {
11
+            node.description = "Remap example"
12
+            media.name       = "Remap example"
13
+            filter.graph = {
14
+                nodes = 
15
+                    {
16
+                        name   = copyIL
17
+                        type   = builtin
18
+                        label  = copy
19
+                    }
20
+                    {
21
+                        name   = copyOL
22
+                        type   = builtin
23
+                        label  = copy
24
+                    }
25
+                    {
26
+                        name   = copyOR
27
+                        type   = builtin
28
+                        label  = copy
29
+                    }
30
+                
31
+                links = 
32
+           # we can only tee from nodes, not inputs so we need
33
+           # to copy the inputs and then tee.
34
+                    { output = "copyIL:Out" input = "copyOL:In" }
35
+                    { output = "copyIL:Out" input = "copyOR:In" }
36
+                
37
+                inputs  =  "copyIL:In" 
38
+                outputs =  "copyOL:Out" "copyOR:Out" 
39
+            }
40
+            capture.props = {
41
+                node.name         = "remap_input.remap-FL-to-FL-FR"
42
+                audio.position    =  FL 
43
+                stream.dont-remix = true
44
+                node.passive      = true
45
+            }
46
+            playback.props = {
47
+                node.name         = "remap_output.remap-FL-to-FL-FR"
48
+                audio.position    =  FL FR 
49
+                media.class       = "Audio/Source"
50
+            }
51
+        }
52
+    }
53
+
54
pipewire-0.3.54.tar.gz/src/daemon/filter-chain/source-rnnoise.conf -> pipewire-0.3.56.tar.gz/src/daemon/filter-chain/source-rnnoise.conf Changed
33
 
1
@@ -1,29 +1,9 @@
2
 # Noise canceling source
3
 #
4
-# start with pipewire -c filter-chain/source-rnnoise.conf
5
+# Copy this file into a conf.d/ directory such as
6
+# ~/.config/pipewire/filter-chain.conf.d/
7
 #
8
-context.properties = {
9
-    log.level = 0
10
-}
11
-
12
-context.spa-libs = {
13
-    audio.convert.* = audioconvert/libspa-audioconvert
14
-    support.*       = support/libspa-support
15
-}
16
-
17
 context.modules = 
18
-    { name = libpipewire-module-rt
19
-        args = {
20
-            #rt.prio      = 88
21
-            #rt.time.soft = -1
22
-            #rt.time.hard = -1
23
-        }
24
-        flags =  ifexists nofail 
25
-    }
26
-    { name = libpipewire-module-protocol-native }
27
-    { name = libpipewire-module-client-node }
28
-    { name = libpipewire-module-adapter }
29
-
30
     { name = libpipewire-module-filter-chain
31
         args = {
32
             node.description = "Noise Canceling source"
33
pipewire-0.3.54.tar.gz/src/daemon/meson.build -> pipewire-0.3.56.tar.gz/src/daemon/meson.build Changed
28
 
1
@@ -67,9 +67,11 @@
2
  'pipewire.conf',
3
  'client.conf',
4
  'client-rt.conf',
5
+ 'filter-chain.conf',
6
  'jack.conf',
7
  'minimal.conf',
8
  'pipewire-pulse.conf',
9
+ 'pipewire-avb.conf',
10
 
11
 
12
 foreach c : conf_files
13
@@ -99,6 +101,14 @@
14
   dependencies :  spa_dep, pipewire_dep, ,
15
 )
16
 
17
+executable('pipewire-avb',
18
+  pipewire_daemon_sources,
19
+  install: true,
20
+  c_args : pipewire_c_args,
21
+  include_directories :  configinc ,
22
+  dependencies :  spa_dep, pipewire_dep, ,
23
+)
24
+
25
 ln = find_program('ln')
26
 
27
 custom_target('pipewire-uninstalled',
28
pipewire-0.3.56.tar.gz/src/daemon/pipewire-avb.conf.in Added
75
 
1
@@ -0,0 +1,73 @@
2
+# PulseAudio config file for PipeWire version @VERSION@ #
3
+#
4
+# Copy and edit this file in @PIPEWIRE_CONFIG_DIR@ for system-wide changes
5
+# or in ~/.config/pipewire for local changes.
6
+#
7
+# It is also possible to place a file with an updated section in
8
+# @PIPEWIRE_CONFIG_DIR@/pipewire-pulse.conf.d/ for system-wide changes or in
9
+# ~/.config/pipewire/pipewire-pulse.conf.d/ for local changes.
10
+#
11
+
12
+context.properties = {
13
+    ## Configure properties in the system.
14
+    #mem.warn-mlock  = false
15
+    #mem.allow-mlock = true
16
+    #mem.mlock-all   = false
17
+    #log.level       = 2
18
+
19
+    #default.clock.quantum-limit = 8192
20
+}
21
+
22
+context.spa-libs = {
23
+    audio.convert.* = audioconvert/libspa-audioconvert
24
+    support.*       = support/libspa-support
25
+}
26
+
27
+context.modules = 
28
+    { name = libpipewire-module-rt
29
+        args = {
30
+            nice.level   = -11
31
+            #rt.prio      = 88
32
+            #rt.time.soft = -1
33
+            #rt.time.hard = -1
34
+        }
35
+        flags =  ifexists nofail 
36
+    }
37
+    { name = libpipewire-module-protocol-native }
38
+    { name = libpipewire-module-client-node }
39
+    { name = libpipewire-module-adapter }
40
+    { name = libpipewire-module-avb
41
+        args = {
42
+       # contents of avb.properties can also be placed here
43
+       # to have config per server.
44
+        }
45
+    }
46
+
47
+
48
+# Extra modules can be loaded here. Setup in default.pa can be moved here
49
+context.exec = 
50
+    #{ path = "pactl"        args = "load-module module-always-sink" }
51
+
52
+
53
+stream.properties = {
54
+    #node.latency          = 1024/48000
55
+    #node.autoconnect      = true
56
+    #resample.quality      = 4
57
+    #channelmix.normalize  = false
58
+    #channelmix.mix-lfe    = false
59
+    #channelmix.upmix      = true
60
+    #channelmix.lfe-cutoff = 120
61
+    #channelmix.fc-cutoff  = 6000
62
+    #channelmix.rear-delay = 12.0
63
+    #channelmix.stereo-widen = 0.1
64
+    #channelmix.hilbert-taps = 0
65
+}
66
+
67
+avb.properties = {
68
+    # the addresses this server listens on
69
+    #ifname = "eth0.2"
70
+    ifname = "enp3s0"
71
+    # These overrides are only applied when running in a vm.
72
+    vm.overrides = {
73
+    }
74
+}
75
pipewire-0.3.54.tar.gz/src/daemon/pipewire.conf.in -> pipewire-0.3.56.tar.gz/src/daemon/pipewire.conf.in Changed
9
 
1
@@ -54,6 +54,7 @@
2
     # that factory.
3
     #
4
     audio.convert.* = audioconvert/libspa-audioconvert
5
+    avb.*           = avb/libspa-avb
6
     api.alsa.*      = alsa/libspa-alsa
7
     api.v4l2.*      = v4l2/libspa-v4l2
8
     api.libcamera.* = libcamera/libspa-libcamera
9
pipewire-0.3.54.tar.gz/src/examples/audio-src.c -> pipewire-0.3.56.tar.gz/src/examples/audio-src.c Changed
41
 
1
@@ -120,6 +120,7 @@
2
    struct data data = { 0, };
3
    const struct spa_pod *params1;
4
    uint8_t buffer1024;
5
+   struct pw_properties *props;
6
    struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer));
7
 
8
    pw_init(&argc, &argv);
9
@@ -142,14 +143,17 @@
10
     * you need to listen to is the process event where you need to produce
11
     * the data.
12
     */
13
+   props = pw_properties_new(PW_KEY_MEDIA_TYPE, "Audio",
14
+           PW_KEY_MEDIA_CATEGORY, "Playback",
15
+           PW_KEY_MEDIA_ROLE, "Music",
16
+           NULL);
17
+   if (argc > 1)
18
+       /* Set stream target if given on command line */
19
+       pw_properties_set(props, PW_KEY_TARGET_OBJECT, argv1);
20
    data.stream = pw_stream_new_simple(
21
            pw_main_loop_get_loop(data.loop),
22
            "audio-src",
23
-           pw_properties_new(
24
-               PW_KEY_MEDIA_TYPE, "Audio",
25
-               PW_KEY_MEDIA_CATEGORY, "Playback",
26
-               PW_KEY_MEDIA_ROLE, "Music",
27
-               NULL),
28
+           props,
29
            &stream_events,
30
            &data);
31
 
32
@@ -165,7 +169,7 @@
33
     * called in a realtime thread. */
34
    pw_stream_connect(data.stream,
35
              PW_DIRECTION_OUTPUT,
36
-             argc > 1 ? (uint32_t)atoi(argv1) : PW_ID_ANY,
37
+             PW_ID_ANY,
38
              PW_STREAM_FLAG_AUTOCONNECT |
39
              PW_STREAM_FLAG_MAP_BUFFERS |
40
              PW_STREAM_FLAG_RT_PROCESS,
41
pipewire-0.3.54.tar.gz/src/examples/export-sink.c -> pipewire-0.3.56.tar.gz/src/examples/export-sink.c Changed
10
 
1
@@ -472,7 +472,7 @@
2
 
3
    props = pw_properties_new(PW_KEY_NODE_AUTOCONNECT, "true", NULL);
4
    if (data->path)
5
-       pw_properties_set(props, PW_KEY_NODE_TARGET, data->path);
6
+       pw_properties_set(props, PW_KEY_TARGET_OBJECT, data->path);
7
    pw_properties_set(props, PW_KEY_MEDIA_CLASS, "Stream/Input/Video");
8
    pw_properties_set(props, PW_KEY_MEDIA_TYPE, "Video");
9
    pw_properties_set(props, PW_KEY_MEDIA_CATEGORY, "Capture");
10
pipewire-0.3.54.tar.gz/src/examples/export-source.c -> pipewire-0.3.56.tar.gz/src/examples/export-source.c Changed
10
 
1
@@ -483,7 +483,7 @@
2
                  PW_KEY_MEDIA_ROLE, "Music",
3
                  NULL);
4
    if (data->path)
5
-       pw_properties_set(props, PW_KEY_NODE_TARGET, data->path);
6
+       pw_properties_set(props, PW_KEY_TARGET_OBJECT, data->path);
7
 
8
    data->impl_node.iface = SPA_INTERFACE_INIT(
9
            SPA_TYPE_INTERFACE_Node,
10
pipewire-0.3.54.tar.gz/src/examples/export-spa.c -> pipewire-0.3.56.tar.gz/src/examples/export-spa.c Changed
10
 
1
@@ -93,7 +93,7 @@
2
 
3
    if (data->path) {
4
        pw_properties_set(props, PW_KEY_NODE_AUTOCONNECT, "true");
5
-       pw_properties_set(props, PW_KEY_NODE_TARGET, data->path);
6
+       pw_properties_set(props, PW_KEY_TARGET_OBJECT, data->path);
7
    }
8
 
9
    data->proxy = pw_core_export(data->core,
10
pipewire-0.3.54.tar.gz/src/examples/video-dsp-play.c -> pipewire-0.3.56.tar.gz/src/examples/video-dsp-play.c Changed
10
 
1
@@ -263,7 +263,7 @@
2
                PW_KEY_MEDIA_CATEGORY, "Capture",
3
                PW_KEY_MEDIA_ROLE, "DSP",
4
                PW_KEY_NODE_AUTOCONNECT, data.target ? "true" : "false",
5
-               PW_KEY_NODE_TARGET, data.target,
6
+               PW_KEY_TARGET_OBJECT, data.target,
7
                PW_KEY_MEDIA_CLASS, "Stream/Input/Video",
8
                NULL),
9
            &filter_events,
10
pipewire-0.3.54.tar.gz/src/examples/video-play-fixate.c -> pipewire-0.3.56.tar.gz/src/examples/video-play-fixate.c Changed
49
 
1
@@ -419,6 +419,7 @@
2
    const struct spa_pod *params2;
3
    uint8_t buffer1024;
4
    struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer));
5
+   struct pw_properties *props;
6
    int res, n_params;
7
 
8
    pw_init(&argc, &argv);
9
@@ -440,19 +441,22 @@
10
     * you need to listen to is the process event where you need to consume
11
     * the data provided to you.
12
     */
13
+   props = pw_properties_new(PW_KEY_MEDIA_TYPE, "Video",
14
+           PW_KEY_MEDIA_CATEGORY, "Capture",
15
+           PW_KEY_MEDIA_ROLE, "Camera",
16
+           NULL),
17
+   data.path = argc > 1 ? argv1 : NULL;
18
+   if (data.path)
19
+       /* Set stream target if given on command line */
20
+       pw_properties_set(props, PW_KEY_TARGET_OBJECT, data.path);
21
+
22
    data.stream = pw_stream_new_simple(
23
            pw_main_loop_get_loop(data.loop),
24
-           "video-play-reneg",
25
-           pw_properties_new(
26
-               PW_KEY_MEDIA_TYPE, "Video",
27
-               PW_KEY_MEDIA_CATEGORY, "Capture",
28
-               PW_KEY_MEDIA_ROLE, "Camera",
29
-               NULL),
30
+           "video-play-fixate",
31
+           props,
32
            &stream_events,
33
            &data);
34
 
35
-   data.path = argc > 1 ? argv1 : NULL;
36
-
37
    if (SDL_Init(SDL_INIT_VIDEO) < 0) {
38
        fprintf(stderr, "can't initialize SDL: %s\n", SDL_GetError());
39
        return -1;
40
@@ -477,7 +481,7 @@
41
     */
42
    if ((res = pw_stream_connect(data.stream,
43
              PW_DIRECTION_INPUT,
44
-             data.path ? (uint32_t)atoi(data.path) : PW_ID_ANY,
45
+             PW_ID_ANY,
46
              PW_STREAM_FLAG_AUTOCONNECT |  /* try to automatically connect this stream */
47
              PW_STREAM_FLAG_MAP_BUFFERS,   /* mmap the buffer data for us */
48
              params, n_params))        /* extra parameters, see above */ < 0) {
49
pipewire-0.3.54.tar.gz/src/examples/video-play-pull.c -> pipewire-0.3.56.tar.gz/src/examples/video-play-pull.c Changed
50
 
1
@@ -493,6 +493,7 @@
2
    const struct spa_pod *params2;
3
    uint8_t buffer1024;
4
    struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer));
5
+   struct pw_properties *props;
6
    int res, n_params;
7
 
8
    pw_init(&argc, &argv);
9
@@ -517,20 +518,23 @@
10
     * you need to listen to is the process event where you need to consume
11
     * the data provided to you.
12
     */
13
+   props = pw_properties_new(PW_KEY_MEDIA_TYPE, "Video",
14
+           PW_KEY_MEDIA_CATEGORY, "Capture",
15
+           PW_KEY_MEDIA_ROLE, "Camera",
16
+           PW_KEY_PRIORITY_DRIVER, "10000",
17
+           NULL),
18
+   data.path = argc > 1 ? argv1 : NULL;
19
+   if (data.path)
20
+       /* Set stream target if given on command line */
21
+       pw_properties_set(props, PW_KEY_TARGET_OBJECT, data.path);
22
+
23
    data.stream = pw_stream_new_simple(
24
            pw_main_loop_get_loop(data.loop),
25
            "video-play",
26
-           pw_properties_new(
27
-               PW_KEY_MEDIA_TYPE, "Video",
28
-               PW_KEY_MEDIA_CATEGORY, "Capture",
29
-               PW_KEY_MEDIA_ROLE, "Camera",
30
-               PW_KEY_PRIORITY_DRIVER, "10000",
31
-               NULL),
32
+           props,
33
            &stream_events,
34
            &data);
35
 
36
-   data.path = argc > 1 ? argv1 : NULL;
37
-
38
    if (SDL_Init(SDL_INIT_VIDEO) < 0) {
39
        fprintf(stderr, "can't initialize SDL: %s\n", SDL_GetError());
40
        return -1;
41
@@ -552,7 +556,7 @@
42
     */
43
    if ((res = pw_stream_connect(data.stream,
44
              PW_DIRECTION_INPUT,
45
-             data.path ? (uint32_t)atoi(data.path) : PW_ID_ANY,
46
+             PW_ID_ANY,
47
              PW_STREAM_FLAG_DRIVER |   /* we're driver, we pull */
48
              PW_STREAM_FLAG_AUTOCONNECT |  /* try to automatically connect this stream */
49
              PW_STREAM_FLAG_MAP_BUFFERS,   /* mmap the buffer data for us */
50
pipewire-0.3.54.tar.gz/src/examples/video-play-reneg.c -> pipewire-0.3.56.tar.gz/src/examples/video-play-reneg.c Changed
48
 
1
@@ -346,6 +346,7 @@
2
    const struct spa_pod *params2;
3
    uint8_t buffer1024;
4
    struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer));
5
+   struct pw_properties *props;
6
    int res, n_params;
7
 
8
    pw_init(&argc, &argv);
9
@@ -367,19 +368,22 @@
10
     * you need to listen to is the process event where you need to consume
11
     * the data provided to you.
12
     */
13
+   props = pw_properties_new(PW_KEY_MEDIA_TYPE, "Video",
14
+           PW_KEY_MEDIA_CATEGORY, "Capture",
15
+           PW_KEY_MEDIA_ROLE, "Camera",
16
+           NULL),
17
+   data.path = argc > 1 ? argv1 : NULL;
18
+   if (data.path)
19
+       /* Set stream target if given on command line */
20
+       pw_properties_set(props, PW_KEY_TARGET_OBJECT, data.path);
21
+
22
    data.stream = pw_stream_new_simple(
23
            pw_main_loop_get_loop(data.loop),
24
            "video-play-reneg",
25
-           pw_properties_new(
26
-               PW_KEY_MEDIA_TYPE, "Video",
27
-               PW_KEY_MEDIA_CATEGORY, "Capture",
28
-               PW_KEY_MEDIA_ROLE, "Camera",
29
-               NULL),
30
+           props,
31
            &stream_events,
32
            &data);
33
 
34
-   data.path = argc > 1 ? argv1 : NULL;
35
-
36
    if (SDL_Init(SDL_INIT_VIDEO) < 0) {
37
        fprintf(stderr, "can't initialize SDL: %s\n", SDL_GetError());
38
        return -1;
39
@@ -401,7 +405,7 @@
40
     */
41
    if ((res = pw_stream_connect(data.stream,
42
              PW_DIRECTION_INPUT,
43
-             data.path ? (uint32_t)atoi(data.path) : PW_ID_ANY,
44
+             PW_ID_ANY,
45
              PW_STREAM_FLAG_AUTOCONNECT |  /* try to automatically connect this stream */
46
              PW_STREAM_FLAG_MAP_BUFFERS,   /* mmap the buffer data for us */
47
              params, n_params))        /* extra parameters, see above */ < 0) {
48
pipewire-0.3.54.tar.gz/src/examples/video-play.c -> pipewire-0.3.56.tar.gz/src/examples/video-play.c Changed
47
 
1
@@ -439,6 +439,7 @@
2
    const struct spa_pod *params2;
3
    uint8_t buffer1024;
4
    struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer));
5
+   struct pw_properties *props;
6
    int res, n_params;
7
 
8
    pw_init(&argc, &argv);
9
@@ -460,19 +461,21 @@
10
     * you need to listen to is the process event where you need to consume
11
     * the data provided to you.
12
     */
13
+   props = pw_properties_new(PW_KEY_MEDIA_TYPE, "Video",
14
+           PW_KEY_MEDIA_CATEGORY, "Capture",
15
+           PW_KEY_MEDIA_ROLE, "Camera",
16
+           NULL),
17
+   data.path = argc > 1 ? argv1 : NULL;
18
+   if (data.path)
19
+       pw_properties_set(props, PW_KEY_TARGET_OBJECT, data.path);
20
+
21
    data.stream = pw_stream_new_simple(
22
            pw_main_loop_get_loop(data.loop),
23
            "video-play",
24
-           pw_properties_new(
25
-               PW_KEY_MEDIA_TYPE, "Video",
26
-               PW_KEY_MEDIA_CATEGORY, "Capture",
27
-               PW_KEY_MEDIA_ROLE, "Camera",
28
-               NULL),
29
+           props,
30
            &stream_events,
31
            &data);
32
 
33
-   data.path = argc > 1 ? argv1 : NULL;
34
-
35
    if (SDL_Init(SDL_INIT_VIDEO) < 0) {
36
        fprintf(stderr, "can't initialize SDL: %s\n", SDL_GetError());
37
        return -1;
38
@@ -494,7 +497,7 @@
39
     */
40
    if ((res = pw_stream_connect(data.stream,
41
              PW_DIRECTION_INPUT,
42
-             data.path ? (uint32_t)atoi(data.path) : PW_ID_ANY,
43
+             PW_ID_ANY,
44
              PW_STREAM_FLAG_AUTOCONNECT |  /* try to automatically connect this stream */
45
              PW_STREAM_FLAG_INACTIVE | /* we will activate ourselves */
46
              PW_STREAM_FLAG_MAP_BUFFERS,   /* mmap the buffer data for us */
47
pipewire-0.3.54.tar.gz/src/examples/video-src-alloc.c -> pipewire-0.3.56.tar.gz/src/examples/video-src-alloc.c Changed
10
 
1
@@ -442,7 +442,7 @@
2
     * the server.  */
3
    pw_stream_connect(data.stream,
4
              PW_DIRECTION_OUTPUT,
5
-             PW_ID_ANY,            /* link to any node */
6
+             PW_ID_ANY,
7
              PW_STREAM_FLAG_DRIVER |
8
              PW_STREAM_FLAG_ALLOC_BUFFERS,
9
              params, 1);
10
pipewire-0.3.54.tar.gz/src/examples/video-src-fixate.c -> pipewire-0.3.56.tar.gz/src/examples/video-src-fixate.c Changed
10
 
1
@@ -578,7 +578,7 @@
2
     * the server.  */
3
    pw_stream_connect(data.stream,
4
              PW_DIRECTION_OUTPUT,
5
-             PW_ID_ANY,            /* link to any node */
6
+             PW_ID_ANY,
7
              PW_STREAM_FLAG_DRIVER |
8
              PW_STREAM_FLAG_ALLOC_BUFFERS,
9
              params, 2);
10
pipewire-0.3.54.tar.gz/src/examples/video-src-reneg.c -> pipewire-0.3.56.tar.gz/src/examples/video-src-reneg.c Changed
10
 
1
@@ -487,7 +487,7 @@
2
     * the server.  */
3
    pw_stream_connect(data.stream,
4
              PW_DIRECTION_OUTPUT,
5
-             PW_ID_ANY,            /* link to any node */
6
+             PW_ID_ANY,
7
              PW_STREAM_FLAG_DRIVER |
8
              PW_STREAM_FLAG_ALLOC_BUFFERS,
9
              params, 1);
10
pipewire-0.3.54.tar.gz/src/modules/meson.build -> pipewire-0.3.56.tar.gz/src/modules/meson.build Changed
40
 
1
@@ -5,6 +5,7 @@
2
 module_sources = 
3
   'module-access.c',
4
   'module-adapter.c',
5
+  'module-avb.c',
6
   'module-client-device.c',
7
   'module-client-node.c',
8
   'module-echo-cancel.c',
9
@@ -516,3 +517,30 @@
10
   install_rpath: modules_install_dir,
11
   dependencies : mathlib, dl_lib, rt_lib, pipewire_dep,
12
 )
13
+
14
+build_module_avb = get_option('avb').allowed()
15
+if build_module_avb
16
+pipewire_module_avb = shared_library('pipewire-module-avb',
17
+   'module-avb.c',
18
+    'module-avb/avb.c',
19
+    'module-avb/adp.c',
20
+    'module-avb/acmp.c',
21
+    'module-avb/aecp.c',
22
+    'module-avb/aecp-aem.c',
23
+    'module-avb/avdecc.c',
24
+    'module-avb/maap.c',
25
+    'module-avb/mmrp.c',
26
+    'module-avb/mrp.c',
27
+    'module-avb/msrp.c',
28
+    'module-avb/mvrp.c',
29
+    'module-avb/srp.c',
30
+    'module-avb/stream.c'
31
+    ,
32
+  include_directories : configinc,
33
+  install : true,
34
+  install_dir : modules_install_dir,
35
+  install_rpath: modules_install_dir,
36
+  dependencies : mathlib, dl_lib, rt_lib, pipewire_dep,
37
+)
38
+endif
39
+summary({'avb': build_module_avb}, bool_yn: true, section: 'Optional Modules')
40
pipewire-0.3.56.tar.gz/src/modules/module-avb Added
2
 
1
+(directory)
2
pipewire-0.3.56.tar.gz/src/modules/module-avb.c Added
132
 
1
@@ -0,0 +1,130 @@
2
+/* PipeWire
3
+ *
4
+ * Copyright © 2022 Wim Taymans
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a
7
+ * copy of this software and associated documentation files (the "Software"),
8
+ * to deal in the Software without restriction, including without limitation
9
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
+ * and/or sell copies of the Software, and to permit persons to whom the
11
+ * Software is furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice (including the next
14
+ * paragraph) shall be included in all copies or substantial portions of the
15
+ * Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23
+ * DEALINGS IN THE SOFTWARE.
24
+ */
25
+
26
+#include <string.h>
27
+#include <stdio.h>
28
+#include <errno.h>
29
+#include <sys/types.h>
30
+#include <sys/stat.h>
31
+#include <fcntl.h>
32
+#include <unistd.h>
33
+
34
+#include "config.h"
35
+
36
+#include <spa/utils/result.h>
37
+#include <spa/utils/string.h>
38
+#include <spa/utils/json.h>
39
+
40
+#include <pipewire/impl.h>
41
+#include <pipewire/private.h>
42
+#include <pipewire/i18n.h>
43
+
44
+#include "module-avb/avb.h"
45
+
46
+/** \page page_module_avb PipeWire Module: AVB
47
+ */
48
+
49
+#define NAME "avb"
50
+
51
+PW_LOG_TOPIC_STATIC(mod_topic, "mod." NAME);
52
+#define PW_LOG_TOPIC_DEFAULT mod_topic
53
+
54
+#define MODULE_USAGE   " "
55
+
56
+static const struct spa_dict_item module_props = {
57
+   { PW_KEY_MODULE_AUTHOR, "Wim Taymans <wim.taymans@gmail.com>" },
58
+   { PW_KEY_MODULE_DESCRIPTION, "Manage an AVB network" },
59
+   { PW_KEY_MODULE_USAGE, MODULE_USAGE },
60
+   { PW_KEY_MODULE_VERSION, PACKAGE_VERSION },
61
+};
62
+
63
+
64
+struct impl {
65
+   struct pw_context *context;
66
+
67
+   struct pw_impl_module *module;
68
+   struct spa_hook module_listener;
69
+
70
+   struct pw_avb *avb;
71
+};
72
+
73
+static void impl_free(struct impl *impl)
74
+{
75
+   free(impl);
76
+}
77
+
78
+static void module_destroy(void *data)
79
+{
80
+   struct impl *impl = data;
81
+   spa_hook_remove(&impl->module_listener);
82
+   impl_free(impl);
83
+}
84
+
85
+static const struct pw_impl_module_events module_events = {
86
+   PW_VERSION_IMPL_MODULE_EVENTS,
87
+   .destroy = module_destroy,
88
+};
89
+
90
+SPA_EXPORT
91
+int pipewire__module_init(struct pw_impl_module *module, const char *args)
92
+{
93
+   struct pw_context *context = pw_impl_module_get_context(module);
94
+   struct pw_properties *props;
95
+   struct impl *impl;
96
+   int res;
97
+
98
+   PW_LOG_TOPIC_INIT(mod_topic);
99
+
100
+   impl = calloc(1, sizeof(struct impl));
101
+   if (impl == NULL)
102
+       goto error_errno;
103
+
104
+   pw_log_debug("module %p: new %s", impl, args);
105
+
106
+   if (args == NULL)
107
+       args = "";
108
+
109
+   props = pw_properties_new_string(args);
110
+   if (props == NULL)
111
+       goto error_errno;
112
+
113
+   impl->module = module;
114
+   impl->context = context;
115
+
116
+   impl->avb = pw_avb_new(context, props, 0);
117
+   if (impl->avb == NULL)
118
+       goto error_errno;
119
+
120
+   pw_impl_module_add_listener(module, &impl->module_listener, &module_events, impl);
121
+
122
+   pw_impl_module_update_properties(module, &SPA_DICT_INIT_ARRAY(module_props));
123
+
124
+   return 0;
125
+
126
+error_errno:
127
+   res = -errno;
128
+   if (impl)
129
+       impl_free(impl);
130
+   return res;
131
+}
132
pipewire-0.3.56.tar.gz/src/modules/module-avb/aaf.h Added
104
 
1
@@ -0,0 +1,102 @@
2
+/* AVB support
3
+ *
4
+ * Copyright © 2022 Wim Taymans
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a
7
+ * copy of this software and associated documentation files (the "Software"),
8
+ * to deal in the Software without restriction, including without limitation
9
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
+ * and/or sell copies of the Software, and to permit persons to whom the
11
+ * Software is furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice (including the next
14
+ * paragraph) shall be included in all copies or substantial portions of the
15
+ * Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23
+ * DEALINGS IN THE SOFTWARE.
24
+ */
25
+
26
+#ifndef AVB_AAF_H
27
+#define AVB_AAF_H
28
+
29
+struct avb_packet_aaf {
30
+   uint8_t subtype;
31
+#if __BYTE_ORDER == __BIG_ENDIAN
32
+   unsigned sv:1;
33
+   unsigned version:3;
34
+   unsigned mr:1;
35
+   unsigned _r1:1;
36
+   unsigned gv:1;
37
+   unsigned tv:1;
38
+
39
+   uint8_t seq_number;
40
+
41
+   unsigned _r2:7;
42
+   unsigned tu:1;
43
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
44
+   unsigned tv:1;
45
+   unsigned gv:1;
46
+   unsigned _r1:1;
47
+   unsigned mr:1;
48
+   unsigned version:3;
49
+   unsigned sv:1;
50
+
51
+   uint8_t seq_num;
52
+
53
+   unsigned tu:1;
54
+   unsigned _r2:7;
55
+#endif
56
+   uint64_t stream_id;
57
+   uint32_t timestamp;
58
+#define AVB_AAF_FORMAT_USER        0x00
59
+#define AVB_AAF_FORMAT_FLOAT_32BIT 0x01
60
+#define AVB_AAF_FORMAT_INT_32BIT   0x02
61
+#define AVB_AAF_FORMAT_INT_24BIT   0x03
62
+#define AVB_AAF_FORMAT_INT_16BIT   0x04
63
+#define AVB_AAF_FORMAT_AES3_32BIT  0x05
64
+   uint8_t format;
65
+
66
+#define AVB_AAF_PCM_NSR_USER       0x00
67
+#define AVB_AAF_PCM_NSR_8KHZ       0x01
68
+#define AVB_AAF_PCM_NSR_16KHZ      0x02
69
+#define AVB_AAF_PCM_NSR_32KHZ      0x03
70
+#define AVB_AAF_PCM_NSR_44_1KHZ    0x04
71
+#define AVB_AAF_PCM_NSR_48KHZ      0x05
72
+#define AVB_AAF_PCM_NSR_88_2KHZ    0x06
73
+#define AVB_AAF_PCM_NSR_96KHZ      0x07
74
+#define AVB_AAF_PCM_NSR_176_4KHZ   0x08
75
+#define AVB_AAF_PCM_NSR_192KHZ 0x09
76
+#define AVB_AAF_PCM_NSR_24KHZ      0x0A
77
+#if __BYTE_ORDER == __BIG_ENDIAN
78
+   unsigned nsr:4;
79
+   unsigned _r3:4;
80
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
81
+   unsigned _r3:4;
82
+   unsigned nsr:4;
83
+#endif
84
+   uint8_t chan_per_frame;
85
+   uint8_t bit_depth;
86
+   uint16_t data_len;
87
+
88
+#define AVB_AAF_PCM_SP_NORMAL      0x00
89
+#define AVB_AAF_PCM_SP_SPARSE      0x01
90
+#if __BYTE_ORDER == __BIG_ENDIAN
91
+   unsigned _r4:3;
92
+   unsigned sp:1;
93
+   unsigned event:4;
94
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
95
+   unsigned event:4;
96
+   unsigned sp:1;
97
+   unsigned _r4:3;
98
+#endif
99
+   uint8_t _r5;
100
+   uint8_t payload0;
101
+} __attribute__ ((__packed__));
102
+
103
+#endif /* AVB_AAF_H */
104
pipewire-0.3.56.tar.gz/src/modules/module-avb/acmp.c Added
201
 
1
@@ -0,0 +1,477 @@
2
+/* AVB support
3
+ *
4
+ * Copyright © 2022 Wim Taymans
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a
7
+ * copy of this software and associated documentation files (the "Software"),
8
+ * to deal in the Software without restriction, including without limitation
9
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
+ * and/or sell copies of the Software, and to permit persons to whom the
11
+ * Software is furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice (including the next
14
+ * paragraph) shall be included in all copies or substantial portions of the
15
+ * Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23
+ * DEALINGS IN THE SOFTWARE.
24
+ */
25
+
26
+#include <spa/utils/json.h>
27
+#include <spa/debug/mem.h>
28
+
29
+#include <pipewire/pipewire.h>
30
+
31
+#include "acmp.h"
32
+#include "msrp.h"
33
+#include "internal.h"
34
+#include "stream.h"
35
+
36
+static const uint8_t mac6 = AVB_BROADCAST_MAC;
37
+
38
+struct pending {
39
+   struct spa_list link;
40
+   uint64_t last_time;
41
+   uint64_t timeout;
42
+   uint16_t old_sequence_id;
43
+   uint16_t sequence_id;
44
+   uint16_t retry;
45
+   size_t size;
46
+   void *ptr;
47
+};
48
+
49
+struct acmp {
50
+   struct server *server;
51
+   struct spa_hook server_listener;
52
+
53
+#define PENDING_TALKER     0
54
+#define PENDING_LISTENER   1
55
+#define PENDING_CONTROLLER 2
56
+   struct spa_list pending3;
57
+   uint16_t sequence_id3;
58
+};
59
+
60
+static void *pending_new(struct acmp *acmp, uint32_t type, uint64_t now, uint32_t timeout_ms,
61
+       const void *m, size_t size)
62
+{
63
+   struct pending *p;
64
+   struct avb_ethernet_header *h;
65
+   struct avb_packet_acmp *pm;
66
+
67
+   p = calloc(1, sizeof(*p) + size);
68
+   if (p == NULL)
69
+       return NULL;
70
+   p->last_time = now;
71
+   p->timeout = timeout_ms * SPA_NSEC_PER_MSEC;
72
+   p->sequence_id = acmp->sequence_idtype++;
73
+   p->size = size;
74
+   p->ptr = SPA_PTROFF(p, sizeof(*p), void);
75
+   memcpy(p->ptr, m, size);
76
+
77
+   h = p->ptr;
78
+   pm = SPA_PTROFF(h, sizeof(*h), void);
79
+   p->old_sequence_id = ntohs(pm->sequence_id);
80
+   pm->sequence_id = htons(p->sequence_id);
81
+   spa_list_append(&acmp->pendingtype, &p->link);
82
+
83
+   return p->ptr;
84
+}
85
+
86
+static struct pending *pending_find(struct acmp *acmp, uint32_t type, uint16_t sequence_id)
87
+{
88
+   struct pending *p;
89
+   spa_list_for_each(p, &acmp->pendingtype, link)
90
+       if (p->sequence_id == sequence_id)
91
+           return p;
92
+   return NULL;
93
+}
94
+
95
+static void pending_free(struct acmp *acmp, struct pending *p)
96
+{
97
+   spa_list_remove(&p->link);
98
+   free(p);
99
+}
100
+
101
+struct msg_info {
102
+   uint16_t type;
103
+   const char *name;
104
+   int (*handle) (struct acmp *acmp, uint64_t now, const void *m, int len);
105
+};
106
+
107
+static int reply_not_supported(struct acmp *acmp, uint8_t type, const void *m, int len)
108
+{
109
+   struct server *server = acmp->server;
110
+   uint8_t buflen;
111
+   struct avb_ethernet_header *h = (void*)buf;
112
+   struct avb_packet_acmp *reply = SPA_PTROFF(h, sizeof(*h), void);
113
+
114
+   memcpy(h, m, len);
115
+   AVB_PACKET_ACMP_SET_MESSAGE_TYPE(reply, type);
116
+   AVB_PACKET_ACMP_SET_STATUS(reply, AVB_ACMP_STATUS_NOT_SUPPORTED);
117
+
118
+   return avb_server_send_packet(server, h->src, AVB_TSN_ETH, buf, len);
119
+}
120
+
121
+static int retry_pending(struct acmp *acmp, uint64_t now, struct pending *p)
122
+{
123
+   struct server *server = acmp->server;
124
+   struct avb_ethernet_header *h = p->ptr;
125
+   p->retry++;
126
+   p->last_time = now;
127
+   return avb_server_send_packet(server, h->dest, AVB_TSN_ETH, p->ptr, p->size);
128
+}
129
+
130
+static int handle_connect_tx_command(struct acmp *acmp, uint64_t now, const void *m, int len)
131
+{
132
+   struct server *server = acmp->server;
133
+   uint8_t buflen;
134
+   struct avb_ethernet_header *h = (void*)buf;
135
+   struct avb_packet_acmp *reply = SPA_PTROFF(h, sizeof(*h), void);
136
+   const struct avb_packet_acmp *p = SPA_PTROFF(m, sizeof(*h), void);
137
+   int status = AVB_ACMP_STATUS_SUCCESS;
138
+   struct stream *stream;
139
+
140
+   if (be64toh(p->talker_guid) != server->entity_id)
141
+       return 0;
142
+
143
+   memcpy(buf, m, len);
144
+   stream = server_find_stream(server, SPA_DIRECTION_OUTPUT,
145
+           reply->talker_unique_id);
146
+   if (stream == NULL) {
147
+       status = AVB_ACMP_STATUS_TALKER_NO_STREAM_INDEX;
148
+       goto done;
149
+   }
150
+
151
+   AVB_PACKET_ACMP_SET_MESSAGE_TYPE(reply, AVB_ACMP_MESSAGE_TYPE_CONNECT_TX_RESPONSE);
152
+   reply->stream_id = htobe64(stream->id);
153
+
154
+   stream_activate(stream, now);
155
+
156
+   memcpy(reply->stream_dest_mac, stream->addr, 6);
157
+   reply->connection_count = htons(1);
158
+   reply->stream_vlan_id = htons(stream->vlan_id);
159
+
160
+done:
161
+   AVB_PACKET_ACMP_SET_STATUS(reply, status);
162
+   return avb_server_send_packet(server, h->dest, AVB_TSN_ETH, buf, len);
163
+}
164
+
165
+static int handle_connect_tx_response(struct acmp *acmp, uint64_t now, const void *m, int len)
166
+{
167
+   struct server *server = acmp->server;
168
+   struct avb_ethernet_header *h;
169
+   const struct avb_packet_acmp *resp = SPA_PTROFF(m, sizeof(*h), void);
170
+   struct avb_packet_acmp *reply;
171
+   struct pending *pending;
172
+   uint16_t sequence_id;
173
+   struct stream *stream;
174
+   int res;
175
+
176
+   if (be64toh(resp->listener_guid) != server->entity_id)
177
+       return 0;
178
+
179
+   sequence_id = ntohs(resp->sequence_id);
180
+
181
+   pending = pending_find(acmp, PENDING_TALKER, sequence_id);
182
+   if (pending == NULL)
183
+       return 0;
184
+
185
+   h = pending->ptr;
186
+   pending->size = SPA_MIN((int)pending->size, len);
187
+   memcpy(h, m, pending->size);
188
+
189
+   reply = SPA_PTROFF(h, sizeof(*h), void);
190
+   reply->sequence_id = htons(pending->old_sequence_id);
191
+   AVB_PACKET_ACMP_SET_MESSAGE_TYPE(reply, AVB_ACMP_MESSAGE_TYPE_CONNECT_RX_RESPONSE);
192
+
193
+   stream = server_find_stream(server, SPA_DIRECTION_INPUT,
194
+           ntohs(reply->listener_unique_id));
195
+   if (stream == NULL)
196
+       return 0;
197
+
198
+   stream->peer_id = be64toh(reply->stream_id);
199
+   memcpy(stream->addr, reply->stream_dest_mac, 6);
200
+   stream_activate(stream, now);
201
pipewire-0.3.56.tar.gz/src/modules/module-avb/acmp.h Added
101
 
1
@@ -0,0 +1,99 @@
2
+/* AVB support
3
+ *
4
+ * Copyright © 2022 Wim Taymans
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a
7
+ * copy of this software and associated documentation files (the "Software"),
8
+ * to deal in the Software without restriction, including without limitation
9
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
+ * and/or sell copies of the Software, and to permit persons to whom the
11
+ * Software is furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice (including the next
14
+ * paragraph) shall be included in all copies or substantial portions of the
15
+ * Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23
+ * DEALINGS IN THE SOFTWARE.
24
+ */
25
+
26
+#ifndef AVB_ACMP_H
27
+#define AVB_ACMP_H
28
+
29
+#include "packets.h"
30
+#include "internal.h"
31
+
32
+#define AVB_ACMP_MESSAGE_TYPE_CONNECT_TX_COMMAND       0
33
+#define AVB_ACMP_MESSAGE_TYPE_CONNECT_TX_RESPONSE      1
34
+#define AVB_ACMP_MESSAGE_TYPE_DISCONNECT_TX_COMMAND        2
35
+#define AVB_ACMP_MESSAGE_TYPE_DISCONNECT_TX_RESPONSE       3
36
+#define AVB_ACMP_MESSAGE_TYPE_GET_TX_STATE_COMMAND     4
37
+#define AVB_ACMP_MESSAGE_TYPE_GET_TX_STATE_RESPONSE        5
38
+#define AVB_ACMP_MESSAGE_TYPE_CONNECT_RX_COMMAND       6
39
+#define AVB_ACMP_MESSAGE_TYPE_CONNECT_RX_RESPONSE      7
40
+#define AVB_ACMP_MESSAGE_TYPE_DISCONNECT_RX_COMMAND        8
41
+#define AVB_ACMP_MESSAGE_TYPE_DISCONNECT_RX_RESPONSE       9
42
+#define AVB_ACMP_MESSAGE_TYPE_GET_RX_STATE_COMMAND     10
43
+#define AVB_ACMP_MESSAGE_TYPE_GET_RX_STATE_RESPONSE        11
44
+#define AVB_ACMP_MESSAGE_TYPE_GET_TX_CONNECTION_COMMAND        12
45
+#define AVB_ACMP_MESSAGE_TYPE_GET_TX_CONNECTION_RESPONSE   13
46
+
47
+#define AVB_ACMP_STATUS_SUCCESS                0
48
+#define AVB_ACMP_STATUS_LISTENER_UNKNOWN_ID        1
49
+#define AVB_ACMP_STATUS_TALKER_UNKNOWN_ID      2
50
+#define AVB_ACMP_STATUS_TALKER_DEST_MAC_FAIL       3
51
+#define AVB_ACMP_STATUS_TALKER_NO_STREAM_INDEX     4
52
+#define AVB_ACMP_STATUS_TALKER_NO_BANDWIDTH        5
53
+#define AVB_ACMP_STATUS_TALKER_EXCLUSIVE       6
54
+#define AVB_ACMP_STATUS_LISTENER_TALKER_TIMEOUT        7
55
+#define AVB_ACMP_STATUS_LISTENER_EXCLUSIVE     8
56
+#define AVB_ACMP_STATUS_STATE_UNAVAILABLE      9
57
+#define AVB_ACMP_STATUS_NOT_CONNECTED          10
58
+#define AVB_ACMP_STATUS_NO_SUCH_CONNECTION     11
59
+#define AVB_ACMP_STATUS_COULD_NOT_SEND_MESSAGE     12
60
+#define AVB_ACMP_STATUS_TALKER_MISBEHAVING     13
61
+#define AVB_ACMP_STATUS_LISTENER_MISBEHAVING       14
62
+#define AVB_ACMP_STATUS_RESERVED           15
63
+#define AVB_ACMP_STATUS_CONTROLLER_NOT_AUTHORIZED  16
64
+#define AVB_ACMP_STATUS_INCOMPATIBLE_REQUEST       17
65
+#define AVB_ACMP_STATUS_LISTENER_INVALID_CONNECTION    18
66
+#define AVB_ACMP_STATUS_NOT_SUPPORTED          31
67
+
68
+#define AVB_ACMP_TIMEOUT_CONNECT_TX_COMMAND_MS     2000
69
+#define AVB_ACMP_TIMEOUT_DISCONNECT_TX_COMMAND_MS  200
70
+#define AVB_ACMP_TIMEOUT_GET_TX_STATE_COMMAND      200
71
+#define AVB_ACMP_TIMEOUT_CONNECT_RX_COMMAND_MS     4500
72
+#define AVB_ACMP_TIMEOUT_DISCONNECT_RX_COMMAND_MS  500
73
+#define AVB_ACMP_TIMEOUT_GET_RX_STATE_COMMAND_MS   200
74
+#define AVB_ACMP_TIMEOUT_GET_TX_CONNECTION_COMMAND 200
75
+
76
+struct avb_packet_acmp {
77
+   struct avb_packet_header hdr;
78
+   uint64_t stream_id;
79
+   uint64_t controller_guid;
80
+   uint64_t talker_guid;
81
+   uint64_t listener_guid;
82
+   uint16_t talker_unique_id;
83
+   uint16_t listener_unique_id;
84
+   char stream_dest_mac6;
85
+   uint16_t connection_count;
86
+   uint16_t sequence_id;
87
+   uint16_t flags;
88
+   uint16_t stream_vlan_id;
89
+   uint16_t reserved;
90
+} __attribute__ ((__packed__));
91
+
92
+#define AVB_PACKET_ACMP_SET_MESSAGE_TYPE(p,v)      AVB_PACKET_SET_SUB1(&(p)->hdr, v)
93
+#define AVB_PACKET_ACMP_SET_STATUS(p,v)            AVB_PACKET_SET_SUB2(&(p)->hdr, v)
94
+
95
+#define AVB_PACKET_ACMP_GET_MESSAGE_TYPE(p)        AVB_PACKET_GET_SUB1(&(p)->hdr)
96
+#define AVB_PACKET_ACMP_GET_STATUS(p)          AVB_PACKET_GET_SUB2(&(p)->hdr)
97
+
98
+struct avb_acmp *avb_acmp_register(struct server *server);
99
+
100
+#endif /* AVB_ACMP_H */
101
pipewire-0.3.56.tar.gz/src/modules/module-avb/adp.c Added
201
 
1
@@ -0,0 +1,381 @@
2
+/* AVB support
3
+ *
4
+ * Copyright © 2022 Wim Taymans
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a
7
+ * copy of this software and associated documentation files (the "Software"),
8
+ * to deal in the Software without restriction, including without limitation
9
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
+ * and/or sell copies of the Software, and to permit persons to whom the
11
+ * Software is furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice (including the next
14
+ * paragraph) shall be included in all copies or substantial portions of the
15
+ * Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23
+ * DEALINGS IN THE SOFTWARE.
24
+ */
25
+
26
+#include <spa/utils/json.h>
27
+
28
+#include <pipewire/pipewire.h>
29
+
30
+#include "adp.h"
31
+#include "aecp-aem-descriptors.h"
32
+#include "internal.h"
33
+#include "utils.h"
34
+
35
+static const uint8_t mac6 = AVB_BROADCAST_MAC;
36
+
37
+struct entity {
38
+   struct spa_list link;
39
+   uint64_t entity_id;
40
+   uint64_t last_time;
41
+   int valid_time;
42
+   unsigned advertise:1;
43
+   size_t len;
44
+   uint8_t buf128;
45
+};
46
+
47
+struct adp {
48
+   struct server *server;
49
+   struct spa_hook server_listener;
50
+
51
+   struct spa_list entities;
52
+   uint32_t available_index;
53
+};
54
+
55
+static struct entity *find_entity_by_id(struct adp *adp, uint64_t id)
56
+{
57
+   struct entity *e;
58
+   spa_list_for_each(e, &adp->entities, link)
59
+       if (e->entity_id == id)
60
+           return e;
61
+   return NULL;
62
+}
63
+static void entity_free(struct entity *e)
64
+{
65
+   spa_list_remove(&e->link);
66
+   free(e);
67
+}
68
+
69
+static int send_departing(struct adp *adp, uint64_t now, struct entity *e)
70
+{
71
+   struct avb_ethernet_header *h = (void*)e->buf;
72
+   struct avb_packet_adp *p = SPA_PTROFF(h, sizeof(*h), void);
73
+
74
+   AVB_PACKET_ADP_SET_MESSAGE_TYPE(p, AVB_ADP_MESSAGE_TYPE_ENTITY_DEPARTING);
75
+   p->available_index = htonl(adp->available_index++);
76
+   avb_server_send_packet(adp->server, mac, AVB_TSN_ETH, e->buf, e->len);
77
+   e->last_time = now;
78
+   return 0;
79
+}
80
+
81
+static int send_advertise(struct adp *adp, uint64_t now, struct entity *e)
82
+{
83
+   struct avb_ethernet_header *h = (void*)e->buf;
84
+   struct avb_packet_adp *p = SPA_PTROFF(h, sizeof(*h), void);
85
+
86
+   AVB_PACKET_ADP_SET_MESSAGE_TYPE(p, AVB_ADP_MESSAGE_TYPE_ENTITY_AVAILABLE);
87
+   p->available_index = htonl(adp->available_index++);
88
+   avb_server_send_packet(adp->server, mac, AVB_TSN_ETH, e->buf, e->len);
89
+   e->last_time = now;
90
+   return 0;
91
+}
92
+
93
+static int send_discover(struct adp *adp, uint64_t entity_id)
94
+{
95
+   uint8_t buf128;
96
+   struct avb_ethernet_header *h = (void*)buf;
97
+   struct avb_packet_adp *p = SPA_PTROFF(h, sizeof(*h), void);
98
+   size_t len = sizeof(*h) + sizeof(*p);
99
+
100
+   spa_memzero(buf, sizeof(buf));
101
+   AVB_PACKET_SET_SUBTYPE(&p->hdr, AVB_SUBTYPE_ADP);
102
+   AVB_PACKET_SET_LENGTH(&p->hdr, AVB_ADP_CONTROL_DATA_LENGTH);
103
+   AVB_PACKET_ADP_SET_MESSAGE_TYPE(p, AVB_ADP_MESSAGE_TYPE_ENTITY_DISCOVER);
104
+   p->entity_id = htonl(entity_id);
105
+   avb_server_send_packet(adp->server, mac, AVB_TSN_ETH, buf, len);
106
+   return 0;
107
+}
108
+
109
+static int adp_message(void *data, uint64_t now, const void *message, int len)
110
+{
111
+   struct adp *adp = data;
112
+   struct server *server = adp->server;
113
+   const struct avb_ethernet_header *h = message;
114
+   const struct avb_packet_adp *p = SPA_PTROFF(h, sizeof(*h), void);
115
+   struct entity *e;
116
+   int message_type;
117
+   char buf128;
118
+   uint64_t entity_id;
119
+
120
+   if (ntohs(h->type) != AVB_TSN_ETH)
121
+       return 0;
122
+   if (memcmp(h->dest, mac, 6) != 0 &&
123
+       memcmp(h->dest, server->mac_addr, 6) != 0)
124
+       return 0;
125
+
126
+   if (AVB_PACKET_GET_SUBTYPE(&p->hdr) != AVB_SUBTYPE_ADP ||
127
+       AVB_PACKET_GET_LENGTH(&p->hdr) < AVB_ADP_CONTROL_DATA_LENGTH)
128
+       return 0;
129
+
130
+   message_type = AVB_PACKET_ADP_GET_MESSAGE_TYPE(p);
131
+   entity_id = be64toh(p->entity_id);
132
+
133
+   e = find_entity_by_id(adp, entity_id);
134
+
135
+   switch (message_type) {
136
+   case AVB_ADP_MESSAGE_TYPE_ENTITY_AVAILABLE:
137
+       if (e == NULL) {
138
+           e = calloc(1, sizeof(*e));
139
+           if (e == NULL)
140
+               return -errno;
141
+
142
+           memcpy(e->buf, message, len);
143
+           e->len = len;
144
+           e->valid_time = AVB_PACKET_ADP_GET_VALID_TIME(p);
145
+           e->entity_id = entity_id;
146
+           spa_list_append(&adp->entities, &e->link);
147
+           pw_log_info("entity %s available",
148
+               avb_utils_format_id(buf, sizeof(buf), entity_id));
149
+       }
150
+       e->last_time = now;
151
+       break;
152
+   case AVB_ADP_MESSAGE_TYPE_ENTITY_DEPARTING:
153
+       if (e != NULL) {
154
+           pw_log_info("entity %s departing",
155
+               avb_utils_format_id(buf, sizeof(buf), entity_id));
156
+           entity_free(e);
157
+       }
158
+       break;
159
+   case AVB_ADP_MESSAGE_TYPE_ENTITY_DISCOVER:
160
+       pw_log_info("entity %s advertise",
161
+               avb_utils_format_id(buf, sizeof(buf), entity_id));
162
+       if (entity_id == 0UL) {
163
+           spa_list_for_each(e, &adp->entities, link)
164
+               if (e->advertise)
165
+                   send_advertise(adp, now, e);
166
+       } else if (e != NULL &&
167
+           e->advertise && e->entity_id == entity_id) {
168
+           send_advertise(adp, now, e);
169
+       }
170
+       break;
171
+   default:
172
+       return -EINVAL;
173
+   }
174
+   return 0;
175
+}
176
+
177
+static void adp_destroy(void *data)
178
+{
179
+   struct adp *adp = data;
180
+   spa_hook_remove(&adp->server_listener);
181
+   free(adp);
182
+}
183
+
184
+static void check_timeout(struct adp *adp, uint64_t now)
185
+{
186
+   struct entity *e, *t;
187
+   char buf128;
188
+
189
+   spa_list_for_each_safe(e, t, &adp->entities, link) {
190
+       if (e->last_time + (e->valid_time + 2) * SPA_NSEC_PER_SEC > now)
191
+           continue;
192
+
193
+       pw_log_info("entity %s timeout",
194
+           avb_utils_format_id(buf, sizeof(buf), e->entity_id));
195
+
196
+       if (e->advertise)
197
+           send_departing(adp, now, e);
198
+
199
+       entity_free(e);
200
+   }
201
pipewire-0.3.56.tar.gz/src/modules/module-avb/adp.h Added
107
 
1
@@ -0,0 +1,105 @@
2
+/* AVB support
3
+ *
4
+ * Copyright © 2022 Wim Taymans
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a
7
+ * copy of this software and associated documentation files (the "Software"),
8
+ * to deal in the Software without restriction, including without limitation
9
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
+ * and/or sell copies of the Software, and to permit persons to whom the
11
+ * Software is furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice (including the next
14
+ * paragraph) shall be included in all copies or substantial portions of the
15
+ * Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23
+ * DEALINGS IN THE SOFTWARE.
24
+ */
25
+
26
+#ifndef AVB_ADP_H
27
+#define AVB_ADP_H
28
+
29
+#include "packets.h"
30
+#include "internal.h"
31
+
32
+#define AVB_ADP_MESSAGE_TYPE_ENTITY_AVAILABLE      0
33
+#define AVB_ADP_MESSAGE_TYPE_ENTITY_DEPARTING      1
34
+#define AVB_ADP_MESSAGE_TYPE_ENTITY_DISCOVER       2
35
+
36
+#define AVB_ADP_ENTITY_CAPABILITY_EFU_MODE             (1u<<0)
37
+#define AVB_ADP_ENTITY_CAPABILITY_ADDRESS_ACCESS_SUPPORTED     (1u<<1)
38
+#define AVB_ADP_ENTITY_CAPABILITY_GATEWAY_ENTITY           (1u<<2)
39
+#define AVB_ADP_ENTITY_CAPABILITY_AEM_SUPPORTED                (1u<<3)
40
+#define AVB_ADP_ENTITY_CAPABILITY_LEGACY_AVC               (1u<<4)
41
+#define AVB_ADP_ENTITY_CAPABILITY_ASSOCIATION_ID_SUPPORTED     (1u<<5)
42
+#define AVB_ADP_ENTITY_CAPABILITY_ASSOCIATION_ID_VALID         (1u<<6)
43
+#define AVB_ADP_ENTITY_CAPABILITY_VENDOR_UNIQUE_SUPPORTED      (1u<<7)
44
+#define AVB_ADP_ENTITY_CAPABILITY_CLASS_A_SUPPORTED            (1u<<8)
45
+#define AVB_ADP_ENTITY_CAPABILITY_CLASS_B_SUPPORTED            (1u<<9)
46
+#define AVB_ADP_ENTITY_CAPABILITY_GPTP_SUPPORTED           (1u<<10)
47
+#define AVB_ADP_ENTITY_CAPABILITY_AEM_AUTHENTICATION_SUPPORTED     (1u<<11)
48
+#define AVB_ADP_ENTITY_CAPABILITY_AEM_AUTHENTICATION_REQUIRED      (1u<<12)
49
+#define AVB_ADP_ENTITY_CAPABILITY_AEM_PERSISTENT_ACQUIRE_SUPPORTED (1u<<13)
50
+#define AVB_ADP_ENTITY_CAPABILITY_AEM_IDENTIFY_CONTROL_INDEX_VALID (1u<<14)
51
+#define AVB_ADP_ENTITY_CAPABILITY_AEM_INTERFACE_INDEX_VALID        (1u<<15)
52
+#define AVB_ADP_ENTITY_CAPABILITY_GENERAL_CONTROLLER_IGNORE        (1u<<16)
53
+#define AVB_ADP_ENTITY_CAPABILITY_ENTITY_NOT_READY         (1u<<17)
54
+
55
+#define AVB_ADP_TALKER_CAPABILITY_IMPLEMENTED              (1u<<0)
56
+#define AVB_ADP_TALKER_CAPABILITY_OTHER_SOURCE             (1u<<9)
57
+#define AVB_ADP_TALKER_CAPABILITY_CONTROL_SOURCE           (1u<<10)
58
+#define AVB_ADP_TALKER_CAPABILITY_MEDIA_CLOCK_SOURCE           (1u<<11)
59
+#define AVB_ADP_TALKER_CAPABILITY_SMPTE_SOURCE             (1u<<12)
60
+#define AVB_ADP_TALKER_CAPABILITY_MIDI_SOURCE              (1u<<13)
61
+#define AVB_ADP_TALKER_CAPABILITY_AUDIO_SOURCE             (1u<<14)
62
+#define AVB_ADP_TALKER_CAPABILITY_VIDEO_SOURCE             (1u<<15)
63
+
64
+#define AVB_ADP_LISTENER_CAPABILITY_IMPLEMENTED                (1u<<0)
65
+#define AVB_ADP_LISTENER_CAPABILITY_OTHER_SINK             (1u<<9)
66
+#define AVB_ADP_LISTENER_CAPABILITY_CONTROL_SINK           (1u<<10)
67
+#define AVB_ADP_LISTENER_CAPABILITY_MEDIA_CLOCK_SINK           (1u<<11)
68
+#define AVB_ADP_LISTENER_CAPABILITY_SMPTE_SINK             (1u<<12)
69
+#define AVB_ADP_LISTENER_CAPABILITY_MIDI_SINK              (1u<<13)
70
+#define AVB_ADP_LISTENER_CAPABILITY_AUDIO_SINK             (1u<<14)
71
+#define AVB_ADP_LISTENER_CAPABILITY_VIDEO_SINK             (1u<<15)
72
+
73
+#define AVB_ADP_CONTROLLER_CAPABILITY_IMPLEMENTED          (1u<<0)
74
+#define AVB_ADP_CONTROLLER_CAPABILITY_LAYER3_PROXY         (1u<<1)
75
+
76
+#define AVB_ADP_CONTROL_DATA_LENGTH        56
77
+
78
+struct avb_packet_adp {
79
+   struct avb_packet_header hdr;
80
+   uint64_t entity_id;
81
+   uint64_t entity_model_id;
82
+   uint32_t entity_capabilities;
83
+   uint16_t talker_stream_sources;
84
+   uint16_t talker_capabilities;
85
+   uint16_t listener_stream_sinks;
86
+   uint16_t listener_capabilities;
87
+   uint32_t controller_capabilities;
88
+   uint32_t available_index;
89
+   uint64_t gptp_grandmaster_id;
90
+   uint8_t gptp_domain_number;
91
+   uint8_t reserved03;
92
+   uint16_t identify_control_index;
93
+   uint16_t interface_index;
94
+   uint64_t association_id;
95
+   uint32_t reserved1;
96
+} __attribute__ ((__packed__));
97
+
98
+#define AVB_PACKET_ADP_SET_MESSAGE_TYPE(p,v)       AVB_PACKET_SET_SUB1(&(p)->hdr, v)
99
+#define AVB_PACKET_ADP_SET_VALID_TIME(p,v)     AVB_PACKET_SET_SUB2(&(p)->hdr, v)
100
+
101
+#define AVB_PACKET_ADP_GET_MESSAGE_TYPE(p)     AVB_PACKET_GET_SUB1(&(p)->hdr)
102
+#define AVB_PACKET_ADP_GET_VALID_TIME(p)       AVB_PACKET_GET_SUB2(&(p)->hdr)
103
+
104
+struct avb_adp *avb_adp_register(struct server *server);
105
+
106
+#endif /* AVB_ADP_H */
107
pipewire-0.3.56.tar.gz/src/modules/module-avb/aecp-aem-descriptors.h Added
201
 
1
@@ -0,0 +1,247 @@
2
+/* AVB support
3
+ *
4
+ * Copyright © 2022 Wim Taymans
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a
7
+ * copy of this software and associated documentation files (the "Software"),
8
+ * to deal in the Software without restriction, including without limitation
9
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
+ * and/or sell copies of the Software, and to permit persons to whom the
11
+ * Software is furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice (including the next
14
+ * paragraph) shall be included in all copies or substantial portions of the
15
+ * Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23
+ * DEALINGS IN THE SOFTWARE.
24
+ */
25
+
26
+#ifndef AVB_AECP_AEM_DESCRIPTORS_H
27
+#define AVB_AECP_AEM_DESCRIPTORS_H
28
+
29
+#include "internal.h"
30
+
31
+#define AVB_AEM_DESC_ENTITY            0x0000
32
+#define AVB_AEM_DESC_CONFIGURATION     0x0001
33
+#define AVB_AEM_DESC_AUDIO_UNIT            0x0002
34
+#define AVB_AEM_DESC_VIDEO_UNIT            0x0003
35
+#define AVB_AEM_DESC_SENSOR_UNIT       0x0004
36
+#define AVB_AEM_DESC_STREAM_INPUT      0x0005
37
+#define AVB_AEM_DESC_STREAM_OUTPUT     0x0006
38
+#define AVB_AEM_DESC_JACK_INPUT            0x0007
39
+#define AVB_AEM_DESC_JACK_OUTPUT       0x0008
40
+#define AVB_AEM_DESC_AVB_INTERFACE     0x0009
41
+#define AVB_AEM_DESC_CLOCK_SOURCE      0x000a
42
+#define AVB_AEM_DESC_MEMORY_OBJECT     0x000b
43
+#define AVB_AEM_DESC_LOCALE            0x000c
44
+#define AVB_AEM_DESC_STRINGS           0x000d
45
+#define AVB_AEM_DESC_STREAM_PORT_INPUT     0x000e
46
+#define AVB_AEM_DESC_STREAM_PORT_OUTPUT        0x000f
47
+#define AVB_AEM_DESC_EXTERNAL_PORT_INPUT   0x0010
48
+#define AVB_AEM_DESC_EXTERNAL_PORT_OUTPUT  0x0011
49
+#define AVB_AEM_DESC_INTERNAL_PORT_INPUT   0x0012
50
+#define AVB_AEM_DESC_INTERNAL_PORT_OUTPUT  0x0013
51
+#define AVB_AEM_DESC_AUDIO_CLUSTER     0x0014
52
+#define AVB_AEM_DESC_VIDEO_CLUSTER     0x0015
53
+#define AVB_AEM_DESC_SENSOR_CLUSTER        0x0016
54
+#define AVB_AEM_DESC_AUDIO_MAP         0x0017
55
+#define AVB_AEM_DESC_VIDEO_MAP         0x0018
56
+#define AVB_AEM_DESC_SENSOR_MAP            0x0019
57
+#define AVB_AEM_DESC_CONTROL           0x001a
58
+#define AVB_AEM_DESC_SIGNAL_SELECTOR       0x001b
59
+#define AVB_AEM_DESC_MIXER         0x001c
60
+#define AVB_AEM_DESC_MATRIX            0x001d
61
+#define AVB_AEM_DESC_MATRIX_SIGNAL     0x001e
62
+#define AVB_AEM_DESC_SIGNAL_SPLITTER       0x001f
63
+#define AVB_AEM_DESC_SIGNAL_COMBINER       0x0020
64
+#define AVB_AEM_DESC_SIGNAL_DEMULTIPLEXER  0x0021
65
+#define AVB_AEM_DESC_SIGNAL_MULTIPLEXER        0x0022
66
+#define AVB_AEM_DESC_SIGNAL_TRANSCODER     0x0023
67
+#define AVB_AEM_DESC_CLOCK_DOMAIN      0x0024
68
+#define AVB_AEM_DESC_CONTROL_BLOCK     0x0025
69
+#define AVB_AEM_DESC_INVALID           0xffff
70
+
71
+struct avb_aem_desc_entity {
72
+   uint64_t entity_id;
73
+   uint64_t entity_model_id;
74
+   uint32_t entity_capabilities;
75
+   uint16_t talker_stream_sources;
76
+   uint16_t talker_capabilities;
77
+   uint16_t listener_stream_sinks;
78
+   uint16_t listener_capabilities;
79
+   uint32_t controller_capabilities;
80
+   uint32_t available_index;
81
+   uint64_t association_id;
82
+   char entity_name64;
83
+   uint16_t vendor_name_string;
84
+   uint16_t model_name_string;
85
+   char firmware_version64;
86
+   char group_name64;
87
+   char serial_number64;
88
+   uint16_t configurations_count;
89
+   uint16_t current_configuration;
90
+} __attribute__ ((__packed__));
91
+
92
+struct avb_aem_desc_descriptor_count {
93
+   uint16_t descriptor_type;
94
+   uint16_t descriptor_count;
95
+} __attribute__ ((__packed__));
96
+
97
+struct avb_aem_desc_configuration {
98
+   char object_name64;
99
+   uint16_t localized_description;
100
+   uint16_t descriptor_counts_count;
101
+   uint16_t descriptor_counts_offset;
102
+   struct avb_aem_desc_descriptor_count descriptor_counts0;
103
+} __attribute__ ((__packed__));
104
+
105
+struct avb_aem_desc_sampling_rate {
106
+   uint32_t pull_frequency;
107
+} __attribute__ ((__packed__));
108
+
109
+struct avb_aem_desc_audio_unit {
110
+   char object_name64;
111
+   uint16_t localized_description;
112
+   uint16_t clock_domain_index;
113
+   uint16_t number_of_stream_input_ports;
114
+   uint16_t base_stream_input_port;
115
+   uint16_t number_of_stream_output_ports;
116
+   uint16_t base_stream_output_port;
117
+   uint16_t number_of_external_input_ports;
118
+   uint16_t base_external_input_port;
119
+   uint16_t number_of_external_output_ports;
120
+   uint16_t base_external_output_port;
121
+   uint16_t number_of_internal_input_ports;
122
+   uint16_t base_internal_input_port;
123
+   uint16_t number_of_internal_output_ports;
124
+   uint16_t base_internal_output_port;
125
+   uint16_t number_of_controls;
126
+   uint16_t base_control;
127
+   uint16_t number_of_signal_selectors;
128
+   uint16_t base_signal_selector;
129
+   uint16_t number_of_mixers;
130
+   uint16_t base_mixer;
131
+   uint16_t number_of_matrices;
132
+   uint16_t base_matrix;
133
+   uint16_t number_of_splitters;
134
+   uint16_t base_splitter;
135
+   uint16_t number_of_combiners;
136
+   uint16_t base_combiner;
137
+   uint16_t number_of_demultiplexers;
138
+   uint16_t base_demultiplexer;
139
+   uint16_t number_of_multiplexers;
140
+   uint16_t base_multiplexer;
141
+   uint16_t number_of_transcoders;
142
+   uint16_t base_transcoder;
143
+   uint16_t number_of_control_blocks;
144
+   uint16_t base_control_block;
145
+   uint32_t current_sampling_rate;
146
+   uint16_t sampling_rates_offset;
147
+   uint16_t sampling_rates_count;
148
+   struct avb_aem_desc_sampling_rate sampling_rates0;
149
+} __attribute__ ((__packed__));
150
+
151
+#define AVB_AEM_DESC_STREAM_FLAG_SYNC_SOURCE           (1u<<0)
152
+#define AVB_AEM_DESC_STREAM_FLAG_CLASS_A           (1u<<1)
153
+#define AVB_AEM_DESC_STREAM_FLAG_CLASS_B           (1u<<2)
154
+#define AVB_AEM_DESC_STREAM_FLAG_SUPPORTS_ENCRYPTED        (1u<<3)
155
+#define AVB_AEM_DESC_STREAM_FLAG_PRIMARY_BACKUP_SUPPORTED  (1u<<4)
156
+#define AVB_AEM_DESC_STREAM_FLAG_PRIMARY_BACKUP_VALID      (1u<<5)
157
+#define AVB_AEM_DESC_STREAM_FLAG_SECONDARY_BACKUP_SUPPORTED    (1u<<6)
158
+#define AVB_AEM_DESC_STREAM_FLAG_SECONDARY_BACKUP_VALID        (1u<<7)
159
+#define AVB_AEM_DESC_STREAM_FLAG_TERTIARY_BACKUP_SUPPORTED (1u<<8)
160
+#define AVB_AEM_DESC_STREAM_FLAG_TERTIARY_BACKUP_VALID     (1u<<9)
161
+
162
+struct avb_aem_desc_stream {
163
+   char object_name64;
164
+   uint16_t localized_description;
165
+   uint16_t clock_domain_index;
166
+   uint16_t stream_flags;
167
+   uint64_t current_format;
168
+   uint16_t formats_offset;
169
+   uint16_t number_of_formats;
170
+   uint64_t backup_talker_entity_id_0;
171
+   uint16_t backup_talker_unique_id_0;
172
+   uint64_t backup_talker_entity_id_1;
173
+   uint16_t backup_talker_unique_id_1;
174
+   uint64_t backup_talker_entity_id_2;
175
+   uint16_t backup_talker_unique_id_2;
176
+   uint64_t backedup_talker_entity_id;
177
+   uint16_t backedup_talker_unique;
178
+   uint16_t avb_interface_index;
179
+   uint32_t buffer_length;
180
+   uint64_t stream_formats0;
181
+} __attribute__ ((__packed__));
182
+
183
+#define AVB_AEM_DESC_AVB_INTERFACE_FLAG_GPTP_GRANDMASTER_SUPPORTED (1<<0)
184
+#define AVB_AEM_DESC_AVB_INTERFACE_FLAG_GPTP_SUPPORTED         (1<<1)
185
+#define AVB_AEM_DESC_AVB_INTERFACE_FLAG_SRP_SUPPORTED          (1<<2)
186
+
187
+struct avb_aem_desc_avb_interface {
188
+   char object_name64;
189
+   uint16_t localized_description;
190
+   uint8_t mac_address6;
191
+   uint16_t interface_flags;
192
+   uint64_t clock_identity;
193
+   uint8_t priority1;
194
+   uint8_t clock_class;
195
+   uint16_t offset_scaled_log_variance;
196
+   uint8_t clock_accuracy;
197
+   uint8_t priority2;
198
+   uint8_t domain_number;
199
+   int8_t log_sync_interval;
200
+   int8_t log_announce_interval;
201
pipewire-0.3.56.tar.gz/src/modules/module-avb/aecp-aem.c Added
201
 
1
@@ -0,0 +1,286 @@
2
+/* AVB support
3
+ *
4
+ * Copyright © 2022 Wim Taymans
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a
7
+ * copy of this software and associated documentation files (the "Software"),
8
+ * to deal in the Software without restriction, including without limitation
9
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
+ * and/or sell copies of the Software, and to permit persons to whom the
11
+ * Software is furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice (including the next
14
+ * paragraph) shall be included in all copies or substantial portions of the
15
+ * Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23
+ * DEALINGS IN THE SOFTWARE.
24
+ */
25
+
26
+#include "aecp-aem.h"
27
+#include "aecp-aem-descriptors.h"
28
+
29
+static int reply_status(struct aecp *aecp, int status, const void *m, int len)
30
+{
31
+   struct server *server = aecp->server;
32
+   uint8_t buflen;
33
+   struct avb_ethernet_header *h = (void*)buf;
34
+   struct avb_packet_aecp_header *reply = SPA_PTROFF(h, sizeof(*h), void);
35
+
36
+   memcpy(buf, m, len);
37
+   AVB_PACKET_AECP_SET_MESSAGE_TYPE(reply, AVB_AECP_MESSAGE_TYPE_AEM_RESPONSE);
38
+   AVB_PACKET_AECP_SET_STATUS(reply, status);
39
+
40
+   return avb_server_send_packet(server, h->src, AVB_TSN_ETH, buf, len);
41
+}
42
+
43
+static int reply_not_implemented(struct aecp *aecp, const void *m, int len)
44
+{
45
+   return reply_status(aecp, AVB_AECP_AEM_STATUS_NOT_IMPLEMENTED, m, len);
46
+}
47
+
48
+static int reply_success(struct aecp *aecp, const void *m, int len)
49
+{
50
+   return reply_status(aecp, AVB_AECP_AEM_STATUS_SUCCESS, m, len);
51
+}
52
+
53
+/* ACQUIRE_ENTITY */
54
+static int handle_acquire_entity(struct aecp *aecp, const void *m, int len)
55
+{
56
+   struct server *server = aecp->server;
57
+   const struct avb_packet_aecp_aem *p = m;
58
+   const struct avb_packet_aecp_aem_acquire *ae;
59
+   const struct descriptor *desc;
60
+   uint16_t desc_type, desc_id;
61
+
62
+   ae = (const struct avb_packet_aecp_aem_acquire*)p->payload;
63
+
64
+   desc_type = ntohs(ae->descriptor_type);
65
+   desc_id = ntohs(ae->descriptor_id);
66
+
67
+   desc = server_find_descriptor(server, desc_type, desc_id);
68
+   if (desc == NULL)
69
+       return reply_status(aecp, AVB_AECP_AEM_STATUS_NO_SUCH_DESCRIPTOR, p, len);
70
+
71
+   if (desc_type != AVB_AEM_DESC_ENTITY || desc_id != 0)
72
+       return reply_not_implemented(aecp, m, len);
73
+
74
+   return reply_success(aecp, m, len);
75
+}
76
+
77
+/* LOCK_ENTITY */
78
+static int handle_lock_entity(struct aecp *aecp, const void *m, int len)
79
+{
80
+   struct server *server = aecp->server;
81
+   const struct avb_packet_aecp_aem *p = m;
82
+   const struct avb_packet_aecp_aem_acquire *ae;
83
+   const struct descriptor *desc;
84
+   uint16_t desc_type, desc_id;
85
+
86
+   ae = (const struct avb_packet_aecp_aem_acquire*)p->payload;
87
+
88
+   desc_type = ntohs(ae->descriptor_type);
89
+   desc_id = ntohs(ae->descriptor_id);
90
+
91
+   desc = server_find_descriptor(server, desc_type, desc_id);
92
+   if (desc == NULL)
93
+       return reply_status(aecp, AVB_AECP_AEM_STATUS_NO_SUCH_DESCRIPTOR, p, len);
94
+
95
+   if (desc_type != AVB_AEM_DESC_ENTITY || desc_id != 0)
96
+       return reply_not_implemented(aecp, m, len);
97
+
98
+   return reply_success(aecp, m, len);
99
+}
100
+
101
+/* READ_DESCRIPTOR */
102
+static int handle_read_descriptor(struct aecp *aecp, const void *m, int len)
103
+{
104
+   struct server *server = aecp->server;
105
+   const struct avb_ethernet_header *h = m;
106
+   const struct avb_packet_aecp_aem *p = SPA_PTROFF(h, sizeof(*h), void);
107
+   struct avb_packet_aecp_aem *reply;
108
+   const struct avb_packet_aecp_aem_read_descriptor *rd;
109
+   uint16_t desc_type, desc_id;
110
+   const struct descriptor *desc;
111
+   uint8_t buf2048;
112
+   size_t size, psize;
113
+
114
+   rd = (struct avb_packet_aecp_aem_read_descriptor*)p->payload;
115
+
116
+   desc_type = ntohs(rd->descriptor_type);
117
+   desc_id = ntohs(rd->descriptor_id);
118
+
119
+   pw_log_info("descriptor type:%04x index:%d", desc_type, desc_id);
120
+
121
+   desc = server_find_descriptor(server, desc_type, desc_id);
122
+   if (desc == NULL)
123
+       return reply_status(aecp, AVB_AECP_AEM_STATUS_NO_SUCH_DESCRIPTOR, m, len);
124
+
125
+   memcpy(buf, m, len);
126
+
127
+   psize = sizeof(*rd);
128
+   size = sizeof(*h) + sizeof(*reply) + psize;
129
+
130
+   memcpy(buf + size, desc->ptr, desc->size);
131
+   size += desc->size;
132
+   psize += desc->size;
133
+
134
+   h = (void*)buf;
135
+   reply = SPA_PTROFF(h, sizeof(*h), void);
136
+   AVB_PACKET_AECP_SET_MESSAGE_TYPE(&reply->aecp, AVB_AECP_MESSAGE_TYPE_AEM_RESPONSE);
137
+   AVB_PACKET_AECP_SET_STATUS(&reply->aecp, AVB_AECP_AEM_STATUS_SUCCESS);
138
+   AVB_PACKET_SET_LENGTH(&reply->aecp.hdr, psize + 12);
139
+
140
+   return avb_server_send_packet(server, h->src, AVB_TSN_ETH, buf, size);
141
+}
142
+
143
+/* GET_AVB_INFO */
144
+static int handle_get_avb_info(struct aecp *aecp, const void *m, int len)
145
+{
146
+   struct server *server = aecp->server;
147
+   const struct avb_ethernet_header *h = m;
148
+   const struct avb_packet_aecp_aem *p = SPA_PTROFF(h, sizeof(*h), void);
149
+   struct avb_packet_aecp_aem *reply;
150
+   struct avb_packet_aecp_aem_get_avb_info *i;
151
+   struct avb_aem_desc_avb_interface *avb_interface;
152
+   uint16_t desc_type, desc_id;
153
+   const struct descriptor *desc;
154
+   uint8_t buf2048;
155
+   size_t size, psize;
156
+
157
+   i = (struct avb_packet_aecp_aem_get_avb_info*)p->payload;
158
+
159
+   desc_type = ntohs(i->descriptor_type);
160
+   desc_id = ntohs(i->descriptor_id);
161
+
162
+   desc = server_find_descriptor(server, desc_type, desc_id);
163
+   if (desc == NULL)
164
+       return reply_status(aecp, AVB_AECP_AEM_STATUS_NO_SUCH_DESCRIPTOR, m, len);
165
+
166
+   if (desc_type != AVB_AEM_DESC_AVB_INTERFACE || desc_id != 0)
167
+       return reply_not_implemented(aecp, m, len);
168
+
169
+   avb_interface = desc->ptr;
170
+
171
+   memcpy(buf, m, len);
172
+
173
+   psize = sizeof(*i);
174
+   size = sizeof(*h) + sizeof(*reply) + psize;
175
+
176
+   h = (void*)buf;
177
+   reply = SPA_PTROFF(h, sizeof(*h), void);
178
+   AVB_PACKET_AECP_SET_MESSAGE_TYPE(&reply->aecp, AVB_AECP_MESSAGE_TYPE_AEM_RESPONSE);
179
+   AVB_PACKET_AECP_SET_STATUS(&reply->aecp, AVB_AECP_AEM_STATUS_SUCCESS);
180
+   AVB_PACKET_SET_LENGTH(&reply->aecp.hdr, psize + 12);
181
+
182
+   i = (struct avb_packet_aecp_aem_get_avb_info*)reply->payload;
183
+   i->gptp_grandmaster_id = avb_interface->clock_identity;
184
+   i->propagation_delay = htonl(0);
185
+   i->gptp_domain_number = avb_interface->domain_number;
186
+   i->flags = 0;
187
+   i->msrp_mappings_count = htons(0);
188
+
189
+   return avb_server_send_packet(server, h->src, AVB_TSN_ETH, buf, size);
190
+}
191
+
192
+/* AEM_COMMAND */
193
+struct cmd_info {
194
+   uint16_t type;
195
+   const char *name;
196
+   int (*handle) (struct aecp *aecp, const void *p, int len);
197
+};
198
+
199
+static const struct cmd_info cmd_info = {
200
+   { AVB_AECP_AEM_CMD_ACQUIRE_ENTITY, "acquire-entity", handle_acquire_entity, },
201
pipewire-0.3.56.tar.gz/src/modules/module-avb/aecp-aem.h Added
201
 
1
@@ -0,0 +1,345 @@
2
+/* AVB support
3
+ *
4
+ * Copyright © 2022 Wim Taymans
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a
7
+ * copy of this software and associated documentation files (the "Software"),
8
+ * to deal in the Software without restriction, including without limitation
9
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
+ * and/or sell copies of the Software, and to permit persons to whom the
11
+ * Software is furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice (including the next
14
+ * paragraph) shall be included in all copies or substantial portions of the
15
+ * Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23
+ * DEALINGS IN THE SOFTWARE.
24
+ */
25
+
26
+#ifndef AVB_AEM_H
27
+#define AVB_AEM_H
28
+
29
+#include "aecp.h"
30
+
31
+#define AVB_AECP_AEM_STATUS_SUCCESS            0
32
+#define AVB_AECP_AEM_STATUS_NOT_IMPLEMENTED        1
33
+#define AVB_AECP_AEM_STATUS_NO_SUCH_DESCRIPTOR     2
34
+#define AVB_AECP_AEM_STATUS_ENTITY_LOCKED      3
35
+#define AVB_AECP_AEM_STATUS_ENTITY_ACQUIRED        4
36
+#define AVB_AECP_AEM_STATUS_NOT_AUTHENTICATED      5
37
+#define AVB_AECP_AEM_STATUS_AUTHENTICATION_DISABLED    6
38
+#define AVB_AECP_AEM_STATUS_BAD_ARGUMENTS      7
39
+#define AVB_AECP_AEM_STATUS_NO_RESOURCES       8
40
+#define AVB_AECP_AEM_STATUS_IN_PROGRESS            9
41
+#define AVB_AECP_AEM_STATUS_ENTITY_MISBEHAVING     10
42
+#define AVB_AECP_AEM_STATUS_NOT_SUPPORTED      11
43
+#define AVB_AECP_AEM_STATUS_STREAM_IS_RUNNING      12
44
+
45
+#define AVB_AECP_AEM_CMD_ACQUIRE_ENTITY                0x0000
46
+#define AVB_AECP_AEM_CMD_LOCK_ENTITY               0x0001
47
+#define AVB_AECP_AEM_CMD_ENTITY_AVAILABLE          0x0002
48
+#define AVB_AECP_AEM_CMD_CONTROLLER_AVAILABLE          0x0003
49
+#define AVB_AECP_AEM_CMD_READ_DESCRIPTOR           0x0004
50
+#define AVB_AECP_AEM_CMD_WRITE_DESCRIPTOR          0x0005
51
+#define AVB_AECP_AEM_CMD_SET_CONFIGURATION         0x0006
52
+#define AVB_AECP_AEM_CMD_GET_CONFIGURATION         0x0007
53
+#define AVB_AECP_AEM_CMD_SET_STREAM_FORMAT         0x0008
54
+#define AVB_AECP_AEM_CMD_GET_STREAM_FORMAT         0x0009
55
+#define AVB_AECP_AEM_CMD_SET_VIDEO_FORMAT          0x000a
56
+#define AVB_AECP_AEM_CMD_GET_VIDEO_FORMAT          0x000b
57
+#define AVB_AECP_AEM_CMD_SET_SENSOR_FORMAT         0x000c
58
+#define AVB_AECP_AEM_CMD_GET_SENSOR_FORMAT         0x000d
59
+#define AVB_AECP_AEM_CMD_SET_STREAM_INFO           0x000e
60
+#define AVB_AECP_AEM_CMD_GET_STREAM_INFO           0x000f
61
+#define AVB_AECP_AEM_CMD_SET_NAME              0x0010
62
+#define AVB_AECP_AEM_CMD_GET_NAME              0x0011
63
+#define AVB_AECP_AEM_CMD_SET_ASSOCIATION_ID            0x0012
64
+#define AVB_AECP_AEM_CMD_GET_ASSOCIATION_ID            0x0013
65
+#define AVB_AECP_AEM_CMD_SET_SAMPLING_RATE         0x0014
66
+#define AVB_AECP_AEM_CMD_GET_SAMPLING_RATE         0x0015
67
+#define AVB_AECP_AEM_CMD_SET_CLOCK_SOURCE          0x0016
68
+#define AVB_AECP_AEM_CMD_GET_CLOCK_SOURCE          0x0017
69
+#define AVB_AECP_AEM_CMD_SET_CONTROL               0x0018
70
+#define AVB_AECP_AEM_CMD_GET_CONTROL               0x0019
71
+#define AVB_AECP_AEM_CMD_INCREMENT_CONTROL         0x001a
72
+#define AVB_AECP_AEM_CMD_DECREMENT_CONTROL         0x001b
73
+#define AVB_AECP_AEM_CMD_SET_SIGNAL_SELECTOR           0x001c
74
+#define AVB_AECP_AEM_CMD_GET_SIGNAL_SELECTOR           0x001d
75
+#define AVB_AECP_AEM_CMD_SET_MIXER             0x001e
76
+#define AVB_AECP_AEM_CMD_GET_MIXER             0x001f
77
+#define AVB_AECP_AEM_CMD_SET_MATRIX                0x0020
78
+#define AVB_AECP_AEM_CMD_GET_MATRIX                0x0021
79
+#define AVB_AECP_AEM_CMD_START_STREAMING           0x0022
80
+#define AVB_AECP_AEM_CMD_STOP_STREAMING                0x0023
81
+#define AVB_AECP_AEM_CMD_REGISTER_UNSOLICITED_NOTIFICATION 0x0024
82
+#define AVB_AECP_AEM_CMD_DEREGISTER_UNSOLICITED_NOTIFICATION   0x0025
83
+#define AVB_AECP_AEM_CMD_IDENTIFY_NOTIFICATION         0x0026
84
+#define AVB_AECP_AEM_CMD_GET_AVB_INFO              0x0027
85
+#define AVB_AECP_AEM_CMD_GET_AS_PATH               0x0028
86
+#define AVB_AECP_AEM_CMD_GET_COUNTERS              0x0029
87
+#define AVB_AECP_AEM_CMD_REBOOT                    0x002a
88
+#define AVB_AECP_AEM_CMD_GET_AUDIO_MAP             0x002b
89
+#define AVB_AECP_AEM_CMD_ADD_AUDIO_MAPPINGS            0x002c
90
+#define AVB_AECP_AEM_CMD_REMOVE_AUDIO_MAPPINGS         0x002d
91
+#define AVB_AECP_AEM_CMD_GET_VIDEO_MAP             0x002e
92
+#define AVB_AECP_AEM_CMD_ADD_VIDEO_MAPPINGS            0x002f
93
+#define AVB_AECP_AEM_CMD_REMOVE_VIDEO_MAPPINGS         0x0030
94
+#define AVB_AECP_AEM_CMD_GET_SENSOR_MAP                0x0031
95
+#define AVB_AECP_AEM_CMD_ADD_SENSOR_MAPPINGS           0x0032
96
+#define AVB_AECP_AEM_CMD_REMOVE_SENSOR_MAPPINGS            0x0033
97
+#define AVB_AECP_AEM_CMD_START_OPERATION           0x0034
98
+#define AVB_AECP_AEM_CMD_ABORT_OPERATION           0x0035
99
+#define AVB_AECP_AEM_CMD_OPERATION_STATUS          0x0036
100
+#define AVB_AECP_AEM_CMD_AUTH_ADD_KEY              0x0037
101
+#define AVB_AECP_AEM_CMD_AUTH_DELETE_KEY           0x0038
102
+#define AVB_AECP_AEM_CMD_AUTH_GET_KEY_LIST         0x0039
103
+#define AVB_AECP_AEM_CMD_AUTH_GET_KEY              0x003a
104
+#define AVB_AECP_AEM_CMD_AUTH_ADD_KEY_TO_CHAIN         0x003b
105
+#define AVB_AECP_AEM_CMD_AUTH_DELETE_KEY_FROM_CHAIN        0x003c
106
+#define AVB_AECP_AEM_CMD_AUTH_GET_KEYCHAIN_LIST            0x003d
107
+#define AVB_AECP_AEM_CMD_AUTH_GET_IDENTITY         0x003e
108
+#define AVB_AECP_AEM_CMD_AUTH_ADD_TOKEN                0x003f
109
+#define AVB_AECP_AEM_CMD_AUTH_DELETE_TOKEN         0x0040
110
+#define AVB_AECP_AEM_CMD_AUTHENTICATE              0x0041
111
+#define AVB_AECP_AEM_CMD_DEAUTHENTICATE                0x0042
112
+#define AVB_AECP_AEM_CMD_ENABLE_TRANSPORT_SECURITY     0x0043
113
+#define AVB_AECP_AEM_CMD_DISABLE_TRANSPORT_SECURITY        0x0044
114
+#define AVB_AECP_AEM_CMD_ENABLE_STREAM_ENCRYPTION      0x0045
115
+#define AVB_AECP_AEM_CMD_DISABLE_STREAM_ENCRYPTION     0x0046
116
+#define AVB_AECP_AEM_CMD_SET_MEMORY_OBJECT_LENGTH      0x0047
117
+#define AVB_AECP_AEM_CMD_GET_MEMORY_OBJECT_LENGTH      0x0048
118
+#define AVB_AECP_AEM_CMD_SET_STREAM_BACKUP         0x0049
119
+#define AVB_AECP_AEM_CMD_GET_STREAM_BACKUP         0x004a
120
+#define AVB_AECP_AEM_CMD_EXPANSION             0x7fff
121
+
122
+#define AVB_AEM_ACQUIRE_ENTITY_PERSISTENT_FLAG         (1<<0)
123
+
124
+struct avb_packet_aecp_aem_acquire {
125
+   uint32_t flags;
126
+   uint64_t owner_guid;
127
+   uint16_t descriptor_type;
128
+   uint16_t descriptor_id;
129
+} __attribute__ ((__packed__));
130
+
131
+struct avb_packet_aecp_aem_lock {
132
+   uint32_t flags;
133
+   uint64_t locked_guid;
134
+   uint16_t descriptor_type;
135
+   uint16_t descriptor_id;
136
+} __attribute__ ((__packed__));
137
+
138
+struct avb_packet_aecp_aem_read_descriptor {
139
+   uint16_t configuration;
140
+   uint8_t reserved2;
141
+   uint16_t descriptor_type;
142
+   uint16_t descriptor_id;
143
+} __attribute__ ((__packed__));
144
+
145
+struct avb_packet_aecp_aem_setget_configuration {
146
+   uint16_t reserved;
147
+   uint16_t configuration_index;
148
+} __attribute__ ((__packed__));
149
+
150
+struct avb_packet_aecp_aem_setget_stream_format {
151
+   uint16_t descriptor_type;
152
+   uint16_t descriptor_id;
153
+   uint64_t stream_format;
154
+} __attribute__ ((__packed__));
155
+
156
+struct avb_packet_aecp_aem_setget_video_format {
157
+   uint16_t descriptor_type;
158
+   uint16_t descriptor_id;
159
+   uint32_t format_specific;
160
+   uint16_t aspect_ratio;
161
+   uint16_t color_space;
162
+   uint32_t frame_size;
163
+} __attribute__ ((__packed__));
164
+
165
+struct avb_packet_aecp_aem_setget_sensor_format {
166
+   uint16_t descriptor_type;
167
+   uint16_t descriptor_id;
168
+   uint64_t sensor_format;
169
+} __attribute__ ((__packed__));
170
+
171
+
172
+#define AVB_AEM_STREAM_INFO_FLAG_CLASS_B           (1u<<0)
173
+#define AVB_AEM_STREAM_INFO_FLAG_FAST_CONNECT          (1u<<1)
174
+#define AVB_AEM_STREAM_INFO_FLAG_SAVED_STATE           (1u<<2)
175
+#define AVB_AEM_STREAM_INFO_FLAG_STREAMING_WAIT            (1u<<3)
176
+#define AVB_AEM_STREAM_INFO_FLAG_ENCRYPTED_PDU         (1u<<4)
177
+#define AVB_AEM_STREAM_INFO_FLAG_STREAM_VLAN_ID_VALID      (1u<<25)
178
+#define AVB_AEM_STREAM_INFO_FLAG_CONNECTED         (1u<<26)
179
+#define AVB_AEM_STREAM_INFO_FLAG_MSRP_FAILURE_VALID        (1u<<27)
180
+#define AVB_AEM_STREAM_INFO_FLAG_STREAM_DEST_MAC_VALID     (1u<<28)
181
+#define AVB_AEM_STREAM_INFO_FLAG_MSRP_ACC_LAT_VALID        (1u<<29)
182
+#define AVB_AEM_STREAM_INFO_FLAG_STREAM_ID_VALID       (1u<<30)
183
+#define AVB_AEM_STREAM_INFO_FLAG_STREAM_FORMAT_VALID       (1u<<31)
184
+
185
+struct avb_packet_aecp_aem_setget_stream_info {
186
+   uint16_t descriptor_type;
187
+   uint16_t descriptor_index;
188
+   uint32_t aem_stream_info_flags;
189
+   uint64_t stream_format;
190
+   uint64_t stream_id;
191
+   uint32_t msrp_accumulated_latency;
192
+   uint8_t stream_dest_mac6;
193
+   uint8_t msrp_failure_code;
194
+   uint8_t reserved;
195
+   uint64_t msrp_failure_bridge_id;
196
+   uint16_t stream_vlan_id;
197
+   uint16_t reserved2;
198
+} __attribute__ ((__packed__));
199
+
200
+struct avb_packet_aecp_aem_setget_name {
201
pipewire-0.3.56.tar.gz/src/modules/module-avb/aecp.c Added
171
 
1
@@ -0,0 +1,169 @@
2
+/* AVB support
3
+ *
4
+ * Copyright © 2022 Wim Taymans
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a
7
+ * copy of this software and associated documentation files (the "Software"),
8
+ * to deal in the Software without restriction, including without limitation
9
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
+ * and/or sell copies of the Software, and to permit persons to whom the
11
+ * Software is furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice (including the next
14
+ * paragraph) shall be included in all copies or substantial portions of the
15
+ * Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23
+ * DEALINGS IN THE SOFTWARE.
24
+ */
25
+
26
+#include <spa/utils/json.h>
27
+#include <spa/debug/mem.h>
28
+
29
+#include <pipewire/pipewire.h>
30
+
31
+#include "aecp.h"
32
+#include "aecp-aem.h"
33
+#include "internal.h"
34
+
35
+static const uint8_t mac6 = AVB_BROADCAST_MAC;
36
+
37
+struct msg_info {
38
+   uint16_t type;
39
+   const char *name;
40
+   int (*handle) (struct aecp *aecp, const void *p, int len);
41
+};
42
+
43
+static int reply_not_implemented(struct aecp *aecp, const void *p, int len)
44
+{
45
+   struct server *server = aecp->server;
46
+   uint8_t buflen;
47
+   struct avb_ethernet_header *h = (void*)buf;
48
+   struct avb_packet_aecp_header *reply = SPA_PTROFF(h, sizeof(*h), void);
49
+
50
+   memcpy(h, p, len);
51
+   AVB_PACKET_AECP_SET_STATUS(reply, AVB_AECP_STATUS_NOT_IMPLEMENTED);
52
+
53
+   return avb_server_send_packet(server, h->src, AVB_TSN_ETH, buf, len);
54
+}
55
+
56
+static const struct msg_info msg_info = {
57
+   { AVB_AECP_MESSAGE_TYPE_AEM_COMMAND, "aem-command", avb_aecp_aem_handle_command, },
58
+   { AVB_AECP_MESSAGE_TYPE_AEM_RESPONSE, "aem-response", avb_aecp_aem_handle_response, },
59
+   { AVB_AECP_MESSAGE_TYPE_ADDRESS_ACCESS_COMMAND, "address-access-command", NULL, },
60
+   { AVB_AECP_MESSAGE_TYPE_ADDRESS_ACCESS_RESPONSE, "address-access-response", NULL, },
61
+   { AVB_AECP_MESSAGE_TYPE_AVC_COMMAND, "avc-command", NULL, },
62
+   { AVB_AECP_MESSAGE_TYPE_AVC_RESPONSE, "avc-response", NULL, },
63
+   { AVB_AECP_MESSAGE_TYPE_VENDOR_UNIQUE_COMMAND, "vendor-unique-command", NULL, },
64
+   { AVB_AECP_MESSAGE_TYPE_VENDOR_UNIQUE_RESPONSE, "vendor-unique-response", NULL, },
65
+   { AVB_AECP_MESSAGE_TYPE_EXTENDED_COMMAND, "extended-command", NULL, },
66
+   { AVB_AECP_MESSAGE_TYPE_EXTENDED_RESPONSE, "extended-response", NULL, },
67
+};
68
+
69
+static inline const struct msg_info *find_msg_info(uint16_t type, const char *name)
70
+{
71
+   uint32_t i;
72
+   for (i = 0; i < SPA_N_ELEMENTS(msg_info); i++) {
73
+       if ((name == NULL && type == msg_infoi.type) ||
74
+           (name != NULL && spa_streq(name, msg_infoi.name)))
75
+           return &msg_infoi;
76
+   }
77
+   return NULL;
78
+}
79
+
80
+static int aecp_message(void *data, uint64_t now, const void *message, int len)
81
+{
82
+   struct aecp *aecp = data;
83
+   struct server *server = aecp->server;
84
+   const struct avb_ethernet_header *h = message;
85
+   const struct avb_packet_aecp_header *p = SPA_PTROFF(h, sizeof(*h), void);
86
+   const struct msg_info *info;
87
+   int message_type;
88
+
89
+   if (ntohs(h->type) != AVB_TSN_ETH)
90
+       return 0;
91
+   if (memcmp(h->dest, mac, 6) != 0 &&
92
+       memcmp(h->dest, server->mac_addr, 6) != 0)
93
+       return 0;
94
+   if (AVB_PACKET_GET_SUBTYPE(&p->hdr) != AVB_SUBTYPE_AECP)
95
+       return 0;
96
+
97
+   message_type = AVB_PACKET_AECP_GET_MESSAGE_TYPE(p);
98
+
99
+   info = find_msg_info(message_type, NULL);
100
+   if (info == NULL)
101
+       return reply_not_implemented(aecp, message, len);
102
+
103
+   pw_log_debug("got AECP message %s", info->name);
104
+
105
+   if (info->handle == NULL)
106
+       return reply_not_implemented(aecp, message, len);
107
+
108
+   return info->handle(aecp, message, len);
109
+}
110
+
111
+static void aecp_destroy(void *data)
112
+{
113
+   struct aecp *aecp = data;
114
+   spa_hook_remove(&aecp->server_listener);
115
+   free(aecp);
116
+}
117
+
118
+static int do_help(struct aecp *aecp, const char *args, FILE *out)
119
+{
120
+   fprintf(out, "{ \"type\": \"help\","
121
+           "\"text\": \""
122
+             "/adp/help: this help \\n"
123
+           "\" }");
124
+   return 0;
125
+}
126
+
127
+static int aecp_command(void *data, uint64_t now, const char *command, const char *args, FILE *out)
128
+{
129
+   struct aecp *aecp = data;
130
+   int res;
131
+
132
+   if (!spa_strstartswith(command, "/aecp/"))
133
+       return 0;
134
+
135
+   command += strlen("/aecp/");
136
+
137
+   if (spa_streq(command, "help"))
138
+       res = do_help(aecp, args, out);
139
+   else
140
+       res = -ENOTSUP;
141
+
142
+   return res;
143
+}
144
+
145
+static const struct server_events server_events = {
146
+   AVB_VERSION_SERVER_EVENTS,
147
+   .destroy = aecp_destroy,
148
+   .message = aecp_message,
149
+   .command = aecp_command
150
+};
151
+
152
+struct avb_aecp *avb_aecp_register(struct server *server)
153
+{
154
+   struct aecp *aecp;
155
+
156
+   aecp = calloc(1, sizeof(*aecp));
157
+   if (aecp == NULL)
158
+       return NULL;
159
+
160
+   aecp->server = server;
161
+
162
+   avdecc_server_add_listener(server, &aecp->server_listener, &server_events, aecp);
163
+
164
+   return (struct avb_aecp*)aecp;
165
+}
166
+
167
+void avb_aecp_unregister(struct avb_aecp *aecp)
168
+{
169
+   aecp_destroy(aecp);
170
+}
171
pipewire-0.3.56.tar.gz/src/modules/module-avb/aecp.h Added
62
 
1
@@ -0,0 +1,60 @@
2
+/* AVB support
3
+ *
4
+ * Copyright © 2022 Wim Taymans
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a
7
+ * copy of this software and associated documentation files (the "Software"),
8
+ * to deal in the Software without restriction, including without limitation
9
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
+ * and/or sell copies of the Software, and to permit persons to whom the
11
+ * Software is furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice (including the next
14
+ * paragraph) shall be included in all copies or substantial portions of the
15
+ * Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23
+ * DEALINGS IN THE SOFTWARE.
24
+ */
25
+
26
+#ifndef AVB_AECP_H
27
+#define AVB_AECP_H
28
+
29
+#include "packets.h"
30
+#include "internal.h"
31
+
32
+#define AVB_AECP_MESSAGE_TYPE_AEM_COMMAND      0
33
+#define AVB_AECP_MESSAGE_TYPE_AEM_RESPONSE     1
34
+#define AVB_AECP_MESSAGE_TYPE_ADDRESS_ACCESS_COMMAND   2
35
+#define AVB_AECP_MESSAGE_TYPE_ADDRESS_ACCESS_RESPONSE  3
36
+#define AVB_AECP_MESSAGE_TYPE_AVC_COMMAND      4
37
+#define AVB_AECP_MESSAGE_TYPE_AVC_RESPONSE     5
38
+#define AVB_AECP_MESSAGE_TYPE_VENDOR_UNIQUE_COMMAND    6
39
+#define AVB_AECP_MESSAGE_TYPE_VENDOR_UNIQUE_RESPONSE   7
40
+#define AVB_AECP_MESSAGE_TYPE_EXTENDED_COMMAND     14
41
+#define AVB_AECP_MESSAGE_TYPE_EXTENDED_RESPONSE        15
42
+
43
+#define AVB_AECP_STATUS_SUCCESS                0
44
+#define AVB_AECP_STATUS_NOT_IMPLEMENTED            1
45
+
46
+struct avb_packet_aecp_header {
47
+   struct avb_packet_header hdr;
48
+   uint64_t target_guid;
49
+   uint64_t controller_guid;
50
+   uint16_t sequence_id;
51
+} __attribute__ ((__packed__));
52
+
53
+#define AVB_PACKET_AECP_SET_MESSAGE_TYPE(p,v)      AVB_PACKET_SET_SUB1(&(p)->hdr, v)
54
+#define AVB_PACKET_AECP_SET_STATUS(p,v)            AVB_PACKET_SET_SUB2(&(p)->hdr, v)
55
+
56
+#define AVB_PACKET_AECP_GET_MESSAGE_TYPE(p)        AVB_PACKET_GET_SUB1(&(p)->hdr)
57
+#define AVB_PACKET_AECP_GET_STATUS(p)          AVB_PACKET_GET_SUB2(&(p)->hdr)
58
+
59
+struct avb_aecp *avb_aecp_register(struct server *server);
60
+
61
+#endif /* AVB_AECP_H */
62
pipewire-0.3.56.tar.gz/src/modules/module-avb/avb.c Added
110
 
1
@@ -0,0 +1,108 @@
2
+/* PipeWire
3
+ *
4
+ * Copyright © 2022 Wim Taymans
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a
7
+ * copy of this software and associated documentation files (the "Software"),
8
+ * to deal in the Software without restriction, including without limitation
9
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
+ * and/or sell copies of the Software, and to permit persons to whom the
11
+ * Software is furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice (including the next
14
+ * paragraph) shall be included in all copies or substantial portions of the
15
+ * Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23
+ * DEALINGS IN THE SOFTWARE.
24
+ */
25
+
26
+#include "internal.h"
27
+
28
+#include <spa/support/cpu.h>
29
+
30
+struct pw_avb *pw_avb_new(struct pw_context *context,
31
+       struct pw_properties *props, size_t user_data_size)
32
+{
33
+   struct impl *impl;
34
+   const struct spa_support *support;
35
+   uint32_t n_support;
36
+   struct spa_cpu *cpu;
37
+   const char *str;
38
+   int res = 0;
39
+
40
+   impl = calloc(1, sizeof(*impl) + user_data_size);
41
+   if (impl == NULL)
42
+       goto error_exit;
43
+
44
+   if (props == NULL)
45
+       props = pw_properties_new(NULL, NULL);
46
+   if (props == NULL)
47
+       goto error_free;
48
+
49
+   support = pw_context_get_support(context, &n_support);
50
+   cpu = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_CPU);
51
+
52
+   pw_context_conf_update_props(context, "avb.properties", props);
53
+
54
+   if ((str = pw_properties_get(props, "vm.overrides")) != NULL) {
55
+       if (cpu != NULL && spa_cpu_get_vm_type(cpu) != SPA_CPU_VM_NONE)
56
+           pw_properties_update_string(props, str, strlen(str));
57
+       pw_properties_set(props, "vm.overrides", NULL);
58
+   }
59
+
60
+   impl->context = context;
61
+   impl->loop = pw_context_get_main_loop(context);
62
+   impl->props = props;
63
+   impl->core = pw_context_get_object(context, PW_TYPE_INTERFACE_Core);
64
+   if (impl->core == NULL) {
65
+       str = pw_properties_get(props, PW_KEY_REMOTE_NAME);
66
+       impl->core = pw_context_connect(context,
67
+               pw_properties_new(
68
+                   PW_KEY_REMOTE_NAME, str,
69
+                   NULL),
70
+               0);
71
+       impl->do_disconnect = true;
72
+   }
73
+   if (impl->core == NULL) {
74
+       res = -errno;
75
+       pw_log_error("can't connect: %m");
76
+       goto error_free;
77
+   }
78
+
79
+   impl->work_queue = pw_context_get_work_queue(context);
80
+
81
+   spa_list_init(&impl->servers);
82
+
83
+   avdecc_server_new(impl, &props->dict);
84
+
85
+   return (struct pw_avb*)impl;
86
+
87
+error_free:
88
+   free(impl);
89
+error_exit:
90
+   pw_properties_free(props);
91
+   if (res < 0)
92
+       errno = -res;
93
+   return NULL;
94
+}
95
+
96
+static void impl_free(struct impl *impl)
97
+{
98
+   struct server *s;
99
+
100
+   spa_list_consume(s, &impl->servers, link)
101
+       avdecc_server_free(s);
102
+   free(impl);
103
+}
104
+
105
+void pw_avb_destroy(struct pw_avb *avb)
106
+{
107
+   struct impl *impl = (struct impl*)avb;
108
+   impl_free(impl);
109
+}
110
pipewire-0.3.56.tar.gz/src/modules/module-avb/avb.h Added
46
 
1
@@ -0,0 +1,44 @@
2
+/* PipeWire
3
+ *
4
+ * Copyright © 2022 Wim Taymans
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a
7
+ * copy of this software and associated documentation files (the "Software"),
8
+ * to deal in the Software without restriction, including without limitation
9
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
+ * and/or sell copies of the Software, and to permit persons to whom the
11
+ * Software is furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice (including the next
14
+ * paragraph) shall be included in all copies or substantial portions of the
15
+ * Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23
+ * DEALINGS IN THE SOFTWARE.
24
+ */
25
+
26
+#ifndef PIPEWIRE_AVB_H
27
+#define PIPEWIRE_AVB_H
28
+
29
+#ifdef __cplusplus
30
+extern "C" {
31
+#endif
32
+
33
+struct pw_context;
34
+struct pw_properties;
35
+struct pw_avb;
36
+
37
+struct pw_avb *pw_avb_new(struct pw_context *context,
38
+       struct pw_properties *props, size_t user_data_size);
39
+void pw_avb_destroy(struct pw_avb *avb);
40
+
41
+#ifdef __cplusplus
42
+}  /* extern "C" */
43
+#endif
44
+
45
+#endif /* PIPEWIRE_AVB_H */
46
pipewire-0.3.56.tar.gz/src/modules/module-avb/avdecc.c Added
201
 
1
@@ -0,0 +1,335 @@
2
+/* PipeWire
3
+ *
4
+ * Copyright © 2022 Wim Taymans
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a
7
+ * copy of this software and associated documentation files (the "Software"),
8
+ * to deal in the Software without restriction, including without limitation
9
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
+ * and/or sell copies of the Software, and to permit persons to whom the
11
+ * Software is furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice (including the next
14
+ * paragraph) shall be included in all copies or substantial portions of the
15
+ * Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23
+ * DEALINGS IN THE SOFTWARE.
24
+ */
25
+
26
+#include <linux/if_ether.h>
27
+#include <linux/if_packet.h>
28
+#include <linux/filter.h>
29
+#include <linux/net_tstamp.h>
30
+#include <limits.h>
31
+#include <net/if.h>
32
+#include <arpa/inet.h>
33
+#include <sys/ioctl.h>
34
+#include <unistd.h>
35
+
36
+#include <spa/support/cpu.h>
37
+#include <spa/debug/mem.h>
38
+
39
+#include <pipewire/pipewire.h>
40
+
41
+#include "avb.h"
42
+#include "packets.h"
43
+#include "internal.h"
44
+#include "stream.h"
45
+#include "acmp.h"
46
+#include "adp.h"
47
+#include "aecp.h"
48
+#include "maap.h"
49
+#include "mmrp.h"
50
+#include "msrp.h"
51
+#include "mvrp.h"
52
+#include "descriptors.h"
53
+#include "utils.h"
54
+
55
+#define DEFAULT_INTERVAL   1
56
+
57
+#define server_emit(s,m,v,...) spa_hook_list_call(&s->listener_list, struct server_events, m, v, ##__VA_ARGS__)
58
+#define server_emit_destroy(s)     server_emit(s, destroy, 0)
59
+#define server_emit_message(s,n,m,l)   server_emit(s, message, 0, n, m, l)
60
+#define server_emit_periodic(s,n)  server_emit(s, periodic, 0, n)
61
+#define server_emit_command(s,n,c,a,f) server_emit(s, command, 0, n, c, a, f)
62
+
63
+static void on_timer_event(void *data, uint64_t expirations)
64
+{
65
+   struct server *server = data;
66
+   struct timespec now;
67
+   clock_gettime(CLOCK_REALTIME, &now);
68
+   server_emit_periodic(server, SPA_TIMESPEC_TO_NSEC(&now));
69
+}
70
+
71
+static void on_socket_data(void *data, int fd, uint32_t mask)
72
+{
73
+   struct server *server = data;
74
+   struct timespec now;
75
+
76
+   if (mask & SPA_IO_IN) {
77
+       int len;
78
+       uint8_t buffer2048;
79
+
80
+       len = recv(fd, buffer, sizeof(buffer), 0);
81
+
82
+       if (len < 0) {
83
+           pw_log_warn("got recv error: %m");
84
+       }
85
+       else if (len < (int)sizeof(struct avb_packet_header)) {
86
+           pw_log_warn("short packet received (%d < %d)", len,
87
+                   (int)sizeof(struct avb_packet_header));
88
+       } else {
89
+           clock_gettime(CLOCK_REALTIME, &now);
90
+           server_emit_message(server, SPA_TIMESPEC_TO_NSEC(&now), buffer, len);
91
+       }
92
+   }
93
+}
94
+
95
+int avb_server_send_packet(struct server *server, const uint8_t dest6,
96
+       uint16_t type, void *data, size_t size)
97
+{
98
+   struct avb_ethernet_header *hdr = (struct avb_ethernet_header*)data;
99
+   int res = 0;
100
+
101
+   memcpy(hdr->dest, dest, ETH_ALEN);
102
+   memcpy(hdr->src, server->mac_addr, ETH_ALEN);
103
+   hdr->type = htons(type);
104
+
105
+   if (send(server->source->fd, data, size, 0) < 0) {
106
+       res = -errno;
107
+       pw_log_warn("got send error: %m");
108
+   }
109
+   return res;
110
+}
111
+
112
+static int load_filter(int fd, uint16_t eth, const uint8_t dest6, const uint8_t mac6)
113
+{
114
+   struct sock_fprog filter;
115
+   struct sock_filter bpf_code = {
116
+       BPF_STMT(BPF_LD|BPF_H|BPF_ABS,  12),
117
+       BPF_JUMP(BPF_JMP|BPF_JEQ,       eth,        0, 8),
118
+       BPF_STMT(BPF_LD|BPF_W|BPF_ABS,  2),
119
+       BPF_JUMP(BPF_JMP|BPF_JEQ,       (dest2 << 24) |
120
+                       (dest3 << 16) |
121
+                       (dest4 <<  8) |
122
+                       (dest5),  0, 2),
123
+       BPF_STMT(BPF_LD|BPF_H|BPF_ABS,  0),
124
+       BPF_JUMP(BPF_JMP|BPF_JEQ,       (dest0 << 8) |
125
+                       (dest1),  3, 4),
126
+       BPF_JUMP(BPF_JMP|BPF_JEQ,       (mac2 << 24) |
127
+                       (mac3 << 16) |
128
+                       (mac4 <<  8) |
129
+                       (mac5),   0, 3),
130
+       BPF_STMT(BPF_LD|BPF_H|BPF_ABS,  0),
131
+       BPF_JUMP(BPF_JMP|BPF_JEQ,       (mac0 <<  8) |
132
+                       (mac1), 0, 1),
133
+       BPF_STMT(BPF_RET,               0x00040000),
134
+       BPF_STMT(BPF_RET,               0x00000000),
135
+   };
136
+   filter.len = sizeof(bpf_code) / 8;
137
+   filter.filter = bpf_code;
138
+
139
+   if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER,
140
+               &filter, sizeof(filter)) < 0) {
141
+       pw_log_error("setsockopt(ATTACH_FILTER) failed: %m");
142
+       return -errno;
143
+   }
144
+   return 0;
145
+}
146
+
147
+int avb_server_make_socket(struct server *server, uint16_t type, const uint8_t mac6)
148
+{
149
+   int fd, res;
150
+   struct ifreq req;
151
+   struct packet_mreq mreq;
152
+   struct sockaddr_ll sll;
153
+
154
+   fd = socket(AF_PACKET, SOCK_RAW|SOCK_NONBLOCK, htons(ETH_P_ALL));
155
+   if (fd < 0) {
156
+       pw_log_error("socket() failed: %m");
157
+       return -errno;
158
+   }
159
+
160
+   spa_zero(req);
161
+   snprintf(req.ifr_name, sizeof(req.ifr_name), "%s", server->ifname);
162
+   if (ioctl(fd, SIOCGIFINDEX, &req) < 0) {
163
+       res = -errno;
164
+       pw_log_error("SIOCGIFINDEX %s failed: %m", server->ifname);
165
+       goto error_close;
166
+   }
167
+   server->ifindex = req.ifr_ifindex;
168
+
169
+   spa_zero(req);
170
+   snprintf(req.ifr_name, sizeof(req.ifr_name), "%s", server->ifname);
171
+   if (ioctl(fd, SIOCGIFHWADDR, &req) < 0) {
172
+       res = -errno;
173
+       pw_log_error("SIOCGIFHWADDR %s failed: %m", server->ifname);
174
+       goto error_close;
175
+   }
176
+   memcpy(server->mac_addr, req.ifr_hwaddr.sa_data, sizeof(server->mac_addr));
177
+
178
+   server->entity_id = (uint64_t)server->mac_addr0 << 56 |
179
+           (uint64_t)server->mac_addr1 << 48 |
180
+           (uint64_t)server->mac_addr2 << 40 |
181
+           (uint64_t)0xff << 32 |
182
+           (uint64_t)0xfe << 24 |
183
+           (uint64_t)server->mac_addr3 << 16 |
184
+           (uint64_t)server->mac_addr4 << 8 |
185
+           (uint64_t)server->mac_addr5;
186
+
187
+   spa_zero(sll);
188
+   sll.sll_family = AF_PACKET;
189
+   sll.sll_protocol = htons(ETH_P_ALL);
190
+   sll.sll_ifindex = server->ifindex;
191
+   if (bind(fd, (struct sockaddr *) &sll, sizeof(sll)) < 0) {
192
+       res = -errno;
193
+       pw_log_error("bind() failed: %m");
194
+       goto error_close;
195
+   }
196
+
197
+   spa_zero(mreq);
198
+   mreq.mr_ifindex = server->ifindex;
199
+   mreq.mr_type = PACKET_MR_MULTICAST;
200
+   mreq.mr_alen = ETH_ALEN;
201
pipewire-0.3.56.tar.gz/src/modules/module-avb/descriptors.h Added
201
 
1
@@ -0,0 +1,274 @@
2
+/* PipeWire
3
+ *
4
+ * Copyright © 2022 Wim Taymans
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a
7
+ * copy of this software and associated documentation files (the "Software"),
8
+ * to deal in the Software without restriction, including without limitation
9
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
+ * and/or sell copies of the Software, and to permit persons to whom the
11
+ * Software is furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice (including the next
14
+ * paragraph) shall be included in all copies or substantial portions of the
15
+ * Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23
+ * DEALINGS IN THE SOFTWARE.
24
+ */
25
+
26
+#include "aecp-aem.h"
27
+#include "aecp-aem-descriptors.h"
28
+#include "internal.h"
29
+
30
+void init_descriptors(struct server *server)
31
+{
32
+   server_add_descriptor(server, AVB_AEM_DESC_STRINGS, 0,
33
+           sizeof(struct avb_aem_desc_strings),
34
+           &(struct avb_aem_desc_strings)
35
+   {
36
+       .string_0 = "PipeWire",
37
+       .string_1 = "Configuration 1",
38
+       .string_2 = "Wim Taymans",
39
+   });
40
+   server_add_descriptor(server, AVB_AEM_DESC_LOCALE, 0,
41
+           sizeof(struct avb_aem_desc_locale),
42
+           &(struct avb_aem_desc_locale)
43
+   {
44
+       .locale_identifier = "en-EN",
45
+       .number_of_strings = htons(1),
46
+       .base_strings = htons(0)
47
+   });
48
+   server_add_descriptor(server, AVB_AEM_DESC_ENTITY, 0,
49
+           sizeof(struct avb_aem_desc_entity),
50
+           &(struct avb_aem_desc_entity)
51
+   {
52
+       .entity_id = htobe64(server->entity_id),
53
+       .entity_model_id = htobe64(0),
54
+       .entity_capabilities = htonl(
55
+           AVB_ADP_ENTITY_CAPABILITY_AEM_SUPPORTED |
56
+           AVB_ADP_ENTITY_CAPABILITY_CLASS_A_SUPPORTED |
57
+           AVB_ADP_ENTITY_CAPABILITY_GPTP_SUPPORTED |
58
+           AVB_ADP_ENTITY_CAPABILITY_AEM_IDENTIFY_CONTROL_INDEX_VALID |
59
+           AVB_ADP_ENTITY_CAPABILITY_AEM_INTERFACE_INDEX_VALID),
60
+
61
+       .talker_stream_sources = htons(8),
62
+       .talker_capabilities = htons(
63
+           AVB_ADP_TALKER_CAPABILITY_IMPLEMENTED |
64
+           AVB_ADP_TALKER_CAPABILITY_AUDIO_SOURCE),
65
+       .listener_stream_sinks = htons(8),
66
+       .listener_capabilities = htons(
67
+           AVB_ADP_LISTENER_CAPABILITY_IMPLEMENTED |
68
+           AVB_ADP_LISTENER_CAPABILITY_AUDIO_SINK),
69
+       .controller_capabilities = htons(0),
70
+       .available_index = htonl(0),
71
+       .association_id = htobe64(0),
72
+       .entity_name = "PipeWire",
73
+       .vendor_name_string = htons(2),
74
+       .model_name_string = htons(0),
75
+       .firmware_version = "0.3.48",
76
+       .group_name = "",
77
+       .serial_number = "",
78
+       .configurations_count = htons(1),
79
+       .current_configuration = htons(0)
80
+   });
81
+   struct {
82
+       struct avb_aem_desc_configuration desc;
83
+       struct avb_aem_desc_descriptor_count descriptor_counts8;
84
+   } __attribute__ ((__packed__)) config =
85
+   {
86
+       {
87
+       .object_name = "Configuration 1",
88
+       .localized_description = htons(1),
89
+       .descriptor_counts_count = htons(8),
90
+       .descriptor_counts_offset = htons(
91
+           4 + sizeof(struct avb_aem_desc_configuration)),
92
+       },
93
+       .descriptor_counts = {
94
+           { htons(AVB_AEM_DESC_AUDIO_UNIT), htons(1) },
95
+           { htons(AVB_AEM_DESC_STREAM_INPUT), htons(1) },
96
+           { htons(AVB_AEM_DESC_STREAM_OUTPUT), htons(1) },
97
+           { htons(AVB_AEM_DESC_AVB_INTERFACE), htons(1) },
98
+           { htons(AVB_AEM_DESC_CLOCK_SOURCE), htons(1) },
99
+           { htons(AVB_AEM_DESC_CONTROL), htons(2) },
100
+           { htons(AVB_AEM_DESC_LOCALE), htons(1) },
101
+           { htons(AVB_AEM_DESC_CLOCK_DOMAIN), htons(1) }
102
+       }
103
+   };
104
+   server_add_descriptor(server, AVB_AEM_DESC_CONFIGURATION, 0,
105
+           sizeof(config), &config);
106
+
107
+   struct {
108
+       struct avb_aem_desc_audio_unit desc;
109
+       struct avb_aem_desc_sampling_rate sampling_rates6;
110
+   } __attribute__ ((__packed__)) audio_unit =
111
+   {
112
+       {
113
+       .object_name = "PipeWire",
114
+       .localized_description = htons(0),
115
+       .clock_domain_index = htons(0),
116
+       .number_of_stream_input_ports = htons(1),
117
+       .base_stream_input_port = htons(0),
118
+       .number_of_stream_output_ports = htons(1),
119
+       .base_stream_output_port = htons(0),
120
+       .number_of_external_input_ports = htons(8),
121
+       .base_external_input_port = htons(0),
122
+       .number_of_external_output_ports = htons(8),
123
+       .base_external_output_port = htons(0),
124
+       .number_of_internal_input_ports = htons(0),
125
+       .base_internal_input_port = htons(0),
126
+       .number_of_internal_output_ports = htons(0),
127
+       .base_internal_output_port = htons(0),
128
+       .number_of_controls = htons(0),
129
+       .base_control = htons(0),
130
+       .number_of_signal_selectors = htons(0),
131
+       .base_signal_selector = htons(0),
132
+       .number_of_mixers = htons(0),
133
+       .base_mixer = htons(0),
134
+       .number_of_matrices = htons(0),
135
+       .base_matrix = htons(0),
136
+       .number_of_splitters = htons(0),
137
+       .base_splitter = htons(0),
138
+       .number_of_combiners = htons(0),
139
+       .base_combiner = htons(0),
140
+       .number_of_demultiplexers = htons(0),
141
+       .base_demultiplexer = htons(0),
142
+       .number_of_multiplexers = htons(0),
143
+       .base_multiplexer = htons(0),
144
+       .number_of_transcoders = htons(0),
145
+       .base_transcoder = htons(0),
146
+       .number_of_control_blocks = htons(0),
147
+       .base_control_block = htons(0),
148
+       .current_sampling_rate = htonl(48000),
149
+       .sampling_rates_offset = htons(
150
+           4 + sizeof(struct avb_aem_desc_audio_unit)),
151
+       .sampling_rates_count = htons(6),
152
+       },
153
+       .sampling_rates = {
154
+           { .pull_frequency = htonl(44100) },
155
+           { .pull_frequency = htonl(48000) },
156
+           { .pull_frequency = htonl(88200) },
157
+           { .pull_frequency = htonl(96000) },
158
+           { .pull_frequency = htonl(176400) },
159
+           { .pull_frequency = htonl(192000) },
160
+       }
161
+   };
162
+   server_add_descriptor(server, AVB_AEM_DESC_AUDIO_UNIT, 0,
163
+           sizeof(audio_unit), &audio_unit);
164
+
165
+   struct {
166
+       struct avb_aem_desc_stream desc;
167
+       uint64_t stream_formats6;
168
+   } __attribute__ ((__packed__)) stream_input_0 =
169
+   {
170
+       {
171
+       .object_name = "Stream Input 1",
172
+       .localized_description = htons(0xffff),
173
+       .clock_domain_index = htons(0),
174
+       .stream_flags = htons(
175
+               AVB_AEM_DESC_STREAM_FLAG_SYNC_SOURCE |
176
+               AVB_AEM_DESC_STREAM_FLAG_CLASS_A),
177
+       .current_format = htobe64(0x00a0020840000800ULL),
178
+       .formats_offset = htons(
179
+           4 + sizeof(struct avb_aem_desc_stream)),
180
+       .number_of_formats = htons(6),
181
+       .backup_talker_entity_id_0 = htobe64(0),
182
+       .backup_talker_unique_id_0 = htons(0),
183
+       .backup_talker_entity_id_1 = htobe64(0),
184
+       .backup_talker_unique_id_1 = htons(0),
185
+       .backup_talker_entity_id_2 = htobe64(0),
186
+       .backup_talker_unique_id_2 = htons(0),
187
+       .backedup_talker_entity_id = htobe64(0),
188
+       .backedup_talker_unique = htons(0),
189
+       .avb_interface_index = htons(0),
190
+       .buffer_length = htons(8)
191
+       },
192
+       .stream_formats = {
193
+           htobe64(0x00a0010860000800ULL),
194
+           htobe64(0x00a0020860000800ULL),
195
+           htobe64(0x00a0030860000800ULL),
196
+           htobe64(0x00a0040860000800ULL),
197
+           htobe64(0x00a0050860000800ULL),
198
+           htobe64(0x00a0060860000800ULL),
199
+       },
200
+   };
201
pipewire-0.3.56.tar.gz/src/modules/module-avb/iec61883.h Added
112
 
1
@@ -0,0 +1,110 @@
2
+/* AVB support
3
+ *
4
+ * Copyright © 2022 Wim Taymans
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a
7
+ * copy of this software and associated documentation files (the "Software"),
8
+ * to deal in the Software without restriction, including without limitation
9
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
+ * and/or sell copies of the Software, and to permit persons to whom the
11
+ * Software is furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice (including the next
14
+ * paragraph) shall be included in all copies or substantial portions of the
15
+ * Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23
+ * DEALINGS IN THE SOFTWARE.
24
+ */
25
+
26
+#ifndef AVB_IEC61883_H
27
+#define AVB_IEC61883_H
28
+
29
+#include "packets.h"
30
+
31
+struct avb_packet_iec61883 {
32
+   uint8_t subtype;
33
+#if __BYTE_ORDER == __BIG_ENDIAN
34
+   unsigned sv:1;
35
+   unsigned version:3;
36
+   unsigned mr:1;
37
+   unsigned _r1:1;
38
+   unsigned gv:1;
39
+   unsigned tv:1;
40
+
41
+   uint8_t seq_number;
42
+
43
+   unsigned _r2:7;
44
+   unsigned tu:1;
45
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
46
+   unsigned tv:1;
47
+   unsigned gv:1;
48
+   unsigned _r1:1;
49
+   unsigned mr:1;
50
+   unsigned version:3;
51
+   unsigned sv:1;
52
+
53
+   uint8_t seq_num;
54
+
55
+   unsigned tu:1;
56
+   unsigned _r2:7;
57
+#endif
58
+   uint64_t stream_id;
59
+   uint32_t timestamp;
60
+   uint32_t gateway_info;
61
+   uint16_t data_len;
62
+#if __BYTE_ORDER == __BIG_ENDIAN
63
+   uint8_t tag:2;
64
+   uint8_t channel:6;
65
+
66
+   uint8_t tcode:4;
67
+   uint8_t app:4;
68
+
69
+   uint8_t qi1:2;      /* CIP Quadlet Indicator 1 */
70
+   uint8_t sid:6;      /* CIP Source ID */
71
+
72
+   uint8_t dbs;        /* CIP Data Block Size */
73
+
74
+   uint8_t fn:2;       /* CIP Fraction Number */
75
+   uint8_t qpc:3;      /* CIP Quadlet Padding Count */
76
+   uint8_t sph:1;      /* CIP Source Packet Header */
77
+   uint8_t _r3:2;
78
+
79
+   uint8_t dbc;        /* CIP Data Block Continuity */
80
+
81
+   uint8_t qi2:2;      /* CIP Quadlet Indicator 2 */
82
+   uint8_t format_id:6;    /* CIP Format ID */
83
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
84
+   uint8_t channel:6;
85
+   uint8_t tag:2;
86
+
87
+   uint8_t app:4;
88
+   uint8_t tcode:4;
89
+
90
+   uint8_t sid:6;      /* CIP Source ID */
91
+   uint8_t qi1:2;      /* CIP Quadlet Indicator 1 */
92
+
93
+   uint8_t dbs;        /* CIP Data Block Size */
94
+
95
+   uint8_t _r3:2;
96
+   uint8_t sph:1;      /* CIP Source Packet Header */
97
+   uint8_t qpc:3;      /* CIP Quadlet Padding Count */
98
+   uint8_t fn:2;       /* CIP Fraction Number */
99
+
100
+   uint8_t dbc;        /* CIP Data Block Continuity */
101
+
102
+   uint8_t format_id:6;    /* CIP Format ID */
103
+   uint8_t qi2:2;      /* CIP Quadlet Indicator 2 */
104
+#endif
105
+   uint8_t fdf;        /* CIP Format Dependent Field */
106
+        uint16_t syt;
107
+
108
+   uint8_t payload0;
109
+} __attribute__ ((__packed__));
110
+
111
+#endif /* AVB_IEC61883_H */
112
pipewire-0.3.56.tar.gz/src/modules/module-avb/internal.h Added
169
 
1
@@ -0,0 +1,167 @@
2
+/* PipeWire
3
+ *
4
+ * Copyright © 2022 Wim Taymans
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a
7
+ * copy of this software and associated documentation files (the "Software"),
8
+ * to deal in the Software without restriction, including without limitation
9
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
+ * and/or sell copies of the Software, and to permit persons to whom the
11
+ * Software is furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice (including the next
14
+ * paragraph) shall be included in all copies or substantial portions of the
15
+ * Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23
+ * DEALINGS IN THE SOFTWARE.
24
+ */
25
+
26
+#ifndef AVB_INTERNAL_H
27
+#define AVB_INTERNAL_H
28
+
29
+#ifdef __cplusplus
30
+extern "C" {
31
+#endif
32
+
33
+#include <pipewire/pipewire.h>
34
+
35
+struct server;
36
+struct avb_mrp;
37
+
38
+#define AVB_TSN_ETH 0x22f0
39
+#define AVB_BROADCAST_MAC { 0x91, 0xe0, 0xf0, 0x01, 0x00, 0x00 };
40
+
41
+struct impl {
42
+   struct pw_loop *loop;
43
+   struct pw_context *context;
44
+   struct spa_hook context_listener;
45
+   struct pw_core *core;
46
+   unsigned do_disconnect:1;
47
+
48
+   struct pw_properties *props;
49
+   struct pw_work_queue *work_queue;
50
+
51
+   struct spa_list servers;
52
+};
53
+
54
+struct server_events {
55
+#define AVB_VERSION_SERVER_EVENTS  0
56
+   uint32_t version;
57
+
58
+   /** the server is destroyed */
59
+   void (*destroy) (void *data);
60
+
61
+   int (*message) (void *data, uint64_t now, const void *message, int len);
62
+
63
+   void (*periodic) (void *data, uint64_t now);
64
+
65
+   int (*command) (void *data, uint64_t now, const char *command, const char *args, FILE *out);
66
+};
67
+
68
+struct descriptor {
69
+   struct spa_list link;
70
+   uint16_t type;
71
+   uint16_t index;
72
+   uint32_t size;
73
+   void *ptr;
74
+};
75
+
76
+struct server {
77
+   struct spa_list link;
78
+   struct impl *impl;
79
+
80
+   char *ifname;
81
+   uint8_t mac_addr6;
82
+   uint64_t entity_id;
83
+   int ifindex;
84
+
85
+   struct spa_source *source;
86
+   struct spa_source *timer;
87
+
88
+   struct spa_hook_list listener_list;
89
+
90
+   struct spa_list descriptors;
91
+   struct spa_list streams;
92
+
93
+   unsigned debug_messages:1;
94
+
95
+   struct avb_mrp *mrp;
96
+   struct avb_mmrp *mmrp;
97
+   struct avb_mvrp *mvrp;
98
+   struct avb_msrp *msrp;
99
+   struct avb_maap *maap;
100
+
101
+   struct avb_msrp_attribute *domain_attr;
102
+};
103
+
104
+#include "stream.h"
105
+
106
+static inline const struct descriptor *server_find_descriptor(struct server *server,
107
+       uint16_t type, uint16_t index)
108
+{
109
+   struct descriptor *d;
110
+   spa_list_for_each(d, &server->descriptors, link) {
111
+       if (d->type == type &&
112
+           d->index == index)
113
+           return d;
114
+   }
115
+   return NULL;
116
+}
117
+static inline void *server_add_descriptor(struct server *server,
118
+       uint16_t type, uint16_t index, size_t size, void *ptr)
119
+{
120
+   struct descriptor *d;
121
+
122
+   if ((d = calloc(1, sizeof(struct descriptor) + size)) == NULL)
123
+       return NULL;
124
+
125
+   d->type = type;
126
+   d->index = index;
127
+   d->size = size;
128
+   d->ptr = SPA_PTROFF(d, sizeof(struct descriptor), void);
129
+   if (ptr)
130
+       memcpy(d->ptr, ptr, size);
131
+   spa_list_append(&server->descriptors, &d->link);
132
+   return d->ptr;
133
+}
134
+
135
+static inline struct stream *server_find_stream(struct server *server,
136
+       enum spa_direction direction, uint16_t index)
137
+{
138
+   struct stream *s;
139
+   spa_list_for_each(s, &server->streams, link) {
140
+       if (s->direction == direction &&
141
+           s->index == index)
142
+           return s;
143
+   }
144
+   return NULL;
145
+}
146
+
147
+struct server *avdecc_server_new(struct impl *impl, struct spa_dict *props);
148
+void avdecc_server_free(struct server *server);
149
+
150
+void avdecc_server_add_listener(struct server *server, struct spa_hook *listener,
151
+       const struct server_events *events, void *data);
152
+
153
+int avb_server_make_socket(struct server *server, uint16_t type, const uint8_t mac6);
154
+
155
+int avb_server_send_packet(struct server *server, const uint8_t dest6,
156
+       uint16_t type, void *data, size_t size);
157
+
158
+struct aecp {
159
+   struct server *server;
160
+   struct spa_hook server_listener;
161
+};
162
+
163
+
164
+#ifdef __cplusplus
165
+}  /* extern "C" */
166
+#endif
167
+
168
+#endif /* AVB_INTERNAL_H */
169
pipewire-0.3.56.tar.gz/src/modules/module-avb/maap.c Added
201
 
1
@@ -0,0 +1,467 @@
2
+/* AVB support
3
+ *
4
+ * Copyright © 2022 Wim Taymans
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a
7
+ * copy of this software and associated documentation files (the "Software"),
8
+ * to deal in the Software without restriction, including without limitation
9
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
+ * and/or sell copies of the Software, and to permit persons to whom the
11
+ * Software is furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice (including the next
14
+ * paragraph) shall be included in all copies or substantial portions of the
15
+ * Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23
+ * DEALINGS IN THE SOFTWARE.
24
+ */
25
+
26
+#include <unistd.h>
27
+
28
+#include <spa/utils/json.h>
29
+
30
+#include <pipewire/pipewire.h>
31
+#include <pipewire/conf.h>
32
+
33
+#include "utils.h"
34
+#include "maap.h"
35
+
36
+#define MAAP_ALLOCATION_POOL_SIZE  0xFE00
37
+#define MAAP_ALLOCATION_POOL_BASE   { 0x91, 0xe0, 0xf0, 0x00, 0x00, 0x00 }
38
+static uint8_t maap_base6 = MAAP_ALLOCATION_POOL_BASE;
39
+
40
+#define MAAP_PROBE_RETRANSMITS     3
41
+
42
+#define MAAP_PROBE_INTERVAL_MS     500
43
+#define MAAP_PROBE_INTERVAL_VAR_MS 100
44
+
45
+#define MAAP_ANNOUNCE_INTERVAL_MS  3000
46
+#define MAAP_ANNOUNCE_INTERVAL_VAR_MS  2000
47
+
48
+struct maap {
49
+   struct server *server;
50
+   struct spa_hook server_listener;
51
+
52
+   struct pw_properties *props;
53
+
54
+   struct spa_source *source;
55
+
56
+#define STATE_IDLE 0
57
+#define STATE_PROBE    1
58
+#define STATE_ANNOUNCE 2
59
+   uint32_t state;
60
+   uint64_t timeout;
61
+   uint32_t probe_count;
62
+
63
+   unsigned short xsubi3;
64
+
65
+   uint16_t offset;
66
+   uint16_t count;
67
+};
68
+
69
+static const char *message_type_as_string(uint8_t message_type)
70
+{
71
+   switch (message_type) {
72
+   case AVB_MAAP_MESSAGE_TYPE_PROBE:
73
+       return "PROBE";
74
+   case AVB_MAAP_MESSAGE_TYPE_DEFEND:
75
+       return "DEFEND";
76
+   case AVB_MAAP_MESSAGE_TYPE_ANNOUNCE:
77
+       return "ANNOUNCE";
78
+   }
79
+   return "INVALID";
80
+}
81
+
82
+static void maap_message_debug(struct maap *maap, const struct avb_packet_maap *p)
83
+{
84
+   uint32_t v;
85
+   const uint8_t *addr;
86
+
87
+   v = AVB_PACKET_MAAP_GET_MESSAGE_TYPE(p);
88
+   pw_log_info("message-type: %d (%s)", v, message_type_as_string(v));
89
+   pw_log_info("  maap-version: %d", AVB_PACKET_MAAP_GET_MAAP_VERSION(p));
90
+   pw_log_info("  length: %d", AVB_PACKET_GET_LENGTH(&p->hdr));
91
+
92
+   pw_log_info("  stream-id: 0x%"PRIx64, AVB_PACKET_MAAP_GET_STREAM_ID(p));
93
+   addr = AVB_PACKET_MAAP_GET_REQUEST_START(p);
94
+   pw_log_info("  request-start: %02x:%02x:%02x:%02x:%02x:%02x",
95
+           addr0, addr1, addr2, addr3, addr4, addr5);
96
+   pw_log_info("  request-count: %d", AVB_PACKET_MAAP_GET_REQUEST_COUNT(p));
97
+   addr = AVB_PACKET_MAAP_GET_CONFLICT_START(p);
98
+   pw_log_info("  conflict-start: %02x:%02x:%02x:%02x:%02x:%02x",
99
+           addr0, addr1, addr2, addr3, addr4, addr5);
100
+   pw_log_info("  conflict-count: %d", AVB_PACKET_MAAP_GET_CONFLICT_COUNT(p));
101
+}
102
+
103
+#define PROBE_TIMEOUT(n) ((n) + (MAAP_PROBE_INTERVAL_MS + \
104
+                        drand48() * MAAP_PROBE_INTERVAL_VAR_MS) * SPA_NSEC_PER_MSEC)
105
+#define ANNOUNCE_TIMEOUT(n) ((n) + (MAAP_ANNOUNCE_INTERVAL_MS + \
106
+                        drand48() * MAAP_ANNOUNCE_INTERVAL_VAR_MS) * SPA_NSEC_PER_MSEC)
107
+
108
+static int make_new_address(struct maap *maap, uint64_t now, int range)
109
+{
110
+   maap->offset = nrand48(maap->xsubi) % (MAAP_ALLOCATION_POOL_SIZE - range);
111
+   maap->count = range;
112
+   maap->state = STATE_PROBE;
113
+   maap->probe_count = MAAP_PROBE_RETRANSMITS;
114
+   maap->timeout = PROBE_TIMEOUT(now);
115
+   return 0;
116
+}
117
+
118
+static uint16_t maap_check_conflict(struct maap *maap, const uint8_t request_start6,
119
+       uint16_t request_count, uint8_t conflict_start6)
120
+{
121
+   uint16_t our_start, our_end;
122
+   uint16_t req_start, req_end;
123
+   uint16_t conf_start, conf_count = 0;
124
+
125
+   if (memcmp(request_start, maap_base, 4) != 0)
126
+       return 0;
127
+
128
+   our_start = maap->offset;
129
+   our_end = our_start + maap->count;
130
+   req_start = request_start4 << 8 | request_start5;
131
+   req_end = req_start + request_count;
132
+
133
+   if (our_start >= req_start && our_start <= req_end) {
134
+       conf_start = our_start;
135
+       conf_count = SPA_MIN(our_end, req_end) - our_start;
136
+   }
137
+   else if (req_start >= our_start && req_start <= our_end) {
138
+       conf_start = req_start;
139
+       conf_count = SPA_MIN(req_end, our_end) - req_start;
140
+   }
141
+   if (conf_count == 0)
142
+       return 0;
143
+
144
+   conflict_start4 = conf_start >> 8;
145
+   conflict_start5 = conf_start;
146
+   return conf_count;
147
+}
148
+
149
+static int send_packet(struct maap *maap, uint64_t now,
150
+       uint8_t type, const uint8_t conflict_start6, uint16_t conflict_count)
151
+{
152
+   struct avb_ethernet_header *h;
153
+   struct avb_packet_maap *p;
154
+   uint8_t buf1024;
155
+   uint8_t bmac6 = AVB_MAAP_MAC;
156
+   int res = 0;
157
+   uint8_t start6;
158
+
159
+   spa_memzero(buf, sizeof(buf));
160
+   h = (void*)buf;
161
+   p = SPA_PTROFF(h, sizeof(*h), void);
162
+
163
+   memcpy(h->dest, bmac, 6);
164
+   memcpy(h->src, maap->server->mac_addr, 6);
165
+   h->type = htons(AVB_TSN_ETH);
166
+
167
+   p->hdr.subtype = AVB_SUBTYPE_MAAP;
168
+   AVB_PACKET_SET_LENGTH(&p->hdr, sizeof(*p));
169
+
170
+   AVB_PACKET_MAAP_SET_MAAP_VERSION(p, 1);
171
+   AVB_PACKET_MAAP_SET_MESSAGE_TYPE(p, type);
172
+
173
+   memcpy(start, maap_base, 4);
174
+   start4 = maap->offset >> 8;
175
+   start5 = maap->offset;
176
+   AVB_PACKET_MAAP_SET_REQUEST_START(p, start);
177
+   AVB_PACKET_MAAP_SET_REQUEST_COUNT(p, maap->count);
178
+   if (conflict_count) {
179
+       AVB_PACKET_MAAP_SET_CONFLICT_START(p, conflict_start);
180
+       AVB_PACKET_MAAP_SET_CONFLICT_COUNT(p, conflict_count);
181
+   }
182
+
183
+   if (maap->server->debug_messages) {
184
+       pw_log_info("send: %d (%s)", type, message_type_as_string(type));
185
+       maap_message_debug(maap, p);
186
+   }
187
+
188
+   if (send(maap->source->fd, p, sizeof(*h) + sizeof(*p), 0) < 0) {
189
+       res = -errno;
190
+       pw_log_warn("got send error: %m");
191
+   }
192
+   return res;
193
+}
194
+
195
+static int handle_probe(struct maap *maap, uint64_t now, const struct avb_packet_maap *p)
196
+{
197
+   uint8_t conflict_start6;
198
+   uint16_t conflict_count;
199
+
200
+   conflict_count = maap_check_conflict(maap, p->request_start, ntohs(p->request_count),
201
pipewire-0.3.56.tar.gz/src/modules/module-avb/maap.h Added
72
 
1
@@ -0,0 +1,70 @@
2
+/* AVB support
3
+ *
4
+ * Copyright © 2022 Wim Taymans
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a
7
+ * copy of this software and associated documentation files (the "Software"),
8
+ * to deal in the Software without restriction, including without limitation
9
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
+ * and/or sell copies of the Software, and to permit persons to whom the
11
+ * Software is furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice (including the next
14
+ * paragraph) shall be included in all copies or substantial portions of the
15
+ * Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23
+ * DEALINGS IN THE SOFTWARE.
24
+ */
25
+
26
+#ifndef AVB_MAAP_H
27
+#define AVB_MAAP_H
28
+
29
+#include "packets.h"
30
+#include "internal.h"
31
+
32
+#define AVB_TSN_ETH 0x22f0
33
+#define AVB_MAAP_MAC { 0x91, 0xe0, 0xf0, 0x00, 0xff, 0x00 };
34
+
35
+#define AVB_MAAP_MESSAGE_TYPE_PROBE        1
36
+#define AVB_MAAP_MESSAGE_TYPE_DEFEND       2
37
+#define AVB_MAAP_MESSAGE_TYPE_ANNOUNCE     3
38
+
39
+struct avb_packet_maap {
40
+   struct avb_packet_header hdr;
41
+   uint64_t stream_id;
42
+   uint8_t request_start6;
43
+   uint16_t request_count;
44
+   uint8_t conflict_start6;
45
+   uint16_t conflict_count;
46
+} __attribute__ ((__packed__));
47
+
48
+#define AVB_PACKET_MAAP_SET_MESSAGE_TYPE(p,v)      AVB_PACKET_SET_SUB1(&(p)->hdr, v)
49
+#define AVB_PACKET_MAAP_SET_MAAP_VERSION(p,v)      AVB_PACKET_SET_SUB2(&(p)->hdr, v)
50
+#define AVB_PACKET_MAAP_SET_STREAM_ID(p,v)     ((p)->stream_id = htobe64(v))
51
+#define AVB_PACKET_MAAP_SET_REQUEST_START(p,v)     memcpy((p)->request_start, (v), 6)
52
+#define AVB_PACKET_MAAP_SET_REQUEST_COUNT(p,v)     ((p)->request_count = htons(v))
53
+#define AVB_PACKET_MAAP_SET_CONFLICT_START(p,v)        memcpy((p)->conflict_start, (v), 6)
54
+#define AVB_PACKET_MAAP_SET_CONFLICT_COUNT(p,v)        ((p)->conflict_count = htons(v))
55
+
56
+#define AVB_PACKET_MAAP_GET_MESSAGE_TYPE(p)        AVB_PACKET_GET_SUB1(&(p)->hdr)
57
+#define AVB_PACKET_MAAP_GET_MAAP_VERSION(p)        AVB_PACKET_GET_SUB2(&(p)->hdr)
58
+#define AVB_PACKET_MAAP_GET_STREAM_ID(p)       be64toh((p)->stream_id)
59
+#define AVB_PACKET_MAAP_GET_REQUEST_START(p)       ((p)->request_start)
60
+#define AVB_PACKET_MAAP_GET_REQUEST_COUNT(p)       ntohs((p)->request_count)
61
+#define AVB_PACKET_MAAP_GET_CONFLICT_START(p)      ((p)->conflict_start)
62
+#define AVB_PACKET_MAAP_GET_CONFLICT_COUNT(p)      ntohs((p)->conflict_count)
63
+
64
+struct avb_maap;
65
+
66
+struct avb_maap *avb_maap_register(struct server *server);
67
+
68
+int avb_maap_reserve(struct avb_maap *maap, uint32_t count);
69
+int avb_maap_get_address(struct avb_maap *maap, uint8_t addr6, uint32_t index);
70
+
71
+#endif /* AVB_MAAP_H */
72
pipewire-0.3.56.tar.gz/src/modules/module-avb/mmrp.c Added
201
 
1
@@ -0,0 +1,233 @@
2
+/* AVB support
3
+ *
4
+ * Copyright © 2022 Wim Taymans
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a
7
+ * copy of this software and associated documentation files (the "Software"),
8
+ * to deal in the Software without restriction, including without limitation
9
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
+ * and/or sell copies of the Software, and to permit persons to whom the
11
+ * Software is furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice (including the next
14
+ * paragraph) shall be included in all copies or substantial portions of the
15
+ * Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23
+ * DEALINGS IN THE SOFTWARE.
24
+ */
25
+
26
+#include <unistd.h>
27
+
28
+#include <pipewire/pipewire.h>
29
+
30
+#include "utils.h"
31
+#include "mmrp.h"
32
+
33
+static const uint8_t mmrp_mac6 = AVB_MMRP_MAC;
34
+
35
+struct attr {
36
+   struct avb_mmrp_attribute attr;
37
+   struct spa_list link;
38
+};
39
+
40
+struct mmrp {
41
+   struct server *server;
42
+   struct spa_hook server_listener;
43
+
44
+   struct spa_source *source;
45
+
46
+   struct spa_list attributes;
47
+};
48
+
49
+static bool mmrp_check_header(void *data, const void *hdr, size_t *hdr_size, bool *has_params)
50
+{
51
+   const struct avb_packet_mmrp_msg *msg = hdr;
52
+   uint8_t attr_type = msg->attribute_type;
53
+
54
+   if (!AVB_MMRP_ATTRIBUTE_TYPE_VALID(attr_type))
55
+       return false;
56
+
57
+   *hdr_size = sizeof(*msg);
58
+   *has_params = false;
59
+   return true;
60
+}
61
+
62
+static int mmrp_attr_event(void *data, uint64_t now, uint8_t attribute_type, uint8_t event)
63
+{
64
+   struct mmrp *mmrp = data;
65
+   struct attr *a;
66
+   spa_list_for_each(a, &mmrp->attributes, link)
67
+       if (a->attr.type == attribute_type)
68
+           avb_mrp_attribute_update_state(a->attr.mrp, now, event);
69
+   return 0;
70
+}
71
+
72
+static void debug_service_requirement(const struct avb_packet_mmrp_service_requirement *t)
73
+{
74
+   char buf128;
75
+   pw_log_info("service requirement");
76
+   pw_log_info(" %s", avb_utils_format_addr(buf, sizeof(buf), t->addr));
77
+}
78
+
79
+static int process_service_requirement(struct mmrp *mmrp, uint64_t now, uint8_t attr_type,
80
+       const void *m, uint8_t event, uint8_t param, int num)
81
+{
82
+   const struct avb_packet_mmrp_service_requirement *t = m;
83
+   struct attr *a;
84
+
85
+   debug_service_requirement(t);
86
+
87
+   spa_list_for_each(a, &mmrp->attributes, link)
88
+       if (a->attr.type == attr_type &&
89
+           memcmp(a->attr.attr.service_requirement.addr, t->addr, 6) == 0)
90
+           avb_mrp_attribute_rx_event(a->attr.mrp, now, event);
91
+   return 0;
92
+}
93
+
94
+static void debug_process_mac(const struct avb_packet_mmrp_mac *t)
95
+{
96
+   char buf128;
97
+   pw_log_info("mac");
98
+   pw_log_info(" %s", avb_utils_format_addr(buf, sizeof(buf), t->addr));
99
+}
100
+
101
+static int process_mac(struct mmrp *mmrp, uint64_t now, uint8_t attr_type,
102
+       const void *m, uint8_t event, uint8_t param, int num)
103
+{
104
+   const struct avb_packet_mmrp_mac *t = m;
105
+   struct attr *a;
106
+
107
+   debug_process_mac(t);
108
+
109
+   spa_list_for_each(a, &mmrp->attributes, link)
110
+       if (a->attr.type == attr_type &&
111
+           memcmp(a->attr.attr.mac.addr, t->addr, 6) == 0)
112
+           avb_mrp_attribute_rx_event(a->attr.mrp, now, event);
113
+   return 0;
114
+}
115
+
116
+static const struct {
117
+   int (*dispatch) (struct mmrp *mmrp, uint64_t now, uint8_t attr_type,
118
+           const void *m, uint8_t event, uint8_t param, int num);
119
+} dispatch = {
120
+   AVB_MMRP_ATTRIBUTE_TYPE_SERVICE_REQUIREMENT = { process_service_requirement, },
121
+   AVB_MMRP_ATTRIBUTE_TYPE_MAC = { process_mac, },
122
+};
123
+
124
+static int mmrp_process(void *data, uint64_t now, uint8_t attribute_type, const void *value,
125
+           uint8_t event, uint8_t param, int index)
126
+{
127
+   struct mmrp *mmrp = data;
128
+   return dispatchattribute_type.dispatch(mmrp, now,
129
+               attribute_type, value, event, param, index);
130
+}
131
+
132
+static const struct avb_mrp_parse_info info = {
133
+   AVB_VERSION_MRP_PARSE_INFO,
134
+   .check_header = mmrp_check_header,
135
+   .attr_event = mmrp_attr_event,
136
+   .process = mmrp_process,
137
+};
138
+
139
+static int mmrp_message(struct mmrp *mmrp, uint64_t now, const void *message, int len)
140
+{
141
+   pw_log_debug("MMRP");
142
+   return avb_mrp_parse_packet(mmrp->server->mrp,
143
+           now, message, len, &info, mmrp);
144
+}
145
+
146
+static void on_socket_data(void *data, int fd, uint32_t mask)
147
+{
148
+   struct mmrp *mmrp = data;
149
+   struct timespec now;
150
+
151
+   if (mask & SPA_IO_IN) {
152
+       int len;
153
+       uint8_t buffer2048;
154
+
155
+       len = recv(fd, buffer, sizeof(buffer), 0);
156
+
157
+       if (len < 0) {
158
+           pw_log_warn("got recv error: %m");
159
+       }
160
+       else if (len < (int)sizeof(struct avb_packet_header)) {
161
+           pw_log_warn("short packet received (%d < %d)", len,
162
+                   (int)sizeof(struct avb_packet_header));
163
+       } else {
164
+           clock_gettime(CLOCK_REALTIME, &now);
165
+           mmrp_message(mmrp, SPA_TIMESPEC_TO_NSEC(&now), buffer, len);
166
+       }
167
+   }
168
+}
169
+static void mmrp_destroy(void *data)
170
+{
171
+   struct mmrp *mmrp = data;
172
+   spa_hook_remove(&mmrp->server_listener);
173
+   pw_loop_destroy_source(mmrp->server->impl->loop, mmrp->source);
174
+   free(mmrp);
175
+}
176
+
177
+static const struct server_events server_events = {
178
+   AVB_VERSION_SERVER_EVENTS,
179
+   .destroy = mmrp_destroy,
180
+};
181
+
182
+struct avb_mmrp_attribute *avb_mmrp_attribute_new(struct avb_mmrp *m,
183
+       uint8_t type)
184
+{
185
+   struct mmrp *mmrp = (struct mmrp*)m;
186
+   struct avb_mrp_attribute *attr;
187
+   struct attr *a;
188
+
189
+   attr = avb_mrp_attribute_new(mmrp->server->mrp, sizeof(struct attr));
190
+
191
+   a = attr->user_data;
192
+   a->attr.mrp = attr;
193
+   a->attr.type = type;
194
+   spa_list_append(&mmrp->attributes, &a->link);
195
+
196
+   return &a->attr;
197
+}
198
+
199
+struct avb_mmrp *avb_mmrp_register(struct server *server)
200
+{
201
pipewire-0.3.56.tar.gz/src/modules/module-avb/mmrp.h Added
70
 
1
@@ -0,0 +1,68 @@
2
+/* AVB support
3
+ *
4
+ * Copyright © 2022 Wim Taymans
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a
7
+ * copy of this software and associated documentation files (the "Software"),
8
+ * to deal in the Software without restriction, including without limitation
9
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
+ * and/or sell copies of the Software, and to permit persons to whom the
11
+ * Software is furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice (including the next
14
+ * paragraph) shall be included in all copies or substantial portions of the
15
+ * Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23
+ * DEALINGS IN THE SOFTWARE.
24
+ */
25
+
26
+#ifndef AVB_MMRP_H
27
+#define AVB_MMRP_H
28
+
29
+#include "mrp.h"
30
+#include "internal.h"
31
+
32
+#define AVB_MMRP_ETH 0x88f6
33
+#define AVB_MMRP_MAC { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x20 }
34
+
35
+#define AVB_MMRP_ATTRIBUTE_TYPE_SERVICE_REQUIREMENT    1
36
+#define AVB_MMRP_ATTRIBUTE_TYPE_MAC            2
37
+#define AVB_MMRP_ATTRIBUTE_TYPE_VALID(t)       ((t)>=1 && (t)<=2)
38
+
39
+struct avb_packet_mmrp_msg {
40
+   uint8_t attribute_type;
41
+   uint8_t attribute_length;
42
+   uint8_t attribute_list0;
43
+} __attribute__ ((__packed__));
44
+
45
+struct avb_packet_mmrp_service_requirement {
46
+   unsigned char addr6;
47
+} __attribute__ ((__packed__));
48
+
49
+struct avb_packet_mmrp_mac {
50
+   unsigned char addr6;
51
+} __attribute__ ((__packed__));
52
+
53
+struct avb_mmrp;
54
+
55
+struct avb_mmrp_attribute {
56
+   struct avb_mrp_attribute *mrp;
57
+   uint8_t type;
58
+   union {
59
+       struct avb_packet_mmrp_service_requirement service_requirement;
60
+       struct avb_packet_mmrp_mac mac;
61
+   } attr;
62
+};
63
+
64
+struct avb_mmrp_attribute *avb_mmrp_attribute_new(struct avb_mmrp *mmrp,
65
+       uint8_t type);
66
+
67
+struct avb_mmrp *avb_mmrp_register(struct server *server);
68
+
69
+#endif /* AVB_MMRP_H */
70
pipewire-0.3.56.tar.gz/src/modules/module-avb/mrp.c Added
201
 
1
@@ -0,0 +1,612 @@
2
+/* AVB support
3
+ *
4
+ * Copyright © 2022 Wim Taymans
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a
7
+ * copy of this software and associated documentation files (the "Software"),
8
+ * to deal in the Software without restriction, including without limitation
9
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
+ * and/or sell copies of the Software, and to permit persons to whom the
11
+ * Software is furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice (including the next
14
+ * paragraph) shall be included in all copies or substantial portions of the
15
+ * Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23
+ * DEALINGS IN THE SOFTWARE.
24
+ */
25
+
26
+#include <pipewire/pipewire.h>
27
+
28
+#include "mrp.h"
29
+
30
+#define MRP_JOINTIMER_MS   100
31
+#define MRP_LVTIMER_MS     1000
32
+#define MRP_LVATIMER_MS        10000
33
+#define MRP_PERIODTIMER_MS 1000
34
+
35
+#define mrp_emit(s,m,v,...)        spa_hook_list_call(&s->listener_list, struct avb_mrp_events, m, v, ##__VA_ARGS__)
36
+#define mrp_emit_event(s,n,e)      mrp_emit(s,event,0,n,e)
37
+#define mrp_emit_notify(s,n,a,e)   mrp_emit(s,notify,0,n,a,e)
38
+
39
+#define mrp_attribute_emit(a,m,v,...)      spa_hook_list_call(&a->listener_list, struct avb_mrp_attribute_events, m, v, ##__VA_ARGS__)
40
+#define mrp_attribute_emit_notify(a,n,e)   mrp_attribute_emit(a,notify,0,n,e)
41
+
42
+
43
+struct mrp;
44
+
45
+struct attribute {
46
+   struct avb_mrp_attribute attr;
47
+   struct mrp *mrp;
48
+   struct spa_list link;
49
+   uint8_t applicant_state;
50
+   uint8_t registrar_state;
51
+   uint64_t leave_timeout;
52
+   unsigned joined:1;
53
+   struct spa_hook_list listener_list;
54
+};
55
+
56
+struct mrp {
57
+   struct server *server;
58
+   struct spa_hook server_listener;
59
+
60
+   struct spa_hook_list listener_list;
61
+
62
+   struct spa_list attributes;
63
+
64
+   uint64_t periodic_timeout;
65
+   uint64_t leave_all_timeout;
66
+   uint64_t join_timeout;
67
+};
68
+
69
+static void mrp_destroy(void *data)
70
+{
71
+   struct mrp *mrp = data;
72
+   spa_hook_remove(&mrp->server_listener);
73
+   free(mrp);
74
+}
75
+
76
+static void global_event(struct mrp *mrp, uint64_t now, uint8_t event)
77
+{
78
+   struct attribute *a;
79
+   spa_list_for_each(a, &mrp->attributes, link)
80
+       avb_mrp_attribute_update_state(&a->attr, now, event);
81
+   mrp_emit_event(mrp, now, event);
82
+}
83
+
84
+static void mrp_periodic(void *data, uint64_t now)
85
+{
86
+   struct mrp *mrp = data;
87
+   bool leave_all = false;
88
+   struct attribute *a;
89
+
90
+   if (now > mrp->periodic_timeout) {
91
+       if (mrp->periodic_timeout > 0)
92
+           global_event(mrp, now, AVB_MRP_EVENT_PERIODIC);
93
+       mrp->periodic_timeout = now + MRP_PERIODTIMER_MS * SPA_NSEC_PER_MSEC;
94
+   }
95
+   if (now > mrp->leave_all_timeout) {
96
+       if (mrp->leave_all_timeout > 0) {
97
+           global_event(mrp, now, AVB_MRP_EVENT_RX_LVA);
98
+           leave_all = true;
99
+       }
100
+       mrp->leave_all_timeout = now + (MRP_LVATIMER_MS + (random() % (MRP_LVATIMER_MS / 2)))
101
+           * SPA_NSEC_PER_MSEC;
102
+   }
103
+
104
+   if (now > mrp->join_timeout) {
105
+       if (mrp->join_timeout > 0) {
106
+           uint8_t event = leave_all ? AVB_MRP_EVENT_TX_LVA : AVB_MRP_EVENT_TX;
107
+           global_event(mrp, now, event);
108
+       }
109
+       mrp->join_timeout = now + MRP_JOINTIMER_MS * SPA_NSEC_PER_MSEC;
110
+   }
111
+
112
+   spa_list_for_each(a, &mrp->attributes, link) {
113
+       if (a->leave_timeout > 0 && now > a->leave_timeout) {
114
+           a->leave_timeout = 0;
115
+           avb_mrp_attribute_update_state(&a->attr, now, AVB_MRP_EVENT_LV_TIMER);
116
+       }
117
+   }
118
+}
119
+
120
+static const struct server_events server_events = {
121
+   AVB_VERSION_SERVER_EVENTS,
122
+   .destroy = mrp_destroy,
123
+   .periodic = mrp_periodic,
124
+};
125
+
126
+int avb_mrp_parse_packet(struct avb_mrp *mrp, uint64_t now, const void *pkt, int len,
127
+       const struct avb_mrp_parse_info *info, void *data)
128
+{
129
+   uint8_t *e = SPA_PTROFF(pkt, len, uint8_t);
130
+   uint8_t *m = SPA_PTROFF(pkt, sizeof(struct avb_packet_mrp), uint8_t);
131
+
132
+   while (m < e && (m0 != 0 || m1 != 0)) {
133
+       const struct avb_packet_mrp_hdr *hdr = (const struct avb_packet_mrp_hdr*)m;
134
+       uint8_t attr_type = hdr->attribute_type;
135
+       uint8_t attr_len = hdr->attribute_length;
136
+       size_t hdr_size;
137
+       bool has_param;
138
+
139
+       if (!info->check_header(data, hdr, &hdr_size, &has_param))
140
+           return -EINVAL;
141
+
142
+       m += hdr_size;
143
+
144
+       while (m < e && (m0 != 0 || m1 != 0)) {
145
+           const struct avb_packet_mrp_vector *v =
146
+               (const struct avb_packet_mrp_vector*)m;
147
+           uint16_t i, num_values = AVB_MRP_VECTOR_GET_NUM_VALUES(v);
148
+           uint8_t event_len = (num_values+2)/3;
149
+           uint8_t param_len = has_param ? (num_values+3)/4 : 0;
150
+           int plen = sizeof(*v) + attr_len + event_len + param_len;
151
+           const uint8_t *first = v->first_value;
152
+           uint8_t event3, param4 = { 0, };
153
+
154
+           if (m + plen > e)
155
+               return -EPROTO;
156
+
157
+           if (v->lva)
158
+               info->attr_event(data, now, attr_type, AVB_MRP_EVENT_RX_LVA);
159
+
160
+           for (i = 0; i < num_values; i++) {
161
+               if (i % 3 == 0) {
162
+                   uint8_t ep = firstattr_len + i/3;
163
+                   event2 = ep % 6; ep /= 6;
164
+                   event1 = ep % 6; ep /= 6;
165
+                   event0 = ep % 6;
166
+               }
167
+               if (has_param && (i % 4 == 0)) {
168
+                   uint8_t ep = firstattr_len + event_len + i/4;
169
+                   param3 = ep % 4; ep /= 4;
170
+                   param2 = ep % 4; ep /= 4;
171
+                   param1 = ep % 4; ep /= 4;
172
+                   param0 = ep % 4;
173
+               }
174
+               info->process(data, now, attr_type, first,
175
+                       eventi%3, parami%4, i);
176
+           }
177
+           m += plen;
178
+       }
179
+       m += 2;
180
+   }
181
+   return 0;
182
+}
183
+
184
+const char *avb_mrp_notify_name(uint8_t notify)
185
+{
186
+   switch(notify) {
187
+   case AVB_MRP_NOTIFY_NEW:
188
+       return "new";
189
+   case AVB_MRP_NOTIFY_JOIN:
190
+       return "join";
191
+   case AVB_MRP_NOTIFY_LEAVE:
192
+       return "leave";
193
+   }
194
+   return "unknown";
195
+}
196
+
197
+const char *avb_mrp_send_name(uint8_t send)
198
+{
199
+   switch(send) {
200
+   case AVB_MRP_SEND_NEW:
201
pipewire-0.3.56.tar.gz/src/modules/module-avb/mrp.h Added
183
 
1
@@ -0,0 +1,181 @@
2
+/* AVB support
3
+ *
4
+ * Copyright © 2022 Wim Taymans
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a
7
+ * copy of this software and associated documentation files (the "Software"),
8
+ * to deal in the Software without restriction, including without limitation
9
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
+ * and/or sell copies of the Software, and to permit persons to whom the
11
+ * Software is furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice (including the next
14
+ * paragraph) shall be included in all copies or substantial portions of the
15
+ * Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23
+ * DEALINGS IN THE SOFTWARE.
24
+ */
25
+
26
+#ifndef AVB_MRP_H
27
+#define AVB_MRP_H
28
+
29
+#include "packets.h"
30
+#include "internal.h"
31
+
32
+#define AVB_MRP_PROTOCOL_VERSION   0
33
+
34
+struct avb_packet_mrp {
35
+   struct avb_ethernet_header eth;
36
+   uint8_t version;
37
+} __attribute__ ((__packed__));
38
+
39
+struct avb_packet_mrp_hdr {
40
+   uint8_t attribute_type;
41
+   uint8_t attribute_length;
42
+} __attribute__ ((__packed__));
43
+
44
+struct avb_packet_mrp_vector {
45
+#if __BYTE_ORDER == __BIG_ENDIAN
46
+   unsigned lva:3;
47
+   unsigned nv1:5;
48
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
49
+   unsigned nv1:5;
50
+   unsigned lva:3;
51
+#endif
52
+   uint8_t nv2;
53
+   uint8_t first_value0;
54
+} __attribute__ ((__packed__));
55
+
56
+#define AVB_MRP_VECTOR_SET_NUM_VALUES(a,v) ((a)->nv1 = ((v) >> 8),(a)->nv2 = (v))
57
+#define AVB_MRP_VECTOR_GET_NUM_VALUES(a)   ((a)->nv1 << 8 | (a)->nv2)
58
+
59
+struct avb_packet_mrp_footer {
60
+   uint16_t end_mark;
61
+} __attribute__ ((__packed__));
62
+
63
+/* applicant states */
64
+#define AVB_MRP_VO 0       /* Very anxious Observer */
65
+#define AVB_MRP_VP 1       /* Very anxious Passive */
66
+#define AVB_MRP_VN 2       /* Very anxious New */
67
+#define AVB_MRP_AN 3       /* Anxious New */
68
+#define AVB_MRP_AA 4       /* Anxious Active */
69
+#define AVB_MRP_QA 5       /* Quiet Active */
70
+#define AVB_MRP_LA 6       /* Leaving Active */
71
+#define AVB_MRP_AO 7       /* Anxious Observer */
72
+#define AVB_MRP_QO 8       /* Quiet Observer */
73
+#define AVB_MRP_AP 9       /* Anxious Passive */
74
+#define AVB_MRP_QP 10      /* Quiet Passive */
75
+#define AVB_MRP_LO 11      /* Leaving Observer */
76
+
77
+/* registrar states */
78
+#define AVB_MRP_IN 16
79
+#define AVB_MRP_LV 17
80
+#define AVB_MRP_MT 18
81
+
82
+/* events */
83
+#define AVB_MRP_EVENT_BEGIN        0
84
+#define AVB_MRP_EVENT_NEW      1
85
+#define AVB_MRP_EVENT_JOIN     2
86
+#define AVB_MRP_EVENT_LV       3
87
+#define AVB_MRP_EVENT_TX       4
88
+#define AVB_MRP_EVENT_TX_LVA       5
89
+#define AVB_MRP_EVENT_TX_LVAF      6
90
+#define AVB_MRP_EVENT_RX_NEW       7
91
+#define AVB_MRP_EVENT_RX_JOININ        8
92
+#define AVB_MRP_EVENT_RX_IN        9
93
+#define AVB_MRP_EVENT_RX_JOINMT        10
94
+#define AVB_MRP_EVENT_RX_MT        11
95
+#define AVB_MRP_EVENT_RX_LV        12
96
+#define AVB_MRP_EVENT_RX_LVA       13
97
+#define AVB_MRP_EVENT_FLUSH        14
98
+#define AVB_MRP_EVENT_REDECLARE        15
99
+#define AVB_MRP_EVENT_PERIODIC     16
100
+#define AVB_MRP_EVENT_LV_TIMER     17
101
+#define AVB_MRP_EVENT_LVA_TIMER        18
102
+
103
+/* attribute events */
104
+#define AVB_MRP_ATTRIBUTE_EVENT_NEW    0
105
+#define AVB_MRP_ATTRIBUTE_EVENT_JOININ 1
106
+#define AVB_MRP_ATTRIBUTE_EVENT_IN 2
107
+#define AVB_MRP_ATTRIBUTE_EVENT_JOINMT 3
108
+#define AVB_MRP_ATTRIBUTE_EVENT_MT 4
109
+#define AVB_MRP_ATTRIBUTE_EVENT_LV 5
110
+
111
+#define AVB_MRP_SEND_NEW       1
112
+#define AVB_MRP_SEND_JOININ        2
113
+#define AVB_MRP_SEND_IN            3
114
+#define AVB_MRP_SEND_JOINMT        4
115
+#define AVB_MRP_SEND_MT            5
116
+#define AVB_MRP_SEND_LV            6
117
+
118
+#define AVB_MRP_NOTIFY_NEW     1
119
+#define AVB_MRP_NOTIFY_JOIN        2
120
+#define AVB_MRP_NOTIFY_LEAVE       3
121
+
122
+const char *avb_mrp_notify_name(uint8_t notify);
123
+const char *avb_mrp_send_name(uint8_t send);
124
+
125
+struct avb_mrp_attribute {
126
+   uint8_t pending_send;
127
+   void *user_data;
128
+};
129
+
130
+struct avb_mrp_attribute_events {
131
+#define AVB_VERSION_MRP_ATTRIBUTE_EVENTS   0
132
+   uint32_t version;
133
+
134
+   void (*notify) (void *data, uint64_t now, uint8_t notify);
135
+};
136
+
137
+struct avb_mrp_attribute *avb_mrp_attribute_new(struct avb_mrp *mrp,
138
+       size_t user_size);
139
+void avb_mrp_attribute_destroy(struct avb_mrp_attribute *attr);
140
+
141
+void avb_mrp_attribute_update_state(struct avb_mrp_attribute *attr, uint64_t now, int event);
142
+
143
+void avb_mrp_attribute_rx_event(struct avb_mrp_attribute *attr, uint64_t now, uint8_t event);
144
+
145
+void avb_mrp_attribute_begin(struct avb_mrp_attribute *attr, uint64_t now);
146
+void avb_mrp_attribute_join(struct avb_mrp_attribute *attr, uint64_t now, bool is_new);
147
+void avb_mrp_attribute_leave(struct avb_mrp_attribute *attr, uint64_t now);
148
+
149
+void avb_mrp_attribute_add_listener(struct avb_mrp_attribute *attr, struct spa_hook *listener,
150
+       const struct avb_mrp_attribute_events *events, void *data);
151
+
152
+struct avb_mrp_parse_info {
153
+#define AVB_VERSION_MRP_PARSE_INFO 0
154
+   uint32_t version;
155
+
156
+   bool (*check_header) (void *data, const void *hdr, size_t *hdr_size, bool *has_params);
157
+
158
+   int (*attr_event) (void *data, uint64_t now, uint8_t attribute_type, uint8_t event);
159
+
160
+   int (*process) (void *data, uint64_t now, uint8_t attribute_type, const void *value,
161
+           uint8_t event, uint8_t param, int index);
162
+};
163
+
164
+int avb_mrp_parse_packet(struct avb_mrp *mrp, uint64_t now, const void *pkt, int size,
165
+       const struct avb_mrp_parse_info *cb, void *data);
166
+
167
+struct avb_mrp_events {
168
+#define AVB_VERSION_MRP_EVENTS 0
169
+   uint32_t version;
170
+
171
+   void (*event) (void *data, uint64_t now, uint8_t event);
172
+
173
+   void (*notify) (void *data, uint64_t now, struct avb_mrp_attribute *attr, uint8_t notify);
174
+};
175
+
176
+struct avb_mrp *avb_mrp_new(struct server *server);
177
+void avb_mrp_destroy(struct avb_mrp *mrp);
178
+
179
+void avb_mrp_add_listener(struct avb_mrp *mrp, struct spa_hook *listener,
180
+       const struct avb_mrp_events *events, void *data);
181
+
182
+#endif /* AVB_MRP_H */
183
pipewire-0.3.56.tar.gz/src/modules/module-avb/msrp.c Added
201
 
1
@@ -0,0 +1,459 @@
2
+/* AVB support
3
+ *
4
+ * Copyright © 2022 Wim Taymans
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a
7
+ * copy of this software and associated documentation files (the "Software"),
8
+ * to deal in the Software without restriction, including without limitation
9
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
+ * and/or sell copies of the Software, and to permit persons to whom the
11
+ * Software is furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice (including the next
14
+ * paragraph) shall be included in all copies or substantial portions of the
15
+ * Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23
+ * DEALINGS IN THE SOFTWARE.
24
+ */
25
+
26
+#include <unistd.h>
27
+
28
+#include <spa/debug/mem.h>
29
+
30
+#include <pipewire/pipewire.h>
31
+
32
+#include "utils.h"
33
+#include "msrp.h"
34
+
35
+static const uint8_t msrp_mac6 = AVB_MSRP_MAC;
36
+
37
+struct attr {
38
+   struct avb_msrp_attribute attr;
39
+   struct msrp *msrp;
40
+   struct spa_hook listener;
41
+   struct spa_list link;
42
+};
43
+
44
+struct msrp {
45
+   struct server *server;
46
+   struct spa_hook server_listener;
47
+   struct spa_hook mrp_listener;
48
+
49
+   struct spa_source *source;
50
+
51
+   struct spa_list attributes;
52
+};
53
+
54
+static void debug_msrp_talker_common(const struct avb_packet_msrp_talker *t)
55
+{
56
+   char buf128;
57
+   pw_log_info(" stream-id: %s", avb_utils_format_id(buf, sizeof(buf), be64toh(t->stream_id)));
58
+   pw_log_info(" dest-addr: %s", avb_utils_format_addr(buf, sizeof(buf), t->dest_addr));
59
+   pw_log_info(" vlan-id:   %d", ntohs(t->vlan_id));
60
+   pw_log_info(" tspec-max-frame-size: %d", ntohs(t->tspec_max_frame_size));
61
+   pw_log_info(" tspec-max-interval-frames: %d", ntohs(t->tspec_max_interval_frames));
62
+   pw_log_info(" priority: %d", t->priority);
63
+   pw_log_info(" rank: %d", t->rank);
64
+   pw_log_info(" accumulated-latency: %d", ntohl(t->accumulated_latency));
65
+}
66
+
67
+static void debug_msrp_talker(const struct avb_packet_msrp_talker *t)
68
+{
69
+   pw_log_info("talker");
70
+   debug_msrp_talker_common(t);
71
+}
72
+
73
+static void notify_talker(struct msrp *msrp, uint64_t now, struct attr *attr, uint8_t notify)
74
+{
75
+   pw_log_info("> notify talker: %s", avb_mrp_notify_name(notify));
76
+   debug_msrp_talker(&attr->attr.attr.talker);
77
+}
78
+
79
+static int process_talker(struct msrp *msrp, uint64_t now, uint8_t attr_type,
80
+       const void *m, uint8_t event, uint8_t param, int num)
81
+{
82
+   const struct avb_packet_msrp_talker *t = m;
83
+   struct attr *a;
84
+   spa_list_for_each(a, &msrp->attributes, link)
85
+       if (a->attr.type == attr_type &&
86
+           a->attr.attr.talker.stream_id == t->stream_id) {
87
+           a->attr.attr.talker = *t;
88
+           avb_mrp_attribute_rx_event(a->attr.mrp, now, event);
89
+       }
90
+   return 0;
91
+}
92
+static int encode_talker(struct msrp *msrp, struct attr *a, void *m)
93
+{
94
+   struct avb_packet_msrp_msg *msg = m;
95
+   struct avb_packet_mrp_vector *v;
96
+   struct avb_packet_msrp_talker *t;
97
+   struct avb_packet_mrp_footer *f;
98
+   uint8_t *ev;
99
+   size_t attr_list_length = sizeof(*v) + sizeof(*t) + sizeof(*f) + 1;
100
+
101
+   msg->attribute_type = AVB_MSRP_ATTRIBUTE_TYPE_TALKER_ADVERTISE;
102
+   msg->attribute_length = sizeof(*t);
103
+   msg->attribute_list_length = htons(attr_list_length);
104
+
105
+   v = (struct avb_packet_mrp_vector *)msg->attribute_list;
106
+   v->lva = 0;
107
+   AVB_MRP_VECTOR_SET_NUM_VALUES(v, 1);
108
+
109
+   t = (struct avb_packet_msrp_talker *)v->first_value;
110
+   *t = a->attr.attr.talker;
111
+
112
+   ev = SPA_PTROFF(t, sizeof(*t), uint8_t);
113
+   *ev = a->attr.mrp->pending_send * 6 * 6;
114
+
115
+   f = SPA_PTROFF(ev, sizeof(*ev), struct avb_packet_mrp_footer);
116
+   f->end_mark = 0;
117
+
118
+   return attr_list_length + sizeof(*msg);
119
+}
120
+
121
+
122
+static void debug_msrp_talker_fail(const struct avb_packet_msrp_talker_fail *t)
123
+{
124
+   char buf128;
125
+   pw_log_info("talker fail");
126
+   debug_msrp_talker_common(&t->talker);
127
+   pw_log_info(" bridge-id: %s", avb_utils_format_id(buf, sizeof(buf), be64toh(t->bridge_id)));
128
+   pw_log_info(" failure-code: %d", t->failure_code);
129
+}
130
+
131
+static int process_talker_fail(struct msrp *msrp, uint64_t now, uint8_t attr_type,
132
+       const void *m, uint8_t event, uint8_t param, int num)
133
+{
134
+   const struct avb_packet_msrp_talker_fail *t = m;
135
+   struct attr *a;
136
+
137
+   debug_msrp_talker_fail(t);
138
+
139
+   spa_list_for_each(a, &msrp->attributes, link)
140
+       if (a->attr.type == attr_type &&
141
+           a->attr.attr.talker_fail.talker.stream_id == t->talker.stream_id)
142
+           avb_mrp_attribute_rx_event(a->attr.mrp, now, event);
143
+   return 0;
144
+}
145
+
146
+static void debug_msrp_listener(const struct avb_packet_msrp_listener *l, uint8_t param)
147
+{
148
+   char buf128;
149
+   pw_log_info("listener");
150
+   pw_log_info(" %s", avb_utils_format_id(buf, sizeof(buf), be64toh(l->stream_id)));
151
+   pw_log_info(" %d", param);
152
+}
153
+
154
+static void notify_listener(struct msrp *msrp, uint64_t now, struct attr *attr, uint8_t notify)
155
+{
156
+   pw_log_info("> notify listener: %s", avb_mrp_notify_name(notify));
157
+   debug_msrp_listener(&attr->attr.attr.listener, attr->attr.param);
158
+}
159
+
160
+static int process_listener(struct msrp *msrp, uint64_t now, uint8_t attr_type,
161
+       const void *m, uint8_t event, uint8_t param, int num)
162
+{
163
+   const struct avb_packet_msrp_listener *l = m;
164
+   struct attr *a;
165
+   spa_list_for_each(a, &msrp->attributes, link)
166
+       if (a->attr.type == attr_type &&
167
+           a->attr.attr.listener.stream_id == l->stream_id)
168
+           avb_mrp_attribute_rx_event(a->attr.mrp, now, event);
169
+   return 0;
170
+}
171
+static int encode_listener(struct msrp *msrp, struct attr *a, void *m)
172
+{
173
+   struct avb_packet_msrp_msg *msg = m;
174
+   struct avb_packet_mrp_vector *v;
175
+   struct avb_packet_msrp_listener *l;
176
+   struct avb_packet_mrp_footer *f;
177
+   uint8_t *ev;
178
+   size_t attr_list_length = sizeof(*v) + sizeof(*l) + sizeof(*f) + 1 + 1;
179
+
180
+   msg->attribute_type = AVB_MSRP_ATTRIBUTE_TYPE_LISTENER;
181
+   msg->attribute_length = sizeof(*l);
182
+   msg->attribute_list_length = htons(attr_list_length);
183
+
184
+   v = (struct avb_packet_mrp_vector *)msg->attribute_list;
185
+   v->lva = 0;
186
+   AVB_MRP_VECTOR_SET_NUM_VALUES(v, 1);
187
+
188
+   l = (struct avb_packet_msrp_listener *)v->first_value;
189
+   *l = a->attr.attr.listener;
190
+
191
+   ev = SPA_PTROFF(l, sizeof(*l), uint8_t);
192
+   *ev = a->attr.mrp->pending_send * 6 * 6;
193
+
194
+   ev = SPA_PTROFF(ev, sizeof(*ev), uint8_t);
195
+   *ev = a->attr.param * 4 * 4 * 4;
196
+
197
+   f = SPA_PTROFF(ev, sizeof(*ev), struct avb_packet_mrp_footer);
198
+   f->end_mark = 0;
199
+
200
+   return attr_list_length + sizeof(*msg);
201
pipewire-0.3.56.tar.gz/src/modules/module-avb/msrp.h Added
136
 
1
@@ -0,0 +1,134 @@
2
+/* AVB support
3
+ *
4
+ * Copyright © 2022 Wim Taymans
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a
7
+ * copy of this software and associated documentation files (the "Software"),
8
+ * to deal in the Software without restriction, including without limitation
9
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
+ * and/or sell copies of the Software, and to permit persons to whom the
11
+ * Software is furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice (including the next
14
+ * paragraph) shall be included in all copies or substantial portions of the
15
+ * Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23
+ * DEALINGS IN THE SOFTWARE.
24
+ */
25
+
26
+#ifndef AVB_MSRP_H
27
+#define AVB_MSRP_H
28
+
29
+#include "internal.h"
30
+#include "mrp.h"
31
+
32
+#define AVB_MSRP_ETH 0x22ea
33
+#define AVB_MSRP_MAC { 0x01, 0x80, 0xc2, 0x00, 0x00, 0xe };
34
+
35
+#define AVB_MSRP_ATTRIBUTE_TYPE_TALKER_ADVERTISE   1
36
+#define AVB_MSRP_ATTRIBUTE_TYPE_TALKER_FAILED      2
37
+#define AVB_MSRP_ATTRIBUTE_TYPE_LISTENER       3
38
+#define AVB_MSRP_ATTRIBUTE_TYPE_DOMAIN         4
39
+#define AVB_MSRP_ATTRIBUTE_TYPE_VALID(t)       ((t)>=1 && (t)<=4)
40
+
41
+struct avb_packet_msrp_msg {
42
+   uint8_t attribute_type;
43
+   uint8_t attribute_length;
44
+   uint16_t attribute_list_length;
45
+   uint8_t attribute_list0;
46
+} __attribute__ ((__packed__));
47
+
48
+#define AVB_MSRP_TSPEC_MAX_INTERVAL_FRAMES_DEFAULT 1
49
+#define AVB_MSRP_RANK_DEFAULT              1
50
+#define AVB_MSRP_PRIORITY_DEFAULT          3
51
+
52
+struct avb_packet_msrp_talker {
53
+   uint64_t stream_id;
54
+   uint8_t dest_addr6;
55
+   uint16_t vlan_id;
56
+   uint16_t tspec_max_frame_size;
57
+   uint16_t tspec_max_interval_frames;
58
+#if __BYTE_ORDER == __BIG_ENDIAN
59
+   unsigned priority:3;
60
+   unsigned rank:1;
61
+   unsigned reserved:4;
62
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
63
+   unsigned reserved:4;
64
+   unsigned rank:1;
65
+   unsigned priority:3;
66
+#endif
67
+   uint32_t accumulated_latency;
68
+} __attribute__ ((__packed__));
69
+
70
+/* failure codes */
71
+#define AVB_MRP_FAIL_BANDWIDTH         1
72
+#define AVB_MRP_FAIL_BRIDGE            2
73
+#define AVB_MRP_FAIL_TC_BANDWIDTH      3
74
+#define AVB_MRP_FAIL_ID_BUSY           4
75
+#define AVB_MRP_FAIL_DSTADDR_BUSY      5
76
+#define AVB_MRP_FAIL_PREEMPTED         6
77
+#define AVB_MRP_FAIL_LATENCY_CHNG      7
78
+#define AVB_MRP_FAIL_PORT_NOT_AVB      8
79
+#define AVB_MRP_FAIL_DSTADDR_FULL      9
80
+#define AVB_MRP_FAIL_AVB_MRP_RESOURCE      10
81
+#define AVB_MRP_FAIL_MMRP_RESOURCE     11
82
+#define AVB_MRP_FAIL_DSTADDR_FAIL      12
83
+#define AVB_MRP_FAIL_PRIO_NOT_SR       13
84
+#define AVB_MRP_FAIL_FRAME_SIZE            14
85
+#define AVB_MRP_FAIL_FANIN_EXCEED      15
86
+#define AVB_MRP_FAIL_STREAM_CHANGE     16
87
+#define AVB_MRP_FAIL_VLAN_BLOCKED      17
88
+#define AVB_MRP_FAIL_VLAN_DISABLED     18
89
+#define AVB_MRP_FAIL_SR_PRIO_ERR       19
90
+
91
+struct avb_packet_msrp_talker_fail {
92
+   struct avb_packet_msrp_talker talker;
93
+   uint64_t bridge_id;
94
+   uint8_t failure_code;
95
+} __attribute__ ((__packed__));
96
+
97
+struct avb_packet_msrp_listener {
98
+   uint64_t stream_id;
99
+} __attribute__ ((__packed__));
100
+
101
+/* domain discovery */
102
+#define AVB_MSRP_CLASS_ID_DEFAULT  6
103
+#define AVB_DEFAULT_VLAN       2
104
+
105
+struct avb_packet_msrp_domain {
106
+   uint8_t sr_class_id;
107
+   uint8_t sr_class_priority;
108
+   uint16_t sr_class_vid;
109
+} __attribute__ ((__packed__));
110
+
111
+#define AVB_MSRP_LISTENER_PARAM_IGNORE     0
112
+#define AVB_MSRP_LISTENER_PARAM_ASKING_FAILED  1
113
+#define AVB_MSRP_LISTENER_PARAM_READY      2
114
+#define AVB_MSRP_LISTENER_PARAM_READY_FAILED   3
115
+
116
+struct avb_msrp_attribute {
117
+   struct avb_mrp_attribute *mrp;
118
+   uint8_t type;
119
+   uint8_t param;
120
+   union {
121
+       struct avb_packet_msrp_talker talker;
122
+       struct avb_packet_msrp_talker_fail talker_fail;
123
+       struct avb_packet_msrp_listener listener;
124
+       struct avb_packet_msrp_domain domain;
125
+   } attr;
126
+};
127
+
128
+struct avb_msrp;
129
+
130
+struct avb_msrp_attribute *avb_msrp_attribute_new(struct avb_msrp *msrp,
131
+       uint8_t type);
132
+
133
+struct avb_msrp *avb_msrp_register(struct server *server);
134
+
135
+#endif /* AVB_MSRP_H */
136
pipewire-0.3.56.tar.gz/src/modules/module-avb/mvrp.c Added
201
 
1
@@ -0,0 +1,297 @@
2
+/* AVB support
3
+ *
4
+ * Copyright © 2022 Wim Taymans
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a
7
+ * copy of this software and associated documentation files (the "Software"),
8
+ * to deal in the Software without restriction, including without limitation
9
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
+ * and/or sell copies of the Software, and to permit persons to whom the
11
+ * Software is furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice (including the next
14
+ * paragraph) shall be included in all copies or substantial portions of the
15
+ * Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23
+ * DEALINGS IN THE SOFTWARE.
24
+ */
25
+
26
+#include <unistd.h>
27
+
28
+#include <pipewire/pipewire.h>
29
+
30
+#include "mvrp.h"
31
+
32
+static const uint8_t mvrp_mac6 = AVB_MVRP_MAC;
33
+
34
+struct attr {
35
+   struct avb_mvrp_attribute attr;
36
+   struct spa_hook listener;
37
+   struct spa_list link;
38
+   struct mvrp *mvrp;
39
+};
40
+
41
+struct mvrp {
42
+   struct server *server;
43
+   struct spa_hook server_listener;
44
+   struct spa_hook mrp_listener;
45
+
46
+   struct spa_source *source;
47
+
48
+   struct spa_list attributes;
49
+};
50
+
51
+static bool mvrp_check_header(void *data, const void *hdr, size_t *hdr_size, bool *has_params)
52
+{
53
+   const struct avb_packet_mvrp_msg *msg = hdr;
54
+   uint8_t attr_type = msg->attribute_type;
55
+
56
+   if (!AVB_MVRP_ATTRIBUTE_TYPE_VALID(attr_type))
57
+       return false;
58
+
59
+   *hdr_size = sizeof(*msg);
60
+   *has_params = false;
61
+   return true;
62
+}
63
+
64
+static int mvrp_attr_event(void *data, uint64_t now, uint8_t attribute_type, uint8_t event)
65
+{
66
+   struct mvrp *mvrp = data;
67
+   struct attr *a;
68
+   spa_list_for_each(a, &mvrp->attributes, link)
69
+       if (a->attr.type == attribute_type)
70
+           avb_mrp_attribute_rx_event(a->attr.mrp, now, event);
71
+   return 0;
72
+}
73
+
74
+static void debug_vid(const struct avb_packet_mvrp_vid *t)
75
+{
76
+   pw_log_info("vid");
77
+   pw_log_info(" %d", ntohs(t->vlan));
78
+}
79
+
80
+static int process_vid(struct mvrp *mvrp, uint64_t now, uint8_t attr_type,
81
+       const void *m, uint8_t event, uint8_t param, int num)
82
+{
83
+   return mvrp_attr_event(mvrp, now, attr_type, event);
84
+}
85
+
86
+static int encode_vid(struct mvrp *mvrp, struct attr *a, void *m)
87
+{
88
+   struct avb_packet_mvrp_msg *msg = m;
89
+   struct avb_packet_mrp_vector *v;
90
+   struct avb_packet_mvrp_vid *d;
91
+   struct avb_packet_mrp_footer *f;
92
+   uint8_t *ev;
93
+   size_t attr_list_length = sizeof(*v) + sizeof(*d) + sizeof(*f) + 1;
94
+
95
+   msg->attribute_type = AVB_MVRP_ATTRIBUTE_TYPE_VID;
96
+   msg->attribute_length = sizeof(*d);
97
+
98
+   v = (struct avb_packet_mrp_vector *)msg->attribute_list;
99
+   v->lva = 0;
100
+   AVB_MRP_VECTOR_SET_NUM_VALUES(v, 1);
101
+
102
+   d = (struct avb_packet_mvrp_vid *)v->first_value;
103
+   *d = a->attr.attr.vid;
104
+
105
+   ev = SPA_PTROFF(d, sizeof(*d), uint8_t);
106
+   *ev = a->attr.mrp->pending_send * 36;
107
+
108
+   f = SPA_PTROFF(ev, sizeof(*ev), struct avb_packet_mrp_footer);
109
+   f->end_mark = 0;
110
+
111
+   return attr_list_length + sizeof(*msg);
112
+}
113
+
114
+static void notify_vid(struct mvrp *mvrp, uint64_t now, struct attr *attr, uint8_t notify)
115
+{
116
+   pw_log_info("> notify vid: %s", avb_mrp_notify_name(notify));
117
+   debug_vid(&attr->attr.attr.vid);
118
+}
119
+
120
+static const struct {
121
+   const char *name;
122
+   int (*process) (struct mvrp *mvrp, uint64_t now, uint8_t attr_type,
123
+           const void *m, uint8_t event, uint8_t param, int num);
124
+   int (*encode) (struct mvrp *mvrp, struct attr *attr, void *m);
125
+   void (*notify) (struct mvrp *mvrp, uint64_t now, struct attr *attr, uint8_t notify);
126
+} dispatch = {
127
+   AVB_MVRP_ATTRIBUTE_TYPE_VID = { "vid", process_vid, encode_vid, notify_vid },
128
+};
129
+
130
+static int mvrp_process(void *data, uint64_t now, uint8_t attribute_type, const void *value,
131
+           uint8_t event, uint8_t param, int index)
132
+{
133
+   struct mvrp *mvrp = data;
134
+   return dispatchattribute_type.process(mvrp, now,
135
+               attribute_type, value, event, param, index);
136
+}
137
+
138
+static const struct avb_mrp_parse_info info = {
139
+   AVB_VERSION_MRP_PARSE_INFO,
140
+   .check_header = mvrp_check_header,
141
+   .attr_event = mvrp_attr_event,
142
+   .process = mvrp_process,
143
+};
144
+
145
+static int mvrp_message(struct mvrp *mvrp, uint64_t now, const void *message, int len)
146
+{
147
+   pw_log_debug("MVRP");
148
+   return avb_mrp_parse_packet(mvrp->server->mrp,
149
+           now, message, len, &info, mvrp);
150
+}
151
+
152
+static void on_socket_data(void *data, int fd, uint32_t mask)
153
+{
154
+   struct mvrp *mvrp = data;
155
+   struct timespec now;
156
+
157
+   if (mask & SPA_IO_IN) {
158
+       int len;
159
+       uint8_t buffer2048;
160
+
161
+       len = recv(fd, buffer, sizeof(buffer), 0);
162
+
163
+       if (len < 0) {
164
+           pw_log_warn("got recv error: %m");
165
+       }
166
+       else if (len < (int)sizeof(struct avb_packet_header)) {
167
+           pw_log_warn("short packet received (%d < %d)", len,
168
+                   (int)sizeof(struct avb_packet_header));
169
+       } else {
170
+           clock_gettime(CLOCK_REALTIME, &now);
171
+           mvrp_message(mvrp, SPA_TIMESPEC_TO_NSEC(&now), buffer, len);
172
+       }
173
+   }
174
+}
175
+
176
+static void mvrp_destroy(void *data)
177
+{
178
+   struct mvrp *mvrp = data;
179
+   spa_hook_remove(&mvrp->server_listener);
180
+   pw_loop_destroy_source(mvrp->server->impl->loop, mvrp->source);
181
+   free(mvrp);
182
+}
183
+
184
+static const struct server_events server_events = {
185
+   AVB_VERSION_SERVER_EVENTS,
186
+   .destroy = mvrp_destroy,
187
+};
188
+
189
+static void mvrp_notify(void *data, uint64_t now, uint8_t notify)
190
+{
191
+   struct attr *a = data;
192
+   struct mvrp *mvrp = a->mvrp;
193
+   return dispatcha->attr.type.notify(mvrp, now, a, notify);
194
+}
195
+
196
+static const struct avb_mrp_attribute_events mrp_attr_events = {
197
+   AVB_VERSION_MRP_ATTRIBUTE_EVENTS,
198
+   .notify = mvrp_notify,
199
+};
200
+
201
pipewire-0.3.56.tar.gz/src/modules/module-avb/mvrp.h Added
64
 
1
@@ -0,0 +1,62 @@
2
+/* AVB support
3
+ *
4
+ * Copyright © 2022 Wim Taymans
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a
7
+ * copy of this software and associated documentation files (the "Software"),
8
+ * to deal in the Software without restriction, including without limitation
9
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
+ * and/or sell copies of the Software, and to permit persons to whom the
11
+ * Software is furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice (including the next
14
+ * paragraph) shall be included in all copies or substantial portions of the
15
+ * Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23
+ * DEALINGS IN THE SOFTWARE.
24
+ */
25
+
26
+#ifndef AVB_MVRP_H
27
+#define AVB_MVRP_H
28
+
29
+#include "mrp.h"
30
+#include "internal.h"
31
+
32
+#define AVB_MVRP_ETH 0x88f5
33
+#define AVB_MVRP_MAC { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x21 };
34
+
35
+struct avb_packet_mvrp_msg {
36
+   uint8_t attribute_type;
37
+   uint8_t attribute_length;
38
+   uint8_t attribute_list0;
39
+} __attribute__ ((__packed__));
40
+
41
+#define AVB_MVRP_ATTRIBUTE_TYPE_VID            1
42
+#define AVB_MVRP_ATTRIBUTE_TYPE_VALID(t)       ((t)==1)
43
+
44
+struct avb_packet_mvrp_vid {
45
+   uint16_t vlan;
46
+} __attribute__ ((__packed__));
47
+
48
+struct avb_mvrp;
49
+
50
+struct avb_mvrp_attribute {
51
+   struct avb_mrp_attribute *mrp;
52
+   uint8_t type;
53
+   union {
54
+       struct avb_packet_mvrp_vid vid;
55
+   } attr;
56
+};
57
+
58
+struct avb_mvrp_attribute *avb_mvrp_attribute_new(struct avb_mvrp *mvrp,
59
+       uint8_t type);
60
+
61
+struct avb_mvrp *avb_mvrp_register(struct server *server);
62
+
63
+#endif /* AVB_MVRP_H */
64
pipewire-0.3.56.tar.gz/src/modules/module-avb/packets.h Added
103
 
1
@@ -0,0 +1,101 @@
2
+/* Spa AVB support
3
+ *
4
+ * Copyright © 2022 Wim Taymans
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a
7
+ * copy of this software and associated documentation files (the "Software"),
8
+ * to deal in the Software without restriction, including without limitation
9
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
+ * and/or sell copies of the Software, and to permit persons to whom the
11
+ * Software is furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice (including the next
14
+ * paragraph) shall be included in all copies or substantial portions of the
15
+ * Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23
+ * DEALINGS IN THE SOFTWARE.
24
+ */
25
+
26
+#ifndef AVB_PACKETS_H
27
+#define AVB_PACKETS_H
28
+
29
+#include <arpa/inet.h>
30
+
31
+#define AVB_SUBTYPE_61883_IIDC     0x00
32
+#define AVB_SUBTYPE_MMA_STREAM     0x01
33
+#define AVB_SUBTYPE_AAF            0x02
34
+#define AVB_SUBTYPE_CVF            0x03
35
+#define AVB_SUBTYPE_CRF            0x04
36
+#define AVB_SUBTYPE_TSCF       0x05
37
+#define AVB_SUBTYPE_SVF            0x06
38
+#define AVB_SUBTYPE_RVF            0x07
39
+#define AVB_SUBTYPE_AEF_CONTINUOUS 0x6E
40
+#define AVB_SUBTYPE_VSF_STREAM     0x6F
41
+#define AVB_SUBTYPE_EF_STREAM      0x7F
42
+#define AVB_SUBTYPE_NTSCF      0x82
43
+#define AVB_SUBTYPE_ESCF       0xEC
44
+#define AVB_SUBTYPE_EECF       0xED
45
+#define AVB_SUBTYPE_AEF_DISCRETE   0xEE
46
+#define AVB_SUBTYPE_ADP            0xFA
47
+#define AVB_SUBTYPE_AECP       0xFB
48
+#define AVB_SUBTYPE_ACMP       0xFC
49
+#define AVB_SUBTYPE_MAAP       0xFE
50
+#define AVB_SUBTYPE_EF_CONTROL     0xFF
51
+
52
+struct avb_ethernet_header {
53
+   uint8_t dest6;
54
+   uint8_t src6;
55
+   uint16_t type;
56
+} __attribute__ ((__packed__));
57
+
58
+struct avb_frame_header {
59
+   uint8_t dest6;
60
+   uint8_t src6;
61
+   uint16_t type;      /* 802.1Q Virtual Lan 0x8100 */
62
+   uint16_t prio_cfi_id;
63
+   uint16_t etype;
64
+} __attribute__ ((__packed__));
65
+
66
+struct avb_packet_header {
67
+   uint8_t subtype;
68
+#if __BYTE_ORDER == __BIG_ENDIAN
69
+   unsigned sv:1;          /* stream_id valid */
70
+   unsigned version:3;
71
+   unsigned subtype_data1:4;
72
+
73
+   unsigned subtype_data2:5;
74
+   unsigned len1:3;
75
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
76
+   unsigned subtype_data1:4;
77
+   unsigned version:3;
78
+   unsigned sv:1;
79
+
80
+   unsigned len1:3;
81
+   unsigned subtype_data2:5;
82
+#elif
83
+#error "Unknown byte order"
84
+#endif
85
+   uint8_t len2:8;
86
+} __attribute__ ((__packed__));
87
+
88
+#define AVB_PACKET_SET_SUBTYPE(p,v)    ((p)->subtype = (v))
89
+#define AVB_PACKET_SET_SV(p,v)     ((p)->sv = (v))
90
+#define AVB_PACKET_SET_VERSION(p,v)    ((p)->version = (v))
91
+#define AVB_PACKET_SET_SUB1(p,v)   ((p)->subtype_data1 = (v))
92
+#define AVB_PACKET_SET_SUB2(p,v)   ((p)->subtype_data2 = (v))
93
+#define AVB_PACKET_SET_LENGTH(p,v) ((p)->len1 = ((v) >> 8),(p)->len2 = (v))
94
+
95
+#define AVB_PACKET_GET_SUBTYPE(p)  ((p)->subtype)
96
+#define AVB_PACKET_GET_SV(p)       ((p)->sv)
97
+#define AVB_PACKET_GET_VERSION(p)  ((p)->version)
98
+#define AVB_PACKET_GET_SUB1(p)     ((p)->subtype_data1)
99
+#define AVB_PACKET_GET_SUB2(p)     ((p)->subtype_data2)
100
+#define AVB_PACKET_GET_LENGTH(p)   ((p)->len1 << 8 | (p)->len2)
101
+
102
+#endif /* AVB_PACKETS_H */
103
pipewire-0.3.56.tar.gz/src/modules/module-avb/srp.c Added
61
 
1
@@ -0,0 +1,59 @@
2
+/* AVB support
3
+ *
4
+ * Copyright © 2022 Wim Taymans
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a
7
+ * copy of this software and associated documentation files (the "Software"),
8
+ * to deal in the Software without restriction, including without limitation
9
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
+ * and/or sell copies of the Software, and to permit persons to whom the
11
+ * Software is furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice (including the next
14
+ * paragraph) shall be included in all copies or substantial portions of the
15
+ * Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23
+ * DEALINGS IN THE SOFTWARE.
24
+ */
25
+
26
+#include <pipewire/pipewire.h>
27
+
28
+#include "srp.h"
29
+
30
+struct srp {
31
+   struct server *server;
32
+   struct spa_hook server_listener;
33
+};
34
+
35
+static void srp_destroy(void *data)
36
+{
37
+   struct srp *srp = data;
38
+   spa_hook_remove(&srp->server_listener);
39
+   free(srp);
40
+}
41
+
42
+static const struct server_events server_events = {
43
+   AVB_VERSION_SERVER_EVENTS,
44
+   .destroy = srp_destroy,
45
+};
46
+
47
+int avb_srp_register(struct server *server)
48
+{
49
+   struct srp *srp;
50
+
51
+   srp = calloc(1, sizeof(*srp));
52
+   if (srp == NULL)
53
+       return -errno;
54
+
55
+   srp->server = server;
56
+
57
+   avdecc_server_add_listener(server, &srp->server_listener, &server_events, srp);
58
+
59
+   return 0;
60
+}
61
pipewire-0.3.56.tar.gz/src/modules/module-avb/srp.h Added
34
 
1
@@ -0,0 +1,32 @@
2
+/* AVB support
3
+ *
4
+ * Copyright © 2022 Wim Taymans
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a
7
+ * copy of this software and associated documentation files (the "Software"),
8
+ * to deal in the Software without restriction, including without limitation
9
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
+ * and/or sell copies of the Software, and to permit persons to whom the
11
+ * Software is furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice (including the next
14
+ * paragraph) shall be included in all copies or substantial portions of the
15
+ * Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23
+ * DEALINGS IN THE SOFTWARE.
24
+ */
25
+
26
+#ifndef AVB_SRP_H
27
+#define AVB_SRP_H
28
+
29
+#include "internal.h"
30
+
31
+int avb_srp_register(struct server *server);
32
+
33
+#endif /* AVB_SRP_H */
34
pipewire-0.3.56.tar.gz/src/modules/module-avb/stream.c Added
201
 
1
@@ -0,0 +1,589 @@
2
+/* AVB support
3
+ *
4
+ * Copyright © 2022 Wim Taymans
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a
7
+ * copy of this software and associated documentation files (the "Software"),
8
+ * to deal in the Software without restriction, including without limitation
9
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
+ * and/or sell copies of the Software, and to permit persons to whom the
11
+ * Software is furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice (including the next
14
+ * paragraph) shall be included in all copies or substantial portions of the
15
+ * Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23
+ * DEALINGS IN THE SOFTWARE.
24
+ */
25
+
26
+#include <unistd.h>
27
+#include <linux/if_ether.h>
28
+#include <linux/if_packet.h>
29
+#include <linux/net_tstamp.h>
30
+#include <net/if.h>
31
+#include <sys/ioctl.h>
32
+
33
+#include <spa/debug/mem.h>
34
+#include <spa/pod/builder.h>
35
+#include <spa/param/audio/format-utils.h>
36
+
37
+#include "iec61883.h"
38
+#include "stream.h"
39
+#include "utils.h"
40
+#include "aecp-aem-descriptors.h"
41
+
42
+static void on_stream_destroy(void *d)
43
+{
44
+   struct stream *stream = d;
45
+   spa_hook_remove(&stream->stream_listener);
46
+   stream->stream = NULL;
47
+}
48
+
49
+static void on_source_stream_process(void *data)
50
+{
51
+   struct stream *stream = data;
52
+   struct pw_buffer *buf;
53
+   struct spa_data *d;
54
+   uint32_t index, n_bytes;
55
+   int32_t avail, wanted;
56
+
57
+   if ((buf = pw_stream_dequeue_buffer(stream->stream)) == NULL) {
58
+       pw_log_debug("out of buffers: %m");
59
+       return;
60
+   }
61
+
62
+   d = buf->buffer->datas;
63
+
64
+   wanted = buf->requested ? buf->requested * stream->stride : d0.maxsize;
65
+
66
+   n_bytes = SPA_MIN(d0.maxsize, (uint32_t)wanted);
67
+
68
+   avail = spa_ringbuffer_get_read_index(&stream->ring, &index);
69
+
70
+   if (avail < wanted) {
71
+       pw_log_debug("capture underrun %d < %d", avail, wanted);
72
+       memset(d0.data, 0, n_bytes);
73
+   } else {
74
+       spa_ringbuffer_read_data(&stream->ring,
75
+               stream->buffer_data,
76
+               stream->buffer_size,
77
+               index % stream->buffer_size,
78
+               d0.data, n_bytes);
79
+       index += n_bytes;
80
+       spa_ringbuffer_read_update(&stream->ring, index);
81
+   }
82
+
83
+   d0.chunk->size = n_bytes;
84
+   d0.chunk->stride = stream->stride;
85
+   d0.chunk->offset = 0;
86
+   buf->size = n_bytes / stream->stride;
87
+
88
+   pw_stream_queue_buffer(stream->stream, buf);
89
+}
90
+
91
+static const struct pw_stream_events source_stream_events = {
92
+   PW_VERSION_STREAM_EVENTS,
93
+   .destroy = on_stream_destroy,
94
+   .process = on_source_stream_process
95
+};
96
+
97
+static inline void
98
+set_iovec(struct spa_ringbuffer *rbuf, void *buffer, uint32_t size,
99
+       uint32_t offset, struct iovec *iov, uint32_t len)
100
+{
101
+   iov0.iov_len = SPA_MIN(len, size - offset);
102
+   iov0.iov_base = SPA_PTROFF(buffer, offset, void);
103
+   iov1.iov_len = len - iov0.iov_len;
104
+   iov1.iov_base = buffer;
105
+}
106
+
107
+static int flush_write(struct stream *stream, uint64_t current_time)
108
+{
109
+   int32_t avail;
110
+   uint32_t index;
111
+        uint64_t ptime, txtime;
112
+   int pdu_count;
113
+   ssize_t n;
114
+   struct avb_frame_header *h = (void*)stream->pdu;
115
+   struct avb_packet_iec61883 *p = SPA_PTROFF(h, sizeof(*h), void);
116
+   uint8_t dbc;
117
+
118
+   avail = spa_ringbuffer_get_read_index(&stream->ring, &index);
119
+
120
+   pdu_count = (avail / stream->stride) / stream->frames_per_pdu;
121
+
122
+   txtime = current_time + stream->t_uncertainty;
123
+   ptime = txtime + stream->mtt;
124
+   dbc = stream->dbc;
125
+
126
+   while (pdu_count--) {
127
+       *(uint64_t*)CMSG_DATA(stream->cmsg) = txtime;
128
+
129
+       set_iovec(&stream->ring,
130
+           stream->buffer_data,
131
+           stream->buffer_size,
132
+           index % stream->buffer_size,
133
+           &stream->iov1, stream->payload_size);
134
+
135
+       p->seq_num = stream->pdu_seq++;
136
+       p->tv = 1;
137
+       p->timestamp = ptime;
138
+       p->dbc = dbc;
139
+
140
+       n = sendmsg(stream->source->fd, &stream->msg, 0);
141
+       if (n < 0 || n != (ssize_t)stream->pdu_size) {
142
+           pw_log_error("sendmsg() failed %zd != %zd: %m",
143
+                   n, stream->pdu_size);
144
+       }
145
+       txtime += stream->pdu_period;
146
+       ptime += stream->pdu_period;
147
+       index += stream->payload_size;
148
+       dbc += stream->frames_per_pdu;
149
+   }
150
+   stream->dbc = dbc;
151
+   spa_ringbuffer_read_update(&stream->ring, index);
152
+   return 0;
153
+}
154
+
155
+static void on_sink_stream_process(void *data)
156
+{
157
+   struct stream *stream = data;
158
+   struct pw_buffer *buf;
159
+   struct spa_data *d;
160
+   int32_t filled;
161
+   uint32_t index, offs, avail, size;
162
+   struct timespec now;
163
+
164
+   if ((buf = pw_stream_dequeue_buffer(stream->stream)) == NULL) {
165
+       pw_log_debug("out of buffers: %m");
166
+       return;
167
+   }
168
+
169
+   d = buf->buffer->datas;
170
+
171
+   offs = SPA_MIN(d0.chunk->offset, d0.maxsize);
172
+   size = SPA_MIN(d0.chunk->size, d0.maxsize - offs);
173
+   avail = size - offs;
174
+
175
+   filled = spa_ringbuffer_get_write_index(&stream->ring, &index);
176
+
177
+   if (filled >= (int32_t)stream->buffer_size) {
178
+       pw_log_warn("playback overrun %d >= %zd", filled, stream->buffer_size);
179
+   } else {
180
+       spa_ringbuffer_write_data(&stream->ring,
181
+               stream->buffer_data,
182
+               stream->buffer_size,
183
+               index % stream->buffer_size,
184
+               SPA_PTROFF(d0.data, offs, void), avail);
185
+       index += avail;
186
+       spa_ringbuffer_write_update(&stream->ring, index);
187
+   }
188
+   pw_stream_queue_buffer(stream->stream, buf);
189
+
190
+   clock_gettime(CLOCK_TAI, &now);
191
+   flush_write(stream, SPA_TIMESPEC_TO_NSEC(&now));
192
+}
193
+
194
+static void setup_pdu(struct stream *stream)
195
+{
196
+   struct avb_frame_header *h;
197
+   struct avb_packet_iec61883 *p;
198
+   ssize_t payload_size, hdr_size, pdu_size;
199
+
200
+   spa_memzero(stream->pdu, sizeof(stream->pdu));
201
pipewire-0.3.56.tar.gz/src/modules/module-avb/stream.h Added
106
 
1
@@ -0,0 +1,104 @@
2
+/* AVB support
3
+ *
4
+ * Copyright © 2022 Wim Taymans
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a
7
+ * copy of this software and associated documentation files (the "Software"),
8
+ * to deal in the Software without restriction, including without limitation
9
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
+ * and/or sell copies of the Software, and to permit persons to whom the
11
+ * Software is furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice (including the next
14
+ * paragraph) shall be included in all copies or substantial portions of the
15
+ * Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23
+ * DEALINGS IN THE SOFTWARE.
24
+ */
25
+
26
+#ifndef AVB_STREAM_H
27
+#define AVB_STREAM_H
28
+
29
+#include <sys/socket.h>
30
+#include <sys/types.h>
31
+#include <linux/if_packet.h>
32
+#include <net/if.h>
33
+
34
+#include <spa/utils/ringbuffer.h>
35
+#include <spa/param/audio/format.h>
36
+
37
+#include <pipewire/pipewire.h>
38
+
39
+#define BUFFER_SIZE    (1u<<16)
40
+#define BUFFER_MASK    (BUFFER_SIZE-1)
41
+
42
+struct stream {
43
+   struct spa_list link;
44
+
45
+   struct server *server;
46
+
47
+   uint16_t direction;
48
+   uint16_t index;
49
+   const struct descriptor *desc;
50
+   uint64_t id;
51
+   uint64_t peer_id;
52
+
53
+   struct pw_stream *stream;
54
+   struct spa_hook stream_listener;
55
+
56
+   uint8_t addr6;
57
+   struct spa_source *source;
58
+   int prio;
59
+   int vlan_id;
60
+   int mtt;
61
+   int t_uncertainty;
62
+   uint32_t frames_per_pdu;
63
+   int ptime_tolerance;
64
+
65
+   uint8_t pdu2048;
66
+   size_t hdr_size;
67
+   size_t payload_size;
68
+   size_t pdu_size;
69
+   int64_t pdu_period;
70
+   uint8_t pdu_seq;
71
+   uint8_t prev_seq;
72
+   uint8_t dbc;
73
+
74
+   struct iovec iov3;
75
+   struct sockaddr_ll sock_addr;
76
+   struct msghdr msg;
77
+   char controlCMSG_SPACE(sizeof(uint64_t));
78
+   struct cmsghdr *cmsg;
79
+
80
+   struct spa_ringbuffer ring;
81
+   void *buffer_data;
82
+   size_t buffer_size;
83
+
84
+   uint64_t format;
85
+   uint32_t stride;
86
+   struct spa_audio_info info;
87
+
88
+   struct avb_msrp_attribute *talker_attr;
89
+   struct avb_msrp_attribute *listener_attr;
90
+   struct avb_mvrp_attribute *vlan_attr;
91
+};
92
+
93
+#include "msrp.h"
94
+#include "mvrp.h"
95
+#include "maap.h"
96
+
97
+struct stream *server_create_stream(struct server *server,
98
+       enum spa_direction direction, uint16_t index);
99
+
100
+void stream_destroy(struct stream *stream);
101
+
102
+int stream_activate(struct stream *stream, uint64_t now);
103
+int stream_deactivate(struct stream *stream, uint64_t now);
104
+
105
+#endif /* AVB_STREAM_H */
106
pipewire-0.3.56.tar.gz/src/modules/module-avb/utils.h Added
88
 
1
@@ -0,0 +1,86 @@
2
+/* AVB support
3
+ *
4
+ * Copyright © 2022 Wim Taymans
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a
7
+ * copy of this software and associated documentation files (the "Software"),
8
+ * to deal in the Software without restriction, including without limitation
9
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
+ * and/or sell copies of the Software, and to permit persons to whom the
11
+ * Software is furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice (including the next
14
+ * paragraph) shall be included in all copies or substantial portions of the
15
+ * Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23
+ * DEALINGS IN THE SOFTWARE.
24
+ */
25
+
26
+#ifndef AVB_UTILS_H
27
+#define AVB_UTILS_H
28
+
29
+#include <spa/utils/json.h>
30
+
31
+#include "internal.h"
32
+
33
+static inline char *avb_utils_format_id(char *str, size_t size, const uint64_t id)
34
+{
35
+   snprintf(str, size, "%02x:%02x:%02x:%02x:%02x:%02x:%04x",
36
+           (uint8_t)(id >> 56),
37
+           (uint8_t)(id >> 48),
38
+           (uint8_t)(id >> 40),
39
+           (uint8_t)(id >> 32),
40
+           (uint8_t)(id >> 24),
41
+           (uint8_t)(id >> 16),
42
+           (uint16_t)(id));
43
+   return str;
44
+}
45
+
46
+static inline int avb_utils_parse_id(const char *str, int len, uint64_t *id)
47
+{
48
+   char s64;
49
+   uint8_t v6;
50
+   uint16_t unique_id;
51
+   if (spa_json_parse_stringn(str, len, s, sizeof(s)) <= 0)
52
+       return -EINVAL;
53
+   if (sscanf(s, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hx",
54
+           &v0, &v1, &v2, &v3,
55
+           &v4, &v5, &unique_id) == 7) {
56
+       *id = (uint64_t) v0 << 56 |
57
+               (uint64_t) v1 << 48 |
58
+               (uint64_t) v2 << 40 |
59
+               (uint64_t) v3 << 32 |
60
+               (uint64_t) v4 << 24 |
61
+               (uint64_t) v5 << 16 |
62
+               unique_id;
63
+   } else if (!spa_atou64(str, id, 0))
64
+       return -EINVAL;
65
+   return 0;
66
+}
67
+
68
+static inline char *avb_utils_format_addr(char *str, size_t size, const uint8_t addr6)
69
+{
70
+   snprintf(str, size, "%02x:%02x:%02x:%02x:%02x:%02x",
71
+           addr0, addr1, addr2, addr3, addr4, addr5);
72
+   return str;
73
+}
74
+static inline int avb_utils_parse_addr(const char *str, int len, uint8_t addr6)
75
+{
76
+   char s64;
77
+   uint8_t v6;
78
+   if (spa_json_parse_stringn(str, len, s, sizeof(s)) <= 0)
79
+       return -EINVAL;
80
+   if (sscanf(s, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
81
+           &v0, &v1, &v2, &v3, &v4, &v5) != 6)
82
+       return -EINVAL;
83
+   memcpy(addr, v, 6);
84
+   return 0;
85
+}
86
+
87
+#endif /* AVB_UTILS_H */
88
pipewire-0.3.54.tar.gz/src/modules/module-filter-chain.c -> pipewire-0.3.56.tar.gz/src/modules/module-filter-chain.c Changed
64
 
1
@@ -591,6 +591,8 @@
2
    struct graph *graph = &impl->graph;
3
    uint32_t i, outsize = 0, n_hndl = graph->n_hndl;
4
    int32_t stride = 0;
5
+   struct graph_port *port;
6
+   struct spa_data *bd;
7
 
8
    if ((in = pw_stream_dequeue_buffer(impl->capture)) == NULL)
9
        pw_log_debug("out of capture buffers: %m");
10
@@ -602,30 +604,37 @@
11
        goto done;
12
 
13
    for (i = 0; i < in->buffer->n_datas; i++) {
14
-       struct spa_data *ds = &in->buffer->datasi;
15
-       struct graph_port *port = &graph->inputi;
16
        uint32_t offs, size;
17
 
18
-       offs = SPA_MIN(ds->chunk->offset, ds->maxsize);
19
-       size = SPA_MIN(ds->chunk->size, ds->maxsize - offs);
20
+       bd = &in->buffer->datasi;
21
 
22
-       if (port->desc)
23
+       offs = SPA_MIN(bd->chunk->offset, bd->maxsize);
24
+       size = SPA_MIN(bd->chunk->size, bd->maxsize - offs);
25
+
26
+       port = i < graph->n_input ? &graph->inputi : NULL;
27
+
28
+       if (port && port->desc)
29
            port->desc->connect_port(port->hndl, port->port,
30
-               SPA_PTROFF(ds->data, offs, void));
31
+               SPA_PTROFF(bd->data, offs, void));
32
 
33
-       outsize = SPA_MAX(outsize, size);
34
-       stride = SPA_MAX(stride, ds->chunk->stride);
35
+       outsize = i == 0 ? size : SPA_MIN(outsize, size);
36
+       stride = SPA_MAX(stride, bd->chunk->stride);
37
    }
38
    for (i = 0; i < out->buffer->n_datas; i++) {
39
-       struct spa_data *dd = &out->buffer->datasi;
40
-       struct graph_port *port = &graph->outputi;
41
-       if (port->desc)
42
-           port->desc->connect_port(port->hndl, port->port, dd->data);
43
+       bd = &out->buffer->datasi;
44
+
45
+       outsize = SPA_MIN(outsize, bd->maxsize);
46
+
47
+       port = i < graph->n_output ? &graph->outputi : NULL;
48
+
49
+       if (port && port->desc)
50
+           port->desc->connect_port(port->hndl, port->port, bd->data);
51
        else
52
-           memset(dd->data, 0, outsize);
53
-       dd->chunk->offset = 0;
54
-       dd->chunk->size = outsize;
55
-       dd->chunk->stride = stride;
56
+           memset(bd->data, 0, outsize);
57
+
58
+       bd->chunk->offset = 0;
59
+       bd->chunk->size = outsize;
60
+       bd->chunk->stride = stride;
61
    }
62
    for (i = 0; i < n_hndl; i++) {
63
        struct graph_hndl *hndl = &graph->hndli;
64
pipewire-0.3.54.tar.gz/src/modules/module-loopback.c -> pipewire-0.3.56.tar.gz/src/modules/module-loopback.c Changed
68
 
1
@@ -99,7 +99,8 @@
2
  *         playback.props = {
3
  *             node.name = "playback.CM106_stereo_pair_2"
4
  *             audio.position =  RL RR 
5
- *             node.target = "alsa_output.usb-0d8c_USB_Sound_Device-00.analog-surround-71"
6
+ *             target.object = "alsa_output.usb-0d8c_USB_Sound_Device-00.analog-surround-71"
7
+ *             node.dont-reconnect = true
8
  *             stream.dont-remix = true
9
  *             node.passive = true
10
  *         }
11
@@ -188,33 +189,35 @@
12
        pw_log_debug("out of playback buffers: %m");
13
 
14
    if (in != NULL && out != NULL) {
15
+       uint32_t outsize = UINT32_MAX;
16
+       int32_t stride = 0;
17
+       struct spa_data *d;
18
+       const void *srcin->buffer->n_datas;
19
 
20
-       for (i = 0; i < out->buffer->n_datas; i++) {
21
-           struct spa_data *ds, *dd;
22
-           uint32_t outsize = 0;
23
-           int32_t stride = 0;
24
-
25
-           dd = &out->buffer->datasi;
26
+       for (i = 0; i < in->buffer->n_datas; i++) {
27
+           uint32_t offs, size;
28
 
29
-           if (i < in->buffer->n_datas) {
30
-               uint32_t offs, size;
31
+           d = &in->buffer->datasi;
32
+           offs = SPA_MIN(d->chunk->offset, d->maxsize);
33
+           size = SPA_MIN(d->chunk->size, d->maxsize - offs);
34
 
35
-               ds = &in->buffer->datasi;
36
+           srci = SPA_PTROFF(d->data, offs, void);
37
+           outsize = SPA_MIN(outsize, size);
38
+           stride = SPA_MAX(stride, d->chunk->stride);
39
+       }
40
+       for (i = 0; i < out->buffer->n_datas; i++) {
41
+           d = &out->buffer->datasi;
42
 
43
-               offs = SPA_MIN(ds->chunk->offset, ds->maxsize);
44
-               size = SPA_MIN(ds->chunk->size, ds->maxsize - offs);
45
-               stride = SPA_MAX(stride, stride);
46
+           outsize = SPA_MIN(outsize, d->maxsize);
47
 
48
-               memcpy(dd->data,
49
-                   SPA_PTROFF(ds->data, offs, void), size);
50
+           if (i < in->buffer->n_datas)
51
+               memcpy(d->data, srci, outsize);
52
+           else
53
+               memset(d->data, 0, outsize);
54
 
55
-               outsize = SPA_MAX(outsize, size);
56
-           } else {
57
-               memset(dd->data, 0, outsize);
58
-           }
59
-           dd->chunk->offset = 0;
60
-           dd->chunk->size = outsize;
61
-           dd->chunk->stride = stride;
62
+           d->chunk->offset = 0;
63
+           d->chunk->size = outsize;
64
+           d->chunk->stride = stride;
65
        }
66
    }
67
 
68
pipewire-0.3.54.tar.gz/src/modules/module-pipe-tunnel.c -> pipewire-0.3.56.tar.gz/src/modules/module-pipe-tunnel.c Changed
28
 
1
@@ -94,7 +94,7 @@
2
  * - \ref PW_KEY_NODE_GROUP
3
  * - \ref PW_KEY_NODE_VIRTUAL
4
  * - \ref PW_KEY_MEDIA_CLASS
5
- * - \ref PW_KEY_NODE_TARGET to specify the remote name or id to link to
6
+ * - \ref PW_KEY_TARGET_OBJECT to specify the remote name or serial id to link to
7
  *
8
  * When not otherwise specified, the pipe will accept or produce a
9
  * 16 bits, stereo, 48KHz sample stream.
10
@@ -112,7 +112,7 @@
11
  *         #audio.rate=<sample rate>
12
  *         #audio.channels=<number of channels>
13
  *         #audio.position=<channel map>
14
- *         #node.target=<remote target node>
15
+ *         #target.object=<remote target node>
16
  *         stream.props = {
17
  *             # extra sink properties
18
  *         }
19
@@ -139,7 +139,7 @@
20
            " node.latency=<latency as fraction>  "     \
21
            " node.name=<name of the nodes>  "          \
22
            " node.description=<description of the nodes>  "    \
23
-           " node.target=<remote node target name>  "      \
24
+           " target.object=<remote node target name>  "        \
25
            " audio.format=<sample format>  "           \
26
            " audio.rate=<sample rate>  "               \
27
            " audio.channels=<number of channels>  "        \
28
pipewire-0.3.54.tar.gz/src/modules/module-protocol-pulse/pulse-server.c -> pipewire-0.3.56.tar.gz/src/modules/module-protocol-pulse/pulse-server.c Changed
39
 
1
@@ -1277,7 +1277,7 @@
2
    stream->timestamp = pd->pwt.now;
3
    stream->delay = pd->pwt.buffered * SPA_USEC_PER_SEC / stream->ss.rate;
4
    if (pd->pwt.rate.denom > 0)
5
-       stream->delay = pd->pwt.delay * SPA_USEC_PER_SEC / pd->pwt.rate.denom;
6
+       stream->delay += pd->pwt.delay * SPA_USEC_PER_SEC * pd->pwt.rate.num / pd->pwt.rate.denom;
7
 
8
    if (stream->direction == PW_DIRECTION_OUTPUT) {
9
        if (pd->quantum != stream->last_quantum)
10
@@ -1332,6 +1332,7 @@
11
                stream->read_index += skip;
12
                avail = stream->attr.fragsize;
13
            }
14
+           pw_log_trace("avail:%d index:%u", avail, index);
15
 
16
            while ((uint32_t)avail >= stream->attr.fragsize) {
17
                towrite = SPA_MIN((uint32_t)avail, stream->attr.fragsize);
18
@@ -2124,7 +2125,7 @@
19
    if (stream == NULL || stream->type != STREAM_TYPE_PLAYBACK)
20
        return -ENOENT;
21
 
22
-   pw_log_debug("read:%"PRIx64" write:%"PRIx64" queued:%"PRIi64" delay:%"PRIi64
23
+   pw_log_debug("read:0x%"PRIx64" write:0x%"PRIx64" queued:%"PRIi64" delay:%"PRIi64
24
            " playing:%"PRIu64,
25
            stream->read_index, stream->write_index,
26
            stream->write_index - stream->read_index, stream->delay,
27
@@ -2173,6 +2174,11 @@
28
    if (stream == NULL || stream->type != STREAM_TYPE_RECORD)
29
        return -ENOENT;
30
 
31
+   pw_log_debug("read:0x%"PRIx64" write:0x%"PRIx64" queued:%"PRIi64" delay:%"PRIi64,
32
+           stream->read_index, stream->write_index,
33
+           stream->write_index - stream->read_index, stream->delay);
34
+
35
+
36
    gettimeofday(&now, NULL);
37
    reply = reply_new(client, tag);
38
    message_put(reply,
39
pipewire-0.3.54.tar.gz/src/modules/module-pulse-tunnel.c -> pipewire-0.3.56.tar.gz/src/modules/module-pulse-tunnel.c Changed
30
 
1
@@ -90,7 +90,7 @@
2
  * - \ref PW_KEY_NODE_GROUP
3
  * - \ref PW_KEY_NODE_VIRTUAL
4
  * - \ref PW_KEY_MEDIA_CLASS
5
- * - \ref PW_KEY_NODE_TARGET to specify the remote name or id to link to
6
+ * - \ref PW_KEY_TARGET_OBJECT to specify the remote node.name or serial.id to link to
7
  *
8
  * ## Example configuration of a virtual sink
9
  *
10
@@ -104,7 +104,7 @@
11
  *         #audio.rate=<sample rate>
12
  *         #audio.channels=<number of channels>
13
  *         #audio.position=<channel map>
14
- *         #node.target=<remote target node>
15
+ *         #target.object=<remote target name>
16
  *         stream.props = {
17
  *             # extra sink properties
18
  *         }
19
@@ -660,7 +660,9 @@
20
    pa_stream_set_overflow_callback(impl->pa_stream, stream_overflow_cb, impl);
21
    pa_stream_set_latency_update_callback(impl->pa_stream, stream_latency_update_cb, impl);
22
 
23
-   remote_node_target = pw_properties_get(impl->props, PW_KEY_NODE_TARGET);
24
+   remote_node_target = pw_properties_get(impl->props, PW_KEY_TARGET_OBJECT);
25
+   if (remote_node_target == NULL)
26
+       remote_node_target = pw_properties_get(impl->props, PW_KEY_NODE_TARGET);
27
 
28
    bufferattr.fragsize = (uint32_t) -1;
29
    bufferattr.minreq = (uint32_t) -1;
30
pipewire-0.3.54.tar.gz/src/modules/module-raop-discover.c -> pipewire-0.3.56.tar.gz/src/modules/module-raop-discover.c Changed
10
 
1
@@ -223,6 +223,8 @@
2
         *  4 = FairPlay SAPv2.5. */
3
        if (str_in_list(value, ",", "1"))
4
            value = "RSA";
5
+       else if (str_in_list(value, ",", "4"))
6
+           value = "auth_setup";
7
        else
8
            value = "none";
9
        pw_properties_set(props, "raop.encryption.type", value);
10
pipewire-0.3.54.tar.gz/src/modules/module-raop-sink.c -> pipewire-0.3.56.tar.gz/src/modules/module-raop-sink.c Changed
181
 
1
@@ -130,6 +130,7 @@
2
 enum {
3
    CRYPTO_NONE,
4
    CRYPTO_RSA,
5
+   CRYPTO_AUTH_SETUP,
6
 };
7
 enum {
8
    CODEC_PCM,
9
@@ -257,7 +258,8 @@
10
    return timespec_to_ntp(&now);
11
 }
12
 
13
-static int send_udp_sync_packet(struct impl *impl)
14
+static int send_udp_sync_packet(struct impl *impl,
15
+       struct sockaddr *dest_addr, socklen_t addrlen)
16
 {
17
    uint32_t pkt5;
18
    uint32_t rtptime = impl->rtptime;
19
@@ -278,10 +280,11 @@
20
    pw_log_debug("sync: delayed:%u now:%"PRIu64" rtptime:%u",
21
            rtptime - delay, transmitted, rtptime);
22
 
23
-   return write(impl->control_fd, pkt, sizeof(pkt));
24
+   return sendto(impl->control_fd, pkt, sizeof(pkt), 0, dest_addr, addrlen);
25
 }
26
 
27
-static int send_udp_timing_packet(struct impl *impl, uint64_t remote, uint64_t received)
28
+static int send_udp_timing_packet(struct impl *impl, uint64_t remote, uint64_t received,
29
+       struct sockaddr *dest_addr, socklen_t addrlen)
30
 {
31
    uint32_t pkt8;
32
    uint64_t transmitted;
33
@@ -299,7 +302,7 @@
34
    pw_log_debug("sync: remote:%"PRIu64" received:%"PRIu64" transmitted:%"PRIu64,
35
            remote, received, transmitted);
36
 
37
-   return write(impl->timing_fd, pkt, sizeof(pkt));
38
+   return sendto(impl->timing_fd, pkt, sizeof(pkt), 0, dest_addr, addrlen);
39
 }
40
 
41
 static int write_codec_pcm(void *dst, void *frames, uint32_t n_frames)
42
@@ -345,7 +348,7 @@
43
    impl->sync++;
44
    if (impl->first || impl->sync == impl->sync_period) {
45
        impl->sync = 0;
46
-       send_udp_sync_packet(impl);
47
+       send_udp_sync_packet(impl, NULL, 0);
48
    }
49
    pkt0 = htonl(0x80600000);
50
    if (impl->first)
51
@@ -373,7 +376,7 @@
52
    impl->seq = (impl->seq + 1) & 0xffff;
53
 
54
    pw_log_debug("send %u", len + 12);
55
-   res = write(impl->server_fd, pkt, len + 12);
56
+   res = send(impl->server_fd, pkt, len + 12, 0);
57
 
58
    impl->first = false;
59
 
60
@@ -417,7 +420,7 @@
61
    impl->seq = (impl->seq + 1) & 0xffff;
62
 
63
    pw_log_debug("send %u", len + 16);
64
-   res = write(impl->server_fd, pkt, len + 16);
65
+   res = send(impl->server_fd, pkt, len + 16, 0);
66
 
67
    impl->first = false;
68
 
69
@@ -593,9 +596,12 @@
70
 
71
    if (mask & SPA_IO_IN) {
72
        uint64_t remote, received;
73
+       struct sockaddr_storage sender;
74
+       socklen_t sender_size = sizeof(sender);
75
 
76
        received = ntp_now(CLOCK_MONOTONIC);
77
-       bytes = read(impl->timing_fd, packet, sizeof(packet));
78
+       bytes = recvfrom(impl->timing_fd, packet, sizeof(packet), 0,
79
+               (struct sockaddr*)&sender, &sender_size);
80
        if (bytes < 0) {
81
            pw_log_debug("error reading timing packet: %m");
82
            return;
83
@@ -609,7 +615,11 @@
84
            return;
85
 
86
        remote = ((uint64_t)ntohl(packet6)) << 32 | ntohl(packet7);
87
-       send_udp_timing_packet(impl, remote, received);
88
+       if (send_udp_timing_packet(impl, remote, received,
89
+               (struct sockaddr *)&sender, sender_size) < 0) {
90
+           pw_log_warn("error sending timing packet");
91
+           return;
92
+       }
93
    }
94
 }
95
 
96
@@ -833,10 +843,8 @@
97
            return;
98
 
99
        ntp = ntp_now(CLOCK_MONOTONIC);
100
-       send_udp_timing_packet(impl, ntp, ntp);
101
+       send_udp_timing_packet(impl, ntp, ntp, NULL, 0);
102
 
103
-       impl->timing_source = pw_loop_add_io(impl->loop, impl->timing_fd,
104
-               SPA_IO_IN, false, on_timing_source_io, impl);
105
        impl->control_source = pw_loop_add_io(impl->loop, impl->control_fd,
106
                SPA_IO_IN, false, on_control_source_io, impl);
107
 
108
@@ -868,6 +876,9 @@
109
        if (impl->control_fd < 0 || impl->timing_fd < 0)
110
            goto error;
111
 
112
+       impl->timing_source = pw_loop_add_io(impl->loop, impl->timing_fd,
113
+               SPA_IO_IN, false, on_timing_source_io, impl);
114
+
115
        pw_properties_setf(impl->headers, "Transport",
116
                "RTP/AVP/UDP;unicast;interleaved=0-1;mode=record;"
117
                "control_port=%u;timing_port=%u",
118
@@ -988,7 +999,7 @@
119
    char iv16*2;
120
    int res, frames, i, ip_version;
121
    char *sdp;
122
-        char local_ip256;
123
+   char local_ip256;
124
 
125
    host = pw_properties_get(impl->props, "raop.hostname");
126
 
127
@@ -1048,6 +1059,32 @@
128
    return res;
129
 }
130
 
131
+static void rtsp_auth_setup_reply(void *data, int status, const struct spa_dict *headers)
132
+{
133
+   struct impl *impl = data;
134
+
135
+   pw_log_info("reply %d", status);
136
+
137
+   impl->encryption = CRYPTO_NONE;
138
+
139
+   rtsp_do_announce(impl);
140
+}
141
+
142
+static int rtsp_do_auth_setup(struct impl *impl)
143
+{
144
+   int res;
145
+
146
+   char output = 
147
+       "\x01"
148
+       "\x59\x02\xed\xe9\x0d\x4e\xf2\xbd\x4c\xb6\x8a\x63\x30\x03\x82\x07"
149
+       "\xa9\x4d\xbd\x50\xd8\xaa\x46\x5b\x5d\x8c\x01\x2a\x0c\x7e\x1d\x4e";
150
+
151
+   res = pw_rtsp_client_url_send(impl->rtsp, "/auth-setup", "POST", &impl->headers->dict,
152
+           "application/octet-stream", output, rtsp_auth_setup_reply, impl);
153
+
154
+   return res;
155
+}
156
+
157
 static const char *find_attr(char **tokens, const char *key)
158
 {
159
    int i;
160
@@ -1168,7 +1205,10 @@
161
        rtsp_do_auth(impl, headers);
162
        break;
163
    case 200:
164
-       rtsp_do_announce(impl);
165
+       if (impl->encryption == CRYPTO_AUTH_SETUP)
166
+           rtsp_do_auth_setup(impl);
167
+       else
168
+           rtsp_do_announce(impl);
169
        break;
170
    }
171
 }
172
@@ -1648,6 +1688,8 @@
173
        impl->encryption = CRYPTO_NONE;
174
    else if (spa_streq(str, "RSA"))
175
        impl->encryption = CRYPTO_RSA;
176
+   else if (spa_streq(str, "auth_setup"))
177
+       impl->encryption = CRYPTO_AUTH_SETUP;
178
    else {
179
        pw_log_error( "can't handle encryption type %s", str);
180
        res = -EINVAL;
181
pipewire-0.3.54.tar.gz/src/modules/module-raop/rtsp-client.c -> pipewire-0.3.56.tar.gz/src/modules/module-raop/rtsp-client.c Changed
64
 
1
@@ -273,12 +273,30 @@
2
            int cseq;
3
            struct message *msg;
4
            const struct spa_dict_item *it;
5
+           const char *content_type;
6
+           unsigned int content_length;
7
 
8
            spa_dict_for_each(it, &client->headers->dict)
9
                pw_log_info(" %s: %s", it->key, it->value);
10
 
11
            cseq = pw_properties_get_int32(client->headers, "CSeq", 0);
12
-
13
+           content_type = pw_properties_get(client->headers, "Content-Type");
14
+           if (content_type != NULL && strcmp(content_type, "application/octet-stream") == 0) {
15
+               pw_log_info("binary response received");
16
+               content_length = pw_properties_get_uint64(client->headers, "Content-Length", 0);
17
+               char content_bufcontent_length;
18
+               res = read(client->source->fd, content_buf, content_length);
19
+               pw_log_debug("read %d bytes", res);
20
+               if (res == 0)
21
+                   return -EPIPE;
22
+               if (res < 0) {
23
+                   res = -errno;
24
+                   if (res != -EAGAIN && res != -EWOULDBLOCK)
25
+                       return res;
26
+                   return 0;
27
+               }
28
+               pw_properties_set(client->headers, "body", content_buf);
29
+           }
30
            if ((msg = find_pending(client, cseq)) != NULL) {
31
                msg->reply(msg->user_data, client->status, &client->headers->dict);
32
                spa_list_remove(&msg->link);
33
@@ -466,7 +484,7 @@
34
    return 0;
35
 }
36
 
37
-int pw_rtsp_client_send(struct pw_rtsp_client *client,
38
+int pw_rtsp_client_url_send(struct pw_rtsp_client *client, const char *url,
39
        const char *cmd, const struct spa_dict *headers,
40
        const char *content_type, const char *content,
41
        void (*reply) (void *user_data, int status, const struct spa_dict *headers),
42
@@ -485,7 +503,7 @@
43
 
44
    cseq = ++client->cseq;
45
 
46
-   fprintf(f, "%s %s RTSP/1.0\r\n", cmd, client->url);
47
+   fprintf(f, "%s %s RTSP/1.0\r\n", cmd, url);
48
    fprintf(f, "CSeq: %d\r\n", cseq);
49
 
50
    if (headers != NULL) {
51
@@ -519,3 +537,12 @@
52
         }
53
    return 0;
54
 }
55
+
56
+int pw_rtsp_client_send(struct pw_rtsp_client *client,
57
+       const char *cmd, const struct spa_dict *headers,
58
+       const char *content_type, const char *content,
59
+       void (*reply) (void *user_data, int status, const struct spa_dict *headers),
60
+       void *user_data)
61
+{
62
+   return pw_rtsp_client_url_send(client, client->url, cmd, headers, content_type, content, reply, user_data);
63
+}
64
pipewire-0.3.54.tar.gz/src/modules/module-raop/rtsp-client.h -> pipewire-0.3.56.tar.gz/src/modules/module-raop/rtsp-client.h Changed
14
 
1
@@ -71,6 +71,12 @@
2
 int pw_rtsp_client_get_local_ip(struct pw_rtsp_client *client,
3
        int *version, char *ip, size_t len);
4
 
5
+int pw_rtsp_client_url_send(struct pw_rtsp_client *client, const char *url,
6
+       const char *cmd, const struct spa_dict *headers,
7
+       const char *content_type, const char *content,
8
+       void (*reply) (void *user_data, int status, const struct spa_dict *headers),
9
+       void *user_data);
10
+
11
 int pw_rtsp_client_send(struct pw_rtsp_client *client,
12
        const char *cmd, const struct spa_dict *headers,
13
        const char *content_type, const char *content,
14
pipewire-0.3.54.tar.gz/src/modules/module-rt.c -> pipewire-0.3.56.tar.gz/src/modules/module-rt.c Changed
34
 
1
@@ -520,9 +520,8 @@
2
  */
3
 static bool check_realtime_privileges(rlim_t priority)
4
 {
5
-   int old_policy;
6
+   int err, old_policy, new_policy = REALTIME_POLICY;
7
    struct sched_param old_sched_params;
8
-   int new_policy = REALTIME_POLICY;
9
    struct sched_param new_sched_params;
10
 
11
    /* We could check `RLIMIT_RTPRIO`, but the BSDs generally don't have
12
@@ -530,8 +529,8 @@
13
     * scheduling without that rlimit being set such as `CAP_SYS_NICE` or
14
     * running as root. Instead of checking a bunch of preconditions, we
15
     * just try if setting realtime scheduling works or not. */
16
-   if (pthread_getschedparam(pthread_self(),&old_policy,&old_sched_params) < 0) {
17
-       pw_log_warn("Failed to check RLIMIT_RTPRIO %m");
18
+   if ((err = pthread_getschedparam(pthread_self(),&old_policy,&old_sched_params)) != 0) {
19
+       pw_log_warn("Failed to check RLIMIT_RTPRIO: %s", strerror(err));
20
        return false;
21
    }
22
 
23
@@ -600,8 +599,8 @@
24
        rttime = pw_rtkit_get_rttime_usec_max(impl->system_bus);
25
        if (rttime >= 0) {
26
            if ((rlim_t)rttime < rl.rlim_cur) {
27
-               pw_log_debug("clamping rt.time.soft from %ld to %lld because of RTKit",
28
-                        rl.rlim_cur, rttime);
29
+               pw_log_debug("clamping rt.time.soft from %llu to %lld because of RTKit",
30
+                        (long long)rl.rlim_cur, rttime);
31
            }
32
 
33
            rl.rlim_cur = SPA_MIN(rl.rlim_cur, (rlim_t)rttime);
34
pipewire-0.3.54.tar.gz/src/pipewire/buffers.c -> pipewire-0.3.56.tar.gz/src/pipewire/buffers.c Changed
12
 
1
@@ -166,8 +166,8 @@
2
    uint8_t ibuf4096;
3
         struct spa_pod_builder ib = { 0 };
4
    struct spa_pod *oparam, *iparam;
5
-   uint32_t iidx, oidx, num = 0;
6
-   int in_res = -EIO, out_res = -EIO;
7
+   uint32_t iidx, oidx;
8
+   int in_res = -EIO, out_res = -EIO, num = 0;
9
 
10
    for (iidx = 0;;) {
11
            spa_pod_builder_init(&ib, ibuf, sizeof(ibuf));
12
pipewire-0.3.54.tar.gz/src/pipewire/context.c -> pipewire-0.3.56.tar.gz/src/pipewire/context.c Changed
23
 
1
@@ -543,6 +543,12 @@
2
 }
3
 
4
 SPA_EXPORT
5
+struct pw_data_loop *pw_context_get_data_loop(struct pw_context *context)
6
+{
7
+   return context->data_loop_impl;
8
+}
9
+
10
+SPA_EXPORT
11
 struct pw_work_queue *pw_context_get_work_queue(struct pw_context *context)
12
 {
13
    return context->work_queue;
14
@@ -1113,7 +1119,7 @@
15
  *    the desired final value and activate the followers and then the driver.
16
  *
17
  * A complete graph evaluation is performed for each change that is made to the
18
- * graph, such as making/destroting links, adding/removing nodes, property changes such
19
+ * graph, such as making/destroying links, adding/removing nodes, property changes such
20
  * as quantum/rate changes or metadata changes.
21
  */
22
 int pw_context_recalc_graph(struct pw_context *context, const char *reason)
23
pipewire-0.3.54.tar.gz/src/pipewire/context.h -> pipewire-0.3.56.tar.gz/src/pipewire/context.h Changed
11
 
1
@@ -136,6 +136,9 @@
2
 /** get the context main loop */
3
 struct pw_loop *pw_context_get_main_loop(struct pw_context *context);
4
 
5
+/** get the context data loop. Since 0.3.56 */
6
+struct pw_data_loop *pw_context_get_data_loop(struct pw_context *context);
7
+
8
 /** Get the work queue from the context: Since 0.3.26 */
9
 struct pw_work_queue *pw_context_get_work_queue(struct pw_context *context);
10
 
11
pipewire-0.3.54.tar.gz/src/pipewire/pipewire.c -> pipewire-0.3.56.tar.gz/src/pipewire/pipewire.c Changed
31
 
1
@@ -826,8 +826,7 @@
2
        return global_support.no_color == spa_atob(value);
3
    else if (spa_streq(option, "no-config"))
4
        return global_support.no_config == spa_atob(value);
5
-   else
6
-       return false;
7
+   return false;
8
 }
9
 
10
 /** Get the client name
11
@@ -841,15 +840,11 @@
12
    const char *cc;
13
    static char cname256;
14
 
15
-   if ((cc = pw_get_application_name()))
16
+   if ((cc = pw_get_application_name()) || (cc = pw_get_prgname()))
17
        return cc;
18
-   else if ((cc = pw_get_prgname()))
19
-       return cc;
20
-   else {
21
-       if (snprintf(cname, sizeof(cname), "pipewire-pid-%zd", (size_t) getpid()) < 0)
22
-           return NULL;
23
-       return cname;
24
-   }
25
+   else if (snprintf(cname, sizeof(cname), "pipewire-pid-%zd", (size_t) getpid()) < 0)
26
+       return NULL;
27
+   return cname;
28
 }
29
 
30
 /** Reverse the direction */
31
pipewire-0.3.54.tar.gz/src/pipewire/stream.c -> pipewire-0.3.56.tar.gz/src/pipewire/stream.c Changed
201
 
1
@@ -313,7 +313,7 @@
2
 }
3
 
4
 
5
-static inline int push_queue(struct stream *stream, struct queue *queue, struct buffer *buffer)
6
+static inline int queue_push(struct stream *stream, struct queue *queue, struct buffer *buffer)
7
 {
8
    uint32_t index;
9
 
10
@@ -330,7 +330,13 @@
11
    return 0;
12
 }
13
 
14
-static inline struct buffer *pop_queue(struct stream *stream, struct queue *queue)
15
+static inline bool queue_is_empty(struct stream *stream, struct queue *queue)
16
+{
17
+   uint32_t index;
18
+   return spa_ringbuffer_get_read_index(&queue->ring, &index) < 1;
19
+}
20
+
21
+static inline struct buffer *queue_pop(struct stream *stream, struct queue *queue)
22
 {
23
    uint32_t index, id;
24
    struct buffer *buffer;
25
@@ -568,7 +574,7 @@
26
        buffer->this.requested = impl->quantum;
27
        res = 1;
28
    }
29
-   pw_log_trace_fp("%p: update buffer:%u size:%u", impl, id, r->size);
30
+   pw_log_trace_fp("%p: update buffer:%u size:%"PRIu64, impl, id, buffer->this.requested);
31
    return res;
32
 }
33
 
34
@@ -788,7 +794,7 @@
35
    if (impl->direction == SPA_DIRECTION_INPUT) {
36
        struct buffer *b;
37
 
38
-       while ((b = pop_queue(impl, &impl->dequeued))) {
39
+       while ((b = queue_pop(impl, &impl->dequeued))) {
40
            if (b->busy)
41
                ATOMIC_DEC(b->busy->count);
42
        }
43
@@ -927,7 +933,7 @@
44
 
45
        if (impl->direction == SPA_DIRECTION_OUTPUT) {
46
            pw_log_trace("%p: recycle buffer %d", stream, b->id);
47
-           push_queue(impl, &impl->dequeued, b);
48
+           queue_push(impl, &impl->dequeued, b);
49
        }
50
 
51
        SPA_FLAG_SET(b->flags, BUFFER_FLAG_ADDED);
52
@@ -945,7 +951,7 @@
53
    struct stream *d = object;
54
    pw_log_trace("%p: recycle buffer %d", d, buffer_id);
55
    if (buffer_id < d->n_buffers)
56
-       push_queue(d, &d->queued, &d->buffersbuffer_id);
57
+       queue_push(d, &d->queued, &d->buffersbuffer_id);
58
    return 0;
59
 }
60
 
61
@@ -984,7 +990,7 @@
62
    if (io->status == SPA_STATUS_HAVE_DATA &&
63
        (b = get_buffer(stream, io->buffer_id)) != NULL) {
64
        /* push new buffer */
65
-       if (push_queue(impl, &impl->dequeued, b) == 0) {
66
+       if (queue_push(impl, &impl->dequeued, b) == 0) {
67
            copy_position(impl, impl->dequeued.incount);
68
            if (b->busy)
69
                ATOMIC_INC(b->busy->count);
70
@@ -993,7 +999,7 @@
71
    }
72
    if (io->status != SPA_STATUS_NEED_DATA) {
73
        /* pop buffer to recycle */
74
-       if ((b = pop_queue(impl, &impl->queued))) {
75
+       if ((b = queue_pop(impl, &impl->queued))) {
76
            pw_log_trace_fp("%p: recycle buffer %d", stream, b->id);
77
        } else if (io->status == -EPIPE)
78
            return io->status;
79
@@ -1013,28 +1019,36 @@
80
    struct spa_io_buffers *io = impl->io;
81
    struct buffer *b;
82
    int res;
83
-   uint32_t index;
84
-   bool recycled;
85
+   bool ask_more;
86
 
87
 again:
88
    pw_log_trace_fp("%p: process out status:%d id:%d", stream,
89
            io->status, io->buffer_id);
90
 
91
-   recycled = false;
92
+   ask_more = false;
93
    if ((res = io->status) != SPA_STATUS_HAVE_DATA) {
94
        /* recycle old buffer */
95
        if ((b = get_buffer(stream, io->buffer_id)) != NULL) {
96
            pw_log_trace_fp("%p: recycle buffer %d", stream, b->id);
97
-           push_queue(impl, &impl->dequeued, b);
98
-           recycled = true;
99
+           queue_push(impl, &impl->dequeued, b);
100
        }
101
 
102
        /* pop new buffer */
103
-       if ((b = pop_queue(impl, &impl->queued)) != NULL) {
104
+       if ((b = queue_pop(impl, &impl->queued)) != NULL) {
105
            impl->drained = false;
106
            io->buffer_id = b->id;
107
            res = io->status = SPA_STATUS_HAVE_DATA;
108
            pw_log_trace_fp("%p: pop %d %p", stream, b->id, io);
109
+           /* we have a buffer, if we are not rt and don't follow
110
+            * any rate matching and there are no more
111
+            * buffers queued and there is a buffer to dequeue, ask for
112
+            * more buffers so that we have one in the next round.
113
+            * If we are using rate matching we need to wait until the
114
+            * rate matching node (audioconvert) has been scheduled to
115
+            * update the values. */
116
+           ask_more = !impl->process_rt && impl->rate_match == NULL &&
117
+               queue_is_empty(impl, &impl->queued) &&
118
+               !queue_is_empty(impl, &impl->dequeued);
119
        } else if (impl->draining || impl->drained) {
120
            impl->draining = true;
121
            impl->drained = true;
122
@@ -1045,7 +1059,12 @@
123
            io->buffer_id = SPA_ID_INVALID;
124
            res = io->status = SPA_STATUS_NEED_DATA;
125
            pw_log_trace_fp("%p: no more buffers %p", stream, io);
126
+           ask_more = true;
127
        }
128
+   } else {
129
+       ask_more = !impl->process_rt &&
130
+           queue_is_empty(impl, &impl->queued) &&
131
+           !queue_is_empty(impl, &impl->dequeued);
132
    }
133
 
134
    copy_position(impl, impl->queued.outcount);
135
@@ -1053,18 +1072,13 @@
136
    if (!impl->draining && !impl->driving) {
137
        /* we're not draining, not a driver check if we need to get
138
         * more buffers */
139
-       if (!impl->process_rt && (recycled || res == SPA_STATUS_NEED_DATA)) {
140
-           /* not realtime and we have a free buffer, trigger process so that we have
141
-            * data in the next round. */
142
-           if (update_requested(impl) > 0)
143
-               call_process(impl);
144
-       } else if (res == SPA_STATUS_NEED_DATA) {
145
-           /* realtime and we don't have a buffer, trigger process and try
146
-            * again when there is something in the queue now */
147
+       if (ask_more) {
148
            if (update_requested(impl) > 0)
149
                call_process(impl);
150
-           if (impl->draining ||
151
-               spa_ringbuffer_get_read_index(&impl->queued.ring, &index) > 0)
152
+           /* realtime, we can try again now if there is something.
153
+            * non-realtime, we will have to try in the next round */
154
+           if (impl->process_rt &&
155
+               (impl->draining || !queue_is_empty(impl, &impl->queued)))
156
                goto again;
157
        }
158
    }
159
@@ -1155,7 +1169,7 @@
160
        struct control *c;
161
        const struct spa_pod *type, *pod;
162
        uint32_t iid, choice, n_vals, container = SPA_ID_INVALID;
163
-       float *vals, bool_range3 = { 1.0, 0.0, 1.0 }, dbl3;
164
+       float *vals, bool_range3 = { 1.0f, 0.0f, 1.0f }, dbl3;
165
 
166
        if (spa_pod_parse_object(param,
167
                    SPA_TYPE_OBJECT_PropInfo, NULL,
168
@@ -1279,7 +1293,7 @@
169
            case SPA_TYPE_Bool:
170
                if (spa_pod_get_bool(&prop->value, &value.b) < 0)
171
                    continue;
172
-               value.f = value.b ? 1.0 : 0.0;
173
+               value.f = value.b ? 1.0f : 0.0f;
174
                n_values = 1;
175
                values = &value.f;
176
                break;
177
@@ -2229,7 +2243,7 @@
178
    struct buffer *b;
179
    int res;
180
 
181
-   if ((b = pop_queue(impl, &impl->dequeued)) == NULL) {
182
+   if ((b = queue_pop(impl, &impl->dequeued)) == NULL) {
183
        res = -errno;
184
        pw_log_trace_fp("%p: no more buffers: %m", stream);
185
        errno = -res;
186
@@ -2240,7 +2254,7 @@
187
    if (b->busy && impl->direction == SPA_DIRECTION_OUTPUT) {
188
        if (ATOMIC_INC(b->busy->count) > 1) {
189
            ATOMIC_DEC(b->busy->count);
190
-           push_queue(impl, &impl->dequeued, b);
191
+           queue_push(impl, &impl->dequeued, b);
192
            pw_log_trace_fp("%p: buffer busy", stream);
193
            errno = EBUSY;
194
            return NULL;
195
@@ -2260,7 +2274,7 @@
196
        ATOMIC_DEC(b->busy->count);
197
 
198
    pw_log_trace_fp("%p: queue buffer %d", stream, b->id);
199
-   if ((res = push_queue(impl, &impl->queued, b)) < 0)
200
+   if ((res = queue_push(impl, &impl->queued, b)) < 0)
201
pipewire-0.3.54.tar.gz/src/pipewire/stream.h -> pipewire-0.3.56.tar.gz/src/pipewire/stream.h Changed
21
 
1
@@ -436,9 +436,16 @@
2
 int
3
 pw_stream_connect(struct pw_stream *stream,        /**< a \ref pw_stream */
4
          enum pw_direction direction,      /**< the stream direction */
5
-         uint32_t target_id,           /**< the target object id to connect to or
6
-                             *  PW_ID_ANY to let the manager
7
-                             *  select a target. */
8
+         uint32_t target_id,           /**< should have the value PW_ID_ANY.
9
+                             * To select a specific target
10
+                             * node, specify the
11
+                             * PW_KEY_OBJECT_SERIAL or the
12
+                             * PW_KEY_NODE_NAME value of the target
13
+                             * node in the PW_KEY_TARGET_OBJECT
14
+                             * property of the stream.
15
+                             * Specifying target nodes by
16
+                             * their id is deprecated.
17
+                             */
18
          enum pw_stream_flags flags,       /**< stream flags */
19
          const struct spa_pod **params,    /**< an array with params. The params
20
                              *  should ideally contain supported
21
pipewire-0.3.54.tar.gz/src/tests/meson.build -> pipewire-0.3.56.tar.gz/src/tests/meson.build Changed
9
 
1
@@ -3,6 +3,7 @@
2
   'test-interfaces',
3
   # 'test-remote',
4
   'test-stream',
5
+  'test-filter',
6
 
7
 
8
 foreach a : test_apps
9
pipewire-0.3.56.tar.gz/src/tests/test-filter.c Added
201
 
1
@@ -0,0 +1,375 @@
2
+/* PipeWire
3
+ *
4
+ * Copyright © 2022 Wim Taymans
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a
7
+ * copy of this software and associated documentation files (the "Software"),
8
+ * to deal in the Software without restriction, including without limitation
9
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
+ * and/or sell copies of the Software, and to permit persons to whom the
11
+ * Software is furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice (including the next
14
+ * paragraph) shall be included in all copies or substantial portions of the
15
+ * Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23
+ * DEALINGS IN THE SOFTWARE.
24
+ */
25
+
26
+#include <pipewire/pipewire.h>
27
+#include <pipewire/main-loop.h>
28
+#include <pipewire/filter.h>
29
+
30
+#include <spa/utils/string.h>
31
+
32
+#define TEST_FUNC(a,b,func)    \
33
+do {               \
34
+   a.func = b.func;    \
35
+   spa_assert_se(SPA_PTRDIFF(&a.func, &a) == SPA_PTRDIFF(&b.func, &b)); \
36
+} while(0)
37
+
38
+static void test_abi(void)
39
+{
40
+   static const struct {
41
+       uint32_t version;
42
+       void (*destroy) (void *data);
43
+       void (*state_changed) (void *data, enum pw_filter_state old,
44
+           enum pw_filter_state state, const char *error);
45
+       void (*io_changed) (void *data, void *port_data, uint32_t id, void *area, uint32_t size);
46
+       void (*param_changed) (void *data, void *port_data, uint32_t id, const struct spa_pod *param);
47
+       void (*add_buffer) (void *data, void *port_data, struct pw_buffer *buffer);
48
+       void (*remove_buffer) (void *data, void *port_data, struct pw_buffer *buffer);
49
+       void (*process) (void *data, struct spa_io_position *position);
50
+       void (*drained) (void *data);
51
+       void (*command) (void *data, const struct spa_command *command);
52
+   } test = { PW_VERSION_FILTER_EVENTS, NULL };
53
+
54
+   struct pw_filter_events ev;
55
+
56
+   TEST_FUNC(ev, test, destroy);
57
+   TEST_FUNC(ev, test, state_changed);
58
+   TEST_FUNC(ev, test, io_changed);
59
+   TEST_FUNC(ev, test, param_changed);
60
+   TEST_FUNC(ev, test, add_buffer);
61
+   TEST_FUNC(ev, test, remove_buffer);
62
+   TEST_FUNC(ev, test, process);
63
+   TEST_FUNC(ev, test, drained);
64
+   TEST_FUNC(ev, test, command);
65
+
66
+   spa_assert_se(PW_VERSION_FILTER_EVENTS == 1);
67
+   spa_assert_se(sizeof(ev) == sizeof(test));
68
+
69
+   spa_assert_se(PW_FILTER_STATE_ERROR == -1);
70
+   spa_assert_se(PW_FILTER_STATE_UNCONNECTED == 0);
71
+   spa_assert_se(PW_FILTER_STATE_CONNECTING == 1);
72
+   spa_assert_se(PW_FILTER_STATE_PAUSED == 2);
73
+   spa_assert_se(PW_FILTER_STATE_STREAMING == 3);
74
+
75
+   spa_assert_se(pw_filter_state_as_string(PW_FILTER_STATE_ERROR) != NULL);
76
+   spa_assert_se(pw_filter_state_as_string(PW_FILTER_STATE_UNCONNECTED) != NULL);
77
+   spa_assert_se(pw_filter_state_as_string(PW_FILTER_STATE_CONNECTING) != NULL);
78
+   spa_assert_se(pw_filter_state_as_string(PW_FILTER_STATE_PAUSED) != NULL);
79
+   spa_assert_se(pw_filter_state_as_string(PW_FILTER_STATE_STREAMING) != NULL);
80
+}
81
+
82
+static void filter_destroy_error(void *data)
83
+{
84
+   spa_assert_not_reached();
85
+}
86
+static void filter_state_changed_error(void *data, enum pw_filter_state old,
87
+       enum pw_filter_state state, const char *error)
88
+{
89
+   spa_assert_not_reached();
90
+}
91
+static void filter_io_changed_error(void *data, void *port_data, uint32_t id, void *area, uint32_t size)
92
+{
93
+   spa_assert_not_reached();
94
+}
95
+static void filter_param_changed_error(void *data, void *port_data, uint32_t id, const struct spa_pod *format)
96
+{
97
+   spa_assert_not_reached();
98
+}
99
+static void filter_add_buffer_error(void *data, void *port_data, struct pw_buffer *buffer)
100
+{
101
+   spa_assert_not_reached();
102
+}
103
+static void filter_remove_buffer_error(void *data, void *port_data, struct pw_buffer *buffer)
104
+{
105
+   spa_assert_not_reached();
106
+}
107
+static void filter_process_error(void *data, struct spa_io_position *position)
108
+{
109
+   spa_assert_not_reached();
110
+}
111
+static void filter_drained_error(void *data)
112
+{
113
+   spa_assert_not_reached();
114
+}
115
+
116
+static const struct pw_filter_events filter_events_error =
117
+{
118
+   PW_VERSION_FILTER_EVENTS,
119
+        .destroy = filter_destroy_error,
120
+        .state_changed = filter_state_changed_error,
121
+   .io_changed = filter_io_changed_error,
122
+   .param_changed = filter_param_changed_error,
123
+   .add_buffer = filter_add_buffer_error,
124
+   .remove_buffer = filter_remove_buffer_error,
125
+   .process = filter_process_error,
126
+   .drained = filter_drained_error
127
+};
128
+
129
+static int destroy_count = 0;
130
+static void filter_destroy_count(void *data)
131
+{
132
+   destroy_count++;
133
+}
134
+static void test_create(void)
135
+{
136
+   struct pw_main_loop *loop;
137
+   struct pw_context *context;
138
+   struct pw_core *core;
139
+   struct pw_filter *filter;
140
+   struct pw_filter_events filter_events = filter_events_error;
141
+   struct spa_hook listener = { 0, };
142
+   const char *error = NULL;
143
+
144
+   loop = pw_main_loop_new(NULL);
145
+   context = pw_context_new(pw_main_loop_get_loop(loop), NULL, 12);
146
+   spa_assert_se(context != NULL);
147
+   core = pw_context_connect_self(context, NULL, 0);
148
+   spa_assert_se(core != NULL);
149
+   filter = pw_filter_new(core, "test", NULL);
150
+   spa_assert_se(filter != NULL);
151
+   pw_filter_add_listener(filter, &listener, &filter_events, filter);
152
+
153
+   /* check state */
154
+   spa_assert_se(pw_filter_get_state(filter, &error) == PW_FILTER_STATE_UNCONNECTED);
155
+   spa_assert_se(error == NULL);
156
+   /* check name */
157
+   spa_assert_se(spa_streq(pw_filter_get_name(filter), "test"));
158
+
159
+   /* check id, only when connected */
160
+   spa_assert_se(pw_filter_get_node_id(filter) == SPA_ID_INVALID);
161
+
162
+   /* check destroy */
163
+   destroy_count = 0;
164
+   filter_events.destroy = filter_destroy_count;
165
+   pw_filter_destroy(filter);
166
+   spa_assert_se(destroy_count == 1);
167
+
168
+   pw_context_destroy(context);
169
+   pw_main_loop_destroy(loop);
170
+}
171
+
172
+static void test_properties(void)
173
+{
174
+   struct pw_main_loop *loop;
175
+   struct pw_context *context;
176
+   struct pw_core *core;
177
+   const struct pw_properties *props;
178
+   struct pw_filter *filter;
179
+   struct pw_filter_events filter_events = filter_events_error;
180
+   struct spa_hook listener = { { NULL }, };
181
+   struct spa_dict_item items3;
182
+
183
+   loop = pw_main_loop_new(NULL);
184
+   context = pw_context_new(pw_main_loop_get_loop(loop), NULL, 12);
185
+   spa_assert_se(context != NULL);
186
+   core = pw_context_connect_self(context, NULL, 0);
187
+   spa_assert_se(core != NULL);
188
+   filter = pw_filter_new(core, "test",
189
+           pw_properties_new("foo", "bar",
190
+                     "biz", "fuzz",
191
+                     NULL));
192
+   spa_assert_se(filter != NULL);
193
+   pw_filter_add_listener(filter, &listener, &filter_events, filter);
194
+
195
+   props = pw_filter_get_properties(filter, NULL);
196
+   spa_assert_se(props != NULL);
197
+   spa_assert_se(spa_streq(pw_properties_get(props, "foo"), "bar"));
198
+   spa_assert_se(spa_streq(pw_properties_get(props, "biz"), "fuzz"));
199
+   spa_assert_se(pw_properties_get(props, "buzz") == NULL);
200
+
201
pipewire-0.3.54.tar.gz/src/tests/test-stream.c -> pipewire-0.3.56.tar.gz/src/tests/test-stream.c Changed
9
 
1
@@ -251,5 +251,7 @@
2
    test_create();
3
    test_properties();
4
 
5
+   pw_deinit();
6
+
7
    return 0;
8
 }
9
pipewire-0.3.54.tar.gz/src/tools/pw-cat.c -> pipewire-0.3.56.tar.gz/src/tools/pw-cat.c Changed
11
 
1
@@ -1439,9 +1439,7 @@
2
        case OPT_VOLUME:
3
            data.volume = atof(optarg);
4
            break;
5
-
6
        default:
7
-           fprintf(stderr, "error: unknown option '%c'\n", c);
8
            goto error_usage;
9
        }
10
    }
11
pipewire-0.3.54.tar.gz/test/test-spa-json.c -> pipewire-0.3.56.tar.gz/test/test-spa-json.c Changed
55
 
1
@@ -86,7 +86,7 @@
2
 {
3
    const char *value;
4
    int len;
5
-   float f;
6
+   float f = 0.0f;
7
    pwtest_int_gt((len = spa_json_next(it, &value)), 0);
8
    check_type(TYPE_FLOAT, value, len);
9
    pwtest_int_gt(spa_json_parse_float(value, len, &f), 0);
10
@@ -281,6 +281,36 @@
11
    return PWTEST_PASS;
12
 }
13
 
14
+PWTEST(json_float_check)
15
+{
16
+   struct {
17
+       const char *str;
18
+       int res;
19
+   } val = {
20
+       { "0.0", 1 },
21
+       { ".0", 1 },
22
+       { "+.0E0", 1 },
23
+       { "-.0e0", 1 },
24
+
25
+       { "0,0", 0 },
26
+       { "0.0.5", 0 },
27
+       { "0x0", 0 },
28
+       { "0x0.0", 0 },
29
+       { "E10", 0 },
30
+       { "e20", 0 },
31
+       { " 0.0", 0 },
32
+       { "0.0 ", 0 },
33
+       { " 0.0 ", 0 },
34
+   };
35
+   unsigned i;
36
+   float v;
37
+
38
+   for (i = 0; i < SPA_N_ELEMENTS(val); i++) {
39
+       pwtest_int_eq(spa_json_parse_float(vali.str, strlen(vali.str), &v), vali.res);
40
+   }
41
+   return PWTEST_PASS;
42
+}
43
+
44
 PWTEST(json_int)
45
 {
46
    int v;
47
@@ -296,6 +326,7 @@
48
    pwtest_add(json_array, PWTEST_NOARG);
49
    pwtest_add(json_overflow, PWTEST_NOARG);
50
    pwtest_add(json_float, PWTEST_NOARG);
51
+   pwtest_add(json_float_check, PWTEST_NOARG);
52
    pwtest_add(json_int, PWTEST_NOARG);
53
 
54
    return PWTEST_PASS;
55