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 34
pipewire-aptx.changes
Changed
x
1
2
-------------------------------------------------------------------
3
+Fri Sep 22 17:21:32 UTC 2023 - Bjørn Lie <zaitor@opensuse.org>
4
+
5
+- Update to version 0.3.80
6
+
7
+-------------------------------------------------------------------
8
Wed Aug 30 13:49:39 UTC 2023 - Bjørn Lie <zaitor@opensuse.org>
9
10
- Update to version 0.3.79
11
pipewire-aptx.spec
Changed
10
1
2
%define soversion 0_2
3
4
Name: pipewire-aptx
5
-Version: 0.3.79
6
+Version: 0.3.80
7
Release: 0
8
Summary: PipeWire Bluetooth aptX codec plugin
9
License: MIT
10
pipewire-0.3.79.tar.gz/.gitignore -> pipewire-0.3.80.tar.gz/.gitignore
Changed
9
1
2
subprojects/libyaml.wrap
3
subprojects/libyaml
4
subprojects/libcamera
5
+subprojects/webrtc-audio-processing
6
7
# Created by https://www.gitignore.io/api/vim
8
9
pipewire-0.3.79.tar.gz/NEWS -> pipewire-0.3.80.tar.gz/NEWS
Changed
83
1
2
+# PipeWire 0.3.80 (2023-09-14)
3
+
4
+This is a bugfix release that is API and ABI compatible with previous
5
+0.3.x releases.
6
+
7
+## Highlights
8
+ - A new Tag param was added that allows arbitrary metadata to be transported
9
+ out-of-band in the graph.
10
+ - Vulkan DMA buf support was merged.
11
+ - The echo-canceller was ported to webrtc-audio-processing-1.
12
+ - Fix a regression in locating monitor sources by id in pulse-server.
13
+ - Mixer io areas updates are now synchronized correctly with the data
14
+ thread to avoid potential crashes.
15
+ - Many more bugfixes and improvements.
16
+
17
+
18
+## PipeWire
19
+ - Handle driver nodes that refuse to change the quantum or rate.
20
+ - A new Tag param was added that allows arbitrary metadata to be transported
21
+ out-of-band in the graph.
22
+
23
+## Modules
24
+ - The pipe-tunnel source has been reworked to use a ringbuffer and rate
25
+ adaption to keep the latency constant. It can now also function as a
26
+ driver to reduce resampling. (#3478)
27
+
28
+## Tools
29
+ - pw-cat will now place media properties in Tag params.
30
+ - pw-mon can now filter props and params.
31
+
32
+## SPA
33
+ - ALSA refuses to change quantum and rate when in IRQ mode.
34
+ - ALSA will now be smarter in selecting the period size for batch devices
35
+ and will make it depend on the samplerate. (#3444)
36
+ - Vulkan DMA buf support was merged.
37
+ - ALSA latency will now be reported in the time domain of the graph.
38
+ - Add udev based autodetection for compress-offload devices.
39
+ - The echo-canceller was ported to webrtc-audio-processing-1.
40
+ - The v4l2 inotify code was rewritten to avoid a use-after-free and by
41
+ using a separate watch (but same fd) for each device. (#3439)
42
+ - The tag and latency handling was improved in audioadpter.
43
+ - Don't use -Ofast on alpha because it can crash on denormalized
44
+ values. (#3489)
45
+ - The mixers now synchronize spa_io_buffers updates with the data
46
+ thread to avoid crashes.
47
+ - Handle NULL param updates. (#3504)
48
+
49
+## Pulse-server
50
+ - Fix a regression in locating monitor sources by id. (#3476)
51
+ - Add support for use_system_clock_for_timing in module-pipe-sink.
52
+ - Add support for checking module arguments.
53
+ - Avoid some useless change events.
54
+
55
+## Bluetooth
56
+ - Ports are now marked as physical, which makes the bluetooth devices show
57
+ up as hardware devices in Ardour and other JACK apps. (#3418)
58
+ - Some fixes for LE audio support (#3479)
59
+
60
+## JACK
61
+ - Also emit unregister notify even when supressed when creating the
62
+ client.
63
+ - The notify callbacks now match JACK2 behaviour more.
64
+ - The mixer io areas are updated and handled safely now to avoid
65
+ crashes. (#3506)
66
+
67
+Older versions:
68
+
69
+
70
# PipeWire 0.3.79 (2023-08-29)
71
72
This is a quick bugfix release that is API and ABI compatible with previous
73
74
- Improve property handling, support lists and ranges in addition to
75
fixed values. (#3451)
76
77
-Older versions:
78
-
79
-
80
# PipeWire 0.3.78 (2023-08-22)
81
82
This is a small bugfix release that is API and ABI compatible with previous
83
pipewire-0.3.79.tar.gz/man/pipewire-pulse.1.rst.in -> pipewire-0.3.80.tar.gz/man/pipewire-pulse.1.rst.in
Changed
12
1
2
===========
3
4
**pipewire-pulse** starts a PulseAudio-compatible daemon that integrates with
5
-the PipeWire media server. This daemon is a drop-in replacement for the
6
-PulseAudio daemon.
7
+the PipeWire media server, by running a pipewire process through a systemd
8
+service. This daemon is a drop-in replacement for the PulseAudio daemon.
9
10
OPTIONS
11
=======
12
pipewire-0.3.79.tar.gz/man/pipewire.conf.5.rst.in -> pipewire-0.3.80.tar.gz/man/pipewire.conf.5.rst.in
Changed
10
1
2
of use, a relaxed format may be used where:
3
4
* ``:`` to delimit keys and values can be substuted by ``=`` or a space.
5
- * ``"`` around keys and string can be omited as long as no special characters are used in the strings.
6
+ * ``"`` around keys and string can be omitted as long as no special characters are used in the strings.
7
* ``,`` to separate objects can be replaced with a whitespace character.
8
* ``#`` can be used to start a comment until the line end
9
10
pipewire-0.3.79.tar.gz/man/pw-top.1.rst.in -> pipewire-0.3.80.tar.gz/man/pw-top.1.rst.in
Changed
20
1
2
-h | --help
3
Show help.
4
5
+-b | --batch-mode
6
+ Run in non-interactive batch mode, similar to top's batch mode.
7
+
8
+-n | --iterations=NUMBER
9
+ Exit after NUMBER of batch iterations. Only used in batch mode.
10
+
11
-r | --remote=NAME
12
The name the *remote* instance to monitor. If left unspecified,
13
a connection is made to the default PipeWire instance.
14
15
---version
16
+-V | --version
17
Show version information.
18
19
20
pipewire-0.3.79.tar.gz/meson.build -> pipewire-0.3.80.tar.gz/meson.build
Changed
39
1
2
project('pipewire', 'c' ,
3
- version : '0.3.79',
4
+ version : '0.3.80',
5
license : 'MIT', 'LGPL-2.1-or-later', 'GPL-2.0-only' ,
6
meson_version : '>= 0.61.1',
7
default_options : 'warning_level=3',
8
9
pipewire_confdatadir = pipewire_datadir / 'pipewire'
10
modules_install_dir = pipewire_libdir / pipewire_name
11
12
-if host_machine.system() == 'linux'
13
+cc = meson.get_compiler('c')
14
+
15
+if cc.has_header('features.h') and cc.get_define('__GLIBC__', prefix: '#include <features.h>') != ''
16
# glibc ld.so interprets ${LIB} in a library loading path with an
17
# appropriate value for the current architecture, typically something
18
# like lib, lib64 or lib/x86_64-linux-gnu.
19
20
21
pkgconfig = import('pkgconfig')
22
23
-cc = meson.get_compiler('c')
24
-
25
common_flags =
26
'-fvisibility=hidden',
27
'-fno-strict-aliasing',
28
29
30
cdata.set('HAVE_GSTREAMER_DEVICE_PROVIDER', get_option('gstreamer-device-provider').allowed())
31
32
-webrtc_dep = dependency('webrtc-audio-processing',
33
- version : '>= 0.2', '< 1.0',
34
+webrtc_dep = dependency('webrtc-audio-processing-1',
35
+ version : '>= 1.2' ,
36
required : get_option('echo-cancel-webrtc'))
37
summary({'WebRTC Echo Canceling': webrtc_dep.found()}, bool_yn: true, section: 'Misc dependencies')
38
cdata.set('HAVE_WEBRTC', webrtc_dep.found())
39
pipewire-0.3.79.tar.gz/pipewire-jack/src/pipewire-jack.c -> pipewire-0.3.80.tar.gz/pipewire-jack/src/pipewire-jack.c
Changed
201
1
2
3
struct spa_io_buffers io;
4
struct spa_list mix;
5
+ uint32_t n_mix;
6
struct mix *global_mix;
7
8
struct port *tied;
9
10
11
}
12
13
+struct io_info {
14
+ struct mix *mix;
15
+ void *data;
16
+};
17
+
18
+static int
19
+do_mix_set_io(struct spa_loop *loop, bool async, uint32_t seq,
20
+ const void *data, size_t size, void *user_data)
21
+{
22
+ struct io_info *info = user_data;
23
+ info->mix->io = info->data;
24
+ return 0;
25
+}
26
+
27
+static inline void mix_set_io(struct mix *mix, void *data)
28
+{
29
+ struct io_info info = { .mix = mix, .data = data };
30
+ pw_data_loop_invoke(mix->port->client->loop,
31
+ do_mix_set_io, SPA_ID_INVALID, NULL, 0, true, &info);
32
+}
33
+
34
static void init_mix(struct mix *mix, uint32_t mix_id, struct port *port, uint32_t peer_id)
35
{
36
pw_log_debug("create %p mix:%d peer:%d", port, mix_id, peer_id);
37
38
spa_list_init(&mix->queue);
39
if (mix_id == SPA_ID_INVALID)
40
port->global_mix = mix;
41
+ else if (port->n_mix++ == 0 && port->global_mix != NULL)
42
+ mix_set_io(port->global_mix, &port->io);
43
}
44
static struct mix *find_mix_peer(struct client *c, uint32_t peer_id)
45
{
46
47
48
static void free_mix(struct client *c, struct mix *mix)
49
{
50
+ struct port *port = mix->port;
51
+
52
clear_buffers(c, mix);
53
spa_list_remove(&mix->port_link);
54
if (mix->id == SPA_ID_INVALID)
55
- mix->port->global_mix = NULL;
56
+ port->global_mix = NULL;
57
+ else if (--port->n_mix == 0 && port->global_mix != NULL)
58
+ mix_set_io(port->global_mix, NULL);
59
spa_list_remove(&mix->link);
60
spa_list_append(&c->free_mix, &mix->link);
61
}
62
63
}
64
pw_log_debug("%p: skip notify %08x active:%d emit:%d", c, type,
65
c->active, emit);
66
- if (o != NULL && arg1 == 0 && o->removing) {
67
- o->removing = false;
68
- free_object(c, o);
69
+ if (o != NULL) {
70
+ o->registered = arg1;
71
+ if (arg1 == 0 && o->removing) {
72
+ o->removing = false;
73
+ free_object(c, o);
74
+ }
75
}
76
return res;
77
}
78
79
void *ptr = NULL;
80
struct buffer *b;
81
struct spa_data *d;
82
+ struct spa_io_buffers *io;
83
84
if (frames == 0 || !p->valid)
85
return NULL;
86
87
if (SPA_UNLIKELY((mix = p->global_mix) == NULL))
88
return NULL;
89
90
- pw_log_trace_fp("%p: port %s %d get buffer %d n_buffers:%d",
91
- c, p->object->port.name, p->port_id, frames, mix->n_buffers);
92
+ pw_log_trace_fp("%p: port %s %d get buffer %d n_buffers:%d io:%p",
93
+ c, p->object->port.name, p->port_id, frames,
94
+ mix->n_buffers, mix->io);
95
96
- if (SPA_UNLIKELY(mix->n_buffers == 0))
97
+ if (SPA_UNLIKELY((io = mix->io) == NULL))
98
return NULL;
99
100
- if (p->io.status == SPA_STATUS_HAVE_DATA &&
101
- p->io.buffer_id < mix->n_buffers) {
102
- b = &mix->buffersp->io.buffer_id;
103
+ if (io->status == SPA_STATUS_HAVE_DATA &&
104
+ io->buffer_id < mix->n_buffers) {
105
+ b = &mix->buffersio->buffer_id;
106
d = &b->datas0;
107
} else {
108
- if (p->io.buffer_id < mix->n_buffers) {
109
- reuse_buffer(c, mix, p->io.buffer_id);
110
- p->io.buffer_id = SPA_ID_INVALID;
111
+ if (io->buffer_id < mix->n_buffers) {
112
+ reuse_buffer(c, mix, io->buffer_id);
113
+ io->buffer_id = SPA_ID_INVALID;
114
}
115
if (SPA_UNLIKELY((b = dequeue_buffer(c, mix)) == NULL)) {
116
pw_log_warn("port %p: out of buffers", p);
117
118
d->chunk->size = frames * sizeof(float);
119
d->chunk->stride = stride;
120
121
- p->io.status = SPA_STATUS_HAVE_DATA;
122
- p->io.buffer_id = b->id;
123
+ io->status = SPA_STATUS_HAVE_DATA;
124
+ io->buffer_id = b->id;
125
}
126
ptr = d->data;
127
if (buf)
128
129
static void prepare_output(struct port *p, uint32_t frames)
130
{
131
struct mix *mix;
132
+ struct spa_io_buffers *io;
133
134
if (SPA_UNLIKELY(p->empty_out || p->tied))
135
process_empty(p, frames);
136
137
+ if (p->global_mix == NULL || (io = p->global_mix->io) == NULL)
138
+ return;
139
+
140
spa_list_for_each(mix, &p->mix, port_link) {
141
if (SPA_LIKELY(mix->io != NULL))
142
- *mix->io = p->io;
143
+ *mix->io = *io;
144
}
145
+ io->status = SPA_STATUS_NEED_DATA;
146
}
147
148
static void complete_process(struct client *c, uint32_t frames)
149
150
if (!p->valid)
151
continue;
152
prepare_output(p, frames);
153
- p->io.status = SPA_STATUS_NEED_DATA;
154
}
155
pw_array_for_each(item, &c->portsSPA_DIRECTION_INPUT.items) {
156
if (pw_map_item_is_free(item))
157
158
159
if (param == NULL)
160
return 0;
161
-
162
if ((res = spa_latency_parse(param, &info)) < 0)
163
return res;
164
165
166
167
switch (id) {
168
case SPA_IO_Buffers:
169
- mix->io = ptr;
170
+ mix_set_io(mix, ptr);
171
break;
172
default:
173
break;
174
175
176
mix = find_mix(c, p, mix_id);
177
178
+ pw_log_debug("%p: port %p mix:%d peer_id:%u info:%p", c, p, mix_id,
179
+ peer_id, props);
180
+
181
if (peer_id == SPA_ID_INVALID) {
182
if (mix == NULL) {
183
res = -ENOENT;
184
185
pw_node_state_as_string(info->state), n->node.is_running);
186
187
if (info->change_mask & PW_NODE_CHANGE_MASK_STATE) {
188
- struct object *p;
189
+ struct object *p, *l;
190
spa_list_for_each(p, &c->context.objects, link) {
191
if (p->type != INTERFACE_Port || p->removed ||
192
p->port.node_id != info->id)
193
continue;
194
if (n->node.is_running)
195
queue_notify(c, NOTIFY_TYPE_PORTREGISTRATION, p, 1, NULL);
196
- else
197
+ else {
198
+ spa_list_for_each(l, &c->context.objects, link) {
199
+ if (l->type != INTERFACE_Link || l->removed ||
200
+ (l->port_link.src_serial != p->serial &&
201
pipewire-0.3.79.tar.gz/spa/include/spa/debug/log.h -> pipewire-0.3.80.tar.gz/spa/include/spa/debug/log.h
Changed
37
1
2
3
#define spa_debug_log_pod(l,lev,indent,info,pod) \
4
({ \
5
- struct spa_debug_log_ctx c = SPA_LOG_DEBUG_INIT(l,lev); \
6
+ struct spa_debug_log_ctx c = SPA_LOG_DEBUG_INIT(l,lev); \
7
if (SPA_UNLIKELY(spa_log_level_topic_enabled(c.log, c.topic, c.level))) \
8
spa_debugc_pod(&c.ctx, indent, info, pod); \
9
})
10
11
#define spa_debug_log_format(l,lev,indent,info,format) \
12
({ \
13
- struct spa_debug_log_ctx c = SPA_LOG_DEBUG_INIT(l,lev); \
14
+ struct spa_debug_log_ctx c = SPA_LOG_DEBUG_INIT(l,lev); \
15
if (SPA_UNLIKELY(spa_log_level_topic_enabled(c.log, c.topic, c.level))) \
16
spa_debugc_format(&c.ctx, indent, info, format); \
17
})
18
19
#define spa_debug_log_mem(l,lev,indent,data,len) \
20
({ \
21
- struct spa_debug_log_ctx c = SPA_LOG_DEBUG_INIT(l,lev); \
22
+ struct spa_debug_log_ctx c = SPA_LOG_DEBUG_INIT(l,lev); \
23
if (SPA_UNLIKELY(spa_log_level_topic_enabled(c.log, c.topic, c.level))) \
24
spa_debugc_mem(&c.ctx, indent, data, len); \
25
})
26
27
+#define spa_debug_log_dict(l,lev,indent,dict) \
28
+({ \
29
+ struct spa_debug_log_ctx c = SPA_LOG_DEBUG_INIT(l,lev); \
30
+ if (SPA_UNLIKELY(spa_log_level_topic_enabled(c.log, c.topic, c.level))) \
31
+ spa_debugc_dict(&c.ctx, indent, dict); \
32
+})
33
+
34
/**
35
* \}
36
*/
37
pipewire-0.3.79.tar.gz/spa/include/spa/node/keys.h -> pipewire-0.3.80.tar.gz/spa/include/spa/node/keys.h
Changed
10
1
2
3
/** node keys */
4
#define SPA_KEY_NODE_NAME "node.name" /**< a node name */
5
+#define SPA_KEY_NODE_DESCRIPTION "node.description" /**< localized human readable node one-line
6
+ * description. Ex. "Foobar USB Headset" */
7
#define SPA_KEY_NODE_LATENCY "node.latency" /**< the requested node latency */
8
#define SPA_KEY_NODE_MAX_LATENCY "node.max-latency" /**< maximum supported latency */
9
10
pipewire-0.3.79.tar.gz/spa/include/spa/node/node.h -> pipewire-0.3.80.tar.gz/spa/include/spa/node/node.h
Changed
34
1
2
*
3
* When \a param is NULL, the parameter will be unset.
4
*
5
- * This function must be called from the main thread.
6
+ * This function must be called from the main thread. The node muse be paused
7
+ * or the port SPA_IO_Buffers area is NULL when this function is called with
8
+ * a param that changes the processing state (like a format change).
9
*
10
* \param node a struct \ref spa_node
11
* \param direction a enum \ref spa_direction
12
13
* When this function returns async, use the spa_node_sync operation to
14
* wait for completion.
15
*
16
- * This function must be called from the main thread.
17
+ * This function must be called from the main thread. The node muse be paused
18
+ * or the port SPA_IO_Buffers area is NULL when this function is called.
19
*
20
* \param object an object implementing the interface
21
* \param direction a port direction
22
23
*
24
* This function must be called from the main thread.
25
*
26
+ * This function can be called when the node is running and the node
27
+ * must be prepared to handle changes in io areas while running. This
28
+ * is normally done by synchronizing the port io updates with the
29
+ * data processing loop.
30
+ *
31
* \param direction a spa_direction
32
* \param port_id a port id
33
* \param id the id of the io area, the available ids can be
34
pipewire-0.3.79.tar.gz/spa/include/spa/param/param-types.h -> pipewire-0.3.80.tar.gz/spa/include/spa/param/param-types.h
Changed
9
1
2
{ SPA_PARAM_Control, SPA_TYPE_Sequence, SPA_TYPE_INFO_PARAM_ID_BASE "Control", NULL },
3
{ SPA_PARAM_Latency, SPA_TYPE_OBJECT_ParamLatency, SPA_TYPE_INFO_PARAM_ID_BASE "Latency", NULL },
4
{ SPA_PARAM_ProcessLatency, SPA_TYPE_OBJECT_ParamProcessLatency, SPA_TYPE_INFO_PARAM_ID_BASE "ProcessLatency", NULL },
5
+ { SPA_PARAM_Tag, SPA_TYPE_OBJECT_ParamTag, SPA_TYPE_INFO_PARAM_ID_BASE "Tag", NULL },
6
{ 0, 0, NULL, NULL },
7
};
8
9
pipewire-0.3.79.tar.gz/spa/include/spa/param/param.h -> pipewire-0.3.80.tar.gz/spa/include/spa/param/param.h
Changed
9
1
2
SPA_PARAM_Control, /**< Control parameter, a SPA_TYPE_Sequence */
3
SPA_PARAM_Latency, /**< latency reporting, a SPA_TYPE_OBJECT_ParamLatency */
4
SPA_PARAM_ProcessLatency, /**< processing latency, a SPA_TYPE_OBJECT_ParamProcessLatency */
5
+ SPA_PARAM_Tag, /**< tag reporting, a SPA_TYPE_OBJECT_ParamTag. Since 0.3.79 */
6
};
7
8
/** information about a parameter */
9
pipewire-0.3.80.tar.gz/spa/include/spa/param/tag-types.h
Added
41
1
2
+/* Simple Plugin API */
3
+/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
4
+/* SPDX-License-Identifier: MIT */
5
+
6
+#ifndef SPA_PARAM_TAG_TYPES_H
7
+#define SPA_PARAM_TAG_TYPES_H
8
+
9
+#ifdef __cplusplus
10
+extern "C" {
11
+#endif
12
+
13
+/**
14
+ * \addtogroup spa_param
15
+ * \{
16
+ */
17
+
18
+#include <spa/utils/enum-types.h>
19
+#include <spa/param/param-types.h>
20
+#include <spa/param/tag.h>
21
+
22
+#define SPA_TYPE_INFO_PARAM_Tag SPA_TYPE_INFO_PARAM_BASE "Tag"
23
+#define SPA_TYPE_INFO_PARAM_TAG_BASE SPA_TYPE_INFO_PARAM_Tag ":"
24
+
25
+static const struct spa_type_info spa_type_param_tag = {
26
+ { SPA_PARAM_TAG_START, SPA_TYPE_Id, SPA_TYPE_INFO_PARAM_TAG_BASE, spa_type_param, },
27
+ { SPA_PARAM_TAG_direction, SPA_TYPE_Id, SPA_TYPE_INFO_PARAM_TAG_BASE "direction", spa_type_direction, },
28
+ { SPA_PARAM_TAG_info, SPA_TYPE_Struct, SPA_TYPE_INFO_PARAM_TAG_BASE "info", NULL, },
29
+ { 0, 0, NULL, NULL },
30
+};
31
+
32
+/**
33
+ * \}
34
+ */
35
+
36
+#ifdef __cplusplus
37
+} /* extern "C" */
38
+#endif
39
+
40
+#endif /* SPA_PARAM_TAG_TYPES_H */
41
pipewire-0.3.80.tar.gz/spa/include/spa/param/tag-utils.h
Added
145
1
2
+/* Simple Plugin API */
3
+/* SPDX-FileCopyrightText: Copyright © 2023 Wim Taymans */
4
+/* SPDX-License-Identifier: MIT */
5
+
6
+#ifndef SPA_PARAM_TAG_UTILS_H
7
+#define SPA_PARAM_TAG_UTILS_H
8
+
9
+#ifdef __cplusplus
10
+extern "C" {
11
+#endif
12
+
13
+/**
14
+ * \addtogroup spa_param
15
+ * \{
16
+ */
17
+
18
+#include <float.h>
19
+
20
+#include <spa/utils/dict.h>
21
+#include <spa/pod/builder.h>
22
+#include <spa/pod/parser.h>
23
+#include <spa/param/tag.h>
24
+
25
+static inline int
26
+spa_tag_compare(const struct spa_pod *a, const struct spa_pod *b)
27
+{
28
+ return ((a == b) || (a && b && SPA_POD_SIZE(a) == SPA_POD_SIZE(b) &&
29
+ memcmp(a, b, SPA_POD_SIZE(b)) == 0)) ? 0 : 1;
30
+}
31
+
32
+static inline int
33
+spa_tag_parse(const struct spa_pod *tag, struct spa_tag_info *info, void **state)
34
+{
35
+ int res;
36
+ const struct spa_pod_object *obj = (const struct spa_pod_object*)tag;
37
+ const struct spa_pod_prop *first, *start, *cur;
38
+
39
+ spa_zero(*info);
40
+
41
+ if ((res = spa_pod_parse_object(tag,
42
+ SPA_TYPE_OBJECT_ParamTag, NULL,
43
+ SPA_PARAM_TAG_direction, SPA_POD_Id(&info->direction))) < 0)
44
+ return res;
45
+
46
+ first = spa_pod_prop_first(&obj->body);
47
+ start = *state ? spa_pod_prop_next((struct spa_pod_prop*)*state) : first;
48
+
49
+ res = 0;
50
+ for (cur = start; spa_pod_prop_is_inside(&obj->body, obj->pod.size, cur);
51
+ cur = spa_pod_prop_next(cur)) {
52
+ if (cur->key == SPA_PARAM_TAG_info) {
53
+ info->info = &cur->value;
54
+ *state = (void*)cur;
55
+ return 1;
56
+ }
57
+ }
58
+ return 0;
59
+}
60
+
61
+static inline int
62
+spa_tag_info_parse(const struct spa_tag_info *info, struct spa_dict *dict, struct spa_dict_item *items)
63
+{
64
+ struct spa_pod_parser prs;
65
+ uint32_t n, n_items;
66
+ const char *key, *value;
67
+ struct spa_pod_frame f1;
68
+
69
+ spa_pod_parser_pod(&prs, info->info);
70
+ if (spa_pod_parser_push_struct(&prs, &f0) < 0 ||
71
+ spa_pod_parser_get_int(&prs, (int32_t*)&n_items) < 0)
72
+ return -EINVAL;
73
+
74
+ if (items == NULL) {
75
+ dict->n_items = n_items;
76
+ return 0;
77
+ }
78
+ n_items = SPA_MIN(dict->n_items, n_items);
79
+
80
+ for (n = 0; n < n_items; n++) {
81
+ if (spa_pod_parser_get(&prs,
82
+ SPA_POD_String(&key),
83
+ SPA_POD_String(&value),
84
+ NULL) < 0)
85
+ break;
86
+ itemsn.key = key;
87
+ itemsn.value = value;
88
+ }
89
+ dict->items = items;
90
+ spa_pod_parser_pop(&prs, &f0);
91
+ return 0;
92
+}
93
+
94
+static inline void
95
+spa_tag_build_start(struct spa_pod_builder *builder, struct spa_pod_frame *f,
96
+ uint32_t id, enum spa_direction direction)
97
+{
98
+ spa_pod_builder_push_object(builder, f, SPA_TYPE_OBJECT_ParamTag, id);
99
+ spa_pod_builder_add(builder,
100
+ SPA_PARAM_TAG_direction, SPA_POD_Id(direction),
101
+ 0);
102
+}
103
+
104
+static inline void
105
+spa_tag_build_add_info(struct spa_pod_builder *builder, const struct spa_pod *info)
106
+{
107
+ spa_pod_builder_add(builder,
108
+ SPA_PARAM_TAG_info, SPA_POD_Pod(info),
109
+ 0);
110
+}
111
+
112
+static inline void
113
+spa_tag_build_add_dict(struct spa_pod_builder *builder, const struct spa_dict *dict)
114
+{
115
+ uint32_t i, n_items;
116
+ struct spa_pod_frame f;
117
+
118
+ n_items = dict ? dict->n_items : 0;
119
+
120
+ spa_pod_builder_prop(builder, SPA_PARAM_TAG_info, SPA_POD_PROP_FLAG_HINT_DICT);
121
+ spa_pod_builder_push_struct(builder, &f);
122
+ spa_pod_builder_int(builder, n_items);
123
+ for (i = 0; i < n_items; i++) {
124
+ spa_pod_builder_string(builder, dict->itemsi.key);
125
+ spa_pod_builder_string(builder, dict->itemsi.value);
126
+ }
127
+ spa_pod_builder_pop(builder, &f);
128
+}
129
+
130
+static inline struct spa_pod *
131
+spa_tag_build_end(struct spa_pod_builder *builder, struct spa_pod_frame *f)
132
+{
133
+ return (struct spa_pod*)spa_pod_builder_pop(builder, f);
134
+}
135
+
136
+/**
137
+ * \}
138
+ */
139
+
140
+#ifdef __cplusplus
141
+} /* extern "C" */
142
+#endif
143
+
144
+#endif /* SPA_PARAM_TAG_UTILS_H */
145
pipewire-0.3.80.tar.gz/spa/include/spa/param/tag.h
Added
48
1
2
+/* Simple Plugin API */
3
+/* SPDX-FileCopyrightText: Copyright © 2023 Wim Taymans */
4
+/* SPDX-License-Identifier: MIT */
5
+
6
+#ifndef SPA_PARAM_TAG_H
7
+#define SPA_PARAM_TAG_H
8
+
9
+#ifdef __cplusplus
10
+extern "C" {
11
+#endif
12
+
13
+/**
14
+ * \addtogroup spa_param
15
+ * \{
16
+ */
17
+
18
+#include <spa/param/param.h>
19
+
20
+/** properties for SPA_TYPE_OBJECT_ParamTag */
21
+enum spa_param_tag {
22
+ SPA_PARAM_TAG_START,
23
+ SPA_PARAM_TAG_direction, /**< direction, input/output (Id enum spa_direction) */
24
+ SPA_PARAM_TAG_info, /**< Struct(
25
+ * Int: n_items
26
+ * (String: key
27
+ * String: value)*
28
+ * ) */
29
+};
30
+
31
+/** helper structure for managing tag objects */
32
+struct spa_tag_info {
33
+ enum spa_direction direction;
34
+ const struct spa_pod *info;
35
+};
36
+
37
+#define SPA_TAG_INFO(dir,...) ((struct spa_tag_info) { .direction = (dir), ## __VA_ARGS__ })
38
+
39
+/**
40
+ * \}
41
+ */
42
+
43
+#ifdef __cplusplus
44
+} /* extern "C" */
45
+#endif
46
+
47
+#endif /* SPA_PARAM_TAG_H */
48
pipewire-0.3.79.tar.gz/spa/include/spa/param/type-info.h -> pipewire-0.3.80.tar.gz/spa/include/spa/param/type-info.h
Changed
8
1
2
#include <spa/param/profiler-types.h>
3
#include <spa/param/profile-types.h>
4
#include <spa/param/route-types.h>
5
+#include <spa/param/tag-types.h>
6
7
#endif /* SPA_PARAM_TYPE_INFO_H */
8
pipewire-0.3.79.tar.gz/spa/include/spa/utils/names.h -> pipewire-0.3.80.tar.gz/spa/include/spa/utils/names.h
Changed
14
1
2
#define SPA_NAME_API_ALSA_SEQ_BRIDGE "api.alsa.seq.bridge" /**< an alsa Node interface for
3
* bridging midi ports */
4
#define SPA_NAME_API_ALSA_ACP_DEVICE "api.alsa.acp.device" /**< an alsa ACP Device interface */
5
-#define SPA_NAME_API_ALSA_COMPRESS_OFFLOAD_SINK "api.alsa.compress.offload.sink" /**< an alsa Node interface for
6
- * compressed audio */
7
+#define SPA_NAME_API_ALSA_COMPRESS_OFFLOAD_DEVICE "api.alsa.compress.offload.device" /**< an alsa Device interface for
8
+ * compressed audio */
9
+#define SPA_NAME_API_ALSA_COMPRESS_OFFLOAD_SINK "api.alsa.compress.offload.sink" /**< an alsa Node interface for
10
+ * compressed audio */
11
12
/** keys for bluez5 factory names */
13
#define SPA_NAME_API_BLUEZ5_ENUM_DBUS "api.bluez5.enum.dbus" /**< a dbus Device interface */
14
pipewire-0.3.79.tar.gz/spa/include/spa/utils/ratelimit.h -> pipewire-0.3.80.tar.gz/spa/include/spa/utils/ratelimit.h
Changed
31
1
2
uint64_t begin;
3
unsigned burst;
4
unsigned n_printed;
5
- unsigned n_missed;
6
+ unsigned n_suppressed;
7
};
8
9
static inline int spa_ratelimit_test(struct spa_ratelimit *r, uint64_t now)
10
{
11
- unsigned missed = 0;
12
+ unsigned suppressed = 0;
13
if (r->begin + r->interval < now) {
14
- missed = r->n_missed;
15
+ suppressed = r->n_suppressed;
16
r->begin = now;
17
r->n_printed = 0;
18
- r->n_missed = 0;
19
+ r->n_suppressed = 0;
20
} else if (r->n_printed >= r->burst) {
21
- r->n_missed++;
22
+ r->n_suppressed++;
23
return -1;
24
}
25
r->n_printed++;
26
- return missed;
27
+ return suppressed;
28
}
29
30
#ifdef __cplusplus
31
pipewire-0.3.79.tar.gz/spa/include/spa/utils/type-info.h -> pipewire-0.3.80.tar.gz/spa/include/spa/utils/type-info.h
Changed
9
1
2
{ SPA_TYPE_OBJECT_Profiler, SPA_TYPE_Object, SPA_TYPE_INFO_Profiler, spa_type_profiler },
3
{ SPA_TYPE_OBJECT_ParamLatency, SPA_TYPE_Object, SPA_TYPE_INFO_PARAM_Latency, spa_type_param_latency },
4
{ SPA_TYPE_OBJECT_ParamProcessLatency, SPA_TYPE_Object, SPA_TYPE_INFO_PARAM_ProcessLatency, spa_type_param_process_latency },
5
+ { SPA_TYPE_OBJECT_ParamTag, SPA_TYPE_Object, SPA_TYPE_INFO_PARAM_Tag, spa_type_param_tag },
6
7
{ 0, 0, NULL, NULL }
8
};
9
pipewire-0.3.79.tar.gz/spa/include/spa/utils/type.h -> pipewire-0.3.80.tar.gz/spa/include/spa/utils/type.h
Changed
9
1
2
SPA_TYPE_OBJECT_Profiler,
3
SPA_TYPE_OBJECT_ParamLatency,
4
SPA_TYPE_OBJECT_ParamProcessLatency,
5
+ SPA_TYPE_OBJECT_ParamTag,
6
_SPA_TYPE_OBJECT_LAST, /**< not part of ABI */
7
8
/* vendor extensions */
9
pipewire-0.3.79.tar.gz/spa/plugins/aec/aec-webrtc.cpp -> pipewire-0.3.80.tar.gz/spa/plugins/aec/aec-webrtc.cpp
Changed
182
1
2
#include <spa/utils/json.h>
3
#include <spa/support/plugin.h>
4
5
-#include <webrtc/modules/audio_processing/include/audio_processing.h>
6
-#include <webrtc/modules/interface/module_common_types.h>
7
-#include <webrtc/system_wrappers/include/trace.h>
8
+#include <modules/audio_processing/include/audio_processing.h>
9
10
struct impl_data {
11
struct spa_handle handle;
12
13
return default_value;
14
}
15
16
-
17
-/* f0 f1 f2 */
18
-static int parse_point(struct spa_json *it, float (&f)3)
19
-{
20
- struct spa_json arr;
21
- int i, res;
22
-
23
- if (spa_json_enter_array(it, &arr) <= 0)
24
- return -EINVAL;
25
-
26
- for (i = 0; i < 3; i++) {
27
- if ((res = spa_json_get_float(&arr, &fi)) <= 0)
28
- return -EINVAL;
29
- }
30
- return 0;
31
-}
32
-
33
-/* point1 point2 ... */
34
-static int parse_mic_geometry(struct impl_data *impl, const char *mic_geometry,
35
- std::vector<webrtc::Point>& geometry)
36
-{
37
- int res;
38
- size_t i;
39
- struct spa_json it2;
40
-
41
- spa_json_init(&it0, mic_geometry, strlen(mic_geometry));
42
- if (spa_json_enter_array(&it0, &it1) <= 0) {
43
- spa_log_error(impl->log, "Error: webrtc.mic-geometry expects an array");
44
- return -EINVAL;
45
- }
46
-
47
- for (i = 0; i < geometry.size(); i++) {
48
- float f3;
49
-
50
- if ((res = parse_point(&it1, f)) < 0) {
51
- spa_log_error(impl->log, "Error: can't parse webrtc.mic-geometry points: %d", res);
52
- return res;
53
- }
54
-
55
- spa_log_info(impl->log, "mic %zd position: (%g %g %g)", i, f0, f1, f2);
56
- geometryi.c0 = f0;
57
- geometryi.c1 = f1;
58
- geometryi.c2 = f2;
59
- }
60
- return 0;
61
-}
62
-
63
static int webrtc_init2(void *object, const struct spa_dict *args,
64
struct spa_audio_info_raw *rec_info, struct spa_audio_info_raw *out_info,
65
struct spa_audio_info_raw *play_info)
66
67
auto impl = static_cast<struct impl_data*>(object);
68
int res;
69
70
- bool extended_filter = webrtc_get_spa_bool(args, "webrtc.extended_filter", true);
71
- bool delay_agnostic = webrtc_get_spa_bool(args, "webrtc.delay_agnostic", true);
72
bool high_pass_filter = webrtc_get_spa_bool(args, "webrtc.high_pass_filter", true);
73
bool noise_suppression = webrtc_get_spa_bool(args, "webrtc.noise_suppression", true);
74
+ bool transient_suppression = webrtc_get_spa_bool(args, "webrtc.transient_suppression", true);
75
bool voice_detection = webrtc_get_spa_bool(args, "webrtc.voice_detection", true);
76
77
// Note: AGC seems to mess up with Agnostic Delay Detection, especially with speech,
78
// result in very poor performance, disable by default
79
bool gain_control = webrtc_get_spa_bool(args, "webrtc.gain_control", false);
80
81
- // Disable experimental flags by default
82
- bool experimental_agc = webrtc_get_spa_bool(args, "webrtc.experimental_agc", false);
83
- bool experimental_ns = webrtc_get_spa_bool(args, "webrtc.experimental_ns", false);
84
-
85
- bool beamforming = webrtc_get_spa_bool(args, "webrtc.beamforming", false);
86
-
87
// FIXME: Intelligibility enhancer is not currently supported
88
// This filter will modify playback buffer (when calling ProcessReverseStream), but now
89
// playback buffer modifications are discarded.
90
91
- webrtc::Config config;
92
- config.Set<webrtc::ExtendedFilter>(new webrtc::ExtendedFilter(extended_filter));
93
- config.Set<webrtc::DelayAgnostic>(new webrtc::DelayAgnostic(delay_agnostic));
94
- config.Set<webrtc::ExperimentalAgc>(new webrtc::ExperimentalAgc(experimental_agc));
95
- config.Set<webrtc::ExperimentalNs>(new webrtc::ExperimentalNs(experimental_ns));
96
-
97
- if (beamforming) {
98
- std::vector<webrtc::Point> geometry(rec_info->channels);
99
- const char *mic_geometry, *target_direction;
100
-
101
- /* The beamformer gives a single mono channel */
102
- out_info->channels = 1;
103
- out_info->position0 = SPA_AUDIO_CHANNEL_MONO;
104
-
105
- if ((mic_geometry = spa_dict_lookup(args, "webrtc.mic-geometry")) == NULL) {
106
- spa_log_error(impl->log, "Error: webrtc.beamforming requires webrtc.mic-geometry");
107
- return -EINVAL;
108
- }
109
-
110
- if ((res = parse_mic_geometry(impl, mic_geometry, geometry)) < 0)
111
- return res;
112
-
113
- if ((target_direction = spa_dict_lookup(args, "webrtc.target-direction")) != NULL) {
114
- webrtc::SphericalPointf direction(0.0f, 0.0f, 0.0f);
115
- struct spa_json it;
116
- float f3;
117
-
118
- spa_json_init(&it, target_direction, strlen(target_direction));
119
- if (parse_point(&it, f) < 0) {
120
- spa_log_error(impl->log, "Error: can't parse target-direction %s",
121
- target_direction);
122
- return -EINVAL;
123
- }
124
-
125
- direction.s0 = f0;
126
- direction.s1 = f1;
127
- direction.s2 = f2;
128
-
129
- config.Set<webrtc::Beamforming>(new webrtc::Beamforming(true, geometry, direction));
130
- } else {
131
- config.Set<webrtc::Beamforming>(new webrtc::Beamforming(true, geometry));
132
- }
133
- }
134
+ webrtc::AudioProcessing::Config config;
135
+ config.echo_canceller.enabled = true;
136
+ // FIXME: Example code enables both gain controllers, but that seems sus
137
+ config.gain_controller1.enabled = gain_control;
138
+ config.gain_controller1.mode = webrtc::AudioProcessing::Config::GainController1::Mode::kAdaptiveDigital;
139
+ config.gain_controller1.analog_level_minimum = 0;
140
+ config.gain_controller1.analog_level_maximum = 255;
141
+ config.gain_controller2.enabled = gain_control;
142
+ config.high_pass_filter.enabled = high_pass_filter;
143
+ config.noise_suppression.enabled = noise_suppression;
144
+ config.noise_suppression.level = webrtc::AudioProcessing::Config::NoiseSuppression::kHigh;
145
+ // FIXME: expose pre/postamp gain
146
+ config.transient_suppression.enabled = transient_suppression;
147
+ config.voice_detection.enabled = voice_detection;
148
149
webrtc::ProcessingConfig pconfig = {{
150
webrtc::StreamConfig(rec_info->rate, rec_info->channels, false), /* input stream */
151
152
webrtc::StreamConfig(play_info->rate, play_info->channels, false), /* reverse output stream */
153
}};
154
155
- auto apm = std::unique_ptr<webrtc::AudioProcessing>(webrtc::AudioProcessing::Create(config));
156
+ auto apm = std::unique_ptr<webrtc::AudioProcessing>(webrtc::AudioProcessingBuilder().Create());
157
+
158
+ apm->ApplyConfig(config);
159
+
160
if ((res = apm->Initialize(pconfig)) != webrtc::AudioProcessing::kNoError) {
161
spa_log_error(impl->log, "Error initialising webrtc audio processing module: %d", res);
162
return -EINVAL;
163
}
164
165
- apm->high_pass_filter()->Enable(high_pass_filter);
166
- // Always disable drift compensation since PipeWire will already do
167
- // drift compensation on all sinks and sources linked to this echo-canceler
168
- apm->echo_cancellation()->enable_drift_compensation(false);
169
- apm->echo_cancellation()->Enable(true);
170
- // TODO: wire up supression levels to args
171
- apm->echo_cancellation()->set_suppression_level(webrtc::EchoCancellation::kHighSuppression);
172
- apm->noise_suppression()->set_level(webrtc::NoiseSuppression::kHigh);
173
- apm->noise_suppression()->Enable(noise_suppression);
174
- apm->voice_detection()->Enable(voice_detection);
175
- // TODO: wire up AGC parameters to args
176
- apm->gain_control()->set_analog_level_limits(0, 255);
177
- apm->gain_control()->set_mode(webrtc::GainControl::kAdaptiveDigital);
178
- apm->gain_control()->Enable(gain_control);
179
impl->apm = std::move(apm);
180
impl->rec_info = *rec_info;
181
impl->out_info = *out_info;
182
pipewire-0.3.79.tar.gz/spa/plugins/alsa/acp/volume.h -> pipewire-0.3.80.tar.gz/spa/plugins/alsa/acp/volume.h
Changed
10
1
2
3
static inline pa_volume_t pa_sw_volume_from_dB(double dB)
4
{
5
- if (isinf(dB) < 0 || dB <= PA_DECIBEL_MININFTY)
6
+ if (dB == -INFINITY || dB <= PA_DECIBEL_MININFTY)
7
return PA_VOLUME_MUTED;
8
return pa_sw_volume_from_linear(pa_volume_dB_to_linear(dB));
9
}
10
pipewire-0.3.80.tar.gz/spa/plugins/alsa/alsa-compress-offload-device.c
Added
201
1
2
+/* Spa ALSA Compress-Offload device */
3
+/* SPDX-FileCopyrightText: Copyright @ 2023 Carlos Rafael Giani */
4
+/* SPDX-License-Identifier: MIT */
5
+
6
+#include <sys/types.h>
7
+#include <limits.h>
8
+#include <dirent.h>
9
+
10
+#include <alsa/asoundlib.h>
11
+
12
+#include <spa/debug/dict.h>
13
+#include <spa/debug/log.h>
14
+#include <spa/debug/pod.h>
15
+#include <spa/node/node.h>
16
+#include <spa/support/plugin.h>
17
+#include <spa/monitor/device.h>
18
+#include <spa/monitor/utils.h>
19
+#include <spa/node/keys.h>
20
+#include <spa/param/param.h>
21
+#include <spa/pod/filter.h>
22
+#include <spa/pod/parser.h>
23
+#include <spa/utils/cleanup.h>
24
+#include <spa/utils/dict.h>
25
+#include <spa/utils/keys.h>
26
+#include <spa/utils/names.h>
27
+#include <spa/utils/string.h>
28
+
29
+#include "compress-offload-api-util.h"
30
+#include "alsa.h"
31
+
32
+static const char default_device = "hw:0";
33
+
34
+struct props {
35
+ char device64;
36
+ unsigned int card_nr;
37
+};
38
+
39
+static void reset_props(struct props *props)
40
+{
41
+ strncpy(props->device, default_device, 64);
42
+ props->card_nr = 0;
43
+}
44
+
45
+struct impl {
46
+ struct spa_handle handle;
47
+ struct spa_device device;
48
+
49
+ struct spa_log *log;
50
+
51
+ struct spa_hook_list hooks;
52
+
53
+ struct props props;
54
+ uint32_t n_nodes;
55
+ uint32_t n_capture;
56
+ uint32_t n_playback;
57
+
58
+ uint32_t profile;
59
+};
60
+
61
+#define ADD_DICT_ITEM(key, value) do { itemsn_items++ = SPA_DICT_ITEM_INIT(key, value); } while (0)
62
+
63
+static void emit_node(struct impl *this, const char *device_node, unsigned int device_nr,
64
+ enum spa_compress_offload_direction direction, snd_ctl_card_info_t *cardinfo,
65
+ uint32_t id)
66
+{
67
+ struct spa_dict_item items5;
68
+ uint32_t n_items = 0;
69
+ char alsa_path128, path180;
70
+ char node_name200;
71
+ char node_desc200;
72
+ struct spa_device_object_info info;
73
+ const char *stream;
74
+
75
+ spa_log_debug(this->log, "emitting node info for device %s (card nr %u device nr %u)",
76
+ device_node, this->props.card_nr, device_nr);
77
+
78
+ info = SPA_DEVICE_OBJECT_INFO_INIT();
79
+ info.type = SPA_TYPE_INTERFACE_Node;
80
+
81
+ if (direction == SPA_COMPRESS_OFFLOAD_DIRECTION_PLAYBACK) {
82
+ stream = "playback";
83
+ info.factory_name = SPA_NAME_API_ALSA_COMPRESS_OFFLOAD_SINK;
84
+ } else {
85
+ stream = "capture";
86
+ /* TODO: This is not yet implemented, because getting Compress-Offload
87
+ * hardware that can capture audio is difficult to do. The only hardware
88
+ * known is the Wolfson ADSP; the only driver in the kernel that exposes
89
+ * Compress-Offload capture devices is the one for that hardware. */
90
+ assert(false);
91
+ }
92
+
93
+ info.change_mask = SPA_DEVICE_OBJECT_CHANGE_MASK_PROPS;
94
+
95
+ snprintf(alsa_path, sizeof(alsa_path), "%s,%u", this->props.device, device_nr);
96
+ snprintf(path, sizeof(path), "alsa:compressed:%s:%u:%s", snd_ctl_card_info_get_id(cardinfo), device_nr, stream);
97
+ snprintf(node_name, sizeof(node_name), "comprC%uD%u", this->props.card_nr, device_nr);
98
+ snprintf(node_desc, sizeof(node_desc), "Compress-Offload sink node (ALSA card %u device %u)", this->props.card_nr, device_nr);
99
+
100
+ ADD_DICT_ITEM(SPA_KEY_NODE_NAME, node_name);
101
+ ADD_DICT_ITEM(SPA_KEY_NODE_DESCRIPTION, node_desc);
102
+ ADD_DICT_ITEM(SPA_KEY_OBJECT_PATH, path);
103
+ ADD_DICT_ITEM(SPA_KEY_API_ALSA_PATH, alsa_path);
104
+ /* NOTE: Set alsa.name, since session managers look for this, or for
105
+ * SPA_KEY_API_ALSA_PCM_NAME, or other items. The best fit in this
106
+ * case seems to be alsa.name, since SPA_KEY_API_ALSA_PCM_NAME is
107
+ * PCM specific, as the name suggests. If none of these items are
108
+ * provided, session managers may not work properly. WirePlumber's
109
+ * alsa.lua script looks for these for example.
110
+ * And, since we have no good way of getting a name, just reuse
111
+ * the alsa_path here. */
112
+ ADD_DICT_ITEM("alsa.name", alsa_path);
113
+
114
+ info.props = &SPA_DICT_INIT(items, n_items);
115
+
116
+ spa_log_debug(this->log, "node information:");
117
+ spa_debug_dict(2, info.props);
118
+
119
+ spa_device_emit_object_info(&this->hooks, id, &info);
120
+}
121
+
122
+static int set_profile(struct impl *this, uint32_t id)
123
+{
124
+ int ret = 0;
125
+ uint32_t i, n_cap, n_play;
126
+ char prefix32;
127
+ int prefix_length;
128
+ struct dirent *entry;
129
+ DIR *snd_dir = NULL;
130
+ snd_ctl_t *ctl_handle = NULL;
131
+ snd_ctl_card_info_t *cardinfo;
132
+
133
+ spa_log_debug(this->log, "enumerate Compress-Offload nodes for card %s; profile: %d",
134
+ this->props.device, id);
135
+
136
+ if ((ret = snd_ctl_open(&ctl_handle, this->props.device, 0)) < 0) {
137
+ spa_log_error(this->log, "can't open control for card %s: %s",
138
+ this->props.device, snd_strerror(ret));
139
+ goto finish;
140
+ }
141
+
142
+ this->profile = id;
143
+
144
+ snd_ctl_card_info_alloca(&cardinfo);
145
+ if ((ret = snd_ctl_card_info(ctl_handle, cardinfo)) < 0) {
146
+ spa_log_error(this->log, "error card info: %s", snd_strerror(ret));
147
+ goto finish;
148
+ }
149
+
150
+ /* Clear any previous node object info. */
151
+ for (i = 0; i < this->n_nodes; i++)
152
+ spa_device_emit_object_info(&this->hooks, i, NULL);
153
+
154
+ this->n_nodes = this->n_capture = this->n_playback = 0;
155
+
156
+ /* Profile ID 0 is the "off" profile, that is, the profile where the device
157
+ * is "disabled". To implement such a disabled state, simply exit here without
158
+ * adding any nodes after we removed any existing one (see above). */
159
+ if (id == 0)
160
+ {
161
+ spa_log_debug(this->log, "\"Off\" profile selected - exiting without "
162
+ "creating any nodes after all previous ones were removed");
163
+ goto finish;
164
+ }
165
+
166
+ spa_scnprintf(prefix, sizeof(prefix), "comprC%uD", this->props.card_nr);
167
+ prefix_length = strlen(prefix);
168
+
169
+ /* There is no API to enumerate all Compress-Offload devices, so we have
170
+ * to stick to walking through the /dev/snd directory entries and looking
171
+ * for device nodes that match the comprC<card number>D prefix. */
172
+ snd_dir = opendir("/dev/snd");
173
+ if (snd_dir == NULL)
174
+ goto errno_error;
175
+
176
+ i = 0;
177
+ i = n_cap = n_play = 0;
178
+ while ((errno = 0, entry = readdir(snd_dir)) != NULL) {
179
+ long long device_nr;
180
+ enum spa_compress_offload_direction direction;
181
+
182
+ if (!(entry->d_type == DT_CHR && spa_strstartswith(entry->d_name, prefix)))
183
+ continue;
184
+
185
+ /* Parse the device number from the device filename. We know that the filename
186
+ * is always structured like this: comprC<card number>D<device number>
187
+ * We consider "comprC<card number>D" to form the "prefix" here. Right after
188
+ * that prefix, the device number can be parsed, so skip the prefix. */
189
+ device_nr = strtol(entry->d_name + prefix_length, NULL, 10);
190
+ if ((device_nr < 0) || (device_nr > UINT_MAX)) {
191
+ spa_log_warn(this->log, "device %s contains unusable device number; "
192
+ "skipping", entry->d_name);
193
+ continue;
194
+ }
195
+
196
+ if (get_compress_offload_device_direction(this->props.card_nr, device_nr,
197
+ this->log, &direction) < 0)
198
+ goto finish;
199
+
200
+ switch (direction) {
201
pipewire-0.3.79.tar.gz/spa/plugins/alsa/alsa-pcm-device.c -> pipewire-0.3.80.tar.gz/spa/plugins/alsa/alsa-pcm-device.c
Changed
38
1
2
snd_pcm_info_t *pcminfo;
3
snd_ctl_card_info_t *cardinfo;
4
5
- spa_log_debug(this->log, "profile %d", id);
6
this->profile = id;
7
8
snd_ctl_card_info_alloca(&cardinfo);
9
10
snd_ctl_t *ctl_hndl;
11
int err;
12
13
- spa_log_debug(this->log, "open card %s", this->props.device);
14
+ spa_log_debug(this->log, "enumerate PCM nodes for card %s; profile: %d",
15
+ this->props.device, id);
16
+
17
if ((err = snd_ctl_open(&ctl_hndl, this->props.device, 0)) < 0) {
18
spa_log_error(this->log, "can't open control for card %s: %s",
19
this->props.device, snd_strerror(err));
20
21
22
err = activate_profile(this, ctl_hndl, id);
23
24
- spa_log_debug(this->log, "close card %s", this->props.device);
25
+ spa_log_debug(this->log, "done enumerating PCM nodes for card %s", this->props.device);
26
snd_ctl_close(ctl_hndl);
27
28
return err;
29
30
return 1;
31
}
32
33
-const struct spa_handle_factory spa_alsa_device_factory = {
34
+const struct spa_handle_factory spa_alsa_pcm_device_factory = {
35
SPA_VERSION_HANDLE_FACTORY,
36
SPA_NAME_API_ALSA_PCM_DEVICE,
37
NULL,
38
pipewire-0.3.79.tar.gz/spa/plugins/alsa/alsa-pcm-sink.c -> pipewire-0.3.80.tar.gz/spa/plugins/alsa/alsa-pcm-sink.c
Changed
49
1
2
#include <spa/utils/string.h>
3
#include <spa/param/audio/format.h>
4
#include <spa/pod/filter.h>
5
+#include <spa/debug/log.h>
6
+#include <spa/debug/pod.h>
7
8
#include "alsa-pcm.h"
9
10
11
const struct spa_pod *param)
12
{
13
struct state *this = object;
14
- int res;
15
+ int res = 0;
16
17
spa_return_val_if_fail(this != NULL, -EINVAL);
18
19
20
this->port_info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS;
21
this->port_paramsPORT_Latency.user++;
22
emit_port_info(this, false);
23
- res = 0;
24
break;
25
}
26
+ case SPA_PARAM_Tag:
27
+ if (param != NULL)
28
+ spa_debug_log_pod(this->log, SPA_LOG_LEVEL_DEBUG, 0, NULL, param);
29
+ break;
30
default:
31
res = -ENOENT;
32
break;
33
34
spa_list_append(&this->ready, &b->link);
35
SPA_FLAG_CLEAR(b->flags, BUFFER_FLAG_OUT);
36
io->buffer_id = SPA_ID_INVALID;
37
-
38
- spa_alsa_write(this);
39
-
40
- io->status = SPA_STATUS_OK;
41
}
42
- else if (!spa_list_is_empty(&this->ready)) {
43
+ if (!spa_list_is_empty(&this->ready)) {
44
spa_alsa_write(this);
45
-
46
io->status = SPA_STATUS_OK;
47
}
48
return SPA_STATUS_HAVE_DATA;
49
pipewire-0.3.79.tar.gz/spa/plugins/alsa/alsa-pcm.c -> pipewire-0.3.80.tar.gz/spa/plugins/alsa/alsa-pcm.c
Changed
201
1
2
min = max = rate;
3
4
if (rate == 0)
5
- rate = state->position ? state->position->clock.rate.denom : DEFAULT_RATE;
6
+ rate = state->position ? state->position->clock.target_rate.denom : DEFAULT_RATE;
7
8
rate = SPA_CLAMP(rate, min, max);
9
10
11
return 1;
12
}
13
14
+/* find smaller power of 2 */
15
+static uint32_t flp2(uint32_t x)
16
+{
17
+ x = x | (x >> 1);
18
+ x = x | (x >> 2);
19
+ x = x | (x >> 4);
20
+ x = x | (x >> 8);
21
+ x = x | (x >> 16);
22
+ return x - (x >> 1);
23
+}
24
+
25
int
26
spa_alsa_enum_format(struct state *state, int seq, uint32_t start, uint32_t num,
27
const struct spa_pod *filter)
28
29
unsigned int periods;
30
bool match = true, planar = false, is_batch;
31
char spdif_params128 = "";
32
+ uint32_t default_period, latency;
33
34
spa_log_debug(state->log, "opened:%d format:%d started:%d", state->opened,
35
state->have_format, state->started);
36
37
period_size = state->default_period_size;
38
is_batch = snd_pcm_hw_params_is_batch(params) && !state->disable_batch;
39
40
+ default_period = SPA_SCALE32_UP(DEFAULT_PERIOD, state->rate, DEFAULT_RATE);
41
+ default_period = flp2(2 * default_period - 1);
42
+
43
/* no period size specified. If we are batch or not using timers,
44
* use the graph duration as the period */
45
if (period_size == 0 && (is_batch || state->disable_tsched))
46
- period_size = state->position ? state->position->clock.target_duration : DEFAULT_PERIOD;
47
+ period_size = state->position ? state->position->clock.target_duration : default_period;
48
if (period_size == 0)
49
- period_size = DEFAULT_PERIOD;
50
+ period_size = default_period;
51
52
if (!state->disable_tsched) {
53
if (is_batch) {
54
55
* the period smaller and add one period of headroom. Limit the
56
* period size to our default so that we don't create too much
57
* headroom. */
58
- period_size = SPA_MIN(period_size, DEFAULT_PERIOD) / 2;
59
+ period_size = SPA_MIN(period_size, default_period) / 2;
60
} else {
61
/* disable ALSA wakeups */
62
if (snd_pcm_hw_params_can_disable_period_wakeup(params))
63
64
state->headroom = SPA_MIN(state->headroom, state->buffer_frames);
65
state->start_delay = state->default_start_delay;
66
67
+ latency = SPA_MAX(state->min_delay, SPA_MIN(state->max_delay, state->headroom));
68
+ if (state->position != NULL)
69
+ latency = SPA_SCALE32_UP(latency, state->position->clock.target_rate.denom, state->rate);
70
+
71
state->latencystate->port_direction.min_rate =
72
- state->latencystate->port_direction.max_rate =
73
- SPA_MAX(state->min_delay, SPA_MIN(state->max_delay, state->headroom));
74
+ state->latencystate->port_direction.max_rate = latency;
75
76
spa_log_info(state->log, "%s (%s): format:%s access:%s-%s rate:%d channels:%d "
77
"buffer frames %lu, period frames %lu, periods %u, frame_size %zd "
78
79
80
delay = SPA_TIMEVAL_TO_USEC(&diff);
81
missing = delay * state->rate / SPA_USEC_PER_SEC;
82
- if (missing == 0)
83
- missing = state->threshold;
84
+ missing += state->start_delay + state->threshold + state->headroom;
85
86
spa_log_trace(state->log, "%p: xrun of %"PRIu64" usec %"PRIu64,
87
state, delay, missing);
88
89
- if (state->clock)
90
- state->clock->xrun += missing;
91
- state->sample_count += missing;
92
-
93
+ if (state->clock) {
94
+ state->clock->xrun += SPA_SCALE32_UP(missing,
95
+ state->clock->rate.denom, state->rate);
96
+ }
97
spa_node_call_xrun(&state->callbacks,
98
SPA_TIMEVAL_TO_USEC(&trigger), delay, NULL);
99
break;
100
101
102
static int get_avail(struct state *state, uint64_t current_time, snd_pcm_uframes_t *delay)
103
{
104
- int res, missed;
105
+ int res, suppressed;
106
snd_pcm_sframes_t avail;
107
108
if (SPA_UNLIKELY((avail = snd_pcm_avail(state->hndl)) < 0)) {
109
if ((res = alsa_recover(state, avail)) < 0)
110
return res;
111
if ((avail = snd_pcm_avail(state->hndl)) < 0) {
112
- if ((missed = spa_ratelimit_test(&state->rate_limit, current_time)) >= 0) {
113
- spa_log_warn(state->log, "%s: (%d missed) snd_pcm_avail after recover: %s",
114
- state->props.device, missed, snd_strerror(avail));
115
+ if ((suppressed = spa_ratelimit_test(&state->rate_limit, current_time)) >= 0) {
116
+ spa_log_warn(state->log, "%s: (%d suppressed) snd_pcm_avail after recover: %s",
117
+ state->props.device, suppressed, snd_strerror(avail));
118
}
119
avail = state->threshold * 2;
120
}
121
122
uint64_t then;
123
124
if ((res = snd_pcm_htimestamp(state->hndl, &havail, &tstamp)) < 0) {
125
- if ((missed = spa_ratelimit_test(&state->rate_limit, current_time)) >= 0) {
126
- spa_log_warn(state->log, "%s: (%d missed) snd_pcm_htimestamp error: %s",
127
- state->props.device, missed, snd_strerror(res));
128
+ if ((suppressed = spa_ratelimit_test(&state->rate_limit, current_time)) >= 0) {
129
+ spa_log_warn(state->log, "%s: (%d suppressed) snd_pcm_htimestamp error: %s",
130
+ state->props.device, suppressed, snd_strerror(res));
131
}
132
return avail;
133
}
134
135
state->htimestamp_error = 0;
136
state->htimestamp = false;
137
}
138
- else if ((missed = spa_ratelimit_test(&state->rate_limit, current_time)) >= 0) {
139
- spa_log_warn(state->log, "%s: (%d missed) impossible htimestamp diff:%"PRIi64,
140
- state->props.device, missed, diff);
141
+ else if ((suppressed = spa_ratelimit_test(&state->rate_limit, current_time)) >= 0) {
142
+ spa_log_warn(state->log, "%s: (%d suppressed) impossible htimestamp diff:%"PRIi64,
143
+ state->props.device, suppressed, diff);
144
}
145
}
146
}
147
148
if (SPA_UNLIKELY(state->position == NULL))
149
return 0;
150
151
- target_duration = state->position->clock.target_duration;
152
- target_rate = state->position->clock.target_rate;
153
+ if (state->disable_tsched && state->started && !state->following) {
154
+ target_duration = state->period_frames;
155
+ target_rate = SPA_FRACTION(1, state->rate);
156
+ state->position->clock.target_duration = target_duration;
157
+ state->position->clock.target_rate = target_rate;
158
+ } else {
159
+ target_duration = state->position->clock.target_duration;
160
+ target_rate = state->position->clock.target_rate;
161
+ }
162
163
if (SPA_UNLIKELY((state->duration != target_duration) ||
164
(state->rate_denom != target_rate.denom))) {
165
166
const snd_pcm_channel_area_t *my_areas;
167
snd_pcm_uframes_t written, frames, offset, off, to_write, total_written, max_write;
168
snd_pcm_sframes_t commitres;
169
- int res, missed;
170
+ int res, suppressed;
171
size_t frame_size = state->frame_size;
172
173
if ((res = check_position_config(state)) < 0)
174
175
else
176
lev = SPA_LOG_LEVEL_INFO;
177
178
- if ((missed = spa_ratelimit_test(&state->rate_limit, current_time)) >= 0) {
179
+ if ((suppressed = spa_ratelimit_test(&state->rate_limit, current_time)) >= 0) {
180
spa_log_lev(state->log, lev, "%s: follower avail:%lu delay:%ld "
181
- "target:%ld thr:%u, resync (%d missed)",
182
+ "target:%ld thr:%u, resync (%d suppressed)",
183
state->props.device, avail, delay,
184
- target, state->threshold, missed);
185
+ target, state->threshold, suppressed);
186
}
187
188
if (avail > target)
189
190
const snd_pcm_channel_area_t *my_areas;
191
snd_pcm_uframes_t read, frames, offset;
192
snd_pcm_sframes_t commitres;
193
- int res, missed;
194
+ int res, suppressed;
195
196
if ((res = check_position_config(state)) < 0)
197
return res;
198
199
else
200
lev = SPA_LOG_LEVEL_INFO;
201
pipewire-0.3.79.tar.gz/spa/plugins/alsa/alsa-seq-bridge.c -> pipewire-0.3.80.tar.gz/spa/plugins/alsa/alsa-seq-bridge.c
Changed
12
1
2
case SPA_PARAM_Latency:
3
{
4
struct spa_latency_info info;
5
- if ((res = spa_latency_parse(param, &info)) < 0)
6
+ if (param == NULL)
7
+ info = SPA_LATENCY_INFO(SPA_DIRECTION_REVERSE(direction));
8
+ else if ((res = spa_latency_parse(param, &info)) < 0)
9
return res;
10
if (direction == info.direction)
11
return -EINVAL;
12
pipewire-0.3.79.tar.gz/spa/plugins/alsa/alsa-udev.c -> pipewire-0.3.80.tar.gz/spa/plugins/alsa/alsa-udev.c
Changed
201
1
2
#include <spa/support/plugin.h>
3
#include <spa/monitor/device.h>
4
#include <spa/monitor/utils.h>
5
+#include <spa/debug/log.h>
6
+#include <spa/debug/dict.h>
7
8
#include "alsa.h"
9
10
-#define MAX_DEVICES 64
11
+#define MAX_CARDS 64
12
13
#define ACTION_ADD 0
14
#define ACTION_REMOVE 1
15
#define ACTION_DISABLE 2
16
17
-struct device {
18
- uint32_t id;
19
- struct udev_device *dev;
20
+/* Used for unavailable devices in the card structure. */
21
+#define ID_DEVICE_NOT_SUPPORTED 0
22
+
23
+/* This represents an ALSA card.
24
+ * One card can have up to 1 PCM and 1 Compress-Offload device. */
25
+struct card {
26
+ unsigned int card_nr;
27
+ struct udev_device *udev_device;
28
unsigned int unavailable:1;
29
unsigned int accessible:1;
30
unsigned int ignored:1;
31
unsigned int emitted:1;
32
+
33
+ /* Local SPA object IDs. (Global IDs are produced by PipeWire
34
+ * out of this using its registry.) Compress-Offload or PCM
35
+ * is not available, the corresponding ID is set to
36
+ * ID_DEVICE_NOT_SUPPORTED (= 0).
37
+ * PCM device IDs are (card nr + 1) * 2, and Compress-Offload
38
+ * device IDs are (card nr + 1) * 2 + 1. Assigning IDs like this
39
+ * makes it easy to deal with removed devices. (card nr + 1)
40
+ * is used because 0 is a valid ALSA card number. */
41
+ uint32_t pcm_device_id;
42
+ uint32_t compress_offload_device_id;
43
};
44
45
+static uint32_t calc_pcm_device_id(struct card *card)
46
+{
47
+ return (card->card_nr + 1) * 2 + 0;
48
+}
49
+
50
+static uint32_t calc_compress_offload_device_id(struct card *card)
51
+{
52
+ return (card->card_nr + 1) * 2 + 1;
53
+}
54
+
55
struct impl {
56
struct spa_handle handle;
57
struct spa_device device;
58
59
struct udev *udev;
60
struct udev_monitor *umonitor;
61
62
- struct device devicesMAX_DEVICES;
63
- uint32_t n_devices;
64
+ struct card cardsMAX_CARDS;
65
+ unsigned int n_cards;
66
67
struct spa_source source;
68
struct spa_source notify;
69
70
return 0;
71
}
72
73
-static struct device *add_device(struct impl *this, uint32_t id, struct udev_device *dev)
74
+static struct card *add_card(struct impl *this, unsigned int card_nr, struct udev_device *udev_device)
75
{
76
- struct device *device;
77
+ struct card *card;
78
79
- if (this->n_devices >= MAX_DEVICES)
80
+ if (this->n_cards >= MAX_CARDS)
81
return NULL;
82
- device = &this->devicesthis->n_devices++;
83
- spa_zero(*device);
84
- device->id = id;
85
- udev_device_ref(dev);
86
- device->dev = dev;
87
- return device;
88
+
89
+ card = &this->cardsthis->n_cards++;
90
+ spa_zero(*card);
91
+ card->card_nr = card_nr;
92
+ udev_device_ref(udev_device);
93
+ card->udev_device = udev_device;
94
+
95
+ return card;
96
}
97
98
-static struct device *find_device(struct impl *this, uint32_t id)
99
+static struct card *find_card(struct impl *this, unsigned int card_nr)
100
{
101
- uint32_t i;
102
- for (i = 0; i < this->n_devices; i++) {
103
- if (this->devicesi.id == id)
104
- return &this->devicesi;
105
+ unsigned int i;
106
+ for (i = 0; i < this->n_cards; i++) {
107
+ if (this->cardsi.card_nr == card_nr)
108
+ return &this->cardsi;
109
}
110
return NULL;
111
}
112
113
-static void remove_device(struct impl *this, struct device *device)
114
+static void remove_card(struct impl *this, struct card *card)
115
{
116
- udev_device_unref(device->dev);
117
- *device = this->devices--this->n_devices;
118
+ udev_device_unref(card->udev_device);
119
+ *card = this->cards--this->n_cards;
120
}
121
122
-static void clear_devices(struct impl *this)
123
+static void clear_cards(struct impl *this)
124
{
125
- uint32_t i;
126
- for (i = 0; i < this->n_devices; i++)
127
- udev_device_unref(this->devicesi.dev);
128
- this->n_devices = 0;
129
+ unsigned int i;
130
+ for (i = 0; i < this->n_cards; i++)
131
+ udev_device_unref(this->cardsi.udev_device);
132
+ this->n_cards = 0;
133
}
134
135
-static uint32_t get_card_id(struct impl *this, struct udev_device *dev)
136
+static unsigned int get_card_nr(struct impl *this, struct udev_device *udev_device)
137
{
138
const char *e, *str;
139
140
- if (udev_device_get_property_value(dev, "ACP_IGNORE"))
141
+ if (udev_device_get_property_value(udev_device, "ACP_IGNORE"))
142
return SPA_ID_INVALID;
143
144
- if ((str = udev_device_get_property_value(dev, "SOUND_CLASS")) && spa_streq(str, "modem"))
145
+ if ((str = udev_device_get_property_value(udev_device, "SOUND_CLASS")) && spa_streq(str, "modem"))
146
return SPA_ID_INVALID;
147
148
- if (udev_device_get_property_value(dev, "SOUND_INITIALIZED") == NULL)
149
+ if (udev_device_get_property_value(udev_device, "SOUND_INITIALIZED") == NULL)
150
return SPA_ID_INVALID;
151
152
- if ((str = udev_device_get_property_value(dev, "DEVPATH")) == NULL)
153
+ if ((str = udev_device_get_property_value(udev_device, "DEVPATH")) == NULL)
154
return SPA_ID_INVALID;
155
156
if ((e = strrchr(str, '/')) == NULL)
157
158
return spa_strstartswith(buf, "modem") ? -ENXIO : 0;
159
}
160
161
-static int get_num_pcm_devices(unsigned int card_id)
162
+static int get_num_pcm_devices(unsigned int card_nr)
163
{
164
char prefix32;
165
struct dirent *entry;
166
167
168
/* Check if card has PCM devices, without opening them */
169
170
- spa_scnprintf(prefix, sizeof(prefix), "pcmC%uD", card_id);
171
+ spa_scnprintf(prefix, sizeof(prefix), "pcmC%uD", card_nr);
172
173
spa_autoptr(DIR) snd = opendir("/dev/snd");
174
if (snd == NULL)
175
176
return errno != 0 ? -errno : num_dev;
177
}
178
179
-static int check_device_available(struct impl *this, struct device *device, int *num_pcm)
180
+static int get_num_compress_offload_devices(unsigned int card_nr)
181
+{
182
+ char prefix32;
183
+ struct dirent *entry;
184
+ int num_dev = 0;
185
+
186
+ /* Check if card has Compress-Offload devices, without opening them */
187
+
188
+ spa_scnprintf(prefix, sizeof(prefix), "comprC%uD", card_nr);
189
+
190
+ spa_autoptr(DIR) snd = opendir("/dev/snd");
191
+ if (snd == NULL)
192
+ return -errno;
193
+
194
+ while ((errno = 0, entry = readdir(snd)) != NULL) {
195
+ if (!(entry->d_type == DT_CHR &&
196
+ spa_strstartswith(entry->d_name, prefix)))
197
+ continue;
198
+
199
+ ++num_dev;
200
+ }
201
pipewire-0.3.79.tar.gz/spa/plugins/alsa/alsa.c -> pipewire-0.3.80.tar.gz/spa/plugins/alsa/alsa.c
Changed
34
1
2
extern const struct spa_handle_factory spa_alsa_source_factory;
3
extern const struct spa_handle_factory spa_alsa_sink_factory;
4
extern const struct spa_handle_factory spa_alsa_udev_factory;
5
-extern const struct spa_handle_factory spa_alsa_device_factory;
6
+extern const struct spa_handle_factory spa_alsa_pcm_device_factory;
7
extern const struct spa_handle_factory spa_alsa_seq_bridge_factory;
8
extern const struct spa_handle_factory spa_alsa_acp_device_factory;
9
#ifdef HAVE_ALSA_COMPRESS_OFFLOAD
10
extern const struct spa_handle_factory spa_alsa_compress_offload_sink_factory;
11
+extern const struct spa_handle_factory spa_alsa_compress_offload_device_factory;
12
#endif
13
14
struct spa_log_topic log_topic = SPA_LOG_TOPIC(0, "spa.alsa");
15
16
*factory = &spa_alsa_udev_factory;
17
break;
18
case 3:
19
- *factory = &spa_alsa_device_factory;
20
+ *factory = &spa_alsa_pcm_device_factory;
21
break;
22
case 4:
23
*factory = &spa_alsa_seq_bridge_factory;
24
25
case 6:
26
*factory = &spa_alsa_compress_offload_sink_factory;
27
break;
28
+ case 7:
29
+ *factory = &spa_alsa_compress_offload_device_factory;
30
+ break;
31
#endif
32
default:
33
return 0;
34
pipewire-0.3.80.tar.gz/spa/plugins/alsa/compress-offload-api-util.c
Added
38
1
2
+#include <errno.h>
3
+#include <inttypes.h>
4
+#include "compress-offload-api.h"
5
+#include "compress-offload-api-util.h"
6
+
7
+int get_compress_offload_device_direction(int card_nr, int device_nr,
8
+ struct spa_log *log,
9
+ enum spa_compress_offload_direction *direction)
10
+{
11
+ int ret = 0;
12
+ struct compress_offload_api_context *device_context;
13
+ const struct snd_compr_caps *compr_caps;
14
+
15
+ device_context = compress_offload_api_open(card_nr, device_nr, log);
16
+ if (device_context == NULL)
17
+ return -errno;
18
+
19
+ compr_caps = compress_offload_api_get_caps(device_context);
20
+
21
+ switch (compr_caps->direction) {
22
+ case SND_COMPRESS_PLAYBACK:
23
+ *direction = SPA_COMPRESS_OFFLOAD_DIRECTION_PLAYBACK;
24
+ break;
25
+ case SND_COMPRESS_CAPTURE:
26
+ *direction = SPA_COMPRESS_OFFLOAD_DIRECTION_CAPTURE;
27
+ break;
28
+ default:
29
+ spa_log_error(log, "card nr %d device nr %d: unknown direction %#" PRIx32,
30
+ card_nr, device_nr, (uint32_t)(compr_caps->direction));
31
+ ret = -EINVAL;
32
+ }
33
+
34
+ compress_offload_api_close(device_context);
35
+
36
+ return ret;
37
+}
38
pipewire-0.3.80.tar.gz/spa/plugins/alsa/compress-offload-api-util.h
Added
32
1
2
+#ifndef SPA_ALSA_COMPRESS_OFFLOAD_DEVICE_UTIL_H
3
+#define SPA_ALSA_COMPRESS_OFFLOAD_DEVICE_UTIL_H
4
+
5
+#include <spa/support/log.h>
6
+
7
+#if defined(__GNUC__) && __GNUC__ >= 4
8
+#define COMPR_API_PRIVATE __attribute__((visibility("hidden")))
9
+#elif defined(__SUNPRO_C) && (__SUNPRO_C >= 0x590)
10
+#define COMPR_API_PRIVATE __attribute__((visibility("hidden")))
11
+#elif defined(__SUNPRO_C) && (__SUNPRO_C >= 0x550)
12
+#define COMPR_API_PRIVATE __hidden
13
+#else
14
+#define COMPR_API_PRIVATE
15
+#endif
16
+
17
+enum spa_compress_offload_direction {
18
+ SPA_COMPRESS_OFFLOAD_DIRECTION_PLAYBACK,
19
+ SPA_COMPRESS_OFFLOAD_DIRECTION_CAPTURE
20
+};
21
+
22
+/* This exists for situations where both the direction of the compress-offload
23
+ * device and the functions from asoundlib.h are needed. It is not possible to
24
+ * include asoundlib.h and the compress-offload headers in the same C file,
25
+ * since these headers contain conflicting declarations. Provide this direction
26
+ * check function to keep the compress-offload headers encapsulated. */
27
+COMPR_API_PRIVATE int get_compress_offload_device_direction(int card_nr, int device_nr,
28
+ struct spa_log *log,
29
+ enum spa_compress_offload_direction *direction);
30
+
31
+#endif /* SPA_ALSA_COMPRESS_OFFLOAD_DEVICE_UTIL_H */
32
pipewire-0.3.79.tar.gz/spa/plugins/alsa/compress-offload-api.h -> pipewire-0.3.80.tar.gz/spa/plugins/alsa/compress-offload-api.h
Changed
25
1
2
#include <sound/compress_offload.h>
3
#include <sound/compress_params.h>
4
#include <spa/support/log.h>
5
+#include "compress-offload-api-util.h"
6
7
8
struct compress_offload_api_context;
9
10
11
-#if defined(__GNUC__) && __GNUC__ >= 4
12
-#define COMPR_API_PRIVATE __attribute__((visibility("hidden")))
13
-#elif defined(__SUNPRO_C) && (__SUNPRO_C >= 0x590)
14
-#define COMPR_API_PRIVATE __attribute__((visibility("hidden")))
15
-#elif defined(__SUNPRO_C) && (__SUNPRO_C >= 0x550)
16
-#define COMPR_API_PRIVATE __hidden
17
-#else
18
-#define COMPR_API_PRIVATE
19
-#endif
20
-
21
-
22
/* This is a simple encapsulation of the ALSA Compress-Offload API
23
* and its ioctl calls. It is intentionally not using any PipeWire
24
* or SPA headers to allow for porting it or extracting it as its
25
pipewire-0.3.79.tar.gz/spa/plugins/alsa/meson.build -> pipewire-0.3.80.tar.gz/spa/plugins/alsa/meson.build
Changed
13
1
2
'alsa-seq.c'
3
4
if compress_offload_option.allowed()
5
- spa_alsa_sources += 'alsa-compress-offload-sink.c', 'compress-offload-api.c'
6
+ spa_alsa_sources += 'alsa-compress-offload-sink.c',
7
+ 'alsa-compress-offload-device.c',
8
+ 'compress-offload-api-util.c',
9
+ 'compress-offload-api.c'
10
endif
11
12
spa_alsa = shared_library(
13
pipewire-0.3.79.tar.gz/spa/plugins/audioconvert/audioadapter.c -> pipewire-0.3.80.tar.gz/spa/plugins/audioconvert/audioadapter.c
Changed
201
1
2
#include <spa/param/param.h>
3
#include <spa/param/audio/format-utils.h>
4
#include <spa/param/latency-utils.h>
5
+#include <spa/param/tag-utils.h>
6
#include <spa/debug/format.h>
7
#include <spa/debug/pod.h>
8
#include <spa/debug/log.h>
9
10
#define IDX_PortConfig 5
11
#define IDX_Latency 6
12
#define IDX_ProcessLatency 7
13
-#define N_NODE_PARAMS 8
14
+#define IDX_Tag 8
15
+#define N_NODE_PARAMS 9
16
struct spa_param_info paramsN_NODE_PARAMS;
17
uint32_t convert_params_flagsN_NODE_PARAMS;
18
uint32_t follower_params_flagsN_NODE_PARAMS;
19
20
unsigned int async:1;
21
unsigned int passthrough:1;
22
unsigned int follower_removing:1;
23
+ unsigned int in_recalc;
24
};
25
26
/** \endcond */
27
28
case SPA_PARAM_EnumFormat:
29
case SPA_PARAM_Format:
30
case SPA_PARAM_Latency:
31
+ case SPA_PARAM_Tag:
32
res = spa_node_port_enum_params_sync(this->follower,
33
this->direction, 0,
34
id, &result.next, filter, &result.param, &b.b);
35
36
37
static const struct spa_node_events follower_node_events;
38
39
+static int recalc_latency(struct impl *this, struct spa_node *src, enum spa_direction direction,
40
+ uint32_t port_id, struct spa_node *dst)
41
+{
42
+ struct spa_pod_builder b = { 0 };
43
+ uint8_t buffer1024;
44
+ struct spa_pod *param;
45
+ uint32_t index = 0;
46
+ struct spa_latency_info latency;
47
+ int res;
48
+
49
+ spa_log_info(this->log, "%p: %d:%d", this, direction, port_id);
50
+
51
+ if (this->target == this->follower)
52
+ return 0;
53
+
54
+ while (true) {
55
+ spa_pod_builder_init(&b, buffer, sizeof(buffer));
56
+ if ((res = spa_node_port_enum_params_sync(src,
57
+ direction, port_id, SPA_PARAM_Latency,
58
+ &index, NULL, ¶m, &b)) != 1) {
59
+ param = NULL;
60
+ break;
61
+ }
62
+ if ((res = spa_latency_parse(param, &latency)) < 0)
63
+ return res;
64
+ if (latency.direction == direction)
65
+ break;
66
+ }
67
+ if ((res = spa_node_port_set_param(dst,
68
+ SPA_DIRECTION_REVERSE(direction), 0,
69
+ SPA_PARAM_Latency, 0, param)) < 0)
70
+ return res;
71
+
72
+ return 0;
73
+}
74
+
75
+static int recalc_tag(struct impl *this, struct spa_node *src, enum spa_direction direction,
76
+ uint32_t port_id, struct spa_node *dst)
77
+{
78
+ struct spa_pod_builder b = { 0 };
79
+ uint8_t buffer1024;
80
+ struct spa_pod *param;
81
+ uint32_t index = 0;
82
+ struct spa_tag_info info;
83
+ int res;
84
+
85
+ spa_log_debug(this->log, "%p: %d:%d", this, direction, port_id);
86
+
87
+ if (this->target == this->follower)
88
+ return 0;
89
+
90
+ while (true) {
91
+ void *state = NULL;
92
+ spa_pod_builder_init(&b, buffer, sizeof(buffer));
93
+ if ((res = spa_node_port_enum_params_sync(src,
94
+ direction, port_id, SPA_PARAM_Tag,
95
+ &index, NULL, ¶m, &b)) != 1) {
96
+ param = NULL;
97
+ break;
98
+ }
99
+ if ((res = spa_tag_parse(param, &info, &state)) < 0)
100
+ return res;
101
+ if (info.direction == direction)
102
+ break;
103
+ }
104
+ if ((res = spa_node_port_set_param(dst,
105
+ SPA_DIRECTION_REVERSE(direction), 0,
106
+ SPA_PARAM_Tag, 0, param)) < 0)
107
+ return res;
108
+
109
+ return 0;
110
+}
111
+
112
+
113
static int reconfigure_mode(struct impl *this, bool passthrough,
114
enum spa_direction direction, struct spa_pod *format)
115
{
116
117
118
emit_node_info(this, false);
119
120
+ spa_log_debug(this->log, "%p: passthrough mode %d", this, passthrough);
121
+
122
return 0;
123
}
124
125
126
if (this->target != this->follower) {
127
if ((res = spa_node_set_param(this->target, id, flags, param)) < 0)
128
return res;
129
+
130
+ res = recalc_latency(this, this->follower, this->direction, 0, this->convert);
131
}
132
break;
133
}
134
135
emit_node_info(this, false);
136
}
137
138
+static void follower_convert_port_info(void *data,
139
+ enum spa_direction direction, uint32_t port_id,
140
+ const struct spa_port_info *info)
141
+{
142
+ struct impl *this = data;
143
+ uint32_t i;
144
+ int res;
145
+
146
+ spa_log_info(this->log, "%p: convert port info %s %p %08"PRIx64, this,
147
+ this->direction == SPA_DIRECTION_INPUT ?
148
+ "Input" : "Output", info, info->change_mask);
149
+
150
+ if (info->change_mask & SPA_PORT_CHANGE_MASK_PARAMS) {
151
+ for (i = 0; i < info->n_params; i++) {
152
+ uint32_t idx;
153
+
154
+ switch (info->paramsi.id) {
155
+ case SPA_PARAM_Latency:
156
+ idx = IDX_Latency;
157
+ break;
158
+ case SPA_PARAM_Tag:
159
+ idx = IDX_Tag;
160
+ break;
161
+ default:
162
+ continue;
163
+ }
164
+
165
+ if (!this->add_listener &&
166
+ this->convert_params_flagsidx == info->paramsi.flags)
167
+ continue;
168
+
169
+ this->convert_params_flagsidx = info->paramsi.flags;
170
+
171
+ if (this->add_listener)
172
+ continue;
173
+
174
+ if (idx == IDX_Latency) {
175
+ this->in_recalc++;
176
+ res = recalc_latency(this, this->convert, direction, port_id, this->follower);
177
+ this->in_recalc--;
178
+ spa_log_debug(this->log, "latency: %d (%s)", res,
179
+ spa_strerror(res));
180
+ }
181
+ if (idx == IDX_Tag) {
182
+ this->in_recalc++;
183
+ res = recalc_tag(this, this->convert, direction, port_id, this->follower);
184
+ this->in_recalc--;
185
+ spa_log_debug(this->log, "tag: %d (%s)", res,
186
+ spa_strerror(res));
187
+ }
188
+ spa_log_debug(this->log, "param %d changed", info->paramsi.id);
189
+ }
190
+ }
191
+}
192
+
193
static void convert_port_info(void *data,
194
enum spa_direction direction, uint32_t port_id,
195
const struct spa_port_info *info)
196
197
struct spa_port_info pi;
198
199
if (direction != this->direction) {
200
- /* skip the converter output port into the follower */
201
pipewire-0.3.79.tar.gz/spa/plugins/audioconvert/audioconvert.c -> pipewire-0.3.80.tar.gz/spa/plugins/audioconvert/audioconvert.c
Changed
201
1
2
#include <spa/param/audio/format-utils.h>
3
#include <spa/param/param.h>
4
#include <spa/param/latency-utils.h>
5
+#include <spa/param/tag-utils.h>
6
#include <spa/pod/filter.h>
7
#include <spa/pod/dynamic.h>
8
#include <spa/debug/types.h>
9
10
#define IDX_Format 3
11
#define IDX_Buffers 4
12
#define IDX_Latency 5
13
-#define N_PORT_PARAMS 6
14
+#define IDX_Tag 6
15
+#define N_PORT_PARAMS 7
16
struct spa_param_info paramsN_PORT_PARAMS;
17
char position16;
18
19
struct buffer buffersMAX_BUFFERS;
20
uint32_t n_buffers;
21
22
+ struct spa_latency_info latency2;
23
+ unsigned int have_latency:1;
24
+
25
struct spa_audio_info format;
26
unsigned int have_format:1;
27
unsigned int is_dsp:1;
28
29
struct spa_audio_info format;
30
unsigned int have_format:1;
31
unsigned int have_profile:1;
32
- struct spa_latency_info latency;
33
+ struct spa_pod *tag;
34
35
uint32_t remapMAX_PORTS;
36
37
38
}
39
port->direction = direction;
40
port->id = port_id;
41
+ port->latencySPA_DIRECTION_INPUT = SPA_LATENCY_INFO(SPA_DIRECTION_INPUT);
42
+ port->latencySPA_DIRECTION_OUTPUT = SPA_LATENCY_INFO(SPA_DIRECTION_OUTPUT);
43
44
name = spa_debug_type_find_short_name(spa_type_audio_channel, position);
45
snprintf(port->position, sizeof(port->position), "%s", name ? name : "UNK");
46
47
port->paramsIDX_Format = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE);
48
port->paramsIDX_Buffers = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0);
49
port->paramsIDX_Latency = SPA_PARAM_INFO(SPA_PARAM_Latency, SPA_PARAM_INFO_READWRITE);
50
+ port->paramsIDX_Tag = SPA_PARAM_INFO(SPA_PARAM_Tag, SPA_PARAM_INFO_READWRITE);
51
port->info.params = port->params;
52
port->info.n_params = N_PORT_PARAMS;
53
54
55
spa_log_info(this->log, "generating ramp up sequence from %f to %f with a"
56
" step value %f at scale %d", p->prev_volume, p->volume, volume_step, p->vrp.scale);
57
do {
58
- // spa_log_debug(this->log, "volume accum %f", get_volume_at_scale(this, volume_accum));
59
+ spa_log_trace(this->log, "volume accum %f", get_volume_at_scale(this, volume_accum));
60
spa_pod_builder_control(&b.b, volume_offs, SPA_CONTROL_Properties);
61
spa_pod_builder_add_object(&b.b,
62
SPA_TYPE_OBJECT_Props, 0,
63
64
spa_log_info(this->log, "generating ramp down sequence from %f to %f with a"
65
" step value %f at scale %d", p->prev_volume, p->volume, volume_step, p->vrp.scale);
66
do {
67
- // spa_log_debug(this->log, "volume accum %f", get_volume_at_scale(this, volume_accum));
68
+ spa_log_trace(this->log, "volume accum %f", get_volume_at_scale(this, volume_accum));
69
spa_pod_builder_control(&b.b, volume_offs, SPA_CONTROL_Properties);
70
spa_pod_builder_add_object(&b.b,
71
SPA_TYPE_OBJECT_Props, 0,
72
73
uint32_t idx = result.index;
74
if (port->is_monitor)
75
idx = idx ^ 1;
76
- param = spa_latency_build(&b, id, &this->diridx.latency);
77
+ param = spa_latency_build(&b, id, &port->latencyidx);
78
+ break;
79
+ }
80
+ default:
81
+ return 0;
82
+ }
83
+ break;
84
+ case SPA_PARAM_Tag:
85
+ switch (result.index) {
86
+ case 0: case 1:
87
+ {
88
+ uint32_t idx = result.index;
89
+ if (port->is_monitor)
90
+ idx = idx ^ 1;
91
+ param = this->diridx.tag;
92
+ if (param == NULL)
93
+ goto next;
94
break;
95
}
96
default:
97
98
struct impl *this = object;
99
struct port *port, *oport;
100
enum spa_direction other = SPA_DIRECTION_REVERSE(direction);
101
+ struct spa_latency_info info;
102
+ bool have_latency, emit = false;;
103
uint32_t i;
104
105
- spa_log_debug(this->log, "%p: set latency direction:%d id:%d",
106
- this, direction, port_id);
107
+ spa_log_debug(this->log, "%p: set latency direction:%d id:%d %p",
108
+ this, direction, port_id, latency);
109
110
port = GET_PORT(this, direction, port_id);
111
if (port->is_monitor)
112
return 0;
113
114
if (latency == NULL) {
115
- this->dirother.latency = SPA_LATENCY_INFO(other);
116
+ info = SPA_LATENCY_INFO(other);
117
+ have_latency = false;
118
} else {
119
- struct spa_latency_info info;
120
if (spa_latency_parse(latency, &info) < 0 ||
121
info.direction != other)
122
return -EINVAL;
123
- this->dirother.latency = info;
124
+ have_latency = true;
125
}
126
+ emit = spa_latency_info_compare(&info, &port->latencyother) != 0 ||
127
+ port->have_latency == have_latency;
128
+
129
+ port->latencyother = info;
130
+ port->have_latency = have_latency;
131
+
132
+ spa_log_debug(this->log, "%p: set %s latency %f-%f %d-%d %"PRIu64"-%"PRIu64, this,
133
+ info.direction == SPA_DIRECTION_INPUT ? "input" : "output",
134
+ info.min_quantum, info.max_quantum,
135
+ info.min_rate, info.max_rate,
136
+ info.min_ns, info.max_ns);
137
+
138
+ spa_latency_info_combine_start(&info, other);
139
+ for (i = 0; i < this->dirdirection.n_ports; i++) {
140
+ oport = GET_PORT(this, direction, i);
141
+ if (oport->is_monitor || !oport->have_latency)
142
+ continue;
143
+ spa_log_debug(this->log, "%p: combine %d", this, i);
144
+ spa_latency_info_combine(&info, &oport->latencyother);
145
+ }
146
+ spa_latency_info_combine_finish(&info);
147
+
148
+ spa_log_debug(this->log, "%p: combined %s latency %f-%f %d-%d %"PRIu64"-%"PRIu64, this,
149
+ info.direction == SPA_DIRECTION_INPUT ? "input" : "output",
150
+ info.min_quantum, info.max_quantum,
151
+ info.min_rate, info.max_rate,
152
+ info.min_ns, info.max_ns);
153
154
for (i = 0; i < this->dirother.n_ports; i++) {
155
oport = GET_PORT(this, other, i);
156
- oport->info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS;
157
- oport->paramsIDX_Latency.user++;
158
- emit_port_info(this, oport, false);
159
+
160
+ spa_log_debug(this->log, "%p: change %d", this, i);
161
+ if (spa_latency_info_compare(&info, &oport->latencyother) != 0) {
162
+ oport->latencyother = info;
163
+ oport->info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS;
164
+ oport->paramsIDX_Latency.user++;
165
+ emit_port_info(this, oport, false);
166
+ }
167
+ }
168
+ if (emit) {
169
+ port->info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS;
170
+ port->paramsIDX_Latency.user++;
171
+ emit_port_info(this, port, false);
172
+ }
173
+ return 0;
174
+}
175
+
176
+static int port_set_tag(void *object,
177
+ enum spa_direction direction,
178
+ uint32_t port_id,
179
+ uint32_t flags,
180
+ const struct spa_pod *tag)
181
+{
182
+ struct impl *this = object;
183
+ struct port *port, *oport;
184
+ enum spa_direction other = SPA_DIRECTION_REVERSE(direction);
185
+ uint32_t i;
186
+
187
+ spa_log_debug(this->log, "%p: set tag direction:%d id:%d %p",
188
+ this, direction, port_id, tag);
189
+
190
+ port = GET_PORT(this, direction, port_id);
191
+ if (port->is_monitor)
192
+ return 0;
193
+
194
+ if (tag != NULL) {
195
+ struct spa_tag_info info;
196
+ void *state = NULL;
197
+ if (spa_tag_parse(tag, &info, &state) < 0 ||
198
+ info.direction != other)
199
+ return -EINVAL;
200
+ }
201
pipewire-0.3.79.tar.gz/spa/plugins/audioconvert/meson.build -> pipewire-0.3.80.tar.gz/spa/plugins/audioconvert/meson.build
Changed
33
1
2
simd_cargs =
3
simd_dependencies =
4
5
+opt_flags =
6
+if host_machine.cpu_family() != 'alpha'
7
+ opt_flags += '-Ofast'
8
+else
9
+ opt_flags += '-O3'
10
+endif
11
+
12
audioconvert_c = static_library('audioconvert_c',
13
'channelmix-ops-c.c',
14
'biquad.c',
15
16
'peaks-ops-c.c',
17
'resample-native-c.c',
18
'fmt-ops-c.c' ,
19
- c_args : '-Ofast', '-ffast-math',
20
+ c_args : opt_flags ,
21
dependencies : spa_dep ,
22
install : false
23
)
24
25
'volume-ops-sse.c',
26
'peaks-ops-sse.c',
27
'channelmix-ops-sse.c' ,
28
- c_args : sse_args, '-Ofast', '-DHAVE_SSE',
29
+ c_args : sse_args, opt_flags, '-DHAVE_SSE',
30
dependencies : spa_dep ,
31
install : false
32
)
33
pipewire-0.3.79.tar.gz/spa/plugins/audiomixer/audiomixer.c -> pipewire-0.3.80.tar.gz/spa/plugins/audiomixer/audiomixer.c
Changed
80
1
2
#include <spa/support/plugin.h>
3
#include <spa/support/log.h>
4
#include <spa/support/cpu.h>
5
+#include <spa/support/loop.h>
6
#include <spa/utils/list.h>
7
#include <spa/utils/names.h>
8
#include <spa/utils/string.h>
9
10
struct spa_cpu *cpu;
11
uint32_t cpu_flags;
12
uint32_t max_align;
13
+
14
+ struct spa_loop *data_loop;
15
+
16
uint32_t quantum_limit;
17
18
struct mix_ops ops;
19
20
21
port = GET_PORT(this, direction, port_id);
22
23
+ spa_return_val_if_fail(!this->started || port->io == NULL, -EIO);
24
+
25
if (format == NULL) {
26
if (port->have_format) {
27
port->have_format = false;
28
29
30
port = GET_PORT(this, direction, port_id);
31
32
+ spa_return_val_if_fail(!this->started || port->io == NULL, -EIO);
33
+
34
clear_buffers(this, port);
35
36
if (n_buffers > 0 && !port->have_format)
37
38
return 0;
39
}
40
41
+struct io_info {
42
+ struct port *port;
43
+ void *data;
44
+};
45
+
46
+static int do_port_set_io(struct spa_loop *loop, bool async, uint32_t seq,
47
+ const void *data, size_t size, void *user_data)
48
+{
49
+ struct io_info *info = user_data;
50
+ info->port->io = info->data;
51
+ return 0;
52
+}
53
+
54
static int
55
impl_node_port_set_io(void *object,
56
enum spa_direction direction, uint32_t port_id,
57
58
{
59
struct impl *this = object;
60
struct port *port;
61
+ struct io_info info;
62
63
spa_return_val_if_fail(this != NULL, -EINVAL);
64
65
66
spa_return_val_if_fail(CHECK_PORT(this, direction, port_id), -EINVAL);
67
68
port = GET_PORT(this, direction, port_id);
69
+ info.port = port;
70
+ info.data = data;
71
72
switch (id) {
73
case SPA_IO_Buffers:
74
- port->io = data;
75
+ spa_loop_invoke(this->data_loop,
76
+ do_port_set_io, SPA_ID_INVALID, NULL, 0, true, &info);
77
break;
78
default:
79
return -ENOENT;
80
pipewire-0.3.79.tar.gz/spa/plugins/audiomixer/mixer-dsp.c -> pipewire-0.3.80.tar.gz/spa/plugins/audiomixer/mixer-dsp.c
Changed
92
1
2
#include <spa/support/plugin.h>
3
#include <spa/support/log.h>
4
#include <spa/support/cpu.h>
5
+#include <spa/support/loop.h>
6
#include <spa/utils/list.h>
7
#include <spa/utils/names.h>
8
#include <spa/utils/string.h>
9
10
uint32_t cpu_flags;
11
uint32_t max_align;
12
13
+ struct spa_loop *data_loop;
14
+
15
uint32_t quantum_limit;
16
17
struct mix_ops ops;
18
19
20
port = GET_PORT(this, direction, port_id);
21
22
+ spa_return_val_if_fail(!this->started || port->io == NULL, -EIO);
23
+
24
if (format == NULL) {
25
if (port->have_format) {
26
port->have_format = false;
27
28
29
port = GET_PORT(this, direction, port_id);
30
31
+ spa_return_val_if_fail(!this->started || port->io == NULL, -EIO);
32
+
33
clear_buffers(this, port);
34
35
if (n_buffers > 0 && !port->have_format)
36
37
return 0;
38
}
39
40
+struct io_info {
41
+ struct port *port;
42
+ void *data;
43
+};
44
+
45
+static int do_port_set_io(struct spa_loop *loop, bool async, uint32_t seq,
46
+ const void *data, size_t size, void *user_data)
47
+{
48
+ struct io_info *info = user_data;
49
+ info->port->io = info->data;
50
+ return 0;
51
+}
52
+
53
static int
54
impl_node_port_set_io(void *object,
55
enum spa_direction direction, uint32_t port_id,
56
57
{
58
struct impl *this = object;
59
struct port *port;
60
+ struct io_info info;
61
62
spa_return_val_if_fail(this != NULL, -EINVAL);
63
64
65
spa_return_val_if_fail(CHECK_PORT(this, direction, port_id), -EINVAL);
66
67
port = GET_PORT(this, direction, port_id);
68
+ info.port = port;
69
+ info.data = data;
70
71
switch (id) {
72
case SPA_IO_Buffers:
73
- port->io = data;
74
+ spa_loop_invoke(this->data_loop,
75
+ do_port_set_io, SPA_ID_INVALID, NULL, 0, true, &info);
76
break;
77
default:
78
return -ENOENT;
79
80
this->log = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_Log);
81
spa_log_topic_init(this->log, log_topic);
82
83
+ this->data_loop = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_DataLoop);
84
+ if (this->data_loop == NULL) {
85
+ spa_log_error(this->log, "a data loop is needed");
86
+ return -EINVAL;
87
+ }
88
+
89
this->cpu = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_CPU);
90
if (this->cpu) {
91
this->cpu_flags = spa_cpu_get_flags(this->cpu);
92
pipewire-0.3.79.tar.gz/spa/plugins/avb/avb-pcm-sink.c -> pipewire-0.3.80.tar.gz/spa/plugins/avb/avb-pcm-sink.c
Changed
12
1
2
case SPA_PARAM_Latency:
3
{
4
struct spa_latency_info info;
5
- if ((res = spa_latency_parse(param, &info)) < 0)
6
+ if (param == NULL)
7
+ info = SPA_LATENCY_INFO(SPA_DIRECTION_REVERSE(direction));
8
+ else if ((res = spa_latency_parse(param, &info)) < 0)
9
return res;
10
if (direction == info.direction)
11
return -EINVAL;
12
pipewire-0.3.79.tar.gz/spa/plugins/avb/avb-pcm-source.c -> pipewire-0.3.80.tar.gz/spa/plugins/avb/avb-pcm-source.c
Changed
12
1
2
case SPA_PARAM_Latency:
3
{
4
struct spa_latency_info info;
5
- if ((res = spa_latency_parse(param, &info)) < 0)
6
+ if (param == NULL)
7
+ info = SPA_LATENCY_INFO(SPA_DIRECTION_REVERSE(direction));
8
+ else if ((res = spa_latency_parse(param, &info)) < 0)
9
return res;
10
if (direction == info.direction)
11
return -EINVAL;
12
pipewire-0.3.79.tar.gz/spa/plugins/bluez5/bluez5-dbus.c -> pipewire-0.3.80.tar.gz/spa/plugins/bluez5/bluez5-dbus.c
Changed
201
1
2
}
3
}
4
5
+static enum spa_bt_profile swap_profile(enum spa_bt_profile profile)
6
+{
7
+ switch (profile) {
8
+ case SPA_BT_PROFILE_A2DP_SOURCE:
9
+ return SPA_BT_PROFILE_A2DP_SINK;
10
+ case SPA_BT_PROFILE_A2DP_SINK:
11
+ return SPA_BT_PROFILE_A2DP_SOURCE;
12
+ case SPA_BT_PROFILE_BAP_SOURCE:
13
+ return SPA_BT_PROFILE_BAP_SINK;
14
+ case SPA_BT_PROFILE_BAP_SINK:
15
+ return SPA_BT_PROFILE_BAP_SOURCE;
16
+ case SPA_BT_PROFILE_BAP_BROADCAST_SOURCE:
17
+ return SPA_BT_PROFILE_BAP_BROADCAST_SINK;
18
+ case SPA_BT_PROFILE_BAP_BROADCAST_SINK:
19
+ return SPA_BT_PROFILE_BAP_BROADCAST_SOURCE;
20
+ default:
21
+ return SPA_BT_PROFILE_NULL;
22
+ }
23
+}
24
+
25
static bool endpoint_should_be_registered(struct spa_bt_monitor *monitor,
26
const struct media_codec *codec,
27
enum spa_bt_media_direction direction)
28
29
return device->adapter && device->address;
30
}
31
32
-bool spa_bt_device_supports_media_codec(struct spa_bt_device *device, const struct media_codec *codec, bool sink)
33
+bool spa_bt_device_supports_media_codec(struct spa_bt_device *device, const struct media_codec *codec, enum spa_bt_profile profile)
34
{
35
struct spa_bt_monitor *monitor = device->monitor;
36
struct spa_bt_remote_endpoint *ep;
37
- enum spa_bt_profile codec_profile;
38
+ enum spa_bt_profile codec_target_profile;
39
struct spa_bt_transport *t;
40
const struct { enum spa_bluetooth_audio_codec codec; uint32_t mask; } quirks = {
41
{ SPA_BLUETOOTH_AUDIO_CODEC_SBC_XQ, SPA_BT_FEATURE_SBC_XQ },
42
43
return false;
44
}
45
46
+ for (i = 0, codec_target_profile = 0; i < (size_t)SPA_BT_MEDIA_DIRECTION_LAST; ++i)
47
+ if (codec_has_direction(codec, i))
48
+ codec_target_profile |= swap_profile(get_codec_profile(codec, i));
49
+
50
spa_list_for_each(ep, &device->remote_endpoint_list, device_link) {
51
- enum spa_bt_profile profile = spa_bt_profile_from_uuid(ep->uuid);
52
- if (codec->bap) {
53
- if ((profile == SPA_BT_PROFILE_BAP_BROADCAST_SINK) || (profile == SPA_BT_PROFILE_BAP_BROADCAST_SOURCE))
54
- codec_profile = sink ? SPA_BT_PROFILE_BAP_BROADCAST_SINK : SPA_BT_PROFILE_BAP_BROADCAST_SOURCE;
55
- else
56
- codec_profile = sink ? SPA_BT_PROFILE_BAP_SINK : SPA_BT_PROFILE_BAP_SOURCE;
57
- } else
58
- codec_profile = sink ? SPA_BT_PROFILE_A2DP_SINK : SPA_BT_PROFILE_A2DP_SOURCE;
59
+ enum spa_bt_profile ep_profile = spa_bt_profile_from_uuid(ep->uuid);
60
61
- if (profile != codec_profile)
62
+ if (!(ep_profile & codec_target_profile & profile))
63
continue;
64
65
if (media_codec_check_caps(codec, ep->codec, ep->capabilities, ep->capabilities_len,
66
67
* can only know that the currently configured codec is supported.
68
*/
69
spa_list_for_each(t, &device->transport_list, device_link) {
70
- if (codec->bap) {
71
- if((t->profile == SPA_BT_PROFILE_BAP_BROADCAST_SINK) || (t->profile == SPA_BT_PROFILE_BAP_BROADCAST_SOURCE))
72
- codec_profile = sink ? SPA_BT_PROFILE_BAP_BROADCAST_SINK : SPA_BT_PROFILE_BAP_BROADCAST_SOURCE;
73
- else
74
- codec_profile = sink ? SPA_BT_PROFILE_BAP_SINK : SPA_BT_PROFILE_BAP_SOURCE;
75
- } else
76
- codec_profile = sink ? SPA_BT_PROFILE_A2DP_SINK : SPA_BT_PROFILE_A2DP_SOURCE;
77
-
78
- if (t->profile != codec_profile)
79
+ if (!(t->profile & codec_target_profile & profile))
80
continue;
81
82
if (codec == t->media_codec)
83
84
return false;
85
}
86
87
-const struct media_codec **spa_bt_device_get_supported_media_codecs(struct spa_bt_device *device, size_t *count, bool sink)
88
+const struct media_codec **spa_bt_device_get_supported_media_codecs(struct spa_bt_device *device, size_t *count)
89
{
90
struct spa_bt_monitor *monitor = device->monitor;
91
const struct media_codec * const * const media_codecs = monitor->media_codecs;
92
93
94
j = 0;
95
for (i = 0; media_codecsi != NULL; ++i) {
96
- if (spa_bt_device_supports_media_codec(device, media_codecsi, sink)) {
97
+ if (spa_bt_device_supports_media_codec(device, media_codecsi, device->connected_profiles)) {
98
supported_codecsj = media_codecsi;
99
++j;
100
}
101
102
return NULL;
103
}
104
105
-static struct spa_bt_device* create_bcast_device(struct spa_bt_monitor *monitor,
106
- const char *object_path)
107
+static struct spa_bt_device *create_bcast_device(struct spa_bt_monitor *monitor, const char *object_path)
108
{
109
struct spa_bt_device *d;
110
+ struct spa_bt_adapter *adapter;
111
+
112
+ adapter = adapter_find(monitor, object_path);
113
+ if (adapter == NULL) {
114
+ spa_log_warn(monitor->log, "unknown adapter %s", object_path);
115
+ return NULL;
116
+ }
117
+
118
d = device_create(monitor, object_path);
119
if (d == NULL) {
120
spa_log_warn(monitor->log, "can't create Bluetooth device %s: %m",
121
122
return NULL;
123
}
124
125
- d->adapter = adapter_find(monitor, object_path);
126
- if (d->adapter == NULL) {
127
- spa_log_warn(monitor->log, "unknown adapter %s", d->adapter_path);
128
- }
129
- d->adapter_path = d->adapter->path;
130
- d->alias = strdup("bcast_device");
131
- d->name = strdup("bcast_device");
132
+ d->adapter = adapter;
133
+ d->adapter_path = strdup(adapter->path);
134
+ d->alias = strdup(adapter->alias);
135
+ d->name = strdup(adapter->name);
136
d->address = strdup("00:00:00:00:00:00");
137
-
138
- spa_bt_device_check_profiles(d, false);
139
- d->reconnect_state = BT_DEVICE_RECONNECT_INIT;
140
-
141
- if (!device_props_ready(d))
142
- {
143
- return NULL;
144
- }
145
+ d->reconnect_state = BT_DEVICE_RECONNECT_STOP;
146
147
device_update_hw_volume_profiles(d);
148
149
150
}
151
else if (spa_streq(key, "Device")) {
152
struct spa_bt_device *device;
153
+
154
device = spa_bt_device_find(monitor, value);
155
if (device == NULL) {
156
/*
157
158
* This is done because BlueZ sets the adapter as the device
159
* that is connected to for a broadcast sink endpoint/transport.
160
*/
161
- if(spa_streq(remote_endpoint->uuid, SPA_BT_UUID_BAP_BROADCAST_SINK)) {
162
+ if (spa_streq(remote_endpoint->uuid, SPA_BT_UUID_BAP_BROADCAST_SINK)) {
163
device = create_bcast_device(monitor, value);
164
- if(device == NULL) {
165
+ if (device == NULL)
166
goto next;
167
- }
168
+
169
remote_endpoint->acceptor = true;
170
device_set_connected(device, 1);
171
} else {
172
173
spa_log_debug(monitor->log, "transport %p: %s=%s", transport, key, value);
174
175
if (spa_streq(key, "UUID")) {
176
- switch (spa_bt_profile_from_uuid(value)) {
177
- case SPA_BT_PROFILE_A2DP_SOURCE:
178
- transport->profile = SPA_BT_PROFILE_A2DP_SINK;
179
- break;
180
- case SPA_BT_PROFILE_A2DP_SINK:
181
- transport->profile = SPA_BT_PROFILE_A2DP_SOURCE;
182
- break;
183
- case SPA_BT_PROFILE_BAP_SOURCE:
184
- transport->profile = SPA_BT_PROFILE_BAP_SINK;
185
- break;
186
- case SPA_BT_PROFILE_BAP_SINK:
187
- transport->profile = SPA_BT_PROFILE_BAP_SOURCE;
188
- break;
189
- case SPA_BT_PROFILE_BAP_BROADCAST_SOURCE:
190
- transport->profile = SPA_BT_PROFILE_BAP_BROADCAST_SINK;
191
- break;
192
- case SPA_BT_PROFILE_BAP_BROADCAST_SINK:
193
- transport->profile = SPA_BT_PROFILE_BAP_BROADCAST_SOURCE;
194
- break;
195
- default:
196
+ transport->profile = swap_profile(spa_bt_profile_from_uuid(value));
197
+ if (transport->profile == SPA_BT_PROFILE_NULL)
198
spa_log_warn(monitor->log, "unknown profile %s", value);
199
- break;
200
- }
201
pipewire-0.3.79.tar.gz/spa/plugins/bluez5/bluez5-device.c -> pipewire-0.3.80.tar.gz/spa/plugins/bluez5/bluez5-device.c
Changed
127
1
2
*codecs = NULL;
3
}
4
5
-static const struct media_codec *get_supported_media_codec(struct impl *this, enum spa_bluetooth_audio_codec id, size_t *idx)
6
+static const struct media_codec *get_supported_media_codec(struct impl *this, enum spa_bluetooth_audio_codec id,
7
+ size_t *idx, enum spa_bt_profile profile)
8
{
9
const struct media_codec *media_codec = NULL;
10
size_t i;
11
+
12
for (i = 0; i < this->supported_codec_count; ++i) {
13
if (this->supported_codecsi->id == id) {
14
media_codec = this->supported_codecsi;
15
16
*idx = i;
17
}
18
}
19
+
20
+ if (!media_codec)
21
+ return NULL;
22
+
23
+ if (!spa_bt_device_supports_media_codec(this->bt_dev, media_codec, profile))
24
+ return NULL;
25
+
26
return media_codec;
27
}
28
29
30
char transport32, str_id32, object_path512;
31
bool is_dyn_node = SPA_FLAG_IS_SET(id, DYNAMIC_NODE_ID_FLAG);
32
33
+ spa_log_debug(this->log, "node, transport:%p id:%08x factory:%s", t, id, factory_name);
34
+
35
snprintf(transport, sizeof(transport), "pointer:%p", t);
36
items0 = SPA_DICT_ITEM_INIT(SPA_KEY_API_BLUEZ5_TRANSPORT, transport);
37
items1 = SPA_DICT_ITEM_INIT(SPA_KEY_API_BLUEZ5_PROFILE, spa_bt_profile_name(t->profile));
38
39
}
40
}
41
}
42
-
43
- if (get_supported_media_codec(this, this->props.codec, NULL) == NULL)
44
- this->props.codec = 0;
45
break;
46
case DEVICE_PROFILE_BAP:
47
if (this->bt_dev->connected_profiles & (SPA_BT_PROFILE_BAP_SOURCE)) {
48
49
DEVICE_ID_SOURCE, SPA_NAME_API_BLUEZ5_MEDIA_SOURCE, false);
50
}
51
}
52
-
53
- if (get_supported_media_codec(this, this->props.codec, NULL) == NULL)
54
- this->props.codec = 0;
55
break;
56
case DEVICE_PROFILE_HSP_HFP:
57
if (this->bt_dev->connected_profiles & SPA_BT_PROFILE_HEADSET_HEAD_UNIT) {
58
59
60
static void emit_remove_nodes(struct impl *this)
61
{
62
+ spa_log_debug(this->log, "remove nodes");
63
+
64
remove_dynamic_node (&this->dyn_media_source);
65
remove_dynamic_node (&this->dyn_media_sink);
66
remove_dynamic_node (&this->dyn_sco_source);
67
68
if (this->switching_codec)
69
return;
70
71
- if (this->bt_dev->connected_profiles & SPA_BT_PROFILE_MEDIA_SINK) {
72
- free(this->supported_codecs);
73
- this->supported_codecs = spa_bt_device_get_supported_media_codecs(
74
- this->bt_dev, &this->supported_codec_count, true);
75
- }
76
+ free(this->supported_codecs);
77
+ this->supported_codecs = spa_bt_device_get_supported_media_codecs(
78
+ this->bt_dev, &this->supported_codec_count);
79
80
switch (this->profile) {
81
case DEVICE_PROFILE_OFF:
82
83
break;
84
case DEVICE_PROFILE_A2DP:
85
case DEVICE_PROFILE_BAP:
86
- if (get_supported_media_codec(this, this->props.codec, NULL) == NULL)
87
- this->props.codec = 0;
88
nodes_changed = (connected_change & (SPA_BT_PROFILE_MEDIA_SINK |
89
SPA_BT_PROFILE_MEDIA_SOURCE));
90
spa_log_debug(this->log, "profiles changed: media nodes changed: %d",
91
92
if (device->connected_profiles & SPA_BT_PROFILE_A2DP_SINK)
93
have_output = true;
94
95
- media_codec = get_supported_media_codec(this, codec, NULL);
96
+ media_codec = get_supported_media_codec(this, codec, NULL, device->connected_profiles);
97
if (media_codec && media_codec->duplex_codec)
98
have_input = true;
99
break;
100
101
if (this->supported_codecs)
102
free(this->supported_codecs);
103
this->supported_codecs = spa_bt_device_get_supported_media_codecs(
104
- this->bt_dev, &this->supported_codec_count, true);
105
+ this->bt_dev, &this->supported_codec_count);
106
107
/* Prefer BAP, then A2DP, then HFP, then null, but select AG if the device
108
appears not to have BAP_SINK, A2DP_SINK or any HEAD_UNIT profile */
109
110
n_sink++;
111
if (codec) {
112
size_t idx;
113
- const struct media_codec *media_codec = get_supported_media_codec(this, codec, &idx);
114
+ const struct media_codec *media_codec = get_supported_media_codec(this, codec, &idx, profile);
115
if (media_codec == NULL) {
116
errno = EINVAL;
117
return NULL;
118
119
name = spa_bt_profile_name(profile);
120
121
if (codec) {
122
- media_codec = get_supported_media_codec(this, codec, &idx);
123
+ media_codec = get_supported_media_codec(this, codec, &idx, profile);
124
if (media_codec == NULL) {
125
errno = EINVAL;
126
return NULL;
127
pipewire-0.3.79.tar.gz/spa/plugins/bluez5/defs.h -> pipewire-0.3.80.tar.gz/spa/plugins/bluez5/defs.h
Changed
20
1
2
SPA_BT_MEDIA_SINK,
3
SPA_BT_MEDIA_SOURCE_BROADCAST,
4
SPA_BT_MEDIA_SINK_BROADCAST,
5
+ SPA_BT_MEDIA_DIRECTION_LAST,
6
};
7
8
enum spa_bt_profile {
9
10
int spa_bt_device_connect_profile(struct spa_bt_device *device, enum spa_bt_profile profile);
11
int spa_bt_device_check_profiles(struct spa_bt_device *device, bool force);
12
int spa_bt_device_ensure_media_codec(struct spa_bt_device *device, const struct media_codec * const *codecs);
13
-bool spa_bt_device_supports_media_codec(struct spa_bt_device *device, const struct media_codec *codec, bool sink);
14
-const struct media_codec **spa_bt_device_get_supported_media_codecs(struct spa_bt_device *device, size_t *count, bool sink);
15
+bool spa_bt_device_supports_media_codec(struct spa_bt_device *device, const struct media_codec *codec, enum spa_bt_profile profile);
16
+const struct media_codec **spa_bt_device_get_supported_media_codecs(struct spa_bt_device *device, size_t *count);
17
int spa_bt_device_ensure_hfp_codec(struct spa_bt_device *device, unsigned int codec);
18
int spa_bt_device_supports_hfp_codec(struct spa_bt_device *device, unsigned int codec);
19
int spa_bt_device_release_transports(struct spa_bt_device *device);
20
pipewire-0.3.79.tar.gz/spa/plugins/bluez5/media-sink.c -> pipewire-0.3.80.tar.gz/spa/plugins/bluez5/media-sink.c
Changed
21
1
2
3
port->info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS;
4
if (port->have_format) {
5
- port->info.change_mask |= SPA_PORT_CHANGE_MASK_FLAGS;
6
- port->info.flags = SPA_PORT_FLAG_LIVE;
7
port->info.change_mask |= SPA_PORT_CHANGE_MASK_RATE;
8
port->info.rate = SPA_FRACTION(1, port->current_format.info.raw.rate);
9
port->paramsIDX_Format = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_READWRITE);
10
11
port->info_all = SPA_PORT_CHANGE_MASK_FLAGS |
12
SPA_PORT_CHANGE_MASK_PARAMS;
13
port->info = SPA_PORT_INFO_INIT();
14
- port->info.flags = 0;
15
+ port->info.flags = SPA_PORT_FLAG_LIVE |
16
+ SPA_PORT_FLAG_PHYSICAL |
17
+ SPA_PORT_FLAG_TERMINAL;
18
port->paramsIDX_EnumFormat = SPA_PARAM_INFO(SPA_PARAM_EnumFormat, SPA_PARAM_INFO_READ);
19
port->paramsIDX_Meta = SPA_PARAM_INFO(SPA_PARAM_Meta, SPA_PARAM_INFO_READ);
20
port->paramsIDX_IO = SPA_PARAM_INFO(SPA_PARAM_IO, SPA_PARAM_INFO_READ);
21
pipewire-0.3.79.tar.gz/spa/plugins/bluez5/media-source.c -> pipewire-0.3.80.tar.gz/spa/plugins/bluez5/media-source.c
Changed
18
1
2
3
port->info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS;
4
if (port->have_format) {
5
- port->info.change_mask |= SPA_PORT_CHANGE_MASK_FLAGS;
6
- port->info.flags = SPA_PORT_FLAG_LIVE;
7
port->info.change_mask |= SPA_PORT_CHANGE_MASK_RATE;
8
port->info.rate = SPA_FRACTION(1, port->current_format.info.raw.rate);
9
port->paramsIDX_Format = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_READWRITE);
10
11
port->info = SPA_PORT_INFO_INIT();
12
port->info.change_mask = SPA_PORT_CHANGE_MASK_FLAGS;
13
port->info.flags = SPA_PORT_FLAG_LIVE |
14
+ SPA_PORT_FLAG_PHYSICAL |
15
SPA_PORT_FLAG_TERMINAL;
16
port->paramsIDX_EnumFormat = SPA_PARAM_INFO(SPA_PARAM_EnumFormat, SPA_PARAM_INFO_READ);
17
port->paramsIDX_Meta = SPA_PARAM_INFO(SPA_PARAM_Meta, SPA_PARAM_INFO_READ);
18
pipewire-0.3.79.tar.gz/spa/plugins/bluez5/midi-node.c -> pipewire-0.3.80.tar.gz/spa/plugins/bluez5/midi-node.c
Changed
12
1
2
SPA_PORT_CHANGE_MASK_PARAMS;
3
port->info = SPA_PORT_INFO_INIT();
4
port->info.change_mask = SPA_PORT_CHANGE_MASK_FLAGS;
5
- port->info.flags = SPA_PORT_FLAG_LIVE;
6
+ port->info.flags = SPA_PORT_FLAG_LIVE |
7
+ SPA_PORT_FLAG_PHYSICAL |
8
+ SPA_PORT_FLAG_TERMINAL;
9
port->paramsIDX_EnumFormat = SPA_PARAM_INFO(SPA_PARAM_EnumFormat, SPA_PARAM_INFO_READ);
10
port->paramsIDX_Meta = SPA_PARAM_INFO(SPA_PARAM_Meta, SPA_PARAM_INFO_READ);
11
port->paramsIDX_IO = SPA_PARAM_INFO(SPA_PARAM_IO, SPA_PARAM_INFO_READ);
12
pipewire-0.3.79.tar.gz/spa/plugins/bluez5/sco-sink.c -> pipewire-0.3.80.tar.gz/spa/plugins/bluez5/sco-sink.c
Changed
21
1
2
3
port->info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS;
4
if (port->have_format) {
5
- port->info.change_mask |= SPA_PORT_CHANGE_MASK_FLAGS;
6
- port->info.flags = SPA_PORT_FLAG_LIVE;
7
port->info.change_mask |= SPA_PORT_CHANGE_MASK_RATE;
8
port->info.rate = SPA_FRACTION(1, port->current_format.info.raw.rate);
9
port->paramsIDX_Format = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_READWRITE);
10
11
port->info_all = SPA_PORT_CHANGE_MASK_FLAGS |
12
SPA_PORT_CHANGE_MASK_PARAMS;
13
port->info = SPA_PORT_INFO_INIT();
14
- port->info.flags = 0;
15
+ port->info.flags = SPA_PORT_FLAG_LIVE |
16
+ SPA_PORT_FLAG_PHYSICAL |
17
+ SPA_PORT_FLAG_TERMINAL;
18
port->paramsIDX_EnumFormat = SPA_PARAM_INFO(SPA_PARAM_EnumFormat, SPA_PARAM_INFO_READ);
19
port->paramsIDX_Meta = SPA_PARAM_INFO(SPA_PARAM_Meta, SPA_PARAM_INFO_READ);
20
port->paramsIDX_IO = SPA_PARAM_INFO(SPA_PARAM_IO, SPA_PARAM_INFO_READ);
21
pipewire-0.3.79.tar.gz/spa/plugins/bluez5/sco-source.c -> pipewire-0.3.80.tar.gz/spa/plugins/bluez5/sco-source.c
Changed
18
1
2
3
port->info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS;
4
if (port->have_format) {
5
- port->info.change_mask |= SPA_PORT_CHANGE_MASK_FLAGS;
6
- port->info.flags = SPA_PORT_FLAG_LIVE;
7
port->info.change_mask |= SPA_PORT_CHANGE_MASK_RATE;
8
port->info.rate = SPA_FRACTION(1, port->current_format.info.raw.rate);
9
port->paramsIDX_Format = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_READWRITE);
10
11
port->info = SPA_PORT_INFO_INIT();
12
port->info.change_mask = SPA_PORT_CHANGE_MASK_FLAGS;
13
port->info.flags = SPA_PORT_FLAG_LIVE |
14
+ SPA_PORT_FLAG_PHYSICAL |
15
SPA_PORT_FLAG_TERMINAL;
16
port->paramsIDX_EnumFormat = SPA_PARAM_INFO(SPA_PARAM_EnumFormat, SPA_PARAM_INFO_READ);
17
port->paramsIDX_Meta = SPA_PARAM_INFO(SPA_PARAM_Meta, SPA_PARAM_INFO_READ);
18
pipewire-0.3.79.tar.gz/spa/plugins/control/mixer.c -> pipewire-0.3.80.tar.gz/spa/plugins/control/mixer.c
Changed
102
1
2
#include <string.h>
3
#include <stdio.h>
4
5
-#include <spa/support/plugin.h>
6
-#include <spa/support/log.h>
7
#include <spa/support/cpu.h>
8
+#include <spa/support/log.h>
9
+#include <spa/support/loop.h>
10
+#include <spa/support/plugin.h>
11
#include <spa/utils/list.h>
12
#include <spa/utils/names.h>
13
#include <spa/utils/string.h>
14
15
16
struct spa_log *log;
17
18
+ struct spa_loop *data_loop;
19
+
20
uint64_t info_all;
21
struct spa_node_info info;
22
struct spa_param_info params8;
23
24
25
port = GET_PORT(this, direction, port_id);
26
27
+ spa_return_val_if_fail(!this->started || port->io == NULL, -EIO);
28
+
29
if (format == NULL) {
30
if (port->have_format) {
31
port->have_format = false;
32
33
spa_log_debug(this->log, NAME " %p: use buffers %d on port %d:%d",
34
this, n_buffers, direction, port_id);
35
36
+ spa_return_val_if_fail(!this->started || port->io == NULL, -EIO);
37
+
38
clear_buffers(this, port);
39
40
if (n_buffers > 0 && !port->have_format)
41
42
return 0;
43
}
44
45
+struct io_info {
46
+ struct port *port;
47
+ void *data;
48
+};
49
+
50
+static int do_port_set_io(struct spa_loop *loop, bool async, uint32_t seq,
51
+ const void *data, size_t size, void *user_data)
52
+{
53
+ struct io_info *info = user_data;
54
+ info->port->io = info->data;
55
+ return 0;
56
+}
57
+
58
static int
59
impl_node_port_set_io(void *object,
60
enum spa_direction direction, uint32_t port_id,
61
62
{
63
struct impl *this = object;
64
struct port *port;
65
+ struct io_info info;
66
67
spa_return_val_if_fail(this != NULL, -EINVAL);
68
- spa_return_val_if_fail(CHECK_PORT(this, direction, port_id), -EINVAL);
69
-
70
- port = GET_PORT(this, direction, port_id);
71
72
spa_log_debug(this->log, NAME " %p: port %d:%d io %d %p/%zd", this,
73
direction, port_id, id, data, size);
74
75
+ spa_return_val_if_fail(CHECK_PORT(this, direction, port_id), -EINVAL);
76
+
77
+ port = GET_PORT(this, direction, port_id);
78
+ info.port = port;
79
+ info.data = data;
80
+
81
switch (id) {
82
case SPA_IO_Buffers:
83
- port->io = data;
84
+ spa_loop_invoke(this->data_loop,
85
+ do_port_set_io, SPA_ID_INVALID, NULL, 0, true, &info);
86
break;
87
default:
88
return -ENOENT;
89
90
91
this->log = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_Log);
92
93
+ this->data_loop = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_DataLoop);
94
+ if (this->data_loop == NULL) {
95
+ spa_log_error(this->log, "a data loop is needed");
96
+ return -EINVAL;
97
+ }
98
+
99
spa_hook_list_init(&this->hooks);
100
101
this->node.iface = SPA_INTERFACE_INIT(
102
pipewire-0.3.79.tar.gz/spa/plugins/support/node-driver.c -> pipewire-0.3.80.tar.gz/spa/plugins/support/node-driver.c
Changed
10
1
2
3
if ((res = spa_system_timerfd_read(this->data_system,
4
this->timer_source.fd, &expirations)) < 0) {
5
- if (res != EAGAIN)
6
+ if (res != -EAGAIN)
7
spa_log_error(this->log, NAME " %p: timerfd error: %s",
8
this, spa_strerror(res));
9
return;
10
pipewire-0.3.79.tar.gz/spa/plugins/support/null-audio-sink.c -> pipewire-0.3.80.tar.gz/spa/plugins/support/null-audio-sink.c
Changed
10
1
2
3
if ((res = spa_system_timerfd_read(this->data_system,
4
this->timer_source.fd, &expirations)) < 0) {
5
- if (res != EAGAIN)
6
+ if (res != -EAGAIN)
7
spa_log_error(this->log, NAME " %p: timerfd error: %s",
8
this, spa_strerror(res));
9
return;
10
pipewire-0.3.79.tar.gz/spa/plugins/v4l2/v4l2-source.c -> pipewire-0.3.80.tar.gz/spa/plugins/v4l2/v4l2-source.c
Changed
12
1
2
case SPA_PARAM_Latency:
3
{
4
struct spa_latency_info info;
5
- if ((res = spa_latency_parse(param, &info)) < 0)
6
+ if (param == NULL)
7
+ info = SPA_LATENCY_INFO(SPA_DIRECTION_REVERSE(direction));
8
+ else if ((res = spa_latency_parse(param, &info)) < 0)
9
return res;
10
if (direction == info.direction)
11
return -EINVAL;
12
pipewire-0.3.79.tar.gz/spa/plugins/v4l2/v4l2-udev.c -> pipewire-0.3.80.tar.gz/spa/plugins/v4l2/v4l2-udev.c
Changed
201
1
2
#define ACTION_DISABLE 2
3
4
struct device {
5
- struct impl *impl;
6
uint32_t id;
7
struct udev_device *dev;
8
- struct spa_source notify;
9
+ int inotify_wd;
10
unsigned int accessible:1;
11
unsigned int ignored:1;
12
unsigned int emitted:1;
13
14
uint32_t n_devices;
15
16
struct spa_source source;
17
+ struct spa_source notify;
18
};
19
20
-static int stop_inotify(struct device *dev);
21
-static int start_inotify(struct device *dev);
22
-
23
-static int impl_udev_open(struct impl *impl)
24
+static int impl_udev_open(struct impl *this)
25
{
26
- if (impl->udev == NULL) {
27
- impl->udev = udev_new();
28
- if (impl->udev == NULL)
29
+ if (this->udev == NULL) {
30
+ this->udev = udev_new();
31
+ if (this->udev == NULL)
32
return -ENOMEM;
33
}
34
return 0;
35
}
36
37
-static int impl_udev_close(struct impl *impl)
38
+static int impl_udev_close(struct impl *this)
39
{
40
- if (impl->udev != NULL)
41
- udev_unref(impl->udev);
42
- impl->udev = NULL;
43
+ if (this->udev != NULL)
44
+ udev_unref(this->udev);
45
+ this->udev = NULL;
46
return 0;
47
}
48
49
-static struct device *add_device(struct impl *impl, uint32_t id, struct udev_device *dev)
50
+static void start_watching_device(struct impl *this, struct device *device)
51
+{
52
+ if (this->notify.fd < 0 || device->inotify_wd >= 0)
53
+ return;
54
+
55
+ char path64;
56
+ snprintf(path, sizeof(path), "/dev/video%" PRIu32, device->id);
57
+
58
+ device->inotify_wd = inotify_add_watch(this->notify.fd, path, IN_ATTRIB);
59
+}
60
+
61
+static void stop_watching_device(struct impl *this, struct device *device)
62
+{
63
+ if (device->inotify_wd < 0)
64
+ return;
65
+
66
+ spa_assert(this->notify.fd >= 0);
67
+
68
+ inotify_rm_watch(this->notify.fd, device->inotify_wd);
69
+ device->inotify_wd = -1;
70
+}
71
+
72
+static struct device *add_device(struct impl *this, uint32_t id, struct udev_device *dev)
73
{
74
struct device *device;
75
76
- if (impl->n_devices >= MAX_DEVICES)
77
+ if (this->n_devices >= MAX_DEVICES)
78
return NULL;
79
- device = &impl->devicesimpl->n_devices++;
80
+ device = &this->devicesthis->n_devices++;
81
spa_zero(*device);
82
- device->impl = impl;
83
- device->notify.fd = -1;
84
device->id = id;
85
udev_device_ref(dev);
86
device->dev = dev;
87
- start_inotify(device);
88
+ device->inotify_wd = -1;
89
+
90
+ start_watching_device(this, device);
91
+
92
return device;
93
}
94
95
-static struct device *find_device(struct impl *impl, uint32_t id)
96
+static struct device *find_device(struct impl *this, uint32_t id)
97
{
98
uint32_t i;
99
- for (i = 0; i < impl->n_devices; i++) {
100
- if (impl->devicesi.id == id)
101
- return &impl->devicesi;
102
+ for (i = 0; i < this->n_devices; i++) {
103
+ if (this->devicesi.id == id)
104
+ return &this->devicesi;
105
}
106
return NULL;
107
}
108
109
-static void clear_device(struct device *device)
110
+static void remove_device(struct impl *this, struct device *device)
111
{
112
- stop_inotify(device);
113
- if (device->dev)
114
- udev_device_unref(device->dev);
115
+ device->dev = udev_device_unref(device->dev);
116
+ stop_watching_device(this, device);
117
+ *device = this->devices--this->n_devices;
118
}
119
120
-static void remove_device(struct device *device)
121
+static void clear_devices(struct impl *this)
122
{
123
- struct impl *impl = device->impl;
124
- clear_device(device);
125
- *device = impl->devices--impl->n_devices;
126
+ while (this->n_devices > 0)
127
+ remove_device(this, &this->devices0);
128
}
129
130
-static void clear_devices(struct impl *impl)
131
-{
132
- uint32_t i;
133
- for (i = 0; i < impl->n_devices; i++)
134
- clear_device(&impl->devicesi);
135
- impl->n_devices = 0;
136
-}
137
-
138
-static uint32_t get_device_id(struct impl *impl, struct udev_device *dev)
139
+static uint32_t get_device_id(struct impl *this, struct udev_device *dev)
140
{
141
const char *str;
142
143
144
*d = 0;
145
}
146
147
-static int emit_object_info(struct device *device)
148
+static int emit_object_info(struct impl *this, struct device *device)
149
{
150
- struct impl *impl = device->impl;
151
struct spa_device_object_info info;
152
uint32_t id = device->id;
153
struct udev_device *dev = device->dev;
154
155
itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_CAPABILITIES, str);
156
}
157
info.props = &SPA_DICT_INIT(items, n_items);
158
- spa_device_emit_object_info(&impl->hooks, id, &info);
159
+ spa_device_emit_object_info(&this->hooks, id, &info);
160
device->emitted = true;
161
162
return 1;
163
}
164
165
-static bool check_access(struct device *device)
166
+static bool check_access(struct impl *this, struct device *device)
167
{
168
char path128;
169
170
snprintf(path, sizeof(path), "/dev/video%u", device->id);
171
device->accessible = access(path, R_OK|W_OK) >= 0;
172
- spa_log_debug(device->impl->log, "%s accessible:%u", path, device->accessible);
173
+ spa_log_debug(this->log, "%s accessible:%u", path, device->accessible);
174
175
return device->accessible;
176
}
177
178
-static void process_device(struct impl *impl, uint32_t action, struct udev_device *dev)
179
+static void process_device(struct impl *this, uint32_t action, struct udev_device *dev)
180
{
181
uint32_t id;
182
struct device *device;
183
bool emitted;
184
185
- if ((id = get_device_id(impl, dev)) == SPA_ID_INVALID)
186
+ if ((id = get_device_id(this, dev)) == SPA_ID_INVALID)
187
return;
188
189
- device = find_device(impl, id);
190
+ device = find_device(this, id);
191
if (device && device->ignored)
192
return;
193
194
switch (action) {
195
case ACTION_ADD:
196
if (device == NULL)
197
- device = add_device(impl, id, dev);
198
+ device = add_device(this, id, dev);
199
if (device == NULL)
200
return;
201
pipewire-0.3.80.tar.gz/spa/plugins/vulkan/dmabuf.h
Added
64
1
2
+// Copyright (c) 2023 The wlroots contributors
3
+//
4
+// Permission is hereby granted, free of charge, to any person obtaining a copy of
5
+// this software and associated documentation files (the "Software"), to deal in
6
+// the Software without restriction, including without limitation the rights to
7
+// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
8
+// of the Software, and to permit persons to whom the Software is furnished to do
9
+// so, subject to the following conditions:
10
+//
11
+// The above copyright notice and this permission notice shall be included in all
12
+// copies or substantial portions of the Software.
13
+//
14
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
+// SOFTWARE.
21
+//
22
+// Obtained from https://gitlab.freedesktop.org/wlroots/wlroots/
23
+
24
+/* SPDX-FileCopyrightText: Copyright © 2023 The wlroots contributors */
25
+/* SPDX-License-Identifier: MIT */
26
+
27
+#ifndef RENDER_DMABUF_H
28
+#define RENDER_DMABUF_H
29
+
30
+#include <stdbool.h>
31
+#include <stdint.h>
32
+
33
+#include "spa/support/log.h"
34
+
35
+// Copied from <linux/dma-buf.h> to avoid #ifdef soup
36
+#define DMA_BUF_SYNC_READ (1 << 0)
37
+#define DMA_BUF_SYNC_WRITE (2 << 0)
38
+#define DMA_BUF_SYNC_RW (DMA_BUF_SYNC_READ | DMA_BUF_SYNC_WRITE)
39
+
40
+/**
41
+ * Check whether DMA-BUF import/export from/to sync_file is available.
42
+ *
43
+ * If this function returns true, dmabuf_import_sync_file() is supported.
44
+ */
45
+bool dmabuf_check_sync_file_import_export(struct spa_log *log);
46
+
47
+/**
48
+ * Import a sync_file into a DMA-BUF with DMA_BUF_IOCTL_IMPORT_SYNC_FILE.
49
+ *
50
+ * This can be used to make explicit sync interoperate with implicit sync.
51
+ */
52
+bool dmabuf_import_sync_file(struct spa_log *log, int dmabuf_fd, uint32_t flags, int sync_file_fd);
53
+
54
+/**
55
+ * Export a sync_file from a DMA-BUF with DMA_BUF_IOCTL_EXPORT_SYNC_FILE.
56
+ *
57
+ * The sync_file FD is returned on success, -1 is returned on error.
58
+ *
59
+ * This can be used to make explicit sync interoperate with implicit sync.
60
+ */
61
+int dmabuf_export_sync_file(struct spa_log *log, int dmabuf_fd, uint32_t flags);
62
+
63
+#endif
64
pipewire-0.3.80.tar.gz/spa/plugins/vulkan/dmabuf_fallback.c
Added
44
1
2
+// Copyright (c) 2023 The wlroots contributors
3
+//
4
+// Permission is hereby granted, free of charge, to any person obtaining a copy of
5
+// this software and associated documentation files (the "Software"), to deal in
6
+// the Software without restriction, including without limitation the rights to
7
+// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
8
+// of the Software, and to permit persons to whom the Software is furnished to do
9
+// so, subject to the following conditions:
10
+//
11
+// The above copyright notice and this permission notice shall be included in all
12
+// copies or substantial portions of the Software.
13
+//
14
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
+// SOFTWARE.
21
+//
22
+// Obtained from https://gitlab.freedesktop.org/wlroots/wlroots/
23
+
24
+/* SPDX-FileCopyrightText: Copyright © 2023 The wlroots contributors */
25
+/* SPDX-License-Identifier: MIT */
26
+
27
+#include <spa/support/log.h>
28
+#include <spa/utils/result.h>
29
+
30
+
31
+bool dmabuf_check_sync_file_import_export(struct spa_log *log) {
32
+ return false;
33
+}
34
+
35
+bool dmabuf_import_sync_file(struct spa_log *log, int dmabuf_fd, uint32_t flags, int sync_file_fd) {
36
+ spa_log_error("DMA-BUF sync_file import IOCTL not available on this system");
37
+ return false;
38
+}
39
+
40
+int dmabuf_export_sync_file(struct spa_log *log, int dmabuf_fd, uint32_t flags) {
41
+ spa_log_error("DMA-BUF sync_file export IOCTL not available on this system");
42
+ return false;
43
+}
44
pipewire-0.3.80.tar.gz/spa/plugins/vulkan/dmabuf_linux.c
Added
129
1
2
+// Copyright (c) 2023 The wlroots contributors
3
+//
4
+// Permission is hereby granted, free of charge, to any person obtaining a copy of
5
+// this software and associated documentation files (the "Software"), to deal in
6
+// the Software without restriction, including without limitation the rights to
7
+// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
8
+// of the Software, and to permit persons to whom the Software is furnished to do
9
+// so, subject to the following conditions:
10
+//
11
+// The above copyright notice and this permission notice shall be included in all
12
+// copies or substantial portions of the Software.
13
+//
14
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
+// SOFTWARE.
21
+//
22
+// Obtained from https://gitlab.freedesktop.org/wlroots/wlroots/
23
+
24
+/* SPDX-FileCopyrightText: Copyright © 2023 The wlroots contributors */
25
+/* SPDX-License-Identifier: MIT */
26
+
27
+#include <linux/dma-buf.h>
28
+#include <linux/version.h>
29
+#include <stdlib.h>
30
+#include <sys/utsname.h>
31
+#include <xf86drm.h>
32
+#include <errno.h>
33
+
34
+#include <spa/support/log.h>
35
+#include <spa/utils/result.h>
36
+
37
+#include "dmabuf.h"
38
+
39
+bool dmabuf_check_sync_file_import_export(struct spa_log *log) {
40
+ /* Unfortunately there's no better way to check the availability of the
41
+ * IOCTL than to check the kernel version. See the discussion at:
42
+ * https://lore.kernel.org/dri-devel/20220601161303.64797-1-contact@emersion.fr/
43
+ */
44
+
45
+ struct utsname utsname = {0};
46
+ if (uname(&utsname) != 0) {
47
+ spa_log_warn(log, "uname failed");
48
+ return false;
49
+ }
50
+
51
+ if (strcmp(utsname.sysname, "Linux") != 0) {
52
+ return false;
53
+ }
54
+
55
+ // Trim release suffix if any, e.g. "-arch1-1"
56
+ for (size_t i = 0; utsname.releasei != '\0'; i++) {
57
+ char ch = utsname.releasei;
58
+ if ((ch < '0' || ch > '9') && ch != '.') {
59
+ utsname.releasei = '\0';
60
+ break;
61
+ }
62
+ }
63
+
64
+ char *rel = strtok(utsname.release, ".");
65
+ int major = atoi(rel);
66
+
67
+ int minor = 0;
68
+ rel = strtok(NULL, ".");
69
+ if (rel != NULL) {
70
+ minor = atoi(rel);
71
+ }
72
+
73
+ int patch = 0;
74
+ rel = strtok(NULL, ".");
75
+ if (rel != NULL) {
76
+ patch = atoi(rel);
77
+ }
78
+
79
+ return KERNEL_VERSION(major, minor, patch) >= KERNEL_VERSION(5, 20, 0);
80
+}
81
+
82
+// TODO: drop these definitions once widespread
83
+
84
+#if !defined(DMA_BUF_IOCTL_IMPORT_SYNC_FILE)
85
+
86
+struct dma_buf_import_sync_file {
87
+ __u32 flags;
88
+ __s32 fd;
89
+};
90
+
91
+#define DMA_BUF_IOCTL_IMPORT_SYNC_FILE _IOW(DMA_BUF_BASE, 3, struct dma_buf_import_sync_file)
92
+
93
+#endif
94
+
95
+#if !defined(DMA_BUF_IOCTL_EXPORT_SYNC_FILE)
96
+
97
+struct dma_buf_export_sync_file {
98
+ __u32 flags;
99
+ __s32 fd;
100
+};
101
+
102
+#define DMA_BUF_IOCTL_EXPORT_SYNC_FILE _IOWR(DMA_BUF_BASE, 2, struct dma_buf_export_sync_file)
103
+
104
+#endif
105
+
106
+bool dmabuf_import_sync_file(struct spa_log *log, int dmabuf_fd, uint32_t flags, int sync_file_fd) {
107
+ struct dma_buf_import_sync_file data = {
108
+ .flags = flags,
109
+ .fd = sync_file_fd,
110
+ };
111
+ if (drmIoctl(dmabuf_fd, DMA_BUF_IOCTL_IMPORT_SYNC_FILE, &data) != 0) {
112
+ spa_log_error(log, "drmIoctl(IMPORT_SYNC_FILE) failed with %d (%s)", errno, spa_strerror(-errno));
113
+ return false;
114
+ }
115
+ return true;
116
+}
117
+
118
+int dmabuf_export_sync_file(struct spa_log *log, int dmabuf_fd, uint32_t flags) {
119
+ struct dma_buf_export_sync_file data = {
120
+ .flags = flags,
121
+ .fd = -1,
122
+ };
123
+ if (drmIoctl(dmabuf_fd, DMA_BUF_IOCTL_EXPORT_SYNC_FILE, &data) != 0) {
124
+ spa_log_error(log, "drmIoctl(EXPORT_SYNC_FILE) failed with %d (%s)", errno, spa_strerror(-errno));
125
+ return -1;
126
+ }
127
+ return data.fd;
128
+}
129
pipewire-0.3.79.tar.gz/spa/plugins/vulkan/meson.build -> pipewire-0.3.80.tar.gz/spa/plugins/vulkan/meson.build
Changed
23
1
2
'plugin.c',
3
'vulkan-compute-filter.c',
4
'vulkan-compute-source.c',
5
+ 'vulkan-compute-utils.c',
6
'vulkan-utils.c'
7
8
9
+drm = dependency('libdrm')
10
+
11
+if cc.has_header('linux/dma-buf.h') and target_machine.system() == 'linux'
12
+ spa_vulkan_sources += files('dmabuf_linux.c')
13
+else
14
+ spa_vulkan_sources += files('dmabuf_fallback.c')
15
+endif
16
+
17
spa_vulkan = shared_library('spa-vulkan',
18
spa_vulkan_sources,
19
- dependencies : spa_dep, vulkan_dep, mathlib ,
20
+ dependencies : spa_dep, vulkan_dep, mathlib, drm ,
21
install : true,
22
install_dir : spa_plugindir / 'vulkan')
23
pipewire-0.3.79.tar.gz/spa/plugins/vulkan/vulkan-compute-filter.c -> pipewire-0.3.80.tar.gz/spa/plugins/vulkan/vulkan-compute-filter.c
Changed
201
1
2
#include <spa/param/param.h>
3
#include <spa/pod/filter.h>
4
5
-#include "vulkan-utils.h"
6
+#include "vulkan-compute-utils.h"
7
8
#define NAME "vulkan-compute-filter"
9
10
11
12
bool started;
13
14
- struct vulkan_state state;
15
+ struct vulkan_compute_state state;
16
struct port port2;
17
};
18
19
20
return -ENOTSUP;
21
}
22
23
+static struct spa_pod *build_EnumFormat(uint32_t fmt, const struct vulkan_format_info *fmtInfo, struct spa_pod_builder *builder) {
24
+ struct spa_pod_frame f2;
25
+ uint32_t i, c;
26
+
27
+ spa_pod_builder_push_object(builder, &f0, SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat);
28
+ spa_pod_builder_add(builder, SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_video), 0);
29
+ spa_pod_builder_add(builder, SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_dsp), 0);
30
+ spa_pod_builder_add(builder, SPA_FORMAT_VIDEO_format, SPA_POD_Id(fmt), 0);
31
+ if (fmtInfo && fmtInfo->modifierCount > 0) {
32
+ spa_pod_builder_prop(builder, SPA_FORMAT_VIDEO_modifier, SPA_POD_PROP_FLAG_MANDATORY | SPA_POD_PROP_FLAG_DONT_FIXATE);
33
+ spa_pod_builder_push_choice(builder, &f1, SPA_CHOICE_Enum, 0);
34
+ for (i = 0, c = 0; i < fmtInfo->modifierCount; i++) {
35
+ spa_pod_builder_long(builder, fmtInfo->infosi.props.drmFormatModifier);
36
+ if (c++ == 0)
37
+ spa_pod_builder_long(builder, fmtInfo->infosi.props.drmFormatModifier);
38
+ }
39
+ spa_pod_builder_pop(builder, &f1);
40
+ }
41
+ return spa_pod_builder_pop(builder, &f0);
42
+}
43
+
44
+// This function enumerates the available formats in vulkan_state::formats, announcing all formats capable to support DmaBufs
45
+// first and then falling back to those supported with SHM buffers.
46
+static bool find_EnumFormatInfo(struct vulkan_base *s, uint32_t index, uint32_t caps, uint32_t *fmt_idx, bool *has_modifier) {
47
+ int64_t fmtIterator = 0;
48
+ int64_t maxIterator = 0;
49
+ if (caps & VULKAN_BUFFER_TYPE_CAP_SHM)
50
+ maxIterator += s->formatInfoCount;
51
+ if (caps & VULKAN_BUFFER_TYPE_CAP_DMABUF)
52
+ maxIterator += s->formatInfoCount;
53
+ // Count available formats until index underflows, while fmtIterator indexes the current format.
54
+ // Iterate twice over formats first time with modifiers, second time without if both caps are supported.
55
+ while (index < (uint32_t)-1 && fmtIterator < maxIterator) {
56
+ const struct vulkan_format_info *f_info = &s->formatInfosfmtIterator%s->formatInfoCount;
57
+ if (caps & VULKAN_BUFFER_TYPE_CAP_DMABUF && fmtIterator < s->formatInfoCount) {
58
+ // First round, check for modifiers
59
+ if (f_info->modifierCount > 0) {
60
+ index--;
61
+ }
62
+ } else if (caps & VULKAN_BUFFER_TYPE_CAP_SHM) {
63
+ // Second round, every format should be supported.
64
+ index--;
65
+ }
66
+ fmtIterator++;
67
+ }
68
+
69
+ if (index != (uint32_t)-1) {
70
+ // No more formats available
71
+ return false;
72
+ }
73
+ // Undo end of loop increment
74
+ fmtIterator--;
75
+ *fmt_idx = fmtIterator%s->formatInfoCount;
76
+ // Loop finished in first round
77
+ *has_modifier = caps & VULKAN_BUFFER_TYPE_CAP_DMABUF && fmtIterator < s->formatInfoCount;
78
+ return true;
79
+}
80
+
81
static int port_enum_formats(void *object,
82
enum spa_direction direction, uint32_t port_id,
83
uint32_t index,
84
85
struct spa_pod **param,
86
struct spa_pod_builder *builder)
87
{
88
- switch (index) {
89
- case 0:
90
- *param = spa_pod_builder_add_object(builder,
91
- SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat,
92
- SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_video),
93
- SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_dsp),
94
- SPA_FORMAT_VIDEO_format, SPA_POD_Id(SPA_VIDEO_FORMAT_DSP_F32));
95
- break;
96
- default:
97
- return 0;
98
+ struct impl *this = object;
99
+
100
+ uint32_t fmt_index;
101
+ bool has_modifier;
102
+ if (this->portport_id.have_format
103
+ && this->portport_id.current_format.info.dsp.flags & SPA_VIDEO_FLAG_MODIFIER
104
+ && this->portport_id.current_format.info.dsp.flags ^ SPA_VIDEO_FLAG_MODIFIER_FIXATION_REQUIRED) {
105
+ if (index == 0) {
106
+ spa_log_info(this->log, "vulkan-compute-filter: enum_formats fixated format idx: %d, format %d, has_modifier 1",
107
+ index, this->portport_id.current_format.info.dsp.format);
108
+ *param = spa_format_video_dsp_build(builder, SPA_PARAM_EnumFormat, &this->portport_id.current_format.info.dsp);
109
+ return 1;
110
+ }
111
+ if (!find_EnumFormatInfo(&this->state.base, index-1, spa_vulkan_get_buffer_caps(&this->state, direction), &fmt_index, &has_modifier))
112
+ return 0;
113
+ } else {
114
+ if (!find_EnumFormatInfo(&this->state.base, index, spa_vulkan_get_buffer_caps(&this->state, direction), &fmt_index, &has_modifier))
115
+ return 0;
116
}
117
+
118
+ const struct vulkan_format_info *f_info = &this->state.base.formatInfosfmt_index;
119
+ spa_log_info(this->log, "vulkan-compute-filter: enum_formats idx: %d, format %d, has_modifier %d", index, f_info->spa_format, has_modifier);
120
+ *param = build_EnumFormat(f_info->spa_format, has_modifier ? f_info : NULL, builder);
121
+
122
return 1;
123
}
124
125
126
this->position->video.size.height,
127
this->position->video.stride);
128
129
- param = spa_pod_builder_add_object(&b,
130
- SPA_TYPE_OBJECT_ParamBuffers, id,
131
- SPA_PARAM_BUFFERS_buffers, SPA_POD_CHOICE_RANGE_Int(2, 1, MAX_BUFFERS),
132
- SPA_PARAM_BUFFERS_blocks, SPA_POD_Int(1),
133
- SPA_PARAM_BUFFERS_size, SPA_POD_Int(this->position->video.stride *
134
- this->position->video.size.height),
135
- SPA_PARAM_BUFFERS_stride, SPA_POD_Int(this->position->video.stride));
136
+ if (port->current_format.info.dsp.flags & SPA_VIDEO_FLAG_MODIFIER) {
137
+ struct vulkan_modifier_info *mod_info = spa_vulkan_get_modifier_info(&this->state,
138
+ &port->current_format.info.dsp);
139
+ param = spa_pod_builder_add_object(&b,
140
+ SPA_TYPE_OBJECT_ParamBuffers, id,
141
+ SPA_PARAM_BUFFERS_buffers, SPA_POD_CHOICE_RANGE_Int(2, 1, MAX_BUFFERS),
142
+ SPA_PARAM_BUFFERS_blocks, SPA_POD_Int(mod_info->props.drmFormatModifierPlaneCount),
143
+ SPA_PARAM_BUFFERS_dataType, SPA_POD_CHOICE_FLAGS_Int(1<<SPA_DATA_DmaBuf));
144
+ } else {
145
+ param = spa_pod_builder_add_object(&b,
146
+ SPA_TYPE_OBJECT_ParamBuffers, id,
147
+ SPA_PARAM_BUFFERS_buffers, SPA_POD_CHOICE_RANGE_Int(2, 1, MAX_BUFFERS),
148
+ SPA_PARAM_BUFFERS_blocks, SPA_POD_Int(1),
149
+ SPA_PARAM_BUFFERS_size, SPA_POD_Int(this->position->video.stride *
150
+ this->position->video.size.height),
151
+ SPA_PARAM_BUFFERS_stride, SPA_POD_Int(this->position->video.stride),
152
+ SPA_PARAM_BUFFERS_dataType, SPA_POD_CHOICE_FLAGS_Int(1<<SPA_DATA_MemPtr));
153
+ }
154
+
155
break;
156
}
157
case SPA_PARAM_Meta:
158
159
if (port->n_buffers > 0) {
160
spa_log_debug(this->log, NAME " %p: clear buffers", this);
161
spa_vulkan_stop(&this->state);
162
- spa_vulkan_use_buffers(&this->state, &this->state.streamsport->stream_id, 0, 0, NULL);
163
+ spa_vulkan_use_buffers(&this->state, &this->state.streamsport->stream_id, 0, &port->current_format.info.dsp, 0, NULL);
164
port->n_buffers = 0;
165
spa_list_init(&port->empty);
166
spa_list_init(&port->ready);
167
168
this->state.constants.width = this->position->video.size.width;
169
this->state.constants.height = this->position->video.size.height;
170
171
+ bool modifier_fixed = false;
172
+ if (port->direction == SPA_DIRECTION_OUTPUT
173
+ && info.info.dsp.flags & SPA_VIDEO_FLAG_MODIFIER
174
+ && info.info.dsp.flags & SPA_VIDEO_FLAG_MODIFIER_FIXATION_REQUIRED) {
175
+ const struct spa_pod_prop *mod_prop;
176
+ if ((mod_prop = spa_pod_find_prop(format, NULL, SPA_FORMAT_VIDEO_modifier)) == NULL)
177
+ return -EINVAL;
178
+
179
+ const struct spa_pod *mod_pod = &mod_prop->value;
180
+ uint32_t modifierCount = SPA_POD_CHOICE_N_VALUES(mod_pod);
181
+ uint64_t *modifiers = SPA_POD_CHOICE_VALUES(mod_pod);
182
+ if (modifierCount <= 1)
183
+ return -EINVAL;
184
+ // SPA_POD_CHOICE carries the "preferred" value at position 0
185
+ modifierCount -= 1;
186
+ modifiers++;
187
+ uint64_t fixed_modifier;
188
+ if (spa_vulkan_fixate_modifier(&this->state, &this->state.streamsport->stream_id, &info.info.dsp, modifierCount, modifiers, &fixed_modifier) != 0)
189
+ return -EINVAL;
190
+
191
+ spa_log_info(this->log, NAME ": modifier fixated %"PRIu64, fixed_modifier);
192
+
193
+ info.info.dsp.modifier = fixed_modifier;
194
+ info.info.dsp.flags &= ~SPA_VIDEO_FLAG_MODIFIER_FIXATION_REQUIRED;
195
+ modifier_fixed = true;
196
+ }
197
+
198
+ if (info.info.dsp.flags & SPA_VIDEO_FLAG_MODIFIER) {
199
+ port->info.flags |= SPA_PORT_FLAG_CAN_ALLOC_BUFFERS;
200
+ } else {
201
pipewire-0.3.79.tar.gz/spa/plugins/vulkan/vulkan-compute-source.c -> pipewire-0.3.80.tar.gz/spa/plugins/vulkan/vulkan-compute-source.c
Changed
201
1
2
#include <spa/param/param.h>
3
#include <spa/pod/filter.h>
4
5
-#include "vulkan-utils.h"
6
+#include "vulkan-compute-utils.h"
7
8
#define NAME "vulkan-compute-source"
9
10
11
12
uint64_t frame_count;
13
14
- struct vulkan_state state;
15
+ struct vulkan_compute_state state;
16
struct port port;
17
};
18
19
20
return -ENOTSUP;
21
}
22
23
+static struct spa_pod *build_EnumFormat(uint32_t fmt, const struct vulkan_format_info *fmtInfo, struct spa_pod_builder *builder) {
24
+ struct spa_pod_frame f2;
25
+ uint32_t i, c;
26
+
27
+ spa_pod_builder_push_object(builder, &f0, SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat);
28
+ spa_pod_builder_add(builder, SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_video), 0);
29
+ spa_pod_builder_add(builder, SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_dsp), 0);
30
+ spa_pod_builder_add(builder, SPA_FORMAT_VIDEO_format, SPA_POD_Id(fmt), 0);
31
+ if (fmtInfo && fmtInfo->modifierCount > 0) {
32
+ spa_pod_builder_prop(builder, SPA_FORMAT_VIDEO_modifier, SPA_POD_PROP_FLAG_MANDATORY | SPA_POD_PROP_FLAG_DONT_FIXATE);
33
+ spa_pod_builder_push_choice(builder, &f1, SPA_CHOICE_Enum, 0);
34
+ for (i = 0, c = 0; i < fmtInfo->modifierCount; i++) {
35
+ spa_pod_builder_long(builder, fmtInfo->infosi.props.drmFormatModifier);
36
+ if (c++ == 0)
37
+ spa_pod_builder_long(builder, fmtInfo->infosi.props.drmFormatModifier);
38
+ }
39
+ spa_pod_builder_pop(builder, &f1);
40
+ }
41
+ return spa_pod_builder_pop(builder, &f0);
42
+}
43
+
44
+// This function enumerates the available formats in vulkan_state::formats, announcing all formats capable to support DmaBufs
45
+// first and then falling back to those supported with SHM buffers.
46
+static bool find_EnumFormatInfo(struct vulkan_base *s, uint32_t index, uint32_t caps, uint32_t *fmt_idx, bool *has_modifier) {
47
+ int64_t fmtIterator = 0;
48
+ int64_t maxIterator = 0;
49
+ if (caps & VULKAN_BUFFER_TYPE_CAP_SHM)
50
+ maxIterator += s->formatInfoCount;
51
+ if (caps & VULKAN_BUFFER_TYPE_CAP_DMABUF)
52
+ maxIterator += s->formatInfoCount;
53
+ // Count available formats until index underflows, while fmtIterator indexes the current format.
54
+ // Iterate twice over formats first time with modifiers, second time without if both caps are supported.
55
+ while (index < (uint32_t)-1 && fmtIterator < maxIterator) {
56
+ const struct vulkan_format_info *f_info = &s->formatInfosfmtIterator%s->formatInfoCount;
57
+ if (caps & VULKAN_BUFFER_TYPE_CAP_DMABUF && fmtIterator < s->formatInfoCount) {
58
+ // First round, check for modifiers
59
+ if (f_info->modifierCount > 0) {
60
+ index--;
61
+ }
62
+ } else if (caps & VULKAN_BUFFER_TYPE_CAP_SHM) {
63
+ // Second round, every format should be supported.
64
+ index--;
65
+ }
66
+ fmtIterator++;
67
+ }
68
+
69
+ if (index != (uint32_t)-1) {
70
+ // No more formats available
71
+ return false;
72
+ }
73
+ // Undo end of loop increment
74
+ fmtIterator--;
75
+ *fmt_idx = fmtIterator%s->formatInfoCount;
76
+ // Loop finished in first round
77
+ *has_modifier = caps & VULKAN_BUFFER_TYPE_CAP_DMABUF && fmtIterator < s->formatInfoCount;
78
+ return true;
79
+}
80
+
81
static int port_enum_formats(void *object,
82
enum spa_direction direction, uint32_t port_id,
83
uint32_t index,
84
85
struct spa_pod **param,
86
struct spa_pod_builder *builder)
87
{
88
- switch (index) {
89
- case 0:
90
- *param = spa_pod_builder_add_object(builder,
91
- SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat,
92
- SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_video),
93
- SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_dsp),
94
- SPA_FORMAT_VIDEO_format, SPA_POD_Id(SPA_VIDEO_FORMAT_DSP_F32));
95
- break;
96
- default:
97
- return 0;
98
+ struct impl *this = object;
99
+
100
+ uint32_t fmt_index;
101
+ bool has_modifier;
102
+ if (this->port.have_format
103
+ && this->port.current_format.info.dsp.flags & SPA_VIDEO_FLAG_MODIFIER
104
+ && this->port.current_format.info.dsp.flags ^ SPA_VIDEO_FLAG_MODIFIER_FIXATION_REQUIRED) {
105
+ if (index == 0) {
106
+ spa_log_info(this->log, "vulkan-compute-source: enum_formats fixated format idx: %d, format %d, has_modifier 1",
107
+ index, this->port.current_format.info.dsp.format);
108
+ *param = spa_format_video_dsp_build(builder, SPA_PARAM_EnumFormat, &this->port.current_format.info.dsp);
109
+ return 1;
110
+ }
111
+ if (!find_EnumFormatInfo(&this->state.base, index-1, spa_vulkan_get_buffer_caps(&this->state, direction), &fmt_index, &has_modifier))
112
+ return 0;
113
+ } else {
114
+ if (!find_EnumFormatInfo(&this->state.base, index, spa_vulkan_get_buffer_caps(&this->state, direction), &fmt_index, &has_modifier))
115
+ return 0;
116
}
117
+
118
+ const struct vulkan_format_info *f_info = &this->state.base.formatInfosfmt_index;
119
+ spa_log_info(this->log, "vulkan-compute-source: enum_formats idx: %d, format %d, has_modifier %d", index, f_info->spa_format, has_modifier);
120
+ *param = build_EnumFormat(f_info->spa_format, has_modifier ? f_info : NULL, builder);
121
+
122
return 1;
123
}
124
125
126
this->position->video.size.height,
127
this->position->video.stride);
128
129
- param = spa_pod_builder_add_object(&b,
130
- SPA_TYPE_OBJECT_ParamBuffers, id,
131
- SPA_PARAM_BUFFERS_buffers, SPA_POD_CHOICE_RANGE_Int(2, 1, MAX_BUFFERS),
132
- SPA_PARAM_BUFFERS_blocks, SPA_POD_Int(1),
133
- SPA_PARAM_BUFFERS_size, SPA_POD_Int(this->position->video.stride *
134
- this->position->video.size.height),
135
- SPA_PARAM_BUFFERS_stride, SPA_POD_Int(this->position->video.stride));
136
+
137
+ if (port->current_format.info.dsp.flags & SPA_VIDEO_FLAG_MODIFIER) {
138
+ struct vulkan_modifier_info *mod_info = spa_vulkan_get_modifier_info(&this->state,
139
+ &port->current_format.info.dsp);
140
+ param = spa_pod_builder_add_object(&b,
141
+ SPA_TYPE_OBJECT_ParamBuffers, id,
142
+ SPA_PARAM_BUFFERS_buffers, SPA_POD_CHOICE_RANGE_Int(2, 1, MAX_BUFFERS),
143
+ SPA_PARAM_BUFFERS_blocks, SPA_POD_Int(mod_info->props.drmFormatModifierPlaneCount),
144
+ SPA_PARAM_BUFFERS_dataType, SPA_POD_CHOICE_FLAGS_Int(1<<SPA_DATA_DmaBuf));
145
+ } else {
146
+ param = spa_pod_builder_add_object(&b,
147
+ SPA_TYPE_OBJECT_ParamBuffers, id,
148
+ SPA_PARAM_BUFFERS_buffers, SPA_POD_CHOICE_RANGE_Int(2, 1, MAX_BUFFERS),
149
+ SPA_PARAM_BUFFERS_blocks, SPA_POD_Int(1),
150
+ SPA_PARAM_BUFFERS_size, SPA_POD_Int(this->position->video.stride *
151
+ this->position->video.size.height),
152
+ SPA_PARAM_BUFFERS_stride, SPA_POD_Int(this->position->video.stride),
153
+ SPA_PARAM_BUFFERS_dataType, SPA_POD_CHOICE_FLAGS_Int(1<<SPA_DATA_MemPtr));
154
+ }
155
+
156
break;
157
}
158
case SPA_PARAM_Meta:
159
160
{
161
if (port->n_buffers > 0) {
162
spa_log_debug(this->log, NAME " %p: clear buffers", this);
163
- spa_vulkan_use_buffers(&this->state, &this->state.streams0, 0, 0, NULL);
164
+ spa_vulkan_use_buffers(&this->state, &this->state.streams0, 0, &port->current_format.info.dsp, 0, NULL);
165
port->n_buffers = 0;
166
spa_list_init(&port->empty);
167
spa_list_init(&port->ready);
168
169
this->state.constants.width = this->position->video.size.width;
170
this->state.constants.height = this->position->video.size.height;
171
172
+ bool modifier_fixed = false;
173
+ if (info.info.dsp.flags & SPA_VIDEO_FLAG_MODIFIER
174
+ && info.info.dsp.flags & SPA_VIDEO_FLAG_MODIFIER_FIXATION_REQUIRED) {
175
+ const struct spa_pod_prop *mod_prop;
176
+ if ((mod_prop = spa_pod_find_prop(format, NULL, SPA_FORMAT_VIDEO_modifier)) == NULL)
177
+ return -EINVAL;
178
+
179
+ const struct spa_pod *mod_pod = &mod_prop->value;
180
+ uint32_t modifierCount = SPA_POD_CHOICE_N_VALUES(mod_pod);
181
+ uint64_t *modifiers = SPA_POD_CHOICE_VALUES(mod_pod);
182
+ if (modifierCount <= 1)
183
+ return -EINVAL;
184
+ // SPA_POD_CHOICE carries the "preferred" value at position 0
185
+ modifierCount -= 1;
186
+ modifiers++;
187
+
188
+ uint64_t fixed_modifier;
189
+ if (spa_vulkan_fixate_modifier(&this->state, &this->state.streams0, &info.info.dsp, modifierCount, modifiers, &fixed_modifier) != 0)
190
+ return -EINVAL;
191
+
192
+ spa_log_info(this->log, NAME ": modifier fixated %"PRIu64, fixed_modifier);
193
+
194
+ info.info.dsp.modifier = fixed_modifier;
195
+ info.info.dsp.flags &= ~SPA_VIDEO_FLAG_MODIFIER_FIXATION_REQUIRED;
196
+ modifier_fixed = true;
197
+ }
198
+
199
+ if (info.info.dsp.flags & SPA_VIDEO_FLAG_MODIFIER) {
200
+ port->info.flags |= SPA_PORT_FLAG_CAN_ALLOC_BUFFERS;
201
pipewire-0.3.80.tar.gz/spa/plugins/vulkan/vulkan-compute-utils.c
Added
201
1
2
+/* Spa */
3
+/* SPDX-FileCopyrightText: Copyright © 2019 Wim Taymans */
4
+/* SPDX-License-Identifier: MIT */
5
+
6
+#include <vulkan/vulkan.h>
7
+
8
+#include <unistd.h>
9
+#include <sys/types.h>
10
+#include <sys/stat.h>
11
+#include <sys/mman.h>
12
+#include <fcntl.h>
13
+#include <string.h>
14
+#include <vulkan/vulkan_core.h>
15
+#if !defined(__FreeBSD__) && !defined(__MidnightBSD__)
16
+#include <alloca.h>
17
+#endif
18
+#include <errno.h>
19
+#include <stdio.h>
20
+#include <assert.h>
21
+#include <math.h>
22
+#include <time.h>
23
+
24
+#include <spa/utils/result.h>
25
+#include <spa/utils/string.h>
26
+#include <spa/support/log.h>
27
+#include <spa/debug/mem.h>
28
+
29
+#include "vulkan-compute-utils.h"
30
+#include "vulkan-utils.h"
31
+
32
+#define VULKAN_INSTANCE_FUNCTION(name) \
33
+ PFN_##name name = (PFN_##name)vkGetInstanceProcAddr(s->base.instance, #name)
34
+
35
+static int createFence(struct vulkan_compute_state *s) {
36
+ VkFenceCreateInfo createInfo = {
37
+ .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
38
+ .flags = 0,
39
+ };
40
+ VK_CHECK_RESULT(vkCreateFence(s->base.device, &createInfo, NULL, &s->fence));
41
+
42
+ return 0;
43
+};
44
+
45
+static int createDescriptors(struct vulkan_compute_state *s)
46
+{
47
+ uint32_t i;
48
+
49
+ VkDescriptorPoolSize descriptorPoolSizes2 = {
50
+ {
51
+ .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
52
+ .descriptorCount = 1,
53
+ },
54
+ {
55
+ .type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
56
+ .descriptorCount = s->n_streams - 1,
57
+ },
58
+ };
59
+ const VkDescriptorPoolCreateInfo descriptorPoolCreateInfo = {
60
+ .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
61
+ .maxSets = s->n_streams,
62
+ .poolSizeCount = s->n_streams > 1 ? 2 : 1,
63
+ .pPoolSizes = descriptorPoolSizes,
64
+ };
65
+
66
+ VK_CHECK_RESULT(vkCreateDescriptorPool(s->base.device,
67
+ &descriptorPoolCreateInfo, NULL,
68
+ &s->descriptorPool));
69
+
70
+ VkDescriptorSetLayoutBinding descriptorSetLayoutBindings->n_streams;
71
+ descriptorSetLayoutBinding0 = (VkDescriptorSetLayoutBinding) {
72
+ .binding = 0,
73
+ .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
74
+ .descriptorCount = 1,
75
+ .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT
76
+ };
77
+ for (i = 1; i < s->n_streams; i++) {
78
+ descriptorSetLayoutBindingi = (VkDescriptorSetLayoutBinding) {
79
+ .binding = i,
80
+ .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
81
+ .descriptorCount = 1,
82
+ .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT
83
+ };
84
+ };
85
+ const VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCreateInfo = {
86
+ .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
87
+ .bindingCount = s->n_streams,
88
+ .pBindings = descriptorSetLayoutBinding
89
+ };
90
+ VK_CHECK_RESULT(vkCreateDescriptorSetLayout(s->base.device,
91
+ &descriptorSetLayoutCreateInfo, NULL,
92
+ &s->descriptorSetLayout));
93
+
94
+ const VkDescriptorSetAllocateInfo descriptorSetAllocateInfo = {
95
+ .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
96
+ .descriptorPool = s->descriptorPool,
97
+ .descriptorSetCount = 1,
98
+ .pSetLayouts = &s->descriptorSetLayout
99
+ };
100
+
101
+ VK_CHECK_RESULT(vkAllocateDescriptorSets(s->base.device,
102
+ &descriptorSetAllocateInfo,
103
+ &s->descriptorSet));
104
+
105
+ const VkSamplerCreateInfo samplerInfo = {
106
+ .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
107
+ .magFilter = VK_FILTER_LINEAR,
108
+ .minFilter = VK_FILTER_LINEAR,
109
+ .mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR,
110
+ .addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
111
+ .addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
112
+ .addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
113
+ .borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK,
114
+ .unnormalizedCoordinates = VK_FALSE,
115
+ .compareEnable = VK_FALSE,
116
+ .compareOp = VK_COMPARE_OP_ALWAYS,
117
+ .mipLodBias = 0.0f,
118
+ .minLod = 0,
119
+ .maxLod = 5,
120
+ };
121
+ VK_CHECK_RESULT(vkCreateSampler(s->base.device, &samplerInfo, NULL, &s->sampler));
122
+
123
+ return 0;
124
+}
125
+
126
+static int updateDescriptors(struct vulkan_compute_state *s)
127
+{
128
+ uint32_t i;
129
+ VkDescriptorImageInfo descriptorImageInfos->n_streams;
130
+ VkWriteDescriptorSet writeDescriptorSets->n_streams;
131
+ uint32_t descriptorSetLen = 0;
132
+
133
+ for (i = 0; i < s->n_streams; i++) {
134
+ struct vulkan_stream *p = &s->streamsi;
135
+
136
+ if (p->current_buffer_id == p->pending_buffer_id ||
137
+ p->pending_buffer_id == SPA_ID_INVALID)
138
+ continue;
139
+
140
+ p->current_buffer_id = p->pending_buffer_id;
141
+ p->busy_buffer_id = p->current_buffer_id;
142
+ p->pending_buffer_id = SPA_ID_INVALID;
143
+
144
+ descriptorImageInfodescriptorSetLen = (VkDescriptorImageInfo) {
145
+ .sampler = s->sampler,
146
+ .imageView = p->buffersp->current_buffer_id.view,
147
+ .imageLayout = VK_IMAGE_LAYOUT_GENERAL,
148
+ };
149
+ writeDescriptorSetdescriptorSetLen = (VkWriteDescriptorSet) {
150
+ .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
151
+ .dstSet = s->descriptorSet,
152
+ .dstBinding = i,
153
+ .descriptorCount = 1,
154
+ .descriptorType = i == 0 ?
155
+ VK_DESCRIPTOR_TYPE_STORAGE_IMAGE :
156
+ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
157
+ .pImageInfo = &descriptorImageInfoi,
158
+ };
159
+ descriptorSetLen++;
160
+ }
161
+ vkUpdateDescriptorSets(s->base.device, descriptorSetLen,
162
+ writeDescriptorSet, 0, NULL);
163
+
164
+ return 0;
165
+}
166
+
167
+static VkShaderModule createShaderModule(struct vulkan_compute_state *s, const char* shaderFile)
168
+{
169
+ VkShaderModule shaderModule = VK_NULL_HANDLE;
170
+ VkResult result;
171
+ void *data;
172
+ int fd;
173
+ struct stat stat;
174
+
175
+ if ((fd = open(shaderFile, 0, O_RDONLY)) == -1) {
176
+ spa_log_error(s->log, "can't open %s: %m", shaderFile);
177
+ return VK_NULL_HANDLE;
178
+ }
179
+ if (fstat(fd, &stat) < 0) {
180
+ spa_log_error(s->log, "can't stat %s: %m", shaderFile);
181
+ close(fd);
182
+ return VK_NULL_HANDLE;
183
+ }
184
+
185
+ data = mmap(NULL, stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
186
+
187
+ const VkShaderModuleCreateInfo shaderModuleCreateInfo = {
188
+ .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
189
+ .codeSize = stat.st_size,
190
+ .pCode = data,
191
+ };
192
+ result = vkCreateShaderModule(s->base.device,
193
+ &shaderModuleCreateInfo, 0, &shaderModule);
194
+
195
+ munmap(data, stat.st_size);
196
+ close(fd);
197
+
198
+ if (result != VK_SUCCESS) {
199
+ spa_log_error(s->log, "can't create shader %s: %m", shaderFile);
200
+ return VK_NULL_HANDLE;
201
pipewire-0.3.80.tar.gz/spa/plugins/vulkan/vulkan-compute-utils.h
Added
82
1
2
+/* Spa */
3
+/* SPDX-FileCopyrightText: Copyright © 2019 Wim Taymans */
4
+/* SPDX-License-Identifier: MIT */
5
+
6
+#include <vulkan/vulkan.h>
7
+
8
+#include <spa/buffer/buffer.h>
9
+#include <spa/param/video/format.h>
10
+#include <spa/node/node.h>
11
+
12
+#include "vulkan-utils.h"
13
+
14
+#define MAX_STREAMS 2
15
+#define WORKGROUP_SIZE 32
16
+
17
+struct pixel {
18
+ float r, g, b, a;
19
+};
20
+
21
+struct push_constants {
22
+ float time;
23
+ int frame;
24
+ int width;
25
+ int height;
26
+};
27
+
28
+
29
+struct vulkan_compute_state {
30
+ struct spa_log *log;
31
+
32
+ struct push_constants constants;
33
+
34
+ struct vulkan_base base;
35
+
36
+ VkPipeline pipeline;
37
+ VkPipelineLayout pipelineLayout;
38
+ const char *shaderName;
39
+ VkShaderModule computeShaderModule;
40
+
41
+ VkCommandPool commandPool;
42
+ VkCommandBuffer commandBuffer;
43
+
44
+ VkFence fence;
45
+ VkSemaphore pipelineSemaphore;
46
+ unsigned int initialized:1;
47
+ unsigned int prepared:1;
48
+ unsigned int started:1;
49
+
50
+ VkDescriptorPool descriptorPool;
51
+ VkDescriptorSetLayout descriptorSetLayout;
52
+
53
+ VkSampler sampler;
54
+
55
+ uint32_t n_streams;
56
+ VkDescriptorSet descriptorSet;
57
+ struct vulkan_stream streamsMAX_STREAMS;
58
+};
59
+
60
+int spa_vulkan_init_stream(struct vulkan_compute_state *s, struct vulkan_stream *stream, enum spa_direction,
61
+ struct spa_dict *props);
62
+
63
+int spa_vulkan_fixate_modifier(struct vulkan_compute_state *s, struct vulkan_stream *p, struct spa_video_info_dsp *dsp_info,
64
+ uint32_t modifierCount, uint64_t *modifiers, uint64_t *modifier);
65
+int spa_vulkan_prepare(struct vulkan_compute_state *s);
66
+int spa_vulkan_use_buffers(struct vulkan_compute_state *s, struct vulkan_stream *stream, uint32_t flags,
67
+ struct spa_video_info_dsp *dsp_info, uint32_t n_buffers, struct spa_buffer **buffers);
68
+int spa_vulkan_unprepare(struct vulkan_compute_state *s);
69
+
70
+int spa_vulkan_start(struct vulkan_compute_state *s);
71
+int spa_vulkan_stop(struct vulkan_compute_state *s);
72
+int spa_vulkan_ready(struct vulkan_compute_state *s);
73
+int spa_vulkan_process(struct vulkan_compute_state *s);
74
+int spa_vulkan_cleanup(struct vulkan_compute_state *s);
75
+
76
+int spa_vulkan_get_buffer_caps(struct vulkan_compute_state *s, enum spa_direction direction);
77
+struct vulkan_modifier_info *spa_vulkan_get_modifier_info(struct vulkan_compute_state *s,
78
+ struct spa_video_info_dsp *dsp_info);
79
+
80
+int spa_vulkan_init(struct vulkan_compute_state *s);
81
+void spa_vulkan_deinit(struct vulkan_compute_state *s);
82
pipewire-0.3.80.tar.gz/spa/plugins/vulkan/vulkan-types.h
Added
77
1
2
+#pragma once
3
+
4
+#include <vulkan/vulkan.h>
5
+
6
+#include <spa/buffer/buffer.h>
7
+#include <spa/node/node.h>
8
+
9
+#define MAX_BUFFERS 16
10
+#define DMABUF_MAX_PLANES 1
11
+
12
+enum buffer_type_caps {
13
+ VULKAN_BUFFER_TYPE_CAP_SHM = 1<<0,
14
+ VULKAN_BUFFER_TYPE_CAP_DMABUF = 1<<1,
15
+};
16
+
17
+struct vulkan_modifier_info {
18
+ VkDrmFormatModifierPropertiesEXT props;
19
+ VkExtent2D max_extent;
20
+};
21
+
22
+struct vulkan_format_info {
23
+ uint32_t spa_format;
24
+ VkFormat vk_format;
25
+ uint32_t modifierCount;
26
+ struct vulkan_modifier_info *infos;
27
+};
28
+
29
+struct vulkan_buffer {
30
+ int fd;
31
+ VkImage image;
32
+ VkImageView view;
33
+ VkDeviceMemory memory;
34
+ VkSemaphore foreign_semaphore;
35
+};
36
+
37
+struct vulkan_stream {
38
+ enum spa_direction direction;
39
+
40
+ uint32_t pending_buffer_id;
41
+ uint32_t current_buffer_id;
42
+ uint32_t busy_buffer_id;
43
+ uint32_t ready_buffer_id;
44
+
45
+ struct vulkan_buffer buffersMAX_BUFFERS;
46
+ struct spa_buffer *spa_buffersMAX_BUFFERS;
47
+ uint32_t n_buffers;
48
+};
49
+
50
+struct vulkan_base_info {
51
+ uint32_t queueFlags;
52
+
53
+ struct {
54
+ uint32_t formatCount;
55
+ uint32_t *formats;
56
+ } formatInfo;
57
+};
58
+
59
+struct vulkan_base {
60
+ struct spa_log *log;
61
+
62
+ VkInstance instance;
63
+
64
+ VkPhysicalDevice physicalDevice;
65
+
66
+ VkQueue queue;
67
+ uint32_t queueFamilyIndex;
68
+ VkDevice device;
69
+
70
+ uint32_t formatInfoCount;
71
+ struct vulkan_format_info *formatInfos;
72
+
73
+ bool implicit_sync_interop;
74
+
75
+ unsigned int initialized:1;
76
+};
77
pipewire-0.3.79.tar.gz/spa/plugins/vulkan/vulkan-utils.c -> pipewire-0.3.80.tar.gz/spa/plugins/vulkan/vulkan-utils.c
Changed
201
1
2
+/* Spa */
3
+/* SPDX-FileCopyrightText: Copyright © 2019 Wim Taymans */
4
+/* SPDX-License-Identifier: MIT */
5
+
6
#include <vulkan/vulkan.h>
7
8
#include <unistd.h>
9
10
#include <sys/mman.h>
11
#include <fcntl.h>
12
#include <string.h>
13
+#include <poll.h>
14
#if !defined(__FreeBSD__) && !defined(__MidnightBSD__)
15
#include <alloca.h>
16
#endif
17
18
19
#include <spa/utils/result.h>
20
#include <spa/utils/string.h>
21
+#include <spa/param/video/format.h>
22
#include <spa/support/log.h>
23
#include <spa/debug/mem.h>
24
25
#include "vulkan-utils.h"
26
+#include "dmabuf.h"
27
28
//#define ENABLE_VALIDATION
29
30
31
}
32
}
33
34
-#define VK_CHECK_RESULT(f) \
35
-{ \
36
- VkResult _result = (f); \
37
- int _r = -vkresult_to_errno(_result); \
38
- if (_result != VK_SUCCESS) { \
39
- spa_log_error(s->log, "error: %d (%d %s)", _result, _r, spa_strerror(_r)); \
40
- return _r; \
41
- } \
42
-}
43
-#define CHECK(f) \
44
-{ \
45
- int _res = (f); \
46
- if (_res < 0) \
47
- return _res; \
48
-}
49
+static struct {
50
+ VkFormat format;
51
+ uint32_t id;
52
+} vk_video_format_convs = {
53
+ { VK_FORMAT_R32G32B32A32_SFLOAT, SPA_VIDEO_FORMAT_RGBA_F32 },
54
+};
55
56
-static int createInstance(struct vulkan_state *s)
57
+static int createInstance(struct vulkan_base *s)
58
{
59
static const VkApplicationInfo applicationInfo = {
60
.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
61
62
return 0;
63
}
64
65
-static uint32_t getComputeQueueFamilyIndex(struct vulkan_state *s)
66
+static int findPhysicalDevice(struct vulkan_base *s)
67
+{
68
+ uint32_t deviceCount;
69
+ VkPhysicalDevice *devices;
70
+
71
+ vkEnumeratePhysicalDevices(s->instance, &deviceCount, NULL);
72
+ if (deviceCount == 0)
73
+ return -ENODEV;
74
+
75
+ devices = alloca(deviceCount * sizeof(VkPhysicalDevice));
76
+ vkEnumeratePhysicalDevices(s->instance, &deviceCount, devices);
77
+
78
+ s->physicalDevice = devices0;
79
+
80
+ return 0;
81
+}
82
+
83
+static int getComputeQueueFamilyIndex(struct vulkan_base *s, uint32_t queueFlags, uint32_t *queueFamilyIndex)
84
{
85
uint32_t i, queueFamilyCount;
86
VkQueueFamilyProperties *queueFamilies;
87
88
for (i = 0; i < queueFamilyCount; i++) {
89
VkQueueFamilyProperties props = queueFamiliesi;
90
91
- if (props.queueCount > 0 && (props.queueFlags & VK_QUEUE_COMPUTE_BIT))
92
+ if (props.queueCount > 0 && ((props.queueFlags & queueFlags) == queueFlags))
93
break;
94
}
95
if (i == queueFamilyCount)
96
return -ENODEV;
97
98
- return i;
99
-}
100
-
101
-static int findPhysicalDevice(struct vulkan_state *s)
102
-{
103
- uint32_t deviceCount;
104
- VkPhysicalDevice *devices;
105
-
106
- vkEnumeratePhysicalDevices(s->instance, &deviceCount, NULL);
107
- if (deviceCount == 0)
108
- return -ENODEV;
109
-
110
- devices = alloca(deviceCount * sizeof(VkPhysicalDevice));
111
- vkEnumeratePhysicalDevices(s->instance, &deviceCount, devices);
112
-
113
- s->physicalDevice = devices0;
114
-
115
- s->queueFamilyIndex = getComputeQueueFamilyIndex(s);
116
-
117
+ *queueFamilyIndex = i;
118
return 0;
119
}
120
121
-static int createDevice(struct vulkan_state *s)
122
+static int createDevice(struct vulkan_base *s, struct vulkan_base_info *info)
123
{
124
125
+ CHECK(getComputeQueueFamilyIndex(s, info->queueFlags, &s->queueFamilyIndex));
126
+
127
const VkDeviceQueueCreateInfo queueCreateInfo = {
128
.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
129
.queueFamilyIndex = s->queueFamilyIndex,
130
.queueCount = 1,
131
.pQueuePriorities = (const float) { 1.0f }
132
};
133
+ const VkPhysicalDeviceSynchronization2FeaturesKHR sync2_features = {
134
+ .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES_KHR,
135
+ .synchronization2 = VK_TRUE,
136
+ };
137
static const char * const extensions = {
138
VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME,
139
- VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME
140
+ VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME,
141
+ VK_KHR_IMAGE_FORMAT_LIST_EXTENSION_NAME,
142
+ VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME,
143
+ VK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME,
144
+ VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME
145
};
146
const VkDeviceCreateInfo deviceCreateInfo = {
147
.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
148
.queueCreateInfoCount = 1,
149
.pQueueCreateInfos = &queueCreateInfo,
150
- .enabledExtensionCount = 2,
151
+ .enabledExtensionCount = SPA_N_ELEMENTS(extensions),
152
.ppEnabledExtensionNames = extensions,
153
+ .pNext = &sync2_features,
154
};
155
156
VK_CHECK_RESULT(vkCreateDevice(s->physicalDevice, &deviceCreateInfo, NULL, &s->device));
157
158
vkGetDeviceQueue(s->device, s->queueFamilyIndex, 0, &s->queue);
159
160
- static const VkFenceCreateInfo fenceCreateInfo = {
161
- .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
162
- .flags = 0,
163
- };
164
- VK_CHECK_RESULT(vkCreateFence(s->device, &fenceCreateInfo, NULL, &s->fence));
165
-
166
return 0;
167
}
168
169
-static uint32_t findMemoryType(struct vulkan_state *s,
170
- uint32_t memoryTypeBits, VkMemoryPropertyFlags properties)
171
+static int queryFormatInfo(struct vulkan_base *s, struct vulkan_base_info *info)
172
{
173
- uint32_t i;
174
- VkPhysicalDeviceMemoryProperties memoryProperties;
175
+ if (s->formatInfos)
176
+ return 0;
177
178
- vkGetPhysicalDeviceMemoryProperties(s->physicalDevice, &memoryProperties);
179
+ s->formatInfos = calloc(info->formatInfo.formatCount, sizeof(struct vulkan_format_info));
180
+ if (!s->formatInfos)
181
+ return -ENOMEM;
182
183
- for (i = 0; i < memoryProperties.memoryTypeCount; i++) {
184
- if ((memoryTypeBits & (1 << i)) &&
185
- ((memoryProperties.memoryTypesi.propertyFlags & properties) == properties))
186
- return i;
187
- }
188
- return -1;
189
-}
190
+ for (uint32_t i = 0; i < info->formatInfo.formatCount; i++) {
191
+ VkFormat format = vulkan_id_to_vkformat(info->formatInfo.formatsi);
192
+ if (format == VK_FORMAT_UNDEFINED)
193
+ continue;
194
+ struct vulkan_format_info *f_info = &s->formatInfoss->formatInfoCount++;
195
+ f_info->spa_format = info->formatInfo.formatsi;
196
+ f_info->vk_format = format;
197
198
-static int createDescriptors(struct vulkan_state *s)
199
-{
200
- uint32_t i;
201
pipewire-0.3.79.tar.gz/spa/plugins/vulkan/vulkan-utils.h -> pipewire-0.3.80.tar.gz/spa/plugins/vulkan/vulkan-utils.h
Changed
172
1
2
+/* Spa */
3
+/* SPDX-FileCopyrightText: Copyright © 2019 Wim Taymans */
4
+/* SPDX-License-Identifier: MIT */
5
+
6
+#pragma once
7
+
8
#include <vulkan/vulkan.h>
9
10
#include <spa/buffer/buffer.h>
11
#include <spa/node/node.h>
12
13
-#define MAX_STREAMS 2
14
-#define MAX_BUFFERS 16
15
-#define WORKGROUP_SIZE 32
16
-
17
-struct pixel {
18
- float r, g, b, a;
19
+#include "vulkan-types.h"
20
+
21
+#define VK_CHECK_RESULT(f) \
22
+{ \
23
+ VkResult _result = (f); \
24
+ int _r = -vulkan_vkresult_to_errno(_result); \
25
+ if (_result != VK_SUCCESS) { \
26
+ spa_log_error(s->log, "error: %d (%d %s)", _result, _r, spa_strerror(_r)); \
27
+ return _r; \
28
+ } \
29
+}
30
+#define VK_CHECK_RESULT_WITH_CLEANUP(f, c) \
31
+{ \
32
+ VkResult _result = (f); \
33
+ int _r = -vkresult_to_errno(_result); \
34
+ if (_result != VK_SUCCESS) { \
35
+ spa_log_error(s->log, "error: %d (%d %s)", _result, _r, spa_strerror(_r)); \
36
+ (c); \
37
+ return _r; \
38
+ } \
39
+}
40
+#define VK_CHECK_RESULT_LOOP(f) \
41
+{ \
42
+ VkResult _result = (f); \
43
+ int _r = -vkresult_to_errno(_result); \
44
+ if (_result != VK_SUCCESS) { \
45
+ spa_log_error(s->log, "error: %d (%d %s)", _result, _r, spa_strerror(_r)); \
46
+ continue; \
47
+ } \
48
+}
49
+#define CHECK(f) \
50
+{ \
51
+ int _res = (f); \
52
+ if (_res < 0) \
53
+ return _res; \
54
+}
55
+
56
+struct vulkan_read_pixels_info {
57
+ struct spa_rectangle size;
58
+ void *data;
59
+ uint32_t offset;
60
+ uint32_t stride;
61
+ uint32_t bytes_per_pixel;
62
};
63
64
-struct push_constants {
65
- float time;
66
- int frame;
67
- int width;
68
- int height;
69
+struct dmabuf_fixation_info {
70
+ VkFormat format;
71
+ uint64_t modifierCount;
72
+ uint64_t *modifiers;
73
+ struct spa_rectangle size;
74
+ VkImageUsageFlags usage;
75
};
76
77
-struct vulkan_buffer {
78
- int fd;
79
- VkImage image;
80
- VkImageView view;
81
- VkDeviceMemory memory;
82
-};
83
-
84
-struct vulkan_stream {
85
- enum spa_direction direction;
86
-
87
- uint32_t pending_buffer_id;
88
- uint32_t current_buffer_id;
89
- uint32_t busy_buffer_id;
90
- uint32_t ready_buffer_id;
91
-
92
- struct vulkan_buffer buffersMAX_BUFFERS;
93
- uint32_t n_buffers;
94
+struct external_buffer_info {
95
+ VkFormat format;
96
+ uint64_t modifier;
97
+ struct spa_rectangle size;
98
+ VkImageUsageFlags usage;
99
+ struct spa_buffer *spa_buf;
100
};
101
102
-struct vulkan_state {
103
- struct spa_log *log;
104
-
105
- struct push_constants constants;
106
-
107
- VkInstance instance;
108
+int vulkan_read_pixels(struct vulkan_base *s, struct vulkan_read_pixels_info *info, struct vulkan_buffer *vk_buf);
109
110
- VkPhysicalDevice physicalDevice;
111
- VkDevice device;
112
+int vulkan_sync_foreign_dmabuf(struct vulkan_base *s, struct vulkan_buffer *vk_buf);
113
+bool vulkan_sync_export_dmabuf(struct vulkan_base *s, struct vulkan_buffer *vk_buf, int sync_file_fd);
114
115
- VkPipeline pipeline;
116
- VkPipelineLayout pipelineLayout;
117
- const char *shaderName;
118
- VkShaderModule computeShaderModule;
119
+int vulkan_fixate_modifier(struct vulkan_base *s, struct dmabuf_fixation_info *info, uint64_t *modifier);
120
+int vulkan_create_dmabuf(struct vulkan_base *s, struct external_buffer_info *info, struct vulkan_buffer *vk_buf);
121
+int vulkan_import_dmabuf(struct vulkan_base *s, struct external_buffer_info *info, struct vulkan_buffer *vk_buf);
122
+int vulkan_import_memptr(struct vulkan_base *s, struct external_buffer_info *info, struct vulkan_buffer *vk_buf);
123
124
- VkCommandPool commandPool;
125
- VkCommandBuffer commandBuffer;
126
+int vulkan_commandPool_create(struct vulkan_base *s, VkCommandPool *commandPool);
127
+int vulkan_commandBuffer_create(struct vulkan_base *s, VkCommandPool commandPool, VkCommandBuffer *commandBuffer);
128
129
- VkQueue queue;
130
- uint32_t queueFamilyIndex;
131
- VkFence fence;
132
- unsigned int prepared:1;
133
- unsigned int started:1;
134
+uint32_t vulkan_memoryType_find(struct vulkan_base *s,
135
+ uint32_t memoryTypeBits, VkMemoryPropertyFlags properties);
136
+struct vulkan_format_info *vulkan_formatInfo_find(struct vulkan_base *s, VkFormat format);
137
+struct vulkan_modifier_info *vulkan_modifierInfo_find(struct vulkan_base *s, VkFormat format, uint64_t modifier);
138
139
- VkDescriptorPool descriptorPool;
140
- VkDescriptorSetLayout descriptorSetLayout;
141
+void vulkan_buffer_clear(struct vulkan_base *s, struct vulkan_buffer *buffer);
142
143
- VkSampler sampler;
144
+int vulkan_stream_init(struct vulkan_stream *stream, enum spa_direction direction,
145
+ struct spa_dict *props);
146
147
- uint32_t n_streams;
148
- VkDescriptorSet descriptorSet;
149
- struct vulkan_stream streamsMAX_STREAMS;
150
-};
151
+uint32_t vulkan_vkformat_to_id(VkFormat vkFormat);
152
+VkFormat vulkan_id_to_vkformat(uint32_t id);
153
154
-int spa_vulkan_init_stream(struct vulkan_state *s, struct vulkan_stream *stream, enum spa_direction,
155
- struct spa_dict *props);
156
+int vulkan_vkresult_to_errno(VkResult result);
157
158
-int spa_vulkan_prepare(struct vulkan_state *s);
159
-int spa_vulkan_use_buffers(struct vulkan_state *s, struct vulkan_stream *stream, uint32_t flags,
160
- uint32_t n_buffers, struct spa_buffer **buffers);
161
-int spa_vulkan_unprepare(struct vulkan_state *s);
162
+int vulkan_wait_fence(struct vulkan_base *s, VkFence fence);
163
+int vulkan_wait_idle(struct vulkan_base *s);
164
165
-int spa_vulkan_start(struct vulkan_state *s);
166
-int spa_vulkan_stop(struct vulkan_state *s);
167
-int spa_vulkan_ready(struct vulkan_state *s);
168
-int spa_vulkan_process(struct vulkan_state *s);
169
-int spa_vulkan_cleanup(struct vulkan_state *s);
170
+int vulkan_base_init(struct vulkan_base *s, struct vulkan_base_info *info);
171
+void vulkan_base_deinit(struct vulkan_base *s);
172
pipewire-0.3.79.tar.gz/src/daemon/meson.build -> pipewire-0.3.80.tar.gz/src/daemon/meson.build
Changed
40
1
2
build_wp = 'wireplumber' in get_option('session-managers')
3
default_sm = get_option('session-managers').get(0, '')
4
5
+build_vk = get_option('vulkan').enabled()
6
+
7
summary({'Build media-session': build_ms,
8
'Build wireplumber': build_wp,
9
'Default session-manager': default_sm},
10
11
'pipewire-aes67.conf',
12
13
14
+if build_vk
15
+ conf_files += 'pipewire-vulkan.conf'
16
+endif
17
+
18
foreach c : conf_files
19
configure_file(input : '@0@.in'.format(c),
20
output : c,
21
22
23
ln = find_program('ln')
24
25
-foreach alias : 'pipewire-pulse', 'pipewire-avb', 'pipewire-aes67'
26
+pipewire_aliases =
27
+ 'pipewire-pulse',
28
+ 'pipewire-avb',
29
+ 'pipewire-aes67',
30
+
31
+
32
+if build_vk
33
+ pipewire_aliases += 'pipewire-vulkan'
34
+endif
35
+
36
+foreach alias : pipewire_aliases
37
custom_target(
38
alias,
39
build_by_default: true,
40
pipewire-0.3.79.tar.gz/src/daemon/minimal.conf.in -> pipewire-0.3.80.tar.gz/src/daemon/minimal.conf.in
Changed
15
1
2
# Creates an object from a PipeWire factory with the given parameters.
3
# If nofail is given, errors are ignored (and no object is created).
4
#
5
- #{ factory = spa-node-factory args = { factory.name = videotestsrc node.name = videotestsrc Spa:Pod:Object:Param:Props:patternType = 1 } }
6
+ #{ factory = spa-node-factory args = { factory.name = videotestsrc node.name = videotestsrc node.description = videotestsrc Spa:Pod:Object:Param:Props:patternType = 1 } }
7
#{ factory = spa-device-factory args = { factory.name = api.jack.device foo=bar } flags = nofail }
8
#{ factory = spa-device-factory args = { factory.name = api.alsa.enum.udev } }
9
#{ factory = spa-node-factory args = { factory.name = api.alsa.seq.bridge node.name = Internal-MIDI-Bridge } }
10
- #{ factory = adapter args = { factory.name = audiotestsrc node.name = my-test } }
11
+ #{ factory = adapter args = { factory.name = audiotestsrc node.name = my-test node.description = audiotestsrc } }
12
#{ factory = spa-node-factory args = { factory.name = api.vulkan.compute.source node.name = my-compute-source } }
13
14
# Make a default metadata store
15
pipewire-0.3.80.tar.gz/src/daemon/pipewire-vulkan.conf.in
Added
100
1
2
+# Config file for PipeWire version "0.3.77" #
3
+#
4
+# This config file should start the vulkan-compute-source/filter as proxied
5
+# clients
6
+#
7
+
8
+context.properties = {
9
+ ## Configure properties in the system.
10
+ #library.name.system = support/libspa-support
11
+ #context.data-loop.library.name.system = support/libspa-support
12
+ #support.dbus = true
13
+ #link.max-buffers = 64
14
+ #link.max-buffers = 16 # version < 3 clients can't handle more
15
+ #mem.warn-mlock = false
16
+ #mem.allow-mlock = true
17
+ #mem.mlock-all = false
18
+ #clock.power-of-two-quantum = true
19
+ #log.level = 4
20
+ #cpu.zero.denormals = false
21
+
22
+ #default.clock.quantum-limit = 8192
23
+}
24
+
25
+context.spa-libs = {
26
+ #<factory-name regex> = <library-name>
27
+ #
28
+ # Used to find spa factory names. It maps an spa factory name
29
+ # regular expression to a library name that should contain
30
+ # that factory.
31
+ #
32
+ api.vulkan.* = vulkan/libspa-vulkan
33
+ support.* = support/libspa-support
34
+}
35
+
36
+context.modules =
37
+ #{ name = <module-name>
38
+ # ( args = { <key> = <value> ... } )
39
+ # ( flags = ( ifexists ) ( nofail ) )
40
+ # ( condition = { <key> = <value> ... } ... )
41
+ #}
42
+ #
43
+ # Loads a module with the given parameters.
44
+ # If ifexists is given, the module is ignored when it is not found.
45
+ # If nofail is given, module initialization failures are ignored.
46
+ # If condition is given, the module is loaded only when the context
47
+ # properties all match the match rules.
48
+ #
49
+
50
+ # Uses realtime scheduling to boost the audio thread priorities. This uses
51
+ # RTKit if the user doesn't have permission to use regular realtime
52
+ # scheduling.
53
+ { name = libpipewire-module-rt
54
+ args = {
55
+ nice.level = -11
56
+ #rt.prio = 88
57
+ #rt.time.soft = -1
58
+ #rt.time.hard = -1
59
+ }
60
+ flags = ifexists nofail
61
+ }
62
+
63
+ # The native communication protocol.
64
+ { name = libpipewire-module-protocol-native }
65
+
66
+ # Creates a factory for making nodes that run in the
67
+ # context of the PipeWire server.
68
+ { name = libpipewire-module-spa-node-factory }
69
+
70
+ # Allows creating nodes that run in the context of the
71
+ # client. Is used by all clients that want to provide
72
+ # data to PipeWire.
73
+ { name = libpipewire-module-client-node }
74
+
75
+ # Makes a factory for wrapping nodes in an adapter with a
76
+ # converter and resampler.
77
+ { name = libpipewire-module-adapter }
78
+
79
+
80
+context.objects =
81
+ #{ factory = <factory-name>
82
+ # ( args = { <key> = <value> ... } )
83
+ # ( flags = ( nofail ) )
84
+ # ( condition = { <key> = <value> ... } ... )
85
+ #}
86
+ #
87
+ # Creates an object from a PipeWire factory with the given parameters.
88
+ # If nofail is given, errors are ignored (and no object is created).
89
+ # If condition is given, the object is created only when the context properties
90
+ # all match the match rules.
91
+ #
92
+ #{ factory = spa-node-factory args = { factory.name = videotestsrc node.name = videotestsrc Spa:Pod:Object:Param:Props:patternType = 1 } }
93
+ #{ factory = spa-device-factory args = { factory.name = api.jack.device foo=bar } flags = nofail }
94
+ #{ factory = spa-device-factory args = { factory.name = api.alsa.enum.udev } }
95
+ #{ factory = spa-node-factory args = { factory.name = api.alsa.seq.bridge node.name = Internal-MIDI-Bridge } }
96
+ #{ factory = adapter args = { factory.name = audiotestsrc node.name = my-test } }
97
+ { factory = spa-node-factory args = { factory.name = api.vulkan.compute.source node.name = vulkan-compute-source object.export = true } }
98
+ { factory = spa-node-factory args = { factory.name = api.vulkan.compute.filter node.name = vulkan-compute-filter object.export = true } }
99
+
100
pipewire-0.3.79.tar.gz/src/daemon/pipewire.conf.in -> pipewire-0.3.80.tar.gz/src/daemon/pipewire.conf.in
Changed
15
1
2
# If condition is given, the object is created only when the context properties
3
# all match the match rules.
4
#
5
- #{ factory = spa-node-factory args = { factory.name = videotestsrc node.name = videotestsrc Spa:Pod:Object:Param:Props:patternType = 1 } }
6
+ #{ factory = spa-node-factory args = { factory.name = videotestsrc node.name = videotestsrc node.description = videotestsrc Spa:Pod:Object:Param:Props:patternType = 1 } }
7
#{ factory = spa-device-factory args = { factory.name = api.jack.device foo=bar } flags = nofail }
8
#{ factory = spa-device-factory args = { factory.name = api.alsa.enum.udev } }
9
#{ factory = spa-node-factory args = { factory.name = api.alsa.seq.bridge node.name = Internal-MIDI-Bridge } }
10
- #{ factory = adapter args = { factory.name = audiotestsrc node.name = my-test } }
11
+ #{ factory = adapter args = { factory.name = audiotestsrc node.name = my-test node.description = audiotestsrc } }
12
#{ factory = spa-node-factory args = { factory.name = api.vulkan.compute.source node.name = my-compute-source } }
13
14
# A default dummy driver. This handles nodes marked with the "node.always-driver"
15
pipewire-0.3.79.tar.gz/src/examples/video-play.c -> pipewire-0.3.80.tar.gz/src/examples/video-play.c
Changed
49
1
2
3
#include <spa/utils/result.h>
4
#include <spa/param/video/format-utils.h>
5
+#include <spa/param/tag-utils.h>
6
#include <spa/param/props.h>
7
#include <spa/debug/format.h>
8
+#include <spa/debug/pod.h>
9
10
#include <pipewire/pipewire.h>
11
12
13
void *d;
14
int32_t mult, size;
15
16
+ if (param != NULL && id == SPA_PARAM_Tag) {
17
+ spa_debug_pod(0, NULL, param);
18
+ return;
19
+ }
20
/* NULL means to clear the format */
21
if (param == NULL || id != SPA_PARAM_Format)
22
return;
23
24
int main(int argc, char *argv)
25
{
26
struct data data = { 0, };
27
- const struct spa_pod *params2;
28
+ const struct spa_pod *params3;
29
uint8_t buffer1024;
30
struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer));
31
struct pw_properties *props;
32
33
* object to the stack. */
34
n_params = build_format(&data, &b, params);
35
36
+ {
37
+ struct spa_pod_frame f;
38
+ struct spa_dict_item items1;
39
+ /* send a tag, input tags travel upstream */
40
+ spa_tag_build_start(&b, &f, SPA_PARAM_Tag, SPA_DIRECTION_INPUT);
41
+ items0 = SPA_DICT_ITEM_INIT("my-tag-other-key", "my-special-other-tag-value");
42
+ spa_tag_build_add_dict(&b, &SPA_DICT_INIT(items, 1));
43
+ paramsn_params++ = spa_tag_build_end(&b, &f);
44
+ }
45
+
46
/* now connect the stream, we need a direction (input/output),
47
* an optional target node to connect to, some flags and parameters
48
*/
49
pipewire-0.3.79.tar.gz/src/examples/video-src.c -> pipewire-0.3.80.tar.gz/src/examples/video-src.c
Changed
56
1
2
#include <math.h>
3
4
#include <spa/param/video/format-utils.h>
5
+#include <spa/param/tag-utils.h>
6
+#include <spa/debug/pod.h>
7
8
#include <pipewire/pipewire.h>
9
10
11
struct spa_pod_builder b = SPA_POD_BUILDER_INIT(params_buffer, sizeof(params_buffer));
12
const struct spa_pod *params5;
13
14
+ if (param != NULL && id == SPA_PARAM_Tag) {
15
+ spa_debug_pod(0, NULL, param);
16
+ return;
17
+ }
18
if (param == NULL || id != SPA_PARAM_Format)
19
return;
20
21
22
int main(int argc, char *argv)
23
{
24
struct data data = { 0, };
25
- const struct spa_pod *params1;
26
+ const struct spa_pod *params2;
27
uint8_t buffer1024;
28
struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer));
29
30
31
&SPA_RECTANGLE(4096, 4096)),
32
SPA_FORMAT_VIDEO_framerate, SPA_POD_Fraction(&SPA_FRACTION(25, 1)));
33
34
+ {
35
+ struct spa_pod_frame f;
36
+ struct spa_dict_item items1;
37
+ /* send a tag, output tags travel downstream */
38
+ spa_tag_build_start(&b, &f, SPA_PARAM_Tag, SPA_DIRECTION_OUTPUT);
39
+ items0 = SPA_DICT_ITEM_INIT("my-tag-key", "my-special-tag-value");
40
+ spa_tag_build_add_dict(&b, &SPA_DICT_INIT(items, 1));
41
+ params1 = spa_tag_build_end(&b, &f);
42
+ }
43
+
44
pw_stream_add_listener(data.stream,
45
&data.stream_listener,
46
&stream_events,
47
48
PW_ID_ANY,
49
PW_STREAM_FLAG_DRIVER |
50
PW_STREAM_FLAG_MAP_BUFFERS,
51
- params, 1);
52
+ params, 2);
53
54
pw_main_loop_run(data.loop);
55
56
pipewire-0.3.79.tar.gz/src/modules/module-combine-stream.c -> pipewire-0.3.80.tar.gz/src/modules/module-combine-stream.c
Changed
10
1
2
update_delay(s->impl);
3
break;
4
case SPA_PARAM_Latency:
5
- if (!param) {
6
+ if (param == NULL) {
7
s->have_latency = false;
8
} else if (spa_latency_parse(param, &latency) == 0 &&
9
latency.direction == get_combine_direction(s->impl)) {
10
pipewire-0.3.79.tar.gz/src/modules/module-echo-cancel.c -> pipewire-0.3.80.tar.gz/src/modules/module-echo-cancel.c
Changed
19
1
2
struct spa_pod_builder b;
3
const struct spa_pod *params1;
4
5
- if (spa_latency_parse(param, &latency) < 0)
6
+ if (param == NULL || spa_latency_parse(param, &latency) < 0)
7
return;
8
9
spa_pod_builder_init(&b, buffer, sizeof(buffer));
10
11
struct spa_pod_builder b;
12
const struct spa_pod *params1;
13
14
- if (spa_latency_parse(param, &latency) < 0)
15
+ if (param == NULL || spa_latency_parse(param, &latency) < 0)
16
return;
17
18
spa_pod_builder_init(&b, buffer, sizeof(buffer));
19
pipewire-0.3.79.tar.gz/src/modules/module-example-filter.c -> pipewire-0.3.80.tar.gz/src/modules/module-example-filter.c
Changed
10
1
2
struct spa_pod_builder b;
3
const struct spa_pod *params1;
4
5
- if (spa_latency_parse(param, &latency) < 0)
6
+ if (param == NULL || spa_latency_parse(param, &latency) < 0)
7
return;
8
9
*info = latency;
10
pipewire-0.3.79.tar.gz/src/modules/module-ffado-driver.c -> pipewire-0.3.80.tar.gz/src/modules/module-ffado-driver.c
Changed
10
1
2
bool update = false;
3
enum spa_direction direction = port->direction;
4
5
- if (spa_latency_parse(param, &latency) < 0)
6
+ if (param == NULL || spa_latency_parse(param, &latency) < 0)
7
return;
8
9
if (spa_latency_info_compare(&port->latencydirection, &latency)) {
10
pipewire-0.3.79.tar.gz/src/modules/module-filter-chain.c -> pipewire-0.3.80.tar.gz/src/modules/module-filter-chain.c
Changed
50
1
2
#include <spa/utils/json.h>
3
#include <spa/support/cpu.h>
4
#include <spa/param/latency-utils.h>
5
+#include <spa/param/tag-utils.h>
6
#include <spa/pod/dynamic.h>
7
#include <spa/debug/types.h>
8
9
10
struct spa_pod_builder b;
11
const struct spa_pod *params1;
12
13
- if (spa_latency_parse(param, &latency) < 0)
14
+ if (param == NULL || spa_latency_parse(param, &latency) < 0)
15
return;
16
17
spa_pod_builder_init(&b, buffer, sizeof(buffer));
18
19
pw_stream_update_params(impl->playback, params, 1);
20
}
21
22
+static void param_tag_changed(struct impl *impl, const struct spa_pod *param)
23
+{
24
+ struct spa_tag_info tag;
25
+ const struct spa_pod *params1 = { param };
26
+ void *state = NULL;
27
+
28
+ if (param == 0 || spa_tag_parse(param, &tag, &state) < 0)
29
+ return;
30
+
31
+ if (tag.direction == SPA_DIRECTION_INPUT)
32
+ pw_stream_update_params(impl->capture, params, 1);
33
+ else
34
+ pw_stream_update_params(impl->playback, params, 1);
35
+}
36
+
37
static void state_changed(void *data, enum pw_stream_state old,
38
enum pw_stream_state state, const char *error)
39
{
40
41
case SPA_PARAM_Latency:
42
param_latency_changed(impl, param);
43
break;
44
+ case SPA_PARAM_Tag:
45
+ param_tag_changed(impl, param);
46
+ break;
47
}
48
return;
49
50
pipewire-0.3.79.tar.gz/src/modules/module-filter-chain/builtin_plugin.c -> pipewire-0.3.80.tar.gz/src/modules/module-filter-chain/builtin_plugin.c
Changed
10
1
2
pw_log_error("convolver:filename requires a string or an array");
3
return NULL;
4
} else {
5
- filenamesi = strdup(v);
6
+ filenames0 = strdup(v);
7
}
8
}
9
else if (spa_streq(key, "offset")) {
10
pipewire-0.3.79.tar.gz/src/modules/module-jack-tunnel.c -> pipewire-0.3.80.tar.gz/src/modules/module-jack-tunnel.c
Changed
10
1
2
bool update = false;
3
enum spa_direction direction = port->direction;
4
5
- if (spa_latency_parse(param, &latency) < 0)
6
+ if (param == NULL || spa_latency_parse(param, &latency) < 0)
7
return;
8
9
if (spa_latency_info_compare(&port->latencydirection, &latency)) {
10
pipewire-0.3.79.tar.gz/src/modules/module-loopback.c -> pipewire-0.3.80.tar.gz/src/modules/module-loopback.c
Changed
76
1
2
struct pw_stream *capture;
3
struct spa_hook capture_listener;
4
struct spa_audio_info_raw capture_info;
5
- struct spa_latency_info capture_latency;
6
7
struct pw_properties *playback_props;
8
struct pw_stream *playback;
9
struct spa_hook playback_listener;
10
struct spa_audio_info_raw playback_info;
11
- struct spa_latency_info playback_latency;
12
13
unsigned int do_disconnect:1;
14
unsigned int recalc_delay:1;
15
16
}
17
18
static void param_latency_changed(struct impl *impl, const struct spa_pod *param,
19
- struct spa_latency_info *info, struct pw_stream *other)
20
+ struct pw_stream *other)
21
{
22
struct spa_latency_info latency;
23
uint8_t buffer1024;
24
struct spa_pod_builder b;
25
const struct spa_pod *params1;
26
27
- if (spa_latency_parse(param, &latency) < 0)
28
+ if (param == NULL || spa_latency_parse(param, &latency) < 0)
29
return;
30
31
- *info = latency;
32
-
33
spa_pod_builder_init(&b, buffer, sizeof(buffer));
34
params0 = spa_latency_build(&b, SPA_PARAM_Latency, &latency);
35
pw_stream_update_params(other, params, 1);
36
37
impl->recalc_delay = true;
38
}
39
40
+static void param_tag_changed(struct impl *impl, const struct spa_pod *param,
41
+ struct pw_stream *other)
42
+{
43
+ const struct spa_pod *params1 = { param };
44
+ if (param == NULL)
45
+ return;
46
+ pw_stream_update_params(other, params, 1);
47
+}
48
+
49
static void recalculate_buffer(struct impl *impl)
50
{
51
if (impl->target_delay > 0.0f) {
52
53
break;
54
}
55
case SPA_PARAM_Latency:
56
- param_latency_changed(impl, param, &impl->capture_latency, impl->playback);
57
+ param_latency_changed(impl, param, impl->playback);
58
+ break;
59
+ case SPA_PARAM_Tag:
60
+ param_tag_changed(impl, param, impl->playback);
61
break;
62
}
63
}
64
65
66
switch (id) {
67
case SPA_PARAM_Latency:
68
- param_latency_changed(impl, param, &impl->playback_latency, impl->capture);
69
+ param_latency_changed(impl, param, impl->capture);
70
+ break;
71
+ case SPA_PARAM_Tag:
72
+ param_tag_changed(impl, param, impl->capture);
73
break;
74
}
75
}
76
pipewire-0.3.79.tar.gz/src/modules/module-netjack2-driver.c -> pipewire-0.3.80.tar.gz/src/modules/module-netjack2-driver.c
Changed
10
1
2
bool update = false;
3
enum spa_direction direction = port->direction;
4
5
- if (spa_latency_parse(param, &latency) < 0)
6
+ if (param == NULL || spa_latency_parse(param, &latency) < 0)
7
return;
8
9
if (spa_latency_info_compare(&port->latencydirection, &latency)) {
10
pipewire-0.3.79.tar.gz/src/modules/module-netjack2-manager.c -> pipewire-0.3.80.tar.gz/src/modules/module-netjack2-manager.c
Changed
10
1
2
bool update = false;
3
enum spa_direction direction = port->direction;
4
5
- if (spa_latency_parse(param, &latency) < 0)
6
+ if (param == NULL || spa_latency_parse(param, &latency) < 0)
7
return;
8
9
if (spa_latency_info_compare(&port->latencydirection, &latency)) {
10
pipewire-0.3.79.tar.gz/src/modules/module-pipe-tunnel.c -> pipewire-0.3.80.tar.gz/src/modules/module-pipe-tunnel.c
Changed
201
1
2
#define DEFAULT_CHANNELS 2
3
#define DEFAULT_POSITION " FL FR "
4
5
+#define RINGBUFFER_SIZE (1u << 22)
6
+#define RINGBUFFER_MASK (RINGBUFFER_SIZE-1)
7
+
8
PW_LOG_TOPIC_STATIC(mod_topic, "mod." NAME);
9
#define PW_LOG_TOPIC_DEFAULT mod_topic
10
11
12
13
struct impl {
14
struct pw_context *context;
15
+ struct pw_loop *data_loop;
16
17
#define MODE_PLAYBACK 0
18
#define MODE_CAPTURE 1
19
20
char *filename;
21
unsigned int unlink_fifo;
22
int fd;
23
+ struct spa_source *socket;
24
+ struct spa_source *timer;
25
26
struct pw_properties *stream_props;
27
enum pw_direction direction;
28
29
uint32_t frame_size;
30
31
unsigned int do_disconnect:1;
32
- uint32_t leftover_count;
33
- uint8_t *leftover;
34
+ unsigned int driving:1;
35
+ unsigned int have_sync:1;
36
+
37
+ struct spa_ringbuffer ring;
38
+ void *buffer;
39
+ uint32_t target_buffer;
40
+
41
+ struct spa_io_rate_match *rate_match;
42
+ struct spa_io_position *position;
43
+
44
+ struct spa_dll dll;
45
+ float max_error;
46
+ float corr;
47
+
48
+ uint64_t next_time;
49
};
50
51
+static uint64_t get_time_ns(struct impl *impl)
52
+{
53
+ struct timespec now;
54
+ if (spa_system_clock_gettime(impl->data_loop->system, CLOCK_MONOTONIC, &now) < 0)
55
+ return 0;
56
+ return SPA_TIMESPEC_TO_NSEC(&now);
57
+}
58
+
59
+static int set_timeout(struct impl *impl, uint64_t time)
60
+{
61
+ struct timespec timeout, interval;
62
+ timeout.tv_sec = time / SPA_NSEC_PER_SEC;
63
+ timeout.tv_nsec = time % SPA_NSEC_PER_SEC;
64
+ interval.tv_sec = 0;
65
+ interval.tv_nsec = 0;
66
+ pw_loop_update_timer(impl->data_loop,
67
+ impl->timer, &timeout, &interval, true);
68
+ return 0;
69
+}
70
+
71
+static void on_timeout(void *d, uint64_t expirations)
72
+{
73
+ struct impl *impl = d;
74
+ uint64_t duration, current_time;
75
+ uint32_t rate, index;
76
+ int32_t avail;
77
+ struct spa_io_position *pos = impl->position;
78
+
79
+ if (SPA_LIKELY(pos)) {
80
+ duration = pos->clock.target_duration;
81
+ rate = pos->clock.target_rate.denom;
82
+ } else {
83
+ duration = 1024;
84
+ rate = 48000;
85
+ }
86
+ pw_log_debug("timeout %"PRIu64, duration);
87
+
88
+ current_time = impl->next_time;
89
+ impl->next_time += duration / impl->corr * 1e9 / rate;
90
+ avail = spa_ringbuffer_get_read_index(&impl->ring, &index);
91
+
92
+ if (SPA_LIKELY(pos)) {
93
+ pos->clock.nsec = current_time;
94
+ pos->clock.rate = pos->clock.target_rate;
95
+ pos->clock.position += pos->clock.duration;
96
+ pos->clock.duration = pos->clock.target_duration;
97
+ pos->clock.delay = SPA_SCALE32_UP(avail, rate, impl->info.rate);
98
+ pos->clock.rate_diff = impl->corr;
99
+ pos->clock.next_nsec = impl->next_time;
100
+ }
101
+ set_timeout(impl, impl->next_time);
102
+
103
+ pw_stream_trigger_process(impl->stream);
104
+}
105
+
106
static void stream_destroy(void *d)
107
{
108
struct impl *impl = d;
109
110
pw_impl_module_schedule_destroy(impl->module);
111
break;
112
case PW_STREAM_STATE_PAUSED:
113
+ if (impl->direction == PW_DIRECTION_OUTPUT) {
114
+ pw_loop_update_io(impl->data_loop, impl->socket, 0);
115
+ set_timeout(impl, 0);
116
+ }
117
break;
118
case PW_STREAM_STATE_STREAMING:
119
+ if (impl->direction == PW_DIRECTION_OUTPUT) {
120
+ pw_loop_update_io(impl->data_loop, impl->socket, SPA_IO_IN);
121
+ impl->driving = pw_stream_is_driving(impl->stream);
122
+ if (impl->driving) {
123
+ impl->next_time = get_time_ns(impl);
124
+ set_timeout(impl, impl->next_time);
125
+ }
126
+ }
127
break;
128
default:
129
break;
130
131
continue;
132
} else if (errno == EAGAIN || errno == EWOULDBLOCK) {
133
/* Don't continue writing */
134
+ pw_log_debug("pipe (%s) overrun: %m",
135
+ impl->filename);
136
break;
137
} else {
138
- pw_log_warn("Failed to write to pipe sink");
139
+ pw_log_warn("Failed to write to pipe (%s): %m",
140
+ impl->filename);
141
}
142
}
143
offs += written;
144
145
pw_stream_queue_buffer(impl->stream, buf);
146
}
147
148
+static void update_rate(struct impl *impl, uint32_t filled)
149
+{
150
+ float error;
151
+
152
+ if (impl->rate_match == NULL)
153
+ return;
154
+
155
+ error = (float)impl->target_buffer - (float)(filled);
156
+ error = SPA_CLAMP(error, -impl->max_error, impl->max_error);
157
+
158
+ impl->corr = spa_dll_update(&impl->dll, error);
159
+ pw_log_debug("error:%f corr:%f current:%u target:%u",
160
+ error, impl->corr, filled, impl->target_buffer);
161
+
162
+ if (!impl->driving) {
163
+ SPA_FLAG_SET(impl->rate_match->flags, SPA_IO_RATE_MATCH_FLAG_ACTIVE);
164
+ impl->rate_match->rate = 1.0f / impl->corr;
165
+ }
166
+}
167
+
168
static void capture_stream_process(void *data)
169
{
170
struct impl *impl = data;
171
struct pw_buffer *buf;
172
- struct spa_data *d;
173
- uint32_t req;
174
- ssize_t nread;
175
+ struct spa_data *bd;
176
+ uint32_t req, index, size;
177
+ int32_t avail;
178
179
if ((buf = pw_stream_dequeue_buffer(impl->stream)) == NULL) {
180
- pw_log_debug("out of buffers: %m");
181
+ pw_log_warn("out of buffers: %m");
182
return;
183
}
184
185
- d = &buf->buffer->datas0;
186
+ bd = &buf->buffer->datas0;
187
188
if ((req = buf->requested * impl->frame_size) == 0)
189
req = 4096 * impl->frame_size;
190
191
- req = SPA_MIN(req, d->maxsize);
192
+ size = SPA_MIN(req, bd->maxsize);
193
+ size = SPA_ROUND_DOWN(size, impl->frame_size);
194
195
- d->chunk->offset = 0;
196
- d->chunk->stride = impl->frame_size;
197
- d->chunk->size = SPA_MIN(req, impl->leftover_count);
198
- memcpy(d->data, impl->leftover, d->chunk->size);
199
- req -= d->chunk->size;
200
+ avail = spa_ringbuffer_get_read_index(&impl->ring, &index);
201
pipewire-0.3.79.tar.gz/src/modules/module-protocol-pulse/manager.c -> pipewire-0.3.80.tar.gz/src/modules/module-protocol-pulse/manager.c
Changed
28
1
2
case SPA_PARAM_EnumRoute:
3
changed++;
4
break;
5
- case SPA_PARAM_Route:
6
+ default:
7
break;
8
}
9
add_param(&o->pending_list, info->paramsi.seq, id, NULL);
10
11
continue;
12
info->paramsi.user = 0;
13
14
- changed++;
15
+ switch (id) {
16
+ case SPA_PARAM_Props:
17
+ case SPA_PARAM_PropInfo:
18
+ case SPA_PARAM_Format:
19
+ case SPA_PARAM_EnumFormat:
20
+ changed++;
21
+ break;
22
+ default:
23
+ break;
24
+ }
25
add_param(&o->pending_list, info->paramsi.seq, id, NULL);
26
if (!(info->paramsi.flags & SPA_PARAM_INFO_READ))
27
continue;
28
pipewire-0.3.79.tar.gz/src/modules/module-protocol-pulse/module.c -> pipewire-0.3.80.tar.gz/src/modules/module-protocol-pulse/module.c
Changed
76
1
2
}
3
}
4
5
+static bool find_key(const char * const keys, const char *key)
6
+{
7
+ for (int i = 0; keysi != NULL; i++)
8
+ if (spa_streq(keysi, key))
9
+ return true;
10
+ return false;
11
+}
12
+
13
+static int module_args_check(struct pw_properties *props, const char * const valid_args)
14
+{
15
+ if (valid_args != NULL) {
16
+ const struct spa_dict_item *it;
17
+ spa_dict_for_each(it, &props->dict) {
18
+ if (!find_key(valid_args, it->key)) {
19
+ pw_log_warn("'%s' is not a valid module argument key", it->key);
20
+ return -EINVAL;
21
+ }
22
+ }
23
+ }
24
+ return 0;
25
+}
26
+
27
int module_args_to_audioinfo_keys(struct impl *impl, struct pw_properties *props,
28
const char *key_format, const char *key_rate,
29
const char *key_channels, const char *key_channel_map,
30
31
{
32
const struct module_info *info;
33
struct module *module;
34
+ int res;
35
36
info = find_module_info(name);
37
if (info == NULL) {
38
39
return NULL;
40
41
module->props = pw_properties_new(NULL, NULL);
42
- if (module->props == NULL) {
43
- module_free(module);
44
- return NULL;
45
- }
46
+ if (module->props == NULL)
47
+ goto error_free;
48
49
if (args)
50
module_args_add_props(module->props, args);
51
+ if ((res = module_args_check(module->props, info->valid_args)) < 0) {
52
+ errno = -res;
53
+ goto error_free;
54
+ }
55
56
- int res = module->info->prepare(module);
57
- if (res < 0) {
58
- module_free(module);
59
+ if ((res = module->info->prepare(module)) < 0) {
60
errno = -res;
61
- return NULL;
62
+ goto error_free;
63
}
64
65
module->index = pw_map_insert_new(&impl->modules, module);
66
67
module->index |= MODULE_FLAG;
68
69
return module;
70
+
71
+error_free:
72
+ module_free(module);
73
+ return NULL;
74
+
75
}
76
pipewire-0.3.79.tar.gz/src/modules/module-protocol-pulse/module.h -> pipewire-0.3.80.tar.gz/src/modules/module-protocol-pulse/module.h
Changed
9
1
2
int (*load) (struct module *module);
3
int (*unload) (struct module *module);
4
5
+ const char* const *valid_args;
6
const struct spa_dict *properties;
7
size_t data_size;
8
};
9
pipewire-0.3.79.tar.gz/src/modules/module-protocol-pulse/modules/module-pipe-sink.c -> pipewire-0.3.80.tar.gz/src/modules/module-protocol-pulse/modules/module-pipe-sink.c
Changed
116
1
2
struct pw_impl_module *mod;
3
4
struct pw_properties *global_props;
5
- struct pw_properties *capture_props;
6
+ struct pw_properties *stream_props;
7
};
8
9
static void module_destroy(void *data)
10
11
char *args;
12
size_t size;
13
14
- pw_properties_setf(data->capture_props, "pulse.module.id",
15
+ pw_properties_setf(data->stream_props, "pulse.module.id",
16
"%u", module->index);
17
18
if ((f = open_memstream(&args, &size)) == NULL)
19
20
fprintf(f, "{");
21
pw_properties_serialize_dict(f, &data->global_props->dict, 0);
22
fprintf(f, " \"stream.props\": {");
23
- pw_properties_serialize_dict(f, &data->capture_props->dict, 0);
24
+ pw_properties_serialize_dict(f, &data->stream_props->dict, 0);
25
fprintf(f, " } }");
26
fclose(f);
27
28
29
pw_impl_module_destroy(d->mod);
30
d->mod = NULL;
31
}
32
- pw_properties_free(d->capture_props);
33
+ pw_properties_free(d->stream_props);
34
pw_properties_free(d->global_props);
35
return 0;
36
}
37
38
"format=<sample format> "
39
"rate=<sample rate> "
40
"channels=<number of channels> "
41
- "channel_map=<channel map> " },
42
+ "channel_map=<channel map> "
43
+ "use_system_clock_for_timing=<yes or no> " },
44
{ PW_KEY_MODULE_VERSION, PACKAGE_VERSION },
45
};
46
47
48
{
49
struct module_pipesink_data * const d = module->user_data;
50
struct pw_properties * const props = module->props;
51
- struct pw_properties *global_props = NULL, *capture_props = NULL;
52
+ struct pw_properties *global_props = NULL, *stream_props = NULL;
53
struct spa_audio_info_raw info = { 0 };
54
const char *str;
55
+ bool use_system_clock;
56
int res = 0;
57
58
PW_LOG_TOPIC_INIT(mod_topic);
59
60
global_props = pw_properties_new(NULL, NULL);
61
- capture_props = pw_properties_new(NULL, NULL);
62
- if (!global_props || !capture_props) {
63
+ stream_props = pw_properties_new(NULL, NULL);
64
+ if (!global_props || !stream_props) {
65
res = -EINVAL;
66
goto out;
67
}
68
69
audioinfo_to_properties(&info, global_props);
70
71
if ((str = pw_properties_get(props, "sink_name")) != NULL) {
72
- pw_properties_set(capture_props, PW_KEY_NODE_NAME, str);
73
+ pw_properties_set(stream_props, PW_KEY_NODE_NAME, str);
74
pw_properties_set(props, "sink_name", NULL);
75
}
76
if ((str = pw_properties_get(props, "sink_properties")) != NULL)
77
- module_args_add_props(capture_props, str);
78
+ module_args_add_props(stream_props, str);
79
80
if ((str = pw_properties_get(props, "file")) != NULL) {
81
pw_properties_set(global_props, "pipe.filename", str);
82
pw_properties_set(props, "file", NULL);
83
}
84
- if ((str = pw_properties_get(capture_props, PW_KEY_DEVICE_ICON_NAME)) == NULL)
85
- pw_properties_set(capture_props, PW_KEY_DEVICE_ICON_NAME,
86
+ str = pw_properties_get(props, "use_system_clock_for_timing");
87
+ use_system_clock = str ? module_args_parse_bool(str) : false;
88
+
89
+ if ((str = pw_properties_get(stream_props, PW_KEY_NODE_GROUP)) == NULL) {
90
+ if (use_system_clock)
91
+ pw_properties_set(stream_props, PW_KEY_NODE_GROUP,
92
+ "pipewire.dummy");
93
+ }
94
+ if ((str = pw_properties_get(stream_props, PW_KEY_DEVICE_ICON_NAME)) == NULL)
95
+ pw_properties_set(stream_props, PW_KEY_DEVICE_ICON_NAME,
96
"audio-card");
97
- if ((str = pw_properties_get(capture_props, PW_KEY_NODE_NAME)) == NULL)
98
- pw_properties_set(capture_props, PW_KEY_NODE_NAME,
99
+ if ((str = pw_properties_get(stream_props, PW_KEY_NODE_NAME)) == NULL)
100
+ pw_properties_set(stream_props, PW_KEY_NODE_NAME,
101
"fifo_output");
102
103
d->module = module;
104
d->global_props = global_props;
105
- d->capture_props = capture_props;
106
+ d->stream_props = stream_props;
107
108
return 0;
109
out:
110
pw_properties_free(global_props);
111
- pw_properties_free(capture_props);
112
+ pw_properties_free(stream_props);
113
return res;
114
}
115
116
pipewire-0.3.79.tar.gz/src/modules/module-protocol-pulse/modules/module-pipe-source.c -> pipewire-0.3.80.tar.gz/src/modules/module-protocol-pulse/modules/module-pipe-source.c
Changed
102
1
2
struct pw_impl_module *mod;
3
4
struct pw_properties *global_props;
5
- struct pw_properties *playback_props;
6
+ struct pw_properties *stream_props;
7
};
8
9
static void module_destroy(void *data)
10
11
char *args;
12
size_t size;
13
14
- pw_properties_setf(data->playback_props, "pulse.module.id",
15
+ pw_properties_setf(data->stream_props, "pulse.module.id",
16
"%u", module->index);
17
18
if ((f = open_memstream(&args, &size)) == NULL)
19
20
fprintf(f, "{");
21
pw_properties_serialize_dict(f, &data->global_props->dict, 0);
22
fprintf(f, " \"stream.props\": {");
23
- pw_properties_serialize_dict(f, &data->playback_props->dict, 0);
24
+ pw_properties_serialize_dict(f, &data->stream_props->dict, 0);
25
fprintf(f, " } }");
26
fclose(f);
27
28
29
pw_impl_module_destroy(d->mod);
30
d->mod = NULL;
31
}
32
- pw_properties_free(d->playback_props);
33
+ pw_properties_free(d->stream_props);
34
pw_properties_free(d->global_props);
35
return 0;
36
}
37
38
{
39
struct module_pipesrc_data * const d = module->user_data;
40
struct pw_properties * const props = module->props;
41
- struct pw_properties *global_props = NULL, *playback_props = NULL;
42
+ struct pw_properties *global_props = NULL, *stream_props = NULL;
43
struct spa_audio_info_raw info = { 0 };
44
const char *str;
45
int res = 0;
46
47
PW_LOG_TOPIC_INIT(mod_topic);
48
49
global_props = pw_properties_new(NULL, NULL);
50
- playback_props = pw_properties_new(NULL, NULL);
51
- if (!global_props || !playback_props) {
52
+ stream_props = pw_properties_new(NULL, NULL);
53
+ if (!global_props || !stream_props) {
54
res = -errno;
55
goto out;
56
}
57
58
audioinfo_to_properties(&info, global_props);
59
60
if ((str = pw_properties_get(props, "source_name")) != NULL) {
61
- pw_properties_set(playback_props, PW_KEY_NODE_NAME, str);
62
+ pw_properties_set(stream_props, PW_KEY_NODE_NAME, str);
63
pw_properties_set(props, "source_name", NULL);
64
}
65
if ((str = pw_properties_get(props, "source_properties")) != NULL)
66
- module_args_add_props(playback_props, str);
67
+ module_args_add_props(stream_props, str);
68
69
if ((str = pw_properties_get(props, "file")) != NULL) {
70
pw_properties_set(global_props, "pipe.filename", str);
71
pw_properties_set(props, "file", NULL);
72
}
73
- if ((str = pw_properties_get(playback_props, PW_KEY_DEVICE_ICON_NAME)) == NULL)
74
- pw_properties_set(playback_props, PW_KEY_DEVICE_ICON_NAME,
75
+ if ((str = pw_properties_get(stream_props, PW_KEY_DEVICE_ICON_NAME)) == NULL)
76
+ pw_properties_set(stream_props, PW_KEY_DEVICE_ICON_NAME,
77
"audio-input-microphone");
78
- if ((str = pw_properties_get(playback_props, PW_KEY_NODE_NAME)) == NULL)
79
- pw_properties_set(playback_props, PW_KEY_NODE_NAME,
80
+ if ((str = pw_properties_get(stream_props, PW_KEY_NODE_NAME)) == NULL)
81
+ pw_properties_set(stream_props, PW_KEY_NODE_NAME,
82
"fifo_input");
83
84
+ if ((str = pw_properties_get(stream_props, PW_KEY_NODE_DRIVER)) == NULL)
85
+ pw_properties_set(stream_props, PW_KEY_NODE_DRIVER, "true");
86
+ if ((str = pw_properties_get(stream_props, PW_KEY_PRIORITY_DRIVER)) == NULL)
87
+ pw_properties_set(stream_props, PW_KEY_PRIORITY_DRIVER, "50000");
88
+
89
d->module = module;
90
- d->playback_props = playback_props;
91
+ d->stream_props = stream_props;
92
d->global_props = global_props;
93
94
return 0;
95
out:
96
pw_properties_free(global_props);
97
- pw_properties_free(playback_props);
98
+ pw_properties_free(stream_props);
99
return res;
100
}
101
102
pipewire-0.3.79.tar.gz/src/modules/module-protocol-pulse/modules/module-roc-sink.c -> pipewire-0.3.80.tar.gz/src/modules/module-protocol-pulse/modules/module-roc-sink.c
Changed
25
1
2
return 0;
3
}
4
5
+static const char* const valid_args = {
6
+ "sink_name",
7
+ "sink_properties",
8
+ "fec_code",
9
+ "remote_ip",
10
+ "remote_source_port",
11
+ "remote_repair_port",
12
+ NULL
13
+};
14
static const struct spa_dict_item module_roc_sink_info = {
15
{ PW_KEY_MODULE_AUTHOR, "Sanchayan Maity <sanchayan@asymptotic.io>" },
16
{ PW_KEY_MODULE_DESCRIPTION, "roc sink" },
17
18
19
DEFINE_MODULE_INFO(module_roc_sink) = {
20
.name = "module-roc-sink",
21
+ .valid_args = valid_args,
22
.prepare = module_roc_sink_prepare,
23
.load = module_roc_sink_load,
24
.unload = module_roc_sink_unload,
25
pipewire-0.3.79.tar.gz/src/modules/module-protocol-pulse/modules/module-roc-source.c -> pipewire-0.3.80.tar.gz/src/modules/module-protocol-pulse/modules/module-roc-source.c
Changed
28
1
2
return 0;
3
}
4
5
+static const char* const valid_args = {
6
+ "source_name",
7
+ "source_properties",
8
+ "resampler_profile",
9
+ "fec_code",
10
+ "sess_latency_msec",
11
+ "local_ip",
12
+ "local_source_port",
13
+ "local_repair_port",
14
+ NULL
15
+};
16
+
17
static const struct spa_dict_item module_roc_source_info = {
18
{ PW_KEY_MODULE_AUTHOR, "Sanchayan Maity <sanchayan@asymptotic.io>" },
19
{ PW_KEY_MODULE_DESCRIPTION, "roc source" },
20
21
22
DEFINE_MODULE_INFO(module_roc_source) = {
23
.name = "module-roc-source",
24
+ .valid_args = valid_args,
25
.prepare = module_roc_source_prepare,
26
.load = module_roc_source_load,
27
.unload = module_roc_source_unload,
28
pipewire-0.3.79.tar.gz/src/modules/module-protocol-pulse/pulse-server.c -> pipewire-0.3.80.tar.gz/src/modules/module-protocol-pulse/pulse-server.c
Changed
15
1
2
allow_monitor = true;
3
}
4
}
5
- } else if (index == SPA_ID_INVALID)
6
+ } else if (index != SPA_ID_INVALID) {
7
+ if (!sink)
8
+ allow_monitor = true;
9
+ } else {
10
return NULL;
11
+ }
12
13
14
spa_zero(sel);
15
pipewire-0.3.79.tar.gz/src/modules/module-protocol-pulse/stream.c -> pipewire-0.3.80.tar.gz/src/modules/module-protocol-pulse/stream.c
Changed
17
1
2
struct client *client = stream->client;
3
struct impl *impl = client->impl;
4
struct message *reply;
5
- int missed;
6
+ int suppressed;
7
8
- if ((missed = spa_ratelimit_test(&impl->rate_limit, stream->timestamp)) >= 0) {
9
- pw_log_info("%s: UNDERFLOW channel:%u offset:%" PRIi64" (%d missed)",
10
- client->name, stream->channel, offset, missed);
11
+ if ((suppressed = spa_ratelimit_test(&impl->rate_limit, stream->timestamp)) >= 0) {
12
+ pw_log_info("%s: UNDERFLOW channel:%u offset:%" PRIi64" (%d suppressed)",
13
+ client->name, stream->channel, offset, suppressed);
14
}
15
16
reply = message_alloc(impl, -1, 0);
17
pipewire-0.3.79.tar.gz/src/modules/module-pulse-tunnel.c -> pipewire-0.3.80.tar.gz/src/modules/module-pulse-tunnel.c
Changed
67
1
2
req = 4096 * impl->frame_size;
3
4
size = SPA_MIN(bd->maxsize, req);
5
+ size = SPA_ROUND_DOWN(size, impl->frame_size);
6
7
avail = spa_ringbuffer_get_read_index(&impl->ring, &index);
8
- if (avail < (int32_t)size) {
9
+ if (avail < (int32_t)size)
10
memset(bd->data, 0, size);
11
- } else {
12
- if (avail > (int32_t)RINGBUFFER_SIZE) {
13
- avail = impl->target_buffer;
14
- index += avail - impl->target_buffer;
15
- } else {
16
- update_rate(impl, avail / impl->frame_size);
17
- }
18
+ if (avail > (int32_t)RINGBUFFER_SIZE) {
19
+ index += avail - impl->target_buffer;
20
+ avail = impl->target_buffer;
21
+ }
22
+ if (avail > 0) {
23
+ avail = SPA_ROUND_DOWN(avail, impl->frame_size);
24
+ update_rate(impl, avail / impl->frame_size);
25
+
26
+ avail = SPA_MIN(size, (uint32_t)avail);
27
spa_ringbuffer_read_data(&impl->ring,
28
impl->buffer, RINGBUFFER_SIZE,
29
index & RINGBUFFER_MASK,
30
- bd->data, size);
31
+ bd->data, avail);
32
33
- index += size;
34
+ index += avail;
35
spa_ringbuffer_read_update(&impl->ring, index);
36
}
37
bd->chunk->offset = 0;
38
39
{
40
struct impl *impl = userdata;
41
struct timespec ts;
42
- int missed;
43
+ int suppressed;
44
45
clock_gettime(CLOCK_MONOTONIC, &ts);
46
- if ((missed = spa_ratelimit_test(&impl->rate_limit, SPA_TIMESPEC_TO_NSEC(&ts))) >= 0)
47
- pw_log_warn("underflow (%d missed)", missed);
48
+ if ((suppressed = spa_ratelimit_test(&impl->rate_limit, SPA_TIMESPEC_TO_NSEC(&ts))) >= 0)
49
+ pw_log_warn("underflow (%d suppressed)", suppressed);
50
impl->resync = true;
51
}
52
static void stream_overflow_cb(pa_stream *s, void *userdata)
53
{
54
struct impl *impl = userdata;
55
struct timespec ts;
56
- int missed;
57
+ int suppressed;
58
59
clock_gettime(CLOCK_MONOTONIC, &ts);
60
- if ((missed = spa_ratelimit_test(&impl->rate_limit, SPA_TIMESPEC_TO_NSEC(&ts))) >= 0)
61
- pw_log_warn("overflow (%d missed)", missed);
62
+ if ((suppressed = spa_ratelimit_test(&impl->rate_limit, SPA_TIMESPEC_TO_NSEC(&ts))) >= 0)
63
+ pw_log_warn("overflow (%d suppressed)", suppressed);
64
impl->resync = true;
65
}
66
67
pipewire-0.3.79.tar.gz/src/modules/module-rtp-source.c -> pipewire-0.3.80.tar.gz/src/modules/module-rtp-source.c
Changed
10
1
2
* The `rtp-source` module creates a PipeWire source that receives audio
3
* and midi RTP packets.
4
*
5
- * This module is usually loaded from the \page page_module_rtp_sap so that the
6
+ * This module is usually loaded from the \ref page_module_rtp_sap so that the
7
* source.ip and source.port and format parameters matches that of the sender.
8
*
9
* ## Module Options
10
pipewire-0.3.79.tar.gz/src/pipewire/context.c -> pipewire-0.3.80.tar.gz/src/pipewire/context.c
Changed
38
1
2
spa_list_for_each(l, &p->links, input_link) {
3
t = l->output->node;
4
5
- if (!t->active || !l->prepared || (!t->driving && t->runnable))
6
+ if (!t->active || !l->prepared || (!t->driving && SPA_FLAG_IS_SET(t->checked, 1u<<direction)))
7
continue;
8
9
pw_log_debug(" peer %p: '%s'", t, t->name);
10
11
spa_list_for_each(l, &p->links, output_link) {
12
t = l->input->node;
13
14
- if (!t->active || !l->prepared || (!t->driving && t->runnable))
15
+ if (!t->active || !l->prepared || (!t->driving && SPA_FLAG_IS_SET(t->checked, 1u<<direction)))
16
continue;
17
18
pw_log_debug(" peer %p: '%s'", t, t->name);
19
20
if (node->link_group != NULL) {
21
spa_list_for_each(t, nodes, sort_link) {
22
if (t->exported || !t->active ||
23
- SPA_FLAG_IS_SET(t->checked, 1u<<direction))
24
+ SPA_FLAG_IS_SET(t->checked, 1u<<direction))
25
continue;
26
if (!spa_streq(t->link_group, node->link_group))
27
continue;
28
29
n->rt.position->clock.rate = n->target_rate;
30
}
31
n->target_pending = false;
32
+ } else {
33
+ n->target_quantum = n->rt.position->clock.target_duration;
34
+ n->target_rate = n->rt.position->clock.target_rate;
35
}
36
37
pw_log_debug("%p: driver %p running:%d runnable:%d quantum:%u '%s'",
38
pipewire-0.3.79.tar.gz/src/pipewire/filter.c -> pipewire-0.3.80.tar.gz/src/pipewire/filter.c
Changed
63
1
2
#define PORT_Format 3
3
#define PORT_Buffers 4
4
#define PORT_Latency 5
5
-#define N_PORT_PARAMS 6
6
+#define PORT_Tag 6
7
+#define N_PORT_PARAMS 7
8
struct spa_param_info paramsN_PORT_PARAMS;
9
10
struct spa_io_buffers *io;
11
12
return PORT_Buffers;
13
case SPA_PARAM_Latency:
14
return PORT_Latency;
15
+ case SPA_PARAM_Tag:
16
+ return PORT_Tag;
17
default:
18
return -1;
19
}
20
}
21
22
-static void fix_datatype(const struct spa_pod *param)
23
+static void fix_datatype(struct spa_pod *param)
24
{
25
const struct spa_pod_prop *pod_param;
26
- const struct spa_pod *vals;
27
+ struct spa_pod *vals;
28
uint32_t dataType, n_vals, choice;
29
30
pod_param = spa_pod_find_prop(param, NULL, SPA_PARAM_BUFFERS_dataType);
31
32
if (p == NULL)
33
return NULL;
34
35
- if (id == SPA_PARAM_Buffers && port != NULL &&
36
- SPA_FLAG_IS_SET(port->flags, PW_FILTER_PORT_FLAG_MAP_BUFFERS) &&
37
- port->direction == SPA_DIRECTION_INPUT)
38
- fix_datatype(param);
39
-
40
if (id == SPA_PARAM_ProcessLatency && port == NULL)
41
spa_process_latency_parse(param, &impl->process_latency);
42
43
44
memcpy(p->param, param, SPA_POD_SIZE(param));
45
SPA_POD_OBJECT_ID(p->param) = id;
46
47
+ if (id == SPA_PARAM_Buffers && port != NULL &&
48
+ SPA_FLAG_IS_SET(port->flags, PW_FILTER_PORT_FLAG_MAP_BUFFERS) &&
49
+ port->direction == SPA_DIRECTION_INPUT)
50
+ fix_datatype(p->param);
51
+
52
pw_log_debug("%p: port %p param id %d (%s)", impl, p, id,
53
spa_debug_type_find_name(spa_type_param, id));
54
55
56
p->paramsPORT_Format = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE);
57
p->paramsPORT_Buffers = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0);
58
p->paramsPORT_Latency = SPA_PARAM_INFO(SPA_PARAM_Latency, SPA_PARAM_INFO_WRITE);
59
+ p->paramsPORT_Tag = SPA_PARAM_INFO(SPA_PARAM_Tag, SPA_PARAM_INFO_WRITE);
60
p->info.params = p->params;
61
p->info.n_params = N_PORT_PARAMS;
62
63
pipewire-0.3.79.tar.gz/src/pipewire/impl-link.c -> pipewire-0.3.80.tar.gz/src/pipewire/impl-link.c
Changed
70
1
2
pw_impl_port_emit_link_removed(this->input, this);
3
4
pw_impl_port_recalc_latency(this->input);
5
+ pw_impl_port_recalc_tag(this->input);
6
7
if ((res = pw_impl_port_use_buffers(port, mix, 0, NULL, 0)) < 0) {
8
pw_log_warn("%p: port %p clear error %s", this, port, spa_strerror(res));
9
10
pw_impl_port_emit_link_removed(this->output, this);
11
12
pw_impl_port_recalc_latency(this->output);
13
+ pw_impl_port_recalc_tag(this->output);
14
15
/* we don't clear output buffers when the link goes away. They will get
16
* cleared when the node goes to suspend */
17
18
pw_impl_port_recalc_latency(this->output);
19
}
20
21
+static void input_port_tag_changed(void *data)
22
+{
23
+ struct impl *impl = data;
24
+ struct pw_impl_link *this = &impl->this;
25
+ if (!this->feedback)
26
+ pw_impl_port_recalc_tag(this->output);
27
+}
28
+
29
static void output_port_latency_changed(void *data)
30
{
31
struct impl *impl = data;
32
33
pw_impl_port_recalc_latency(this->input);
34
}
35
36
+static void output_port_tag_changed(void *data)
37
+{
38
+ struct impl *impl = data;
39
+ struct pw_impl_link *this = &impl->this;
40
+ if (!this->feedback)
41
+ pw_impl_port_recalc_tag(this->input);
42
+}
43
+
44
static const struct pw_impl_port_events input_port_events = {
45
PW_VERSION_IMPL_PORT_EVENTS,
46
.param_changed = input_port_param_changed,
47
.state_changed = input_port_state_changed,
48
.latency_changed = input_port_latency_changed,
49
+ .tag_changed = input_port_tag_changed,
50
};
51
52
static const struct pw_impl_port_events output_port_events = {
53
54
.param_changed = output_port_param_changed,
55
.state_changed = output_port_state_changed,
56
.latency_changed = output_port_latency_changed,
57
+ .tag_changed = output_port_tag_changed,
58
};
59
60
static void node_result(struct impl *impl, void *obj,
61
62
63
pw_impl_port_recalc_latency(output);
64
pw_impl_port_recalc_latency(input);
65
+ pw_impl_port_recalc_tag(output);
66
+ pw_impl_port_recalc_tag(input);
67
68
if (impl->onode != impl->inode)
69
this->peer = pw_node_peer_ref(impl->onode, impl->inode);
70
pipewire-0.3.79.tar.gz/src/pipewire/impl-node.c -> pipewire-0.3.80.tar.gz/src/pipewire/impl-node.c
Changed
95
1
2
struct pw_node_activation *na = driver->rt.target.activation;
3
struct spa_io_clock *cl = &na->position.clock;
4
enum spa_log_level level = SPA_LOG_LEVEL_DEBUG;
5
- int missed;
6
+ int suppressed;
7
8
- if ((missed = spa_ratelimit_test(&driver->rt.rate_limit, nsec)) >= 0)
9
+ if ((suppressed = spa_ratelimit_test(&driver->rt.rate_limit, nsec)) >= 0)
10
level = SPA_LOG_LEVEL_INFO;
11
12
spa_list_for_each(t, &driver->rt.target_list, link) {
13
14
a->status == PW_NODE_ACTIVATION_AWAKE) {
15
update_xrun_stats(a, nsec / 1000, 0);
16
17
- pw_log(level, "(%s-%u) client too slow! rate:%u/%u pos:%"PRIu64" status:%s (%u missed)",
18
+ pw_log(level, "(%s-%u) client too slow! rate:%u/%u pos:%"PRIu64" status:%s (%u suppressed)",
19
t->name, t->id,
20
(uint32_t)(cl->rate.num * cl->duration), cl->rate.denom,
21
cl->position, str_status(a->status),
22
- missed);
23
+ suppressed);
24
}
25
pw_log_debug("(%s-%u) state:%p pending:%d/%d s:%"PRIu64" a:%"PRIu64" f:%"PRIu64
26
" waiting:%"PRIu64" process:%"PRIu64" status:%s sync:%d",
27
28
struct pw_node_activation *da = this->rt.driver_target.activation;
29
struct spa_system *data_system = this->data_system;
30
uint64_t nsec = get_time_ns(data_system);
31
- int missed;
32
+ int suppressed;
33
34
update_xrun_stats(a, trigger, delay);
35
36
- if ((missed = spa_ratelimit_test(&this->rt.rate_limit, nsec)) >= 0) {
37
+ if ((suppressed = spa_ratelimit_test(&this->rt.rate_limit, nsec)) >= 0) {
38
struct spa_fraction rate;
39
if (da) {
40
struct spa_io_clock *cl = &da->position.clock;
41
42
rate = SPA_FRACTION(0,0);
43
}
44
pw_log_info("(%s-%d) XRun! rate:%u/%u count:%u time:%"PRIu64
45
- " delay:%"PRIu64" max:%"PRIu64" (%d missed)",
46
+ " delay:%"PRIu64" max:%"PRIu64" (%d suppressed)",
47
this->name, this->info.id,
48
rate.num, rate.denom, a->xrun_count,
49
trigger, delay, a->max_delay,
50
- missed);
51
+ suppressed);
52
}
53
54
pw_impl_node_rt_emit_xrun(this);
55
56
uint32_t id, uint32_t index, uint32_t next,
57
struct spa_pod *param);
58
int seq;
59
- uint32_t count;
60
unsigned int cache:1;
61
};
62
63
64
const struct spa_result_node_params *r = result;
65
if (d->seq == seq) {
66
d->callback(d->data, seq, r->id, r->index, r->next, r->param);
67
- if (d->cache) {
68
- if (d->count++ == 0)
69
- pw_param_add(&impl->pending_list, seq, r->id, NULL);
70
+ if (d->cache)
71
pw_param_add(&impl->pending_list, seq, r->id, r->param);
72
- }
73
}
74
break;
75
}
76
77
{
78
int res;
79
struct impl *impl = SPA_CONTAINER_OF(node, struct impl, this);
80
- struct result_node_params_data user_data = { impl, data, callback, seq, 0, false };
81
+ struct result_node_params_data user_data = { impl, data, callback, seq, false };
82
struct spa_hook listener;
83
struct spa_param_info *pi;
84
static const struct spa_node_events node_events = {
85
86
user_data.cache = impl->cache_params &&
87
(filter == NULL && index == 0 && max == UINT32_MAX);
88
89
+ if (user_data.cache)
90
+ pw_param_add(&impl->pending_list, seq, param_id, NULL);
91
+
92
spa_zero(listener);
93
spa_node_add_listener(node->node, &listener, &node_events, &user_data);
94
res = spa_node_enum_params(node->node, seq,
95
pipewire-0.3.79.tar.gz/src/pipewire/impl-port.c -> pipewire-0.3.80.tar.gz/src/pipewire/impl-port.c
Changed
201
1
2
3
#include <spa/pod/parser.h>
4
#include <spa/param/audio/format-utils.h>
5
+#include <spa/param/tag-utils.h>
6
#include <spa/node/utils.h>
7
#include <spa/utils/names.h>
8
#include <spa/utils/string.h>
9
10
#include <spa/debug/types.h>
11
#include <spa/pod/filter.h>
12
#include <spa/pod/dynamic.h>
13
+#include <spa/debug/pod.h>
14
15
#include "pipewire/impl.h"
16
#include "pipewire/private.h"
17
18
struct pw_impl_port *this = data;
19
struct spa_latency_info latency;
20
21
- if (id != SPA_PARAM_Latency)
22
+ if (id != SPA_PARAM_Latency || param == NULL)
23
return -EINVAL;
24
25
if (spa_latency_parse(param, &latency) < 0)
26
27
28
return 0;
29
}
30
+static int process_tag_param(void *data, int seq,
31
+ uint32_t id, uint32_t index, uint32_t next, struct spa_pod *param)
32
+{
33
+ struct pw_impl_port *this = data;
34
+ struct spa_tag_info info;
35
+ struct spa_pod *old;
36
+ void *state = NULL;
37
+
38
+ if (id != SPA_PARAM_Tag || param == NULL)
39
+ return -EINVAL;
40
+ if (spa_tag_parse(param, &info, &state) < 0)
41
+ return 0;
42
+
43
+ old = this->taginfo.direction;
44
+
45
+ if (spa_tag_compare(old, param) == 0)
46
+ return 0;
47
+
48
+ pw_log_debug("port %p: got %s tag %p", this,
49
+ pw_direction_as_string(info.direction), param);
50
+ if (param)
51
+ pw_log_pod(SPA_LOG_LEVEL_DEBUG, param);
52
+
53
+ free(old);
54
+ this->taginfo.direction = spa_pod_copy(param);
55
+
56
+ if (info.direction == this->direction)
57
+ pw_impl_port_emit_tag_changed(this);
58
+
59
+ return 0;
60
+}
61
62
static void update_info(struct pw_impl_port *port, const struct spa_port_info *info)
63
{
64
65
pw_impl_port_for_each_param(port, 0, id, 0, UINT32_MAX,
66
NULL, process_latency_param, port);
67
break;
68
+ case SPA_PARAM_Tag:
69
+ port->have_tag_param =
70
+ SPA_FLAG_IS_SET(info->paramsi.flags, SPA_PARAM_INFO_WRITE);
71
+ if (port->node != NULL)
72
+ pw_impl_port_for_each_param(port, 0, id, 0, UINT32_MAX,
73
+ NULL, process_tag_param, port);
74
+ break;
75
default:
76
break;
77
}
78
79
80
pw_impl_port_for_each_param(port, 0, SPA_PARAM_IO, 0, 0, NULL, check_param_io, port);
81
pw_impl_port_for_each_param(port, 0, SPA_PARAM_Latency, 0, 0, NULL, process_latency_param, port);
82
+ pw_impl_port_for_each_param(port, 0, SPA_PARAM_Tag, 0, 0, NULL, process_tag_param, port);
83
84
nprops = pw_impl_node_get_properties(node);
85
media_class = pw_properties_get(nprops, PW_KEY_MEDIA_CLASS);
86
87
88
pw_param_clear(&impl->param_list, SPA_ID_INVALID);
89
pw_param_clear(&impl->pending_list, SPA_ID_INVALID);
90
+ free(port->tagSPA_DIRECTION_INPUT);
91
+ free(port->tagSPA_DIRECTION_OUTPUT);
92
93
pw_map_clear(&port->mix_port_map);
94
95
96
uint32_t id, uint32_t index, uint32_t next,
97
struct spa_pod *param);
98
int seq;
99
- uint32_t count;
100
unsigned int cache:1;
101
};
102
103
104
const struct spa_result_node_params *r = result;
105
if (d->seq == seq) {
106
d->callback(d->data, seq, r->id, r->index, r->next, r->param);
107
- if (d->cache) {
108
- if (d->count++ == 0)
109
- pw_param_add(&impl->pending_list, seq, r->id, NULL);
110
+ if (d->cache)
111
pw_param_add(&impl->pending_list, seq, r->id, r->param);
112
- }
113
}
114
break;
115
}
116
117
int res;
118
struct impl *impl = SPA_CONTAINER_OF(port, struct impl, this);
119
struct pw_impl_node *node = port->node;
120
- struct result_port_params_data user_data = { impl, data, callback, seq, 0, false };
121
+ struct result_port_params_data user_data = { impl, data, callback, seq, false };
122
struct spa_hook listener;
123
struct spa_param_info *pi;
124
static const struct spa_node_events node_events = {
125
126
user_data.cache = impl->cache_params &&
127
(filter == NULL && index == 0 && max == UINT32_MAX);
128
129
+ if (user_data.cache)
130
+ pw_param_add(&impl->pending_list, seq, param_id, NULL);
131
+
132
spa_zero(listener);
133
spa_node_add_listener(node->node, &listener, &node_events, &user_data);
134
res = spa_node_port_enum_params(node->node, seq,
135
136
struct spa_pod_builder b = { 0 };
137
uint8_t buffer1024;
138
bool changed;
139
+ int count = 0;
140
141
if (port->destroying)
142
return 0;
143
144
latency.min_quantum, latency.max_quantum,
145
latency.min_rate, latency.max_rate,
146
latency.min_ns, latency.max_ns);
147
+ count++;
148
}
149
} else {
150
spa_list_for_each(l, &port->links, input_link) {
151
152
latency.min_quantum, latency.max_quantum,
153
latency.min_rate, latency.max_rate,
154
latency.min_ns, latency.max_ns);
155
+ count++;
156
}
157
}
158
spa_latency_info_combine_finish(&latency);
159
160
- current = &port->latencylatency.direction;
161
-
162
- changed = spa_latency_info_compare(current, &latency) != 0;
163
+ current = port->have_latency ? &port->latencylatency.direction : NULL;
164
+ if (current == NULL)
165
+ changed = count > 0;
166
+ else
167
+ changed = spa_latency_info_compare(current, &latency) != 0;
168
169
pw_log_info("port %d: %s %s latency %f-%f %d-%d %"PRIu64"-%"PRIu64,
170
port->info.id, changed ? "set" : "keep",
171
172
if (!changed)
173
return 0;
174
175
- *current = latency;
176
+ port->latencylatency.direction = latency;
177
+ port->have_latency = count > 0;
178
179
if (!port->have_latency_param)
180
return 0;
181
182
spa_pod_builder_init(&b, buffer, sizeof(buffer));
183
- param = spa_latency_build(&b, SPA_PARAM_Latency, &latency);
184
+ param = port->have_latency ? spa_latency_build(&b, SPA_PARAM_Latency, &latency) : NULL;
185
return pw_impl_port_set_param(port, SPA_PARAM_Latency, 0, param);
186
}
187
188
+int pw_impl_port_recalc_tag(struct pw_impl_port *port)
189
+{
190
+ struct pw_impl_link *l;
191
+ struct pw_impl_port *other;
192
+ struct spa_pod *param, *tag, *old;
193
+ struct spa_pod_dynamic_builder b = { 0 };
194
+ struct spa_pod_frame f;
195
+ struct spa_tag_info info;
196
+ enum spa_direction direction;
197
+ uint8_t buffer1024;
198
+ int count = 0;
199
+ bool changed;
200
+
201
pipewire-0.3.79.tar.gz/src/pipewire/impl-port.h -> pipewire-0.3.80.tar.gz/src/pipewire/impl-port.h
Changed
19
1
2
3
/** Port events, use \ref pw_impl_port_add_listener */
4
struct pw_impl_port_events {
5
-#define PW_VERSION_IMPL_PORT_EVENTS 2
6
+#define PW_VERSION_IMPL_PORT_EVENTS 3
7
uint32_t version;
8
9
/** The port is destroyed */
10
11
12
/** latency changed. Since version 2 */
13
void (*latency_changed) (void *data);
14
+ /** tag changed. Since version 3 */
15
+ void (*tag_changed) (void *data);
16
};
17
18
/** Create a new port
19
pipewire-0.3.79.tar.gz/src/pipewire/private.h -> pipewire-0.3.80.tar.gz/src/pipewire/private.h
Changed
28
1
2
#define pw_impl_port_emit_control_removed(p,c) pw_impl_port_emit(p, control_removed, 0, c)
3
#define pw_impl_port_emit_param_changed(p,i) pw_impl_port_emit(p, param_changed, 1, i)
4
#define pw_impl_port_emit_latency_changed(p) pw_impl_port_emit(p, latency_changed, 2)
5
+#define pw_impl_port_emit_tag_changed(p) pw_impl_port_emit(p, tag_changed, 3)
6
7
#define PW_IMPL_PORT_IS_CONTROL(port) SPA_FLAG_MASK((port)->flags, \
8
PW_IMPL_PORT_FLAG_BUFFERS|PW_IMPL_PORT_FLAG_CONTROL,\
9
10
struct spa_latency_info latency2; /**< latencies */
11
unsigned int have_latency_param:1;
12
unsigned int ignore_latency:1;
13
+ unsigned int have_latency:1;
14
+
15
+ unsigned int have_tag_param:1;
16
+ struct spa_pod *tag2; /**< tags */
17
18
void *owner_data; /**< extra owner data */
19
void *user_data; /**< extra user data */
20
21
struct spa_buffer **buffers, uint32_t n_buffers);
22
23
int pw_impl_port_recalc_latency(struct pw_impl_port *port);
24
+int pw_impl_port_recalc_tag(struct pw_impl_port *port);
25
26
/** Change the state of the node */
27
int pw_impl_node_set_state(struct pw_impl_node *node, enum pw_node_state state);
28
pipewire-0.3.79.tar.gz/src/pipewire/stream.c -> pipewire-0.3.80.tar.gz/src/pipewire/stream.c
Changed
62
1
2
#define PORT_Format 3
3
#define PORT_Buffers 4
4
#define PORT_Latency 5
5
-#define N_PORT_PARAMS 6
6
+#define PORT_Tag 6
7
+#define N_PORT_PARAMS 7
8
struct spa_param_info port_paramsN_PORT_PARAMS;
9
10
struct spa_list param_list;
11
12
return PORT_Buffers;
13
case SPA_PARAM_Latency:
14
return PORT_Latency;
15
+ case SPA_PARAM_Tag:
16
+ return PORT_Tag;
17
default:
18
return -1;
19
}
20
}
21
22
-static void fix_datatype(const struct spa_pod *param)
23
+static void fix_datatype(struct spa_pod *param)
24
{
25
const struct spa_pod_prop *pod_param;
26
- const struct spa_pod *vals;
27
+ struct spa_pod *vals;
28
uint32_t dataType, n_vals, choice;
29
30
pod_param = spa_pod_find_prop(param, NULL, SPA_PARAM_BUFFERS_dataType);
31
32
if (p == NULL)
33
return NULL;
34
35
- if (id == SPA_PARAM_Buffers &&
36
- SPA_FLAG_IS_SET(impl->flags, PW_STREAM_FLAG_MAP_BUFFERS) &&
37
- impl->direction == SPA_DIRECTION_INPUT)
38
- fix_datatype(param);
39
-
40
p->id = id;
41
p->flags = flags;
42
p->param = SPA_PTROFF(p, sizeof(struct param), struct spa_pod);
43
memcpy(p->param, param, SPA_POD_SIZE(param));
44
SPA_POD_OBJECT_ID(p->param) = id;
45
46
+ if (id == SPA_PARAM_Buffers &&
47
+ SPA_FLAG_IS_SET(impl->flags, PW_STREAM_FLAG_MAP_BUFFERS) &&
48
+ impl->direction == SPA_DIRECTION_INPUT)
49
+ fix_datatype(p->param);
50
+
51
spa_list_append(&impl->param_list, &p->link);
52
53
if ((idx = get_param_index(id)) != -1) {
54
55
impl->port_paramsPORT_Format = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE);
56
impl->port_paramsPORT_Buffers = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0);
57
impl->port_paramsPORT_Latency = SPA_PARAM_INFO(SPA_PARAM_Latency, SPA_PARAM_INFO_WRITE);
58
+ impl->port_paramsPORT_Tag = SPA_PARAM_INFO(SPA_PARAM_Tag, SPA_PARAM_INFO_WRITE);
59
impl->port_info.props = &impl->port_props->dict;
60
impl->port_info.params = impl->port_params;
61
impl->port_info.n_params = N_PORT_PARAMS;
62
pipewire-0.3.79.tar.gz/src/pipewire/stream.h -> pipewire-0.3.80.tar.gz/src/pipewire/stream.h
Changed
12
1
2
/** Update the param exposed on the stream. */
3
int
4
pw_stream_update_params(struct pw_stream *stream, /**< a \ref pw_stream */
5
- const struct spa_pod **params, /**< an array of params. The params should
6
- * ideally contain parameters for doing
7
- * buffer allocation. */
8
+ const struct spa_pod **params, /**< an array of params. */
9
uint32_t n_params /**< number of elements in \a params */);
10
11
/**
12
pipewire-0.3.79.tar.gz/src/tools/pw-cat.c -> pipewire-0.3.80.tar.gz/src/tools/pw-cat.c
Changed
118
1
2
#include <spa/param/audio/layout.h>
3
#include <spa/param/audio/format-utils.h>
4
#include <spa/param/audio/type-info.h>
5
+#include <spa/param/tag-utils.h>
6
#include <spa/param/props.h>
7
#include <spa/utils/result.h>
8
#include <spa/utils/string.h>
9
10
{
11
struct data data = { 0, };
12
struct pw_loop *l;
13
- const struct spa_pod *params1;
14
+ const struct spa_pod *params2;
15
+ uint32_t n_params = 0;
16
uint8_t buffer1024;
17
struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer));
18
const char *prog;
19
20
}
21
data.filename = argvoptind++;
22
23
- if (pw_properties_get(data.props, PW_KEY_MEDIA_TYPE) == NULL)
24
- pw_properties_set(data.props, PW_KEY_MEDIA_TYPE, data.media_type);
25
- if (pw_properties_get(data.props, PW_KEY_MEDIA_CATEGORY) == NULL)
26
- pw_properties_set(data.props, PW_KEY_MEDIA_CATEGORY, data.media_category);
27
- if (pw_properties_get(data.props, PW_KEY_MEDIA_ROLE) == NULL)
28
- pw_properties_set(data.props, PW_KEY_MEDIA_ROLE, data.media_role);
29
- if (pw_properties_get(data.props, PW_KEY_MEDIA_FILENAME) == NULL)
30
- pw_properties_set(data.props, PW_KEY_MEDIA_FILENAME, data.filename);
31
- if (pw_properties_get(data.props, PW_KEY_MEDIA_NAME) == NULL)
32
- pw_properties_set(data.props, PW_KEY_MEDIA_NAME, data.filename);
33
- if (pw_properties_get(data.props, PW_KEY_TARGET_OBJECT) == NULL)
34
- pw_properties_set(data.props, PW_KEY_TARGET_OBJECT, data.target);
35
-
36
/* make a main loop. If you already have another main loop, you can add
37
* the fd of this pipewire mainloop to it. */
38
data.loop = pw_main_loop_new(NULL);
39
40
}
41
ret = setup_properties(&data);
42
43
+ if (pw_properties_get(data.props, PW_KEY_MEDIA_TYPE) == NULL)
44
+ pw_properties_set(data.props, PW_KEY_MEDIA_TYPE, data.media_type);
45
+ if (pw_properties_get(data.props, PW_KEY_MEDIA_CATEGORY) == NULL)
46
+ pw_properties_set(data.props, PW_KEY_MEDIA_CATEGORY, data.media_category);
47
+ if (pw_properties_get(data.props, PW_KEY_MEDIA_ROLE) == NULL)
48
+ pw_properties_set(data.props, PW_KEY_MEDIA_ROLE, data.media_role);
49
+ if (pw_properties_get(data.props, PW_KEY_MEDIA_FILENAME) == NULL)
50
+ pw_properties_set(data.props, PW_KEY_MEDIA_FILENAME, data.filename);
51
+ if (pw_properties_get(data.props, PW_KEY_MEDIA_NAME) == NULL)
52
+ pw_properties_set(data.props, PW_KEY_MEDIA_NAME, data.filename);
53
+ if (pw_properties_get(data.props, PW_KEY_TARGET_OBJECT) == NULL)
54
+ pw_properties_set(data.props, PW_KEY_TARGET_OBJECT, data.target);
55
+
56
switch (data.data_type) {
57
#ifdef HAVE_PW_CAT_FFMPEG_INTEGRATION
58
case TYPE_ENCODED:
59
60
ret = av_codec_params_to_audio_info(&data, data.encoded.audio_stream->codecpar, &info);
61
if (ret < 0)
62
goto error_bad_file;
63
- params0 = spa_format_audio_build(&b, SPA_PARAM_EnumFormat, &info);
64
+ paramsn_params++ = spa_format_audio_build(&b, SPA_PARAM_EnumFormat, &info);
65
break;
66
}
67
#endif
68
69
if (data.channelmap.n_channels)
70
memcpy(info.position, data.channelmap.channels, data.channels * sizeof(int));
71
72
- params0 = spa_format_audio_raw_build(&b, SPA_PARAM_EnumFormat, &info);
73
+ paramsn_params++ = spa_format_audio_raw_build(&b, SPA_PARAM_EnumFormat, &info);
74
break;
75
}
76
case TYPE_MIDI:
77
- params0 = spa_pod_builder_add_object(&b,
78
+ paramsn_params++ = spa_pod_builder_add_object(&b,
79
SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat,
80
SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_application),
81
SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_control));
82
83
memcpy(info.position, i->info.position,
84
info.channels * sizeof(uint32_t));
85
}
86
- params0 = spa_format_audio_dsd_build(&b, SPA_PARAM_EnumFormat, &info);
87
+ paramsn_params++ = spa_format_audio_dsd_build(&b, SPA_PARAM_EnumFormat, &info);
88
break;
89
}
90
}
91
+ if (data.mode == mode_playback) {
92
+ struct spa_dict_item items64;
93
+ uint32_t i, n_items = 0;
94
+
95
+ for (i = 0; i < data.props->dict.n_items; i++) {
96
+ if (spa_strstartswith(data.props->dict.itemsi.key, "media."))
97
+ itemsn_items++ = data.props->dict.itemsi;
98
+ }
99
+ if (n_items > 0) {
100
+ struct spa_pod_frame f;
101
+ spa_tag_build_start(&b, &f, SPA_PARAM_Tag, SPA_DIRECTION_OUTPUT);
102
+ spa_tag_build_add_dict(&b, &SPA_DICT_INIT(items, n_items));
103
+ paramsn_params++ = spa_tag_build_end(&b, &f);
104
+ }
105
+ }
106
107
data.stream = pw_stream_new(data.core, prog, data.props);
108
data.props = NULL;
109
110
PW_ID_ANY,
111
flags |
112
PW_STREAM_FLAG_MAP_BUFFERS,
113
- params, 1);
114
+ params, n_params);
115
if (ret < 0) {
116
fprintf(stderr, "error: failed connect: %s\n", spa_strerror(ret));
117
goto error_connect_fail;
118
pipewire-0.3.79.tar.gz/src/tools/pw-mon.c -> pipewire-0.3.80.tar.gz/src/tools/pw-mon.c
Changed
201
1
2
3
struct spa_list pending_list;
4
struct spa_list global_list;
5
+
6
+ bool hide_params;
7
+ bool hide_props;
8
};
9
10
struct proxy_data {
11
12
spa_list_append(&data->param_list, &p->link);
13
}
14
15
-static void print_params(struct proxy_data *data, bool use_prefix)
16
+static void print_parameters(struct proxy_data *data, bool use_prefix)
17
{
18
struct param *p;
19
20
21
22
#define MARK_CHANGE(f) (!!(print_mark && ((info)->change_mask & (f))))
23
24
-static void on_core_info(void *data, const struct pw_core_info *info)
25
+static void on_core_info(void *_data, const struct pw_core_info *info)
26
{
27
- bool print_all = true, print_mark = true;
28
+ struct proxy_data *data = _data;
29
+ bool hide_props, print_mark = true;
30
+
31
+ hide_props = data->data->hide_props;
32
33
printf("\ttype: %s\n", PW_TYPE_INTERFACE_Core);
34
printf("\tcookie: %u\n", info->cookie);
35
36
printf("\thost-name: \"%s\"\n", info->host_name);
37
printf("\tversion: \"%s\"\n", info->version);
38
printf("\tname: \"%s\"\n", info->name);
39
- if (print_all) {
40
+ if (!hide_props) {
41
print_properties(info->props, MARK_CHANGE(PW_CORE_CHANGE_MASK_PROPS));
42
}
43
}
44
45
static void module_event_info(void *_data, const struct pw_module_info *info)
46
{
47
- struct proxy_data *data = _data;
48
- bool print_all, print_mark;
49
+ struct proxy_data *data = _data;
50
+ bool hide_props, print_mark;
51
52
- print_all = true;
53
- if (data->info == NULL) {
54
+ hide_props = data->data->hide_props;
55
+ if (data->info == NULL) {
56
printf("added:\n");
57
print_mark = false;
58
}
59
- else {
60
+ else {
61
printf("changed:\n");
62
print_mark = true;
63
}
64
65
printf("\tname: \"%s\"\n", info->name);
66
printf("\tfilename: \"%s\"\n", info->filename);
67
printf("\targs: \"%s\"\n", info->args);
68
- if (print_all) {
69
+ if (!hide_props) {
70
print_properties(info->props, MARK_CHANGE(PW_MODULE_CHANGE_MASK_PROPS));
71
}
72
}
73
74
static void print_node(struct proxy_data *data)
75
{
76
struct pw_node_info *info = data->info;
77
- bool print_all, print_mark;
78
+ bool hide_params, hide_props, print_mark;
79
80
- print_all = true;
81
- if (data->first) {
82
+ hide_params = data->data->hide_params;
83
+ hide_props = data->data->hide_props;
84
+
85
+ if (data->first) {
86
printf("added:\n");
87
print_mark = false;
88
data->first = false;
89
}
90
- else {
91
+ else {
92
printf("changed:\n");
93
print_mark = true;
94
}
95
96
printf("\tpermissions: "PW_PERMISSION_FORMAT"\n",
97
PW_PERMISSION_ARGS(data->permissions));
98
printf("\ttype: %s (version %d)\n", data->type, data->version);
99
- if (print_all) {
100
- print_params(data, MARK_CHANGE(PW_NODE_CHANGE_MASK_PARAMS));
101
+ if (!hide_params) {
102
+ print_parameters(data, MARK_CHANGE(PW_NODE_CHANGE_MASK_PARAMS));
103
with_prefix(MARK_CHANGE(PW_NODE_CHANGE_MASK_INPUT_PORTS)) {
104
printf("\tinput ports: %u/%u\n",
105
info->n_input_ports, info->max_input_ports);
106
107
printf(" \"%s\"\n", info->error);
108
else
109
printf("\n");
110
+ }
111
+
112
+ if (!hide_props) {
113
print_properties(info->props, MARK_CHANGE(PW_NODE_CHANGE_MASK_PROPS));
114
}
115
}
116
117
static void print_port(struct proxy_data *data)
118
{
119
struct pw_port_info *info = data->info;
120
- bool print_all, print_mark;
121
+ bool hide_params, hide_props, print_mark;
122
+
123
+ hide_params = data->data->hide_params;
124
+ hide_props = data->data->hide_props;
125
126
- print_all = true;
127
- if (data->first) {
128
+ if (data->first) {
129
printf("added:\n");
130
print_mark = false;
131
data->first = false;
132
}
133
- else {
134
+ else {
135
printf("changed:\n");
136
print_mark = true;
137
}
138
139
printf("\ttype: %s (version %d)\n", data->type, data->version);
140
141
printf("\tdirection: \"%s\"\n", pw_direction_as_string(info->direction));
142
- if (print_all) {
143
- print_params(data, MARK_CHANGE(PW_PORT_CHANGE_MASK_PARAMS));
144
+
145
+ if (!hide_params) {
146
+ print_parameters(data, MARK_CHANGE(PW_PORT_CHANGE_MASK_PARAMS));
147
+ }
148
+
149
+ if (!hide_props) {
150
print_properties(info->props, MARK_CHANGE(PW_PORT_CHANGE_MASK_PROPS));
151
}
152
}
153
154
static void factory_event_info(void *_data, const struct pw_factory_info *info)
155
{
156
struct proxy_data *data = _data;
157
- bool print_all, print_mark;
158
+ bool hide_props, print_mark;
159
+
160
+ hide_props = data->data->hide_props;
161
162
- print_all = true;
163
- if (data->info == NULL) {
164
+ if (data->info == NULL) {
165
printf("added:\n");
166
print_mark = false;
167
}
168
- else {
169
+ else {
170
printf("changed:\n");
171
print_mark = true;
172
}
173
174
175
printf("\tname: \"%s\"\n", info->name);
176
printf("\tobject-type: %s/%d\n", info->type, info->version);
177
- if (print_all) {
178
+ if (!hide_props) {
179
print_properties(info->props, MARK_CHANGE(PW_FACTORY_CHANGE_MASK_PROPS));
180
}
181
}
182
183
static void client_event_info(void *_data, const struct pw_client_info *info)
184
{
185
struct proxy_data *data = _data;
186
- bool print_all, print_mark;
187
+ bool hide_props, print_mark;
188
+
189
+ hide_props = data->data->hide_props;
190
191
- print_all = true;
192
- if (data->info == NULL) {
193
+ if (data->info == NULL) {
194
printf("added:\n");
195
print_mark = false;
196
}
197
- else {
198
+ else {
199
printf("changed:\n");
200
print_mark = true;
201
pipewire-0.3.79.tar.gz/src/tools/pw-top.c -> pipewire-0.3.80.tar.gz/src/tools/pw-top.c
Changed
12
1
2
{
3
fprintf(error ? stderr : stdout, "Usage:\n%s options\n\n"
4
"Options:\n"
5
- " -b, --batch-mode run in non-interactive batch_mode mode\n"
6
- " -n, --iterations = NUMBER exit on maximum iterations NUMBER\n"
7
+ " -b, --batch-mode run in non-interactive batch mode\n"
8
+ " -n, --iterations = NUMBER exit after NUMBER batch iterations\n"
9
" -r, --remote Remote daemon name\n"
10
"\n"
11
" -h, --help Show this help\n"
12
pipewire-0.3.80.tar.gz/subprojects/webrtc-audio-processing.wrap
Added
10
1
2
+wrap-git
3
+directory = webrtc-audio-processing
4
+url = https://gitlab.freedesktop.org/pulseaudio/webrtc-audio-processing.git
5
+push-url = git@gitlab.freedesktop.org:pulseaudio/webrtc-audio-processing.git
6
+revision = v1.3
7
+
8
+provide
9
+dependency_names = webrtc-audio-coding-1, webrtc-audio-processing-1
10
pipewire-0.3.79.tar.gz/test/test-spa-utils.c -> pipewire-0.3.80.tar.gz/test/test-spa-utils.c
Changed
11
1
2
pwtest_int_eq(SPA_TYPE_OBJECT_Profiler, 0x4000a);
3
pwtest_int_eq(SPA_TYPE_OBJECT_ParamLatency, 0x4000b);
4
pwtest_int_eq(SPA_TYPE_OBJECT_ParamProcessLatency, 0x4000c);
5
- pwtest_int_eq(_SPA_TYPE_OBJECT_LAST, 0x4000d);
6
+ pwtest_int_eq(SPA_TYPE_OBJECT_ParamTag, 0x4000d);
7
+ pwtest_int_eq(_SPA_TYPE_OBJECT_LAST, 0x4000e);
8
9
pwtest_int_eq(SPA_TYPE_VENDOR_PipeWire, 0x02000000);
10
pwtest_int_eq(SPA_TYPE_VENDOR_Other, 0x7f000000);
11