We truncated the diff of some files because they were too big.
If you want to see the full diff for every file, click here.
Changes of Revision 13
pipewire-0.3.54.tar.gz/src/daemon/filter-chain/duplicate-FL.conf
Deleted
x
1
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
2
audiomixer_sources =
3
'audiomixer.c',
4
- 'mix-ops.c',
5
'mixer-dsp.c',
6
'plugin.c'
7
8
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
2
enum {
3
CRYPTO_NONE,
4
CRYPTO_RSA,
5
+ CRYPTO_AUTH_SETUP,
6
};
7
enum {
8
CODEC_PCM,
9
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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