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
244
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
+ l->port_link.dst_serial != p->serial))
202
+ continue;
203
+ queue_notify(c, NOTIFY_TYPE_CONNECT, l, 0, NULL);
204
+ }
205
queue_notify(c, NOTIFY_TYPE_PORTREGISTRATION, p, 0, NULL);
206
+ }
207
}
208
}
209
}
210
211
pw_thread_loop_lock(c->context.loop);
212
freeze_callbacks(c);
213
214
+ /* reemit buffer_frames */
215
+ c->buffer_frames = 0;
216
+
217
pw_data_loop_start(c->loop);
218
+ c->active = true;
219
220
if ((res = do_activate(c)) < 0)
221
goto done;
222
223
c->activation->pending_new_pos = true;
224
c->activation->pending_sync = true;
225
226
- c->active = true;
227
-
228
spa_list_for_each(o, &c->context.objects, link) {
229
if (o->type != INTERFACE_Port || o->port.port == NULL ||
230
o->port.port->client != c || !o->port.port->valid)
231
continue;
232
+ o->registered = 0;
233
queue_notify(c, NOTIFY_TYPE_PORTREGISTRATION, o, 1, NULL);
234
}
235
done:
236
- if (res < 0)
237
+ if (res < 0) {
238
+ c->active = false;
239
pw_data_loop_stop(c->loop);
240
+ }
241
242
pw_log_debug("%p: activate result:%d", c, res);
243
thaw_callbacks(c);
244
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
580
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
+ case SPA_COMPRESS_OFFLOAD_DIRECTION_PLAYBACK:
202
+ n_play++;
203
+ emit_node(this, entry->d_name, device_nr, direction, cardinfo, i++);
204
+ break;
205
+ case SPA_COMPRESS_OFFLOAD_DIRECTION_CAPTURE:
206
+ /* TODO: Disabled for now. See the TODO in emit_node() for details. */
207
+#if 0
208
+ n_cap++;
209
+ emit_node(this, entry->d_name, device_nr, direction, cardinfo, i++);
210
+#endif
211
+ break;
212
+ }
213
+ }
214
+
215
+ this->n_capture = n_cap;
216
+ this->n_playback = n_play;
217
+ this->n_nodes = i;
218
+
219
+finish:
220
+ if (snd_dir != NULL)
221
+ closedir(snd_dir);
222
+ if (ctl_handle != NULL)
223
+ snd_ctl_close(ctl_handle);
224
+ return ret;
225
+
226
+errno_error:
227
+ ret = -errno;
228
+ goto finish;
229
+}
230
+
231
+static int emit_info(struct impl *this, bool full)
232
+{
233
+ int err = 0;
234
+ struct spa_dict_item items20;
235
+ uint32_t n_items = 0;
236
+ snd_ctl_t *ctl_hndl;
237
+ snd_ctl_card_info_t *info;
238
+ struct spa_device_info dinfo;
239
+ struct spa_param_info params2;
240
+ char path128;
241
+ char device_name200;
242
+ char device_desc200;
243
+
244
+ spa_log_debug(this->log, "open card %s", this->props.device);
245
+ if ((err = snd_ctl_open(&ctl_hndl, this->props.device, 0)) < 0) {
246
+ spa_log_error(this->log, "can't open control for card %s: %s",
247
+ this->props.device, snd_strerror(err));
248
+ return err;
249
+ }
250
+
251
+ snd_ctl_card_info_alloca(&info);
252
+ if ((err = snd_ctl_card_info(ctl_hndl, info)) < 0) {
253
+ spa_log_error(this->log, "error hardware info: %s", snd_strerror(err));
254
+ goto finish;
255
+ }
256
+
257
+ dinfo = SPA_DEVICE_INFO_INIT();
258
+
259
+ dinfo.change_mask = SPA_DEVICE_CHANGE_MASK_PROPS;
260
+
261
+ snprintf(path, sizeof(path), "alsa:compressed:%s", snd_ctl_card_info_get_id(info));
262
+ snprintf(device_name, sizeof(device_name), "comprC%u", this->props.card_nr);
263
+ snprintf(device_desc, sizeof(device_desc), "Compress-Offload device (ALSA card %u)", this->props.card_nr);
264
+
265
+ ADD_DICT_ITEM(SPA_KEY_OBJECT_PATH, path);
266
+ ADD_DICT_ITEM(SPA_KEY_DEVICE_API, "alsa:compressed");
267
+ ADD_DICT_ITEM(SPA_KEY_DEVICE_NICK, "alsa:compressed");
268
+ ADD_DICT_ITEM(SPA_KEY_DEVICE_NAME, device_name);
269
+ ADD_DICT_ITEM(SPA_KEY_DEVICE_DESCRIPTION, device_desc);
270
+ ADD_DICT_ITEM(SPA_KEY_MEDIA_CLASS, "Audio/Device");
271
+ ADD_DICT_ITEM(SPA_KEY_API_ALSA_PATH, (char *)this->props.device);
272
+ ADD_DICT_ITEM(SPA_KEY_API_ALSA_CARD_ID, snd_ctl_card_info_get_id(info));
273
+ ADD_DICT_ITEM(SPA_KEY_API_ALSA_CARD_COMPONENTS, snd_ctl_card_info_get_components(info));
274
+ ADD_DICT_ITEM(SPA_KEY_API_ALSA_CARD_DRIVER, snd_ctl_card_info_get_driver(info));
275
+ ADD_DICT_ITEM(SPA_KEY_API_ALSA_CARD_NAME, snd_ctl_card_info_get_name(info));
276
+ ADD_DICT_ITEM(SPA_KEY_API_ALSA_CARD_LONGNAME, snd_ctl_card_info_get_longname(info));
277
+ ADD_DICT_ITEM(SPA_KEY_API_ALSA_CARD_MIXERNAME, snd_ctl_card_info_get_mixername(info));
278
+
279
+ dinfo.props = &SPA_DICT_INIT(items, n_items);
280
+
281
+ dinfo.change_mask |= SPA_DEVICE_CHANGE_MASK_PARAMS;
282
+ params0 = SPA_PARAM_INFO(SPA_PARAM_EnumProfile, SPA_PARAM_INFO_READ);
283
+ params1 = SPA_PARAM_INFO(SPA_PARAM_Profile, SPA_PARAM_INFO_READWRITE);
284
+ dinfo.n_params = SPA_N_ELEMENTS(params);
285
+ dinfo.params = params;
286
+
287
+ spa_device_emit_info(&this->hooks, &dinfo);
288
+
289
+finish:
290
+ spa_log_debug(this->log, "close card %s", this->props.device);
291
+ snd_ctl_close(ctl_hndl);
292
+ return err;
293
+}
294
+
295
+static int impl_add_listener(void *object,
296
+ struct spa_hook *listener,
297
+ const struct spa_device_events *events,
298
+ void *data)
299
+{
300
+ struct impl *this = object;
301
+ struct spa_hook_list save;
302
+
303
+ spa_return_val_if_fail(this != NULL, -EINVAL);
304
+ spa_return_val_if_fail(events != NULL, -EINVAL);
305
+
306
+ spa_hook_list_isolate(&this->hooks, &save, listener, events, data);
307
+
308
+ if (events->info || events->object_info)
309
+ emit_info(this, true);
310
+
311
+ spa_hook_list_join(&this->hooks, &save);
312
+
313
+ return 0;
314
+}
315
+
316
+static int impl_sync(void *object, int seq)
317
+{
318
+ struct impl *this = object;
319
+
320
+ spa_return_val_if_fail(this != NULL, -EINVAL);
321
+
322
+ spa_device_emit_result(&this->hooks, seq, 0, 0, NULL);
323
+
324
+ return 0;
325
+}
326
+
327
+static struct spa_pod *build_profile(struct impl *this, struct spa_pod_builder *b,
328
+ uint32_t id, uint32_t index)
329
+{
330
+ struct spa_pod_frame f2;
331
+ const char *name, *desc;
332
+
333
+ switch (index) {
334
+ case 0:
335
+ name = "off";
336
+ desc = "Off";
337
+ break;
338
+ case 1:
339
+ name = "on";
340
+ desc = "On";
341
+ break;
342
+ default:
343
+ errno = EINVAL;
344
+ return NULL;
345
+ }
346
+
347
+ spa_pod_builder_push_object(b, &f0, SPA_TYPE_OBJECT_ParamProfile, id);
348
+ spa_pod_builder_add(b,
349
+ SPA_PARAM_PROFILE_index, SPA_POD_Int(index),
350
+ SPA_PARAM_PROFILE_name, SPA_POD_String(name),
351
+ SPA_PARAM_PROFILE_description, SPA_POD_String(desc),
352
+ 0);
353
+ if (index == 1) {
354
+ spa_pod_builder_prop(b, SPA_PARAM_PROFILE_classes, 0);
355
+ spa_pod_builder_push_struct(b, &f1);
356
+ if (this->n_capture) {
357
+ spa_pod_builder_add_struct(b,
358
+ SPA_POD_String("Audio/Source"),
359
+ SPA_POD_Int(this->n_capture));
360
+ }
361
+ if (this->n_playback) {
362
+ spa_pod_builder_add_struct(b,
363
+ SPA_POD_String("Audio/Sink"),
364
+ SPA_POD_Int(this->n_playback));
365
+ }
366
+ spa_pod_builder_pop(b, &f1);
367
+ }
368
+ return spa_pod_builder_pop(b, &f0);
369
+
370
+}
371
+
372
+static int impl_enum_params(void *object, int seq,
373
+ uint32_t id, uint32_t start, uint32_t num,
374
+ const struct spa_pod *filter)
375
+{
376
+ struct impl *this = object;
377
+ struct spa_pod *param;
378
+ struct spa_pod_builder b = { 0 };
379
+ uint8_t buffer1024;
380
+ struct spa_result_device_params result;
381
+ uint32_t count = 0;
382
+
383
+ spa_return_val_if_fail(this != NULL, -EINVAL);
384
+ spa_return_val_if_fail(num != 0, -EINVAL);
385
+
386
+ result.id = id;
387
+ result.next = start;
388
+ next:
389
+ result.index = result.next++;
390
+
391
+ spa_pod_builder_init(&b, buffer, sizeof(buffer));
392
+
393
+ switch (id) {
394
+ case SPA_PARAM_EnumProfile:
395
+ {
396
+ switch (result.index) {
397
+ case 0:
398
+ case 1:
399
+ param = build_profile(this, &b, id, result.index);
400
+ break;
401
+ default:
402
+ return 0;
403
+ }
404
+ break;
405
+ }
406
+ case SPA_PARAM_Profile:
407
+ {
408
+ switch (result.index) {
409
+ case 0:
410
+ param = build_profile(this, &b, id, this->profile);
411
+ break;
412
+ default:
413
+ return 0;
414
+ }
415
+ break;
416
+ }
417
+ default:
418
+ return -ENOENT;
419
+ }
420
+
421
+ if (spa_pod_filter(&b, &result.param, param, filter) < 0)
422
+ goto next;
423
+
424
+ spa_device_emit_result(&this->hooks, seq, 0,
425
+ SPA_RESULT_TYPE_DEVICE_PARAMS, &result);
426
+
427
+ if (++count != num)
428
+ goto next;
429
+
430
+ return 0;
431
+}
432
+
433
+static int impl_set_param(void *object,
434
+ uint32_t id, uint32_t flags,
435
+ const struct spa_pod *param)
436
+{
437
+ struct impl *this = object;
438
+ int res;
439
+
440
+ spa_return_val_if_fail(this != NULL, -EINVAL);
441
+
442
+ switch (id) {
443
+ case SPA_PARAM_Profile:
444
+ {
445
+ uint32_t idx;
446
+
447
+ if ((res = spa_pod_parse_object(param,
448
+ SPA_TYPE_OBJECT_ParamProfile, NULL,
449
+ SPA_PARAM_PROFILE_index, SPA_POD_Int(&idx))) < 0) {
450
+ spa_log_warn(this->log, "can't parse profile");
451
+ spa_debug_log_pod(this->log, SPA_LOG_LEVEL_DEBUG, 0, NULL, param);
452
+ return res;
453
+ }
454
+
455
+ set_profile(this, idx);
456
+ break;
457
+ }
458
+ default:
459
+ return -ENOENT;
460
+ }
461
+ return 0;
462
+}
463
+
464
+static const struct spa_device_methods impl_device = {
465
+ SPA_VERSION_DEVICE_METHODS,
466
+ .add_listener = impl_add_listener,
467
+ .sync = impl_sync,
468
+ .enum_params = impl_enum_params,
469
+ .set_param = impl_set_param,
470
+};
471
+
472
+static int impl_get_interface(struct spa_handle *handle, const char *type, void **interface)
473
+{
474
+ struct impl *this;
475
+
476
+ spa_return_val_if_fail(handle != NULL, -EINVAL);
477
+ spa_return_val_if_fail(interface != NULL, -EINVAL);
478
+
479
+ this = (struct impl *) handle;
480
+
481
+ if (spa_streq(type, SPA_TYPE_INTERFACE_Device))
482
+ *interface = &this->device;
483
+ else
484
+ return -ENOENT;
485
+
486
+ return 0;
487
+}
488
+
489
+static int impl_clear(struct spa_handle *handle)
490
+{
491
+ return 0;
492
+}
493
+
494
+static size_t impl_get_size(const struct spa_handle_factory *factory,
495
+ const struct spa_dict *params)
496
+{
497
+ return sizeof(struct impl);
498
+}
499
+
500
+static int impl_init(const struct spa_handle_factory *factory,
501
+ struct spa_handle *handle,
502
+ const struct spa_dict *info,
503
+ const struct spa_support *support,
504
+ uint32_t n_support)
505
+{
506
+ struct impl *this;
507
+
508
+ spa_return_val_if_fail(factory != NULL, -EINVAL);
509
+ spa_return_val_if_fail(handle != NULL, -EINVAL);
510
+
511
+ handle->get_interface = impl_get_interface;
512
+ handle->clear = impl_clear;
513
+
514
+ this = (struct impl *) handle;
515
+
516
+ this->log = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_Log);
517
+ alsa_log_topic_init(this->log);
518
+
519
+ this->device.iface = SPA_INTERFACE_INIT(
520
+ SPA_TYPE_INTERFACE_Device,
521
+ SPA_VERSION_DEVICE,
522
+ &impl_device, this);
523
+ spa_hook_list_init(&this->hooks);
524
+
525
+ reset_props(&this->props);
526
+
527
+ snd_config_update_free_global();
528
+
529
+ if (info) {
530
+ uint32_t i;
531
+ for (i = 0; info && i < info->n_items; i++) {
532
+ const char *k = info->itemsi.key;
533
+ const char *s = info->itemsi.value;
534
+
535
+ if (spa_streq(k, SPA_KEY_API_ALSA_PATH)) {
536
+ snprintf(this->props.device, 64, "%s", s);
537
+ spa_log_debug(this->log, "using ALSA path \"%s\"", this->props.device);
538
+ } else if (spa_streq(k, SPA_KEY_API_ALSA_CARD)) {
539
+ long long card_nr = strtol(s, NULL, 10);
540
+ if ((card_nr >= 0) && (card_nr <= UINT_MAX)) {
541
+ this->props.card_nr = card_nr;
542
+ spa_log_debug(this->log, "using ALSA card number %u", this->props.card_nr);
543
+ } else
544
+ spa_log_warn(this->log, "invalid ALSA card number \"%s\"; using default", s);
545
+ }
546
+ }
547
+ }
548
+
549
+ return 0;
550
+}
551
+
552
+static const struct spa_interface_info impl_interfaces = {
553
+ {SPA_TYPE_INTERFACE_Device,},
554
+};
555
+
556
+static int
557
+impl_enum_interface_info(const struct spa_handle_factory *factory,
558
+ const struct spa_interface_info **info,
559
+ uint32_t *index)
560
+{
561
+ spa_return_val_if_fail(factory != NULL, -EINVAL);
562
+ spa_return_val_if_fail(info != NULL, -EINVAL);
563
+ spa_return_val_if_fail(index != NULL, -EINVAL);
564
+
565
+ if (*index >= SPA_N_ELEMENTS(impl_interfaces))
566
+ return 0;
567
+
568
+ *info = &impl_interfaces(*index)++;
569
+ return 1;
570
+}
571
+
572
+const struct spa_handle_factory spa_alsa_compress_offload_device_factory = {
573
+ SPA_VERSION_HANDLE_FACTORY,
574
+ SPA_NAME_API_ALSA_COMPRESS_OFFLOAD_DEVICE,
575
+ NULL,
576
+ impl_get_size,
577
+ impl_init,
578
+ impl_enum_interface_info,
579
+};
580
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
237
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
202
- if ((missed = spa_ratelimit_test(&state->rate_limit, current_time)) >= 0) {
203
+ if ((suppressed = spa_ratelimit_test(&state->rate_limit, current_time)) >= 0) {
204
spa_log_lev(state->log, lev, "%s: follower delay:%ld target:%ld thr:%u, "
205
- "resync (%d missed)", state->props.device, delay,
206
- target, state->threshold, missed);
207
+ "resync (%d suppressed)", state->props.device, delay,
208
+ target, state->threshold, suppressed);
209
}
210
211
if (avail < target)
212
213
struct state *state = source->data;
214
snd_pcm_uframes_t avail, delay, target;
215
uint64_t expire, current_time;
216
- int res, missed;
217
+ int res, suppressed;
218
219
if (SPA_UNLIKELY(state->disable_tsched)) {
220
/* ALSA poll fds need to be "demangled" to know whether it's a real wakeup */
221
222
if (!state->disable_tsched &&
223
(state->next_time > current_time + SPA_NSEC_PER_SEC ||
224
current_time > state->next_time + SPA_NSEC_PER_SEC)) {
225
- if ((missed = spa_ratelimit_test(&state->rate_limit, current_time)) >= 0) {
226
+ if ((suppressed = spa_ratelimit_test(&state->rate_limit, current_time)) >= 0) {
227
spa_log_error(state->log, "%s: impossible timeout %lu %lu %lu %"
228
- PRIu64" %"PRIu64" %"PRIi64" %d %"PRIi64" (%d missed)",
229
+ PRIu64" %"PRIu64" %"PRIi64" %d %"PRIi64" (%d suppressed)",
230
state->props.device, avail, delay, target,
231
current_time, state->next_time, state->next_time - current_time,
232
- state->threshold, state->sample_count, missed);
233
+ state->threshold, state->sample_count, suppressed);
234
}
235
state->next_time = current_time + state->threshold * 1e9 / state->rate;
236
}
237
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
924
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
+
202
+ return errno != 0 ? -errno : num_dev;
203
+}
204
+
205
+static int check_pcm_device_availability(struct impl *this, struct card *card,
206
+ int *num_pcm_devices)
207
{
208
char pathPATH_MAX;
209
char buf16;
210
211
struct dirent *entry, *entry_pcm;
212
int res;
213
214
- res = get_num_pcm_devices(device->id);
215
+ res = get_num_pcm_devices(card->card_nr);
216
if (res < 0) {
217
spa_log_error(this->log, "Error finding PCM devices for ALSA card %u: %s",
218
- (unsigned int)device->id, spa_strerror(res));
219
+ card->card_nr, spa_strerror(res));
220
return res;
221
}
222
- *num_pcm = res;
223
+ *num_pcm_devices = res;
224
225
- spa_log_debug(this->log, "card %u has %d pcm device(s)", (unsigned int)device->id, *num_pcm);
226
+ spa_log_debug(this->log, "card %u has %d PCM device(s)",
227
+ card->card_nr, *num_pcm_devices);
228
229
/*
230
* Check if some pcm devices of the card are busy. Check it via /proc, as we
231
232
233
res = 0;
234
235
- spa_scnprintf(path, sizeof(path), "/proc/asound/card%u", (unsigned int)device->id);
236
+ spa_scnprintf(path, sizeof(path), "/proc/asound/card%u", card->card_nr);
237
238
- spa_autoptr(DIR) card = opendir(path);
239
- if (card == NULL)
240
+ spa_autoptr(DIR) card_dir = opendir(path);
241
+ if (card_dir == NULL)
242
goto done;
243
244
- while ((errno = 0, entry = readdir(card)) != NULL) {
245
+ while ((errno = 0, entry = readdir(card_dir)) != NULL) {
246
if (!(entry->d_type == DT_DIR &&
247
spa_strstartswith(entry->d_name, "pcm")))
248
continue;
249
250
spa_scnprintf(path, sizeof(path), "pcmC%uD%s",
251
- (unsigned int)device->id, entry->d_name+3);
252
+ card->card_nr, entry->d_name+3);
253
if (check_device_pcm_class(path) < 0)
254
continue;
255
256
/* Check busy status */
257
spa_scnprintf(path, sizeof(path), "/proc/asound/card%u/%s",
258
- (unsigned int)device->id, entry->d_name);
259
+ card->card_nr, entry->d_name);
260
261
spa_autoptr(DIR) pcm = opendir(path);
262
if (pcm == NULL)
263
264
continue;
265
266
spa_scnprintf(path, sizeof(path), "/proc/asound/card%u/%s/%s/status",
267
- (unsigned int)device->id, entry->d_name, entry_pcm->d_name);
268
+ card->card_nr, entry->d_name, entry_pcm->d_name);
269
270
spa_autoptr(FILE) f = fopen(path, "re");
271
if (f == NULL)
272
273
274
if (!spa_strstartswith(buf, "closed")) {
275
spa_log_debug(this->log, "card %u pcm device %s busy",
276
- (unsigned int)device->id, entry->d_name);
277
+ card->card_nr, entry->d_name);
278
res = -EBUSY;
279
goto done;
280
}
281
spa_log_debug(this->log, "card %u pcm device %s free",
282
- (unsigned int)device->id, entry->d_name);
283
+ card->card_nr, entry->d_name);
284
}
285
if (errno != 0)
286
goto done;
287
288
done:
289
if (errno != 0) {
290
spa_log_info(this->log, "card %u: failed to find busy status (%s)",
291
- (unsigned int)device->id, spa_strerror(-errno));
292
+ card->card_nr, spa_strerror(-errno));
293
}
294
295
return res;
296
}
297
298
-static int emit_object_info(struct impl *this, struct device *device)
299
+static int check_compress_offload_device_availability(struct impl *this, struct card *card,
300
+ int *num_compress_offload_devices)
301
+{
302
+ int res;
303
+
304
+ res = get_num_compress_offload_devices(card->card_nr);
305
+ if (res < 0) {
306
+ spa_log_error(this->log, "Error finding Compress-Offload devices for ALSA card %u: %s",
307
+ card->card_nr, spa_strerror(res));
308
+ return res;
309
+ }
310
+ *num_compress_offload_devices = res;
311
+
312
+ spa_log_debug(this->log, "card %u has %d Compress-Offload device(s)",
313
+ card->card_nr, *num_compress_offload_devices);
314
+
315
+ return 0;
316
+}
317
+
318
+static int emit_added_object_info(struct impl *this, struct card *card)
319
{
320
- struct spa_device_object_info info;
321
- uint32_t id = device->id;
322
- struct udev_device *dev = device->dev;
323
+ char path32;
324
+ int res, num_pcm_devices, num_compress_offload_devices;
325
const char *str;
326
- char path32, *cn = NULL, *cln = NULL;
327
- struct spa_dict_item items25;
328
- uint32_t n_items = 0;
329
- int res, pcm;
330
+ struct udev_device *udev_device = card->udev_device;
331
332
/*
333
* inotify close events under /dev/snd must not be emitted, except after setting
334
- * device->emitted to true. alsalib functions can be used after that.
335
+ * card->emitted to true. alsalib functions can be used after that.
336
*/
337
338
- snprintf(path, sizeof(path), "hw:%u", id);
339
+ snprintf(path, sizeof(path), "hw:%u", card->card_nr);
340
341
- if ((res = check_device_available(this, device, &pcm)) < 0)
342
+ if ((res = check_pcm_device_availability(this, card, &num_pcm_devices)) < 0)
343
+ return res;
344
+ if ((res = check_compress_offload_device_availability(this, card, &num_compress_offload_devices)) < 0)
345
return res;
346
- if (pcm == 0) {
347
- spa_log_debug(this->log, "no pcm devices for %s", path);
348
- device->ignored = true;
349
+
350
+ if ((num_pcm_devices == 0) && (num_compress_offload_devices == 0)) {
351
+ spa_log_debug(this->log, "no PCM and no Compress-Offload devices for %s", path);
352
+ card->ignored = true;
353
return -ENODEV;
354
}
355
356
- spa_log_debug(this->log, "emitting card %s", path);
357
- device->emitted = true;
358
-
359
- info = SPA_DEVICE_OBJECT_INFO_INIT();
360
-
361
- info.type = SPA_TYPE_INTERFACE_Device;
362
- info.factory_name = this->use_acp ?
363
- SPA_NAME_API_ALSA_ACP_DEVICE :
364
- SPA_NAME_API_ALSA_PCM_DEVICE;
365
- info.change_mask = SPA_DEVICE_OBJECT_CHANGE_MASK_FLAGS |
366
- SPA_DEVICE_OBJECT_CHANGE_MASK_PROPS;
367
- info.flags = 0;
368
-
369
- itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_ENUM_API, "udev");
370
- itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_API, "alsa");
371
- itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_MEDIA_CLASS, "Audio/Device");
372
- itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_API_ALSA_PATH, path);
373
- itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_API_ALSA_CARD, path+3);
374
- if (snd_card_get_name(id, &cn) >= 0)
375
- itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_API_ALSA_CARD_NAME, cn);
376
- if (snd_card_get_longname(id, &cln) >= 0)
377
- itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_API_ALSA_CARD_LONGNAME, cln);
378
-
379
- if ((str = udev_device_get_property_value(dev, "ACP_NAME")) && *str)
380
- itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_NAME, str);
381
-
382
- if ((str = udev_device_get_property_value(dev, "ACP_PROFILE_SET")) && *str)
383
- itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_PROFILE_SET, str);
384
-
385
- if ((str = udev_device_get_property_value(dev, "SOUND_CLASS")) && *str)
386
- itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_CLASS, str);
387
-
388
- if ((str = udev_device_get_property_value(dev, "USEC_INITIALIZED")) && *str)
389
- itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_PLUGGED_USEC, str);
390
-
391
- str = udev_device_get_property_value(dev, "ID_PATH");
392
- if (!(str && *str))
393
- str = udev_device_get_syspath(dev);
394
- if (str && *str) {
395
- itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_BUS_PATH, str);
396
- }
397
- if ((str = udev_device_get_devpath(dev)) && *str) {
398
- itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_SYSFS_PATH, str);
399
- }
400
- if ((str = udev_device_get_property_value(dev, "ID_ID")) && *str) {
401
- itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_BUS_ID, str);
402
- }
403
- if ((str = udev_device_get_property_value(dev, "ID_BUS")) && *str) {
404
- itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_BUS, str);
405
- }
406
- if ((str = udev_device_get_property_value(dev, "SUBSYSTEM")) && *str) {
407
- itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_SUBSYSTEM, str);
408
- }
409
- if ((str = udev_device_get_property_value(dev, "ID_VENDOR_ID")) && *str) {
410
- int32_t val;
411
- if (spa_atoi32(str, &val, 16)) {
412
- char *dec = alloca(12); /* 0xffffffff is max */
413
- snprintf(dec, 12, "0x%04x", val);
414
- itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_VENDOR_ID, dec);
415
+ card->emitted = true;
416
+
417
+ if (num_pcm_devices > 0) {
418
+ struct spa_device_object_info info;
419
+ char *cn = NULL, *cln = NULL;
420
+ struct spa_dict_item items25;
421
+ unsigned int n_items = 0;
422
+
423
+ card->pcm_device_id = calc_pcm_device_id(card);
424
+
425
+ spa_log_debug(this->log, "emitting ACP/PCM device interface for card %s; "
426
+ "using local alsa-udev object ID %" PRIu32, path, card->pcm_device_id);
427
+
428
+ info = SPA_DEVICE_OBJECT_INFO_INIT();
429
+
430
+ info.type = SPA_TYPE_INTERFACE_Device;
431
+ info.factory_name = this->use_acp ?
432
+ SPA_NAME_API_ALSA_ACP_DEVICE :
433
+ SPA_NAME_API_ALSA_PCM_DEVICE;
434
+ info.change_mask = SPA_DEVICE_OBJECT_CHANGE_MASK_FLAGS |
435
+ SPA_DEVICE_OBJECT_CHANGE_MASK_PROPS;
436
+ info.flags = 0;
437
+
438
+ itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_ENUM_API, "udev");
439
+ itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_API, "alsa");
440
+ itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_MEDIA_CLASS, "Audio/Device");
441
+ itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_API_ALSA_PATH, path);
442
+ itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_API_ALSA_CARD, path+3);
443
+ if (snd_card_get_name(card->card_nr, &cn) >= 0)
444
+ itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_API_ALSA_CARD_NAME, cn);
445
+ if (snd_card_get_longname(card->card_nr, &cln) >= 0)
446
+ itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_API_ALSA_CARD_LONGNAME, cln);
447
+
448
+ if ((str = udev_device_get_property_value(udev_device, "ACP_NAME")) && *str)
449
+ itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_NAME, str);
450
+
451
+ if ((str = udev_device_get_property_value(udev_device, "ACP_PROFILE_SET")) && *str)
452
+ itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_PROFILE_SET, str);
453
+
454
+ if ((str = udev_device_get_property_value(udev_device, "SOUND_CLASS")) && *str)
455
+ itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_CLASS, str);
456
+
457
+ if ((str = udev_device_get_property_value(udev_device, "USEC_INITIALIZED")) && *str)
458
+ itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_PLUGGED_USEC, str);
459
+
460
+ str = udev_device_get_property_value(udev_device, "ID_PATH");
461
+ if (!(str && *str))
462
+ str = udev_device_get_syspath(udev_device);
463
+ if (str && *str) {
464
+ itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_BUS_PATH, str);
465
}
466
- }
467
- str = udev_device_get_property_value(dev, "ID_VENDOR_FROM_DATABASE");
468
- if (!(str && *str)) {
469
- str = udev_device_get_property_value(dev, "ID_VENDOR_ENC");
470
+ if ((str = udev_device_get_devpath(udev_device)) && *str) {
471
+ itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_SYSFS_PATH, str);
472
+ }
473
+ if ((str = udev_device_get_property_value(udev_device, "ID_ID")) && *str) {
474
+ itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_BUS_ID, str);
475
+ }
476
+ if ((str = udev_device_get_property_value(udev_device, "ID_BUS")) && *str) {
477
+ itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_BUS, str);
478
+ }
479
+ if ((str = udev_device_get_property_value(udev_device, "SUBSYSTEM")) && *str) {
480
+ itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_SUBSYSTEM, str);
481
+ }
482
+ if ((str = udev_device_get_property_value(udev_device, "ID_VENDOR_ID")) && *str) {
483
+ int32_t val;
484
+ if (spa_atoi32(str, &val, 16)) {
485
+ char *dec = alloca(12); /* 0xffffffff is max */
486
+ snprintf(dec, 12, "0x%04x", val);
487
+ itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_VENDOR_ID, dec);
488
+ }
489
+ }
490
+ str = udev_device_get_property_value(udev_device, "ID_VENDOR_FROM_DATABASE");
491
if (!(str && *str)) {
492
- str = udev_device_get_property_value(dev, "ID_VENDOR");
493
- } else {
494
- char *t = alloca(strlen(str) + 1);
495
- unescape(str, t);
496
- str = t;
497
+ str = udev_device_get_property_value(udev_device, "ID_VENDOR_ENC");
498
+ if (!(str && *str)) {
499
+ str = udev_device_get_property_value(udev_device, "ID_VENDOR");
500
+ } else {
501
+ char *t = alloca(strlen(str) + 1);
502
+ unescape(str, t);
503
+ str = t;
504
+ }
505
}
506
- }
507
- if (str && *str) {
508
- itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_VENDOR_NAME, str);
509
- }
510
- if ((str = udev_device_get_property_value(dev, "ID_MODEL_ID")) && *str) {
511
- int32_t val;
512
- if (spa_atoi32(str, &val, 16)) {
513
- char *dec = alloca(12); /* 0xffffffff is max */
514
- snprintf(dec, 12, "0x%04x", val);
515
- itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_PRODUCT_ID, dec);
516
+ if (str && *str) {
517
+ itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_VENDOR_NAME, str);
518
}
519
- }
520
- str = udev_device_get_property_value(dev, "ID_MODEL_FROM_DATABASE");
521
- if (!(str && *str)) {
522
- str = udev_device_get_property_value(dev, "ID_MODEL_ENC");
523
+ if ((str = udev_device_get_property_value(udev_device, "ID_MODEL_ID")) && *str) {
524
+ int32_t val;
525
+ if (spa_atoi32(str, &val, 16)) {
526
+ char *dec = alloca(12); /* 0xffffffff is max */
527
+ snprintf(dec, 12, "0x%04x", val);
528
+ itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_PRODUCT_ID, dec);
529
+ }
530
+ }
531
+ str = udev_device_get_property_value(udev_device, "ID_MODEL_FROM_DATABASE");
532
if (!(str && *str)) {
533
- str = udev_device_get_property_value(dev, "ID_MODEL");
534
- } else {
535
- char *t = alloca(strlen(str) + 1);
536
- unescape(str, t);
537
- str = t;
538
+ str = udev_device_get_property_value(udev_device, "ID_MODEL_ENC");
539
+ if (!(str && *str)) {
540
+ str = udev_device_get_property_value(udev_device, "ID_MODEL");
541
+ } else {
542
+ char *t = alloca(strlen(str) + 1);
543
+ unescape(str, t);
544
+ str = t;
545
+ }
546
}
547
- }
548
- if (str && *str)
549
- itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_PRODUCT_NAME, str);
550
+ if (str && *str)
551
+ itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_PRODUCT_NAME, str);
552
553
- if ((str = udev_device_get_property_value(dev, "ID_SERIAL")) && *str) {
554
- itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_SERIAL, str);
555
- }
556
- if ((str = udev_device_get_property_value(dev, "SOUND_FORM_FACTOR")) && *str) {
557
- itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_FORM_FACTOR, str);
558
+ if ((str = udev_device_get_property_value(udev_device, "ID_SERIAL")) && *str) {
559
+ itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_SERIAL, str);
560
+ }
561
+ if ((str = udev_device_get_property_value(udev_device, "SOUND_FORM_FACTOR")) && *str) {
562
+ itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_FORM_FACTOR, str);
563
+ }
564
+ info.props = &SPA_DICT_INIT(items, n_items);
565
+
566
+ spa_log_debug(this->log, "interface information:");
567
+ spa_debug_log_dict(this->log, SPA_LOG_LEVEL_DEBUG, 2, info.props);
568
+
569
+ spa_device_emit_object_info(&this->hooks, card->pcm_device_id, &info);
570
+ free(cn);
571
+ free(cln);
572
+ } else {
573
+ card->pcm_device_id = ID_DEVICE_NOT_SUPPORTED;
574
}
575
- info.props = &SPA_DICT_INIT(items, n_items);
576
577
- spa_device_emit_object_info(&this->hooks, id, &info);
578
- free(cn);
579
- free(cln);
580
+ if (num_compress_offload_devices > 0) {
581
+ struct spa_device_object_info info;
582
+ struct spa_dict_item items11;
583
+ unsigned int n_items = 0;
584
+ char device_name200;
585
+ char device_desc200;
586
+
587
+ card->compress_offload_device_id = calc_compress_offload_device_id(card);
588
+
589
+ spa_log_debug(this->log, "emitting Compress-Offload device interface for card %s; "
590
+ "using local alsa-udev object ID %" PRIu32, path, card->compress_offload_device_id);
591
+
592
+ info = SPA_DEVICE_OBJECT_INFO_INIT();
593
+
594
+ info.type = SPA_TYPE_INTERFACE_Device;
595
+ info.factory_name = SPA_NAME_API_ALSA_COMPRESS_OFFLOAD_DEVICE;
596
+ info.change_mask = SPA_DEVICE_OBJECT_CHANGE_MASK_FLAGS |
597
+ SPA_DEVICE_OBJECT_CHANGE_MASK_PROPS;
598
+ info.flags = 0;
599
+
600
+ snprintf(device_name, sizeof(device_name), "comprC%u", card->card_nr);
601
+ snprintf(device_desc, sizeof(device_desc), "Compress-Offload device (ALSA card %u)", card->card_nr);
602
+
603
+ itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_ENUM_API, "udev");
604
+ itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_API, "alsa:compressed");
605
+ itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_NAME, device_name);
606
+ itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_DESCRIPTION, device_desc);
607
+ itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_MEDIA_CLASS, "Audio/Device");
608
+ itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_API_ALSA_PATH, path);
609
+ itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_API_ALSA_CARD, path+3);
610
+
611
+ if ((str = udev_device_get_property_value(udev_device, "USEC_INITIALIZED")) && *str)
612
+ itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_PLUGGED_USEC, str);
613
+
614
+ str = udev_device_get_property_value(udev_device, "ID_PATH");
615
+ if (!(str && *str))
616
+ str = udev_device_get_syspath(udev_device);
617
+ if (str && *str) {
618
+ itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_BUS_PATH, str);
619
+ }
620
+ if ((str = udev_device_get_devpath(udev_device)) && *str) {
621
+ itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_SYSFS_PATH, str);
622
+ }
623
+ if ((str = udev_device_get_property_value(udev_device, "SUBSYSTEM")) && *str) {
624
+ itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_SUBSYSTEM, str);
625
+ }
626
+
627
+ info.props = &SPA_DICT_INIT(items, n_items);
628
+
629
+ spa_log_debug(this->log, "interface information:");
630
+ spa_debug_log_dict(this->log, SPA_LOG_LEVEL_DEBUG, 2, info.props);
631
+
632
+ spa_device_emit_object_info(&this->hooks, card->compress_offload_device_id, &info);
633
+ } else {
634
+ card->compress_offload_device_id = ID_DEVICE_NOT_SUPPORTED;
635
+ }
636
637
return 1;
638
}
639
640
-static bool check_access(struct impl *this, struct device *device)
641
+static bool check_access(struct impl *this, struct card *card)
642
{
643
- char path128, prefix32;
644
+ char path128, pcm_prefix32, compr_prefix32;;
645
spa_autoptr(DIR) snd = NULL;
646
struct dirent *entry;
647
bool accessible = false;
648
649
- snprintf(path, sizeof(path), "/dev/snd/controlC%u", device->id);
650
+ snprintf(path, sizeof(path), "/dev/snd/controlC%u", card->card_nr);
651
if (access(path, R_OK|W_OK) >= 0 && (snd = opendir("/dev/snd"))) {
652
/*
653
* It's possible that controlCX is accessible before pcmCX* or
654
655
*/
656
657
accessible = true;
658
- spa_scnprintf(prefix, sizeof(prefix), "pcmC%uD", device->id);
659
+ spa_scnprintf(pcm_prefix, sizeof(pcm_prefix), "pcmC%uD", card->card_nr);
660
+ spa_scnprintf(compr_prefix, sizeof(compr_prefix), "comprC%uD", card->card_nr);
661
while ((entry = readdir(snd)) != NULL) {
662
if (!(entry->d_type == DT_CHR &&
663
- spa_strstartswith(entry->d_name, prefix)))
664
+ (spa_strstartswith(entry->d_name, pcm_prefix) ||
665
+ spa_strstartswith(entry->d_name, compr_prefix))))
666
continue;
667
668
snprintf(path, sizeof(path), "/dev/snd/%.32s", entry->d_name);
669
670
}
671
}
672
673
- if (accessible != device->accessible)
674
+ if (accessible != card->accessible)
675
spa_log_debug(this->log, "%s accessible:%u", path, accessible);
676
- device->accessible = accessible;
677
+ card->accessible = accessible;
678
679
- return device->accessible;
680
+ return card->accessible;
681
}
682
683
-static void process_device(struct impl *this, uint32_t action, struct udev_device *dev)
684
+static void process_card(struct impl *this, uint32_t action, struct udev_device *udev_device)
685
{
686
- uint32_t id;
687
- struct device *device;
688
+ unsigned int card_nr;
689
+ struct card *card;
690
bool emitted;
691
int res;
692
693
- if ((id = get_card_id(this, dev)) == SPA_ID_INVALID)
694
+ if ((card_nr = get_card_nr(this, udev_device)) == SPA_ID_INVALID)
695
return;
696
697
- device = find_device(this, id);
698
- if (device && device->ignored)
699
+ card = find_card(this, card_nr);
700
+ if (card && card->ignored)
701
return;
702
703
switch (action) {
704
case ACTION_ADD:
705
- if (device == NULL)
706
- device = add_device(this, id, dev);
707
- if (device == NULL)
708
+ if (card == NULL)
709
+ card = add_card(this, card_nr, udev_device);
710
+ if (card == NULL)
711
return;
712
- if (!check_access(this, device))
713
+ if (!check_access(this, card))
714
return;
715
- res = emit_object_info(this, device);
716
+ res = emit_added_object_info(this, card);
717
if (res < 0) {
718
- if (device->ignored)
719
+ if (card->ignored)
720
spa_log_info(this->log, "ALSA card %u unavailable (%s): it is ignored",
721
- device->id, spa_strerror(res));
722
- else if (!device->unavailable)
723
+ card->card_nr, spa_strerror(res));
724
+ else if (!card->unavailable)
725
spa_log_info(this->log, "ALSA card %u unavailable (%s): wait for it",
726
- device->id, spa_strerror(res));
727
+ card->card_nr, spa_strerror(res));
728
else
729
spa_log_debug(this->log, "ALSA card %u still unavailable (%s)",
730
- device->id, spa_strerror(res));
731
- device->unavailable = true;
732
+ card->card_nr, spa_strerror(res));
733
+ card->unavailable = true;
734
} else {
735
- if (device->unavailable)
736
+ if (card->unavailable)
737
spa_log_info(this->log, "ALSA card %u now available",
738
- device->id);
739
- device->unavailable = false;
740
+ card->card_nr);
741
+ card->unavailable = false;
742
}
743
break;
744
745
- case ACTION_REMOVE:
746
- if (device == NULL)
747
+ case ACTION_REMOVE: {
748
+ uint32_t pcm_device_id, compress_offload_device_id;
749
+
750
+ if (card == NULL)
751
return;
752
- emitted = device->emitted;
753
- remove_device(this, device);
754
- if (emitted)
755
- spa_device_emit_object_info(&this->hooks, id, NULL);
756
+
757
+ emitted = card->emitted;
758
+ pcm_device_id = card->pcm_device_id;
759
+ compress_offload_device_id = card->compress_offload_device_id;
760
+ remove_card(this, card);
761
+
762
+ if (emitted) {
763
+ if (pcm_device_id != ID_DEVICE_NOT_SUPPORTED)
764
+ spa_device_emit_object_info(&this->hooks, pcm_device_id, NULL);
765
+ if (compress_offload_device_id != ID_DEVICE_NOT_SUPPORTED)
766
+ spa_device_emit_object_info(&this->hooks, compress_offload_device_id, NULL);
767
+ }
768
break;
769
+ }
770
771
case ACTION_DISABLE:
772
- if (device == NULL)
773
+ if (card == NULL)
774
return;
775
- if (device->emitted) {
776
- device->emitted = false;
777
- spa_device_emit_object_info(&this->hooks, id, NULL);
778
+ if (card->emitted) {
779
+ uint32_t pcm_device_id, compress_offload_device_id;
780
+
781
+ pcm_device_id = card->pcm_device_id;
782
+ compress_offload_device_id = card->compress_offload_device_id;
783
+
784
+ card->emitted = false;
785
+
786
+ if (pcm_device_id != ID_DEVICE_NOT_SUPPORTED)
787
+ spa_device_emit_object_info(&this->hooks, pcm_device_id, NULL);
788
+ if (compress_offload_device_id != ID_DEVICE_NOT_SUPPORTED)
789
+ spa_device_emit_object_info(&this->hooks, compress_offload_device_id, NULL);
790
}
791
break;
792
}
793
794
795
for (p = &buf; p < e;
796
p = SPA_PTROFF(p, sizeof(struct inotify_event) + event->len, void)) {
797
- unsigned int id;
798
- struct device *device;
799
+ unsigned int card_nr;
800
+ struct card *card;
801
802
event = (const struct inotify_event *) p;
803
spa_assert_se(SPA_PTRDIFF(e, p) >= (ptrdiff_t)sizeof(struct inotify_event) &&
804
SPA_PTRDIFF(e, p) - sizeof(struct inotify_event) >= event->len &&
805
"bad event from kernel");
806
807
- /* Device becomes accessible or not busy */
808
+ /* card becomes accessible or not busy */
809
if ((event->mask & (IN_ATTRIB | IN_CLOSE_WRITE))) {
810
bool access;
811
- if (sscanf(event->name, "controlC%u", &id) != 1 &&
812
- sscanf(event->name, "pcmC%uD", &id) != 1)
813
+ if (sscanf(event->name, "controlC%u", &card_nr) != 1 &&
814
+ sscanf(event->name, "pcmC%uD", &card_nr) != 1)
815
continue;
816
- if ((device = find_device(this, id)) == NULL)
817
+ if ((card = find_card(this, card_nr)) == NULL)
818
continue;
819
820
- access = check_access(this, device);
821
- if (access && !device->emitted)
822
- process_device(this, ACTION_ADD, device->dev);
823
- else if (!access && device->emitted)
824
- process_device(this, ACTION_DISABLE, device->dev);
825
+ access = check_access(this, card);
826
+ if (access && !card->emitted)
827
+ process_card(this, ACTION_ADD, card->udev_device);
828
+ else if (!access && card->emitted)
829
+ process_card(this, ACTION_DISABLE, card->udev_device);
830
}
831
/* /dev/snd/ might have been removed */
832
if ((event->mask & (IN_DELETE_SELF | IN_MOVE_SELF)))
833
834
static void impl_on_fd_events(struct spa_source *source)
835
{
836
struct impl *this = source->data;
837
- struct udev_device *dev;
838
+ struct udev_device *udev_device;
839
const char *action;
840
841
- dev = udev_monitor_receive_device(this->umonitor);
842
- if (dev == NULL)
843
+ udev_device = udev_monitor_receive_device(this->umonitor);
844
+ if (udev_device == NULL)
845
return;
846
847
- if ((action = udev_device_get_action(dev)) == NULL)
848
+ if ((action = udev_device_get_action(udev_device)) == NULL)
849
action = "change";
850
851
spa_log_debug(this->log, "action %s", action);
852
853
start_inotify(this);
854
855
if (spa_streq(action, "change")) {
856
- process_device(this, ACTION_ADD, dev);
857
+ process_card(this, ACTION_ADD, udev_device);
858
} else if (spa_streq(action, "remove")) {
859
- process_device(this, ACTION_REMOVE, dev);
860
+ process_card(this, ACTION_REMOVE, udev_device);
861
}
862
- udev_device_unref(dev);
863
+ udev_device_unref(udev_device);
864
}
865
866
static int start_monitor(struct impl *this)
867
868
if (this->umonitor == NULL)
869
return 0;
870
871
- clear_devices (this);
872
+ clear_cards (this);
873
874
spa_loop_remove_source(this->main_loop, &this->source);
875
udev_monitor_unref(this->umonitor);
876
877
return 0;
878
}
879
880
-static int enum_devices(struct impl *this)
881
+static int enum_cards(struct impl *this)
882
{
883
struct udev_enumerate *enumerate;
884
- struct udev_list_entry *devices;
885
+ struct udev_list_entry *udev_devices;
886
887
enumerate = udev_enumerate_new(this->udev);
888
if (enumerate == NULL)
889
890
udev_enumerate_add_match_subsystem(enumerate, "sound");
891
udev_enumerate_scan_devices(enumerate);
892
893
- for (devices = udev_enumerate_get_list_entry(enumerate); devices;
894
- devices = udev_list_entry_get_next(devices)) {
895
- struct udev_device *dev;
896
+ for (udev_devices = udev_enumerate_get_list_entry(enumerate); udev_devices;
897
+ udev_devices = udev_list_entry_get_next(udev_devices)) {
898
+ struct udev_device *udev_device;
899
900
- dev = udev_device_new_from_syspath(this->udev, udev_list_entry_get_name(devices));
901
- if (dev == NULL)
902
+ udev_device = udev_device_new_from_syspath(this->udev,
903
+ udev_list_entry_get_name(udev_devices));
904
+ if (udev_device == NULL)
905
continue;
906
907
- process_device(this, ACTION_ADD, dev);
908
+ process_card(this, ACTION_ADD, udev_device);
909
910
- udev_device_unref(dev);
911
+ udev_device_unref(udev_device);
912
}
913
udev_enumerate_unref(enumerate);
914
915
916
if ((res = start_monitor(this)) < 0)
917
return res;
918
919
- if ((res = enum_devices(this)) < 0)
920
+ if ((res = enum_cards(this)) < 0)
921
return res;
922
923
spa_hook_list_join(&this->hooks, &save);
924
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
331
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
- if (port_id == 0)
202
+ if (port_id == 0) {
203
+ /* handle the converter output port into the follower separately */
204
+ follower_convert_port_info(this, direction, port_id, info);
205
return;
206
- else
207
+ } else
208
/* the monitor ports are exposed */
209
port_id--;
210
} else if (info) {
211
212
213
spa_zero(this->info.props);
214
this->info.change_mask &= ~SPA_NODE_CHANGE_MASK_PROPS;
215
-
216
-}
217
-
218
-static int recalc_latency(struct impl *this, enum spa_direction direction, uint32_t port_id)
219
-{
220
- struct spa_pod_builder b = { 0 };
221
- uint8_t buffer1024;
222
- struct spa_pod *param;
223
- uint32_t index = 0;
224
- struct spa_latency_info latency;
225
- int res;
226
-
227
- spa_log_debug(this->log, "%p: ", this);
228
-
229
- if (this->target == this->follower)
230
- return 0;
231
-
232
- while (true) {
233
- spa_pod_builder_init(&b, buffer, sizeof(buffer));
234
- if ((res = spa_node_port_enum_params_sync(this->follower,
235
- direction, port_id, SPA_PARAM_Latency,
236
- &index, NULL, ¶m, &b)) != 1)
237
- return res;
238
- if ((res = spa_latency_parse(param, &latency)) < 0)
239
- return res;
240
- if (latency.direction == direction)
241
- break;
242
- }
243
- if ((res = spa_node_port_set_param(this->target,
244
- SPA_DIRECTION_REVERSE(direction), 0,
245
- SPA_PARAM_Latency, 0, param)) < 0)
246
- return res;
247
-
248
- return 0;
249
}
250
251
static void follower_port_info(void *data,
252
253
SPA_PORT_FLAG_PHYSICAL |
254
SPA_PORT_FLAG_TERMINAL);
255
256
- spa_log_debug(this->log, "%p: follower port info %s %p %08"PRIx64, this,
257
+ spa_log_debug(this->log, "%p: follower port info %s %p %08"PRIx64" recalc:%u", this,
258
this->direction == SPA_DIRECTION_INPUT ?
259
- "Input" : "Output", info, info->change_mask);
260
+ "Input" : "Output", info, info->change_mask,
261
+ this->in_recalc);
262
263
if (info->change_mask & SPA_PORT_CHANGE_MASK_PARAMS) {
264
for (i = 0; i < info->n_params; i++) {
265
266
case SPA_PARAM_Latency:
267
idx = IDX_Latency;
268
break;
269
+ case SPA_PARAM_Tag:
270
+ idx = IDX_Tag;
271
+ break;
272
default:
273
continue;
274
}
275
276
if (this->add_listener)
277
continue;
278
279
- if (idx == IDX_Latency) {
280
- res = recalc_latency(this, direction, port_id);
281
+ if (idx == IDX_Latency && this->in_recalc == 0) {
282
+ res = recalc_latency(this, this->follower, direction, port_id, this->target);
283
spa_log_debug(this->log, "latency: %d (%s)", res,
284
spa_strerror(res));
285
}
286
+ if (idx == IDX_Tag && this->in_recalc == 0) {
287
+ res = recalc_tag(this, this->follower, direction, port_id, this->target);
288
+ spa_log_debug(this->log, "tag: %d (%s)", res,
289
+ spa_strerror(res));
290
+ }
291
if (idx == IDX_EnumFormat) {
292
spa_log_debug(this->log, "new formats");
293
configure_format(this, 0, NULL);
294
295
const struct spa_pod *param)
296
{
297
struct impl *this = object;
298
- int res;
299
300
spa_return_val_if_fail(this != NULL, -EINVAL);
301
302
303
if (direction != this->direction)
304
port_id++;
305
306
- if ((res = spa_node_port_set_param(this->target, direction, port_id, id,
307
- flags, param)) < 0)
308
- return res;
309
-
310
- if ((id == SPA_PARAM_Latency) &&
311
- direction == this->direction) {
312
- if ((res = spa_node_port_set_param(this->follower, direction, 0, id,
313
- flags, param)) < 0)
314
- return res;
315
- }
316
-
317
- return res;
318
+ return spa_node_port_set_param(this->target, direction, port_id, id,
319
+ flags, param);
320
}
321
322
static int
323
324
this->paramsIDX_PortConfig = SPA_PARAM_INFO(SPA_PARAM_PortConfig, SPA_PARAM_INFO_READWRITE);
325
this->paramsIDX_Latency = SPA_PARAM_INFO(SPA_PARAM_Latency, SPA_PARAM_INFO_READWRITE);
326
this->paramsIDX_ProcessLatency = SPA_PARAM_INFO(SPA_PARAM_ProcessLatency, SPA_PARAM_INFO_READWRITE);
327
+ this->paramsIDX_Tag = SPA_PARAM_INFO(SPA_PARAM_Tag, SPA_PARAM_INFO_READWRITE);
328
this->info.params = this->params;
329
this->info.n_params = N_NODE_PARAMS;
330
331
pipewire-0.3.79.tar.gz/spa/plugins/audioconvert/audioconvert.c -> pipewire-0.3.80.tar.gz/spa/plugins/audioconvert/audioconvert.c
Changed
303
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
+ if (spa_tag_compare(tag, this->dirother.tag) != 0) {
202
+ free(this->dirother.tag);
203
+ this->dirother.tag = tag ? spa_pod_copy(tag) : NULL;
204
+
205
+ for (i = 0; i < this->dirother.n_ports; i++) {
206
+ oport = GET_PORT(this, other, i);
207
+ oport->info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS;
208
+ oport->paramsIDX_Tag.user++;
209
+ emit_port_info(this, oport, false);
210
+ }
211
}
212
port->info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS;
213
- port->paramsIDX_Latency.user++;
214
+ port->paramsIDX_Tag.user++;
215
emit_port_info(this, port, false);
216
return 0;
217
}
218
219
switch (id) {
220
case SPA_PARAM_Latency:
221
return port_set_latency(this, direction, port_id, flags, param);
222
+ case SPA_PARAM_Tag:
223
+ return port_set_tag(this, direction, port_id, flags, param);
224
case SPA_PARAM_Format:
225
return port_set_format(this, direction, port_id, flags, param);
226
default:
227
228
struct buffer *buf, *out_bufsMAX_PORTS;
229
struct spa_data *bd;
230
struct dir *dir;
231
- int tmp = 0, res = 0, missed;
232
+ int tmp = 0, res = 0, suppressed;
233
bool in_passthrough, mix_passthrough, resample_passthrough, out_passthrough;
234
bool in_avail = false, flush_in = false, flush_out = false;
235
bool draining = false, in_empty = this->out_offset == 0;
236
237
238
buf = peek_buffer(this, port);
239
if (buf == NULL && port->n_buffers > 0 &&
240
- (missed = spa_ratelimit_test(&this->rate_limit, current_time)) >= 0) {
241
- spa_log_warn(this->log, "%p: (%d missed) out of buffers on port %d %d",
242
- this, missed, port->id, port->n_buffers);
243
+ (suppressed = spa_ratelimit_test(&this->rate_limit, current_time)) >= 0) {
244
+ spa_log_warn(this->log, "%p: (%d suppressed) out of buffers on port %d %d",
245
+ this, suppressed, port->id, port->n_buffers);
246
}
247
}
248
out_bufsi = buf;
249
250
return 0;
251
}
252
253
+static void free_dir(struct dir *dir)
254
+{
255
+ uint32_t i;
256
+ for (i = 0; i < MAX_PORTS; i++)
257
+ free(dir->portsi);
258
+ if (dir->conv.free)
259
+ convert_free(&dir->conv);
260
+ free(dir->tag);
261
+}
262
+
263
static int impl_clear(struct spa_handle *handle)
264
{
265
struct impl *this;
266
- uint32_t i;
267
268
spa_return_val_if_fail(handle != NULL, -EINVAL);
269
270
this = (struct impl *) handle;
271
272
- for (i = 0; i < MAX_PORTS; i++)
273
- free(this->dirSPA_DIRECTION_INPUT.portsi);
274
- for (i = 0; i < MAX_PORTS; i++)
275
- free(this->dirSPA_DIRECTION_OUTPUT.portsi);
276
+ free_dir(&this->dirSPA_DIRECTION_INPUT);
277
+ free_dir(&this->dirSPA_DIRECTION_OUTPUT);
278
+
279
free(this->empty);
280
free(this->scratch);
281
free(this->tmp0);
282
283
284
if (this->resample.free)
285
resample_free(&this->resample);
286
- if (this->dir0.conv.free)
287
- convert_free(&this->dir0.conv);
288
- if (this->dir1.conv.free)
289
- convert_free(&this->dir1.conv);
290
if (this->wav_file != NULL)
291
wav_file_close(this->wav_file);
292
free (this->vol_ramp_sequence);
293
294
this->props.monitor.n_volumes = this->props.n_channels;
295
296
this->dirSPA_DIRECTION_INPUT.direction = SPA_DIRECTION_INPUT;
297
- this->dirSPA_DIRECTION_INPUT.latency = SPA_LATENCY_INFO(SPA_DIRECTION_INPUT);
298
this->dirSPA_DIRECTION_OUTPUT.direction = SPA_DIRECTION_OUTPUT;
299
- this->dirSPA_DIRECTION_OUTPUT.latency = SPA_LATENCY_INFO(SPA_DIRECTION_OUTPUT);
300
301
this->node.iface = SPA_INTERFACE_INIT(
302
SPA_TYPE_INTERFACE_Node,
303
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
213
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
}
202
else if (spa_streq(key, "State")) {
203
enum spa_bt_transport_state state = spa_bt_transport_state_from_string(value);
204
205
}
206
207
for (i = 0; codecsi != NULL; ++i) {
208
- if (spa_bt_device_supports_media_codec(device, codecsi, true)) {
209
+ if (spa_bt_device_supports_media_codec(device, codecsi, device->connected_profiles)) {
210
preferred_codec = codecsi;
211
break;
212
}
213
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
632
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
- if (!check_access(device))
202
+ if (!check_access(this, device))
203
return;
204
- else
205
- emit_object_info(device);
206
+ emit_object_info(this, device);
207
break;
208
209
case ACTION_REMOVE:
210
if (device == NULL)
211
return;
212
emitted = device->emitted;
213
- remove_device(device);
214
+ remove_device(this, device);
215
if (emitted)
216
- spa_device_emit_object_info(&impl->hooks, id, NULL);
217
+ spa_device_emit_object_info(&this->hooks, id, NULL);
218
break;
219
220
case ACTION_DISABLE:
221
222
return;
223
if (device->emitted) {
224
device->emitted = false;
225
- spa_device_emit_object_info(&impl->hooks, id, NULL);
226
+ spa_device_emit_object_info(&this->hooks, id, NULL);
227
}
228
break;
229
}
230
}
231
232
-static int stop_inotify(struct device *dev)
233
+static int stop_inotify(struct impl *this)
234
{
235
- struct impl *impl = dev->impl;
236
- if (dev->notify.fd == -1)
237
+ if (this->notify.fd == -1)
238
return 0;
239
- spa_log_info(impl->log, "stop inotify for /dev/video%u", dev->id);
240
- spa_loop_remove_source(impl->main_loop, &dev->notify);
241
- close(dev->notify.fd);
242
- dev->notify.fd = -1;
243
+ spa_log_info(this->log, "stop inotify");
244
+
245
+ for (size_t i = 0; i < this->n_devices; i++)
246
+ stop_watching_device(this, &this->devicesi);
247
+
248
+ spa_loop_remove_source(this->main_loop, &this->notify);
249
+ close(this->notify.fd);
250
+ this->notify.fd = -1;
251
return 0;
252
}
253
254
-
255
static void impl_on_notify_events(struct spa_source *source)
256
{
257
- struct device *dev = source->data;
258
- struct impl *impl = dev->impl;
259
+ struct impl *this = source->data;
260
union {
261
unsigned char namesizeof(struct inotify_event) + NAME_MAX + 1;
262
struct inotify_event e; /* for appropriate alignment */
263
} buf;
264
265
- if (source->rmask & (SPA_IO_ERR | SPA_IO_HUP)) {
266
- spa_log_warn(impl->log, "notify error on /dev/video%u", dev->id);
267
- stop_inotify(dev);
268
- return;
269
- }
270
- while (source->rmask & SPA_IO_IN) {
271
+ while (true) {
272
ssize_t len;
273
const struct inotify_event *event;
274
void *p, *e;
275
276
277
for (p = &buf; p < e;
278
p = SPA_PTROFF(p, sizeof(struct inotify_event) + event->len, void)) {
279
-
280
event = (const struct inotify_event *) p;
281
282
if ((event->mask & IN_ATTRIB)) {
283
- bool access;
284
- access = check_access(dev);
285
- if (access && !dev->emitted)
286
- process_device(impl, ACTION_ADD, dev->dev);
287
- else if (!access && dev->emitted)
288
- process_device(impl, ACTION_DISABLE, dev->dev);
289
+ struct device *device = NULL;
290
+
291
+ for (size_t i = 0; i < this->n_devices; i++) {
292
+ if (this->devicesi.inotify_wd == event->wd) {
293
+ device = &this->devicesi;
294
+ break;
295
+ }
296
+ }
297
+
298
+ spa_assert(device);
299
+
300
+ bool access = check_access(this, device);
301
+ if (access && !device->emitted)
302
+ process_device(this, ACTION_ADD, device->dev);
303
+ else if (!access && device->emitted)
304
+ process_device(this, ACTION_DISABLE, device->dev);
305
}
306
}
307
}
308
}
309
310
-static int start_inotify(struct device *dev)
311
+static int start_inotify(struct impl *this)
312
{
313
- struct impl *impl = dev->impl;
314
- int res, notify_fd;
315
- char name32;
316
+ int notify_fd;
317
318
- if (dev->notify.fd != -1)
319
+ if (this->notify.fd != -1)
320
return 0;
321
322
if ((notify_fd = inotify_init1(IN_CLOEXEC | IN_NONBLOCK)) < 0)
323
return -errno;
324
325
- snprintf(name, sizeof(name), "/dev/video%u", dev->id);
326
+ spa_log_info(this->log, "start inotify");
327
+ this->notify.func = impl_on_notify_events;
328
+ this->notify.data = this;
329
+ this->notify.fd = notify_fd;
330
+ this->notify.mask = SPA_IO_IN | SPA_IO_ERR;
331
332
- res = inotify_add_watch(notify_fd, name, IN_ATTRIB | IN_CLOSE_WRITE);
333
- if (res < 0) {
334
- res = -errno;
335
- close(notify_fd);
336
-
337
- if (res == -ENOENT) {
338
- spa_log_debug(impl->log, "%s does not exist yet", name);
339
- return 0;
340
- }
341
- spa_log_error(impl->log, "inotify_add_watch() failed: %s", spa_strerror(res));
342
- return res;
343
- }
344
- spa_log_info(impl->log, "start inotify for %s", name);
345
- dev->notify.func = impl_on_notify_events;
346
- dev->notify.data = dev;
347
- dev->notify.fd = notify_fd;
348
- dev->notify.mask = SPA_IO_IN | SPA_IO_ERR;
349
+ spa_loop_add_source(this->main_loop, &this->notify);
350
351
- spa_loop_add_source(impl->main_loop, &dev->notify);
352
+ for (size_t i = 0; i < this->n_devices; i++)
353
+ start_watching_device(this, &this->devicesi);
354
355
return 0;
356
}
357
358
static void impl_on_fd_events(struct spa_source *source)
359
{
360
- struct impl *impl = source->data;
361
+ struct impl *this = source->data;
362
struct udev_device *dev;
363
const char *action;
364
365
- dev = udev_monitor_receive_device(impl->umonitor);
366
+ dev = udev_monitor_receive_device(this->umonitor);
367
if (dev == NULL)
368
return;
369
370
if ((action = udev_device_get_action(dev)) == NULL)
371
action = "change";
372
373
- spa_log_debug(impl->log, "action %s", action);
374
+ spa_log_debug(this->log, "action %s", action);
375
+
376
+ start_inotify(this);
377
378
if (spa_streq(action, "add") ||
379
spa_streq(action, "change")) {
380
- process_device(impl, ACTION_ADD, dev);
381
+ process_device(this, ACTION_ADD, dev);
382
} else if (spa_streq(action, "remove")) {
383
- process_device(impl, ACTION_REMOVE, dev);
384
+ process_device(this, ACTION_REMOVE, dev);
385
}
386
udev_device_unref(dev);
387
}
388
389
-static int start_monitor(struct impl *impl)
390
+static int start_monitor(struct impl *this)
391
{
392
- if (impl->umonitor != NULL)
393
+ int res;
394
+
395
+ if (this->umonitor != NULL)
396
return 0;
397
398
- impl->umonitor = udev_monitor_new_from_netlink(impl->udev, "udev");
399
- if (impl->umonitor == NULL)
400
+ this->umonitor = udev_monitor_new_from_netlink(this->udev, "udev");
401
+ if (this->umonitor == NULL)
402
return -ENOMEM;
403
404
- udev_monitor_filter_add_match_subsystem_devtype(impl->umonitor,
405
+ udev_monitor_filter_add_match_subsystem_devtype(this->umonitor,
406
"video4linux", NULL);
407
- udev_monitor_enable_receiving(impl->umonitor);
408
+ udev_monitor_enable_receiving(this->umonitor);
409
410
- impl->source.func = impl_on_fd_events;
411
- impl->source.data = impl;
412
- impl->source.fd = udev_monitor_get_fd(impl->umonitor);
413
- impl->source.mask = SPA_IO_IN | SPA_IO_ERR;
414
+ this->source.func = impl_on_fd_events;
415
+ this->source.data = this;
416
+ this->source.fd = udev_monitor_get_fd(this->umonitor);
417
+ this->source.mask = SPA_IO_IN | SPA_IO_ERR;
418
419
- spa_log_debug(impl->log, "monitor %p", impl->umonitor);
420
- spa_loop_add_source(impl->main_loop, &impl->source);
421
+ spa_log_debug(this->log, "monitor %p", this->umonitor);
422
+ spa_loop_add_source(this->main_loop, &this->source);
423
+
424
+ if ((res = start_inotify(this)) < 0)
425
+ return res;
426
427
return 0;
428
}
429
430
-static int stop_monitor(struct impl *impl)
431
+static int stop_monitor(struct impl *this)
432
{
433
- if (impl->umonitor == NULL)
434
+ if (this->umonitor == NULL)
435
return 0;
436
437
- clear_devices(impl);
438
+ clear_devices (this);
439
440
- spa_loop_remove_source(impl->main_loop, &impl->source);
441
- udev_monitor_unref(impl->umonitor);
442
- impl->umonitor = NULL;
443
+ spa_loop_remove_source(this->main_loop, &this->source);
444
+ udev_monitor_unref(this->umonitor);
445
+ this->umonitor = NULL;
446
+
447
+ stop_inotify(this);
448
449
return 0;
450
}
451
452
-static int enum_devices(struct impl *impl)
453
+static int enum_devices(struct impl *this)
454
{
455
struct udev_enumerate *enumerate;
456
struct udev_list_entry *devices;
457
458
- enumerate = udev_enumerate_new(impl->udev);
459
+ enumerate = udev_enumerate_new(this->udev);
460
if (enumerate == NULL)
461
return -ENOMEM;
462
463
464
devices = udev_list_entry_get_next(devices)) {
465
struct udev_device *dev;
466
467
- dev = udev_device_new_from_syspath(impl->udev, udev_list_entry_get_name(devices));
468
+ dev = udev_device_new_from_syspath(this->udev, udev_list_entry_get_name(devices));
469
if (dev == NULL)
470
continue;
471
472
- process_device(impl, ACTION_ADD, dev);
473
+ process_device(this, ACTION_ADD, dev);
474
475
udev_device_unref(dev);
476
}
477
478
{ SPA_KEY_API_UDEV_MATCH, "video4linux" },
479
};
480
481
-static void emit_device_info(struct impl *impl, bool full)
482
+static void emit_device_info(struct impl *this, bool full)
483
{
484
- uint64_t old = full ? impl->info.change_mask : 0;
485
+ uint64_t old = full ? this->info.change_mask : 0;
486
if (full)
487
- impl->info.change_mask = impl->info_all;
488
- if (impl->info.change_mask) {
489
- impl->info.props = &SPA_DICT_INIT_ARRAY(device_info_items);
490
- spa_device_emit_info(&impl->hooks, &impl->info);
491
- impl->info.change_mask = old;
492
+ this->info.change_mask = this->info_all;
493
+ if (this->info.change_mask) {
494
+ this->info.props = &SPA_DICT_INIT_ARRAY(device_info_items);
495
+ spa_device_emit_info(&this->hooks, &this->info);
496
+ this->info.change_mask = old;
497
}
498
}
499
500
static void impl_hook_removed(struct spa_hook *hook)
501
{
502
- struct impl *impl = hook->priv;
503
- if (spa_hook_list_is_empty(&impl->hooks)) {
504
- stop_monitor(impl);
505
- impl_udev_close(impl);
506
+ struct impl *this = hook->priv;
507
+ if (spa_hook_list_is_empty(&this->hooks)) {
508
+ stop_monitor(this);
509
+ impl_udev_close(this);
510
}
511
}
512
513
514
const struct spa_device_events *events, void *data)
515
{
516
int res;
517
- struct impl *impl = object;
518
+ struct impl *this = object;
519
struct spa_hook_list save;
520
521
- spa_return_val_if_fail(impl != NULL, -EINVAL);
522
+ spa_return_val_if_fail(this != NULL, -EINVAL);
523
spa_return_val_if_fail(events != NULL, -EINVAL);
524
525
- if ((res = impl_udev_open(impl)) < 0)
526
+ if ((res = impl_udev_open(this)) < 0)
527
return res;
528
529
- spa_hook_list_isolate(&impl->hooks, &save, listener, events, data);
530
+ spa_hook_list_isolate(&this->hooks, &save, listener, events, data);
531
532
- emit_device_info(impl, true);
533
+ emit_device_info(this, true);
534
535
- if ((res = enum_devices(impl)) < 0)
536
+ if ((res = enum_devices(this)) < 0)
537
return res;
538
539
- if ((res = start_monitor(impl)) < 0)
540
+ if ((res = start_monitor(this)) < 0)
541
return res;
542
543
- spa_hook_list_join(&impl->hooks, &save);
544
+ spa_hook_list_join(&this->hooks, &save);
545
546
listener->removed = impl_hook_removed;
547
- listener->priv = impl;
548
+ listener->priv = this;
549
550
return 0;
551
}
552
553
554
static int impl_get_interface(struct spa_handle *handle, const char *type, void **interface)
555
{
556
- struct impl *impl;
557
+ struct impl *this;
558
559
spa_return_val_if_fail(handle != NULL, -EINVAL);
560
spa_return_val_if_fail(interface != NULL, -EINVAL);
561
562
- impl = (struct impl *) handle;
563
+ this = (struct impl *) handle;
564
565
if (spa_streq(type, SPA_TYPE_INTERFACE_Device))
566
- *interface = &impl->device;
567
+ *interface = &this->device;
568
else
569
return -ENOENT;
570
571
572
573
static int impl_clear(struct spa_handle *handle)
574
{
575
- struct impl *impl = (struct impl *) handle;
576
- stop_monitor(impl);
577
- impl_udev_close(impl);
578
+ struct impl *this = (struct impl *) handle;
579
+ stop_monitor(this);
580
+ impl_udev_close(this);
581
return 0;
582
}
583
584
585
const struct spa_support *support,
586
uint32_t n_support)
587
{
588
- struct impl *impl;
589
+ struct impl *this;
590
591
spa_return_val_if_fail(factory != NULL, -EINVAL);
592
spa_return_val_if_fail(handle != NULL, -EINVAL);
593
594
handle->get_interface = impl_get_interface;
595
handle->clear = impl_clear;
596
597
- impl = (struct impl *) handle;
598
- impl->log = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_Log);
599
- impl->main_loop = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_Loop);
600
+ this = (struct impl *) handle;
601
+ this->notify.fd = -1;
602
+
603
+ this->log = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_Log);
604
+ this->main_loop = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_Loop);
605
606
- if (impl->main_loop == NULL) {
607
- spa_log_error(impl->log, "a main-loop is needed");
608
+ if (this->main_loop == NULL) {
609
+ spa_log_error(this->log, "a main-loop is needed");
610
return -EINVAL;
611
}
612
- spa_hook_list_init(&impl->hooks);
613
+ spa_hook_list_init(&this->hooks);
614
615
- impl->device.iface = SPA_INTERFACE_INIT(
616
+ this->device.iface = SPA_INTERFACE_INIT(
617
SPA_TYPE_INTERFACE_Device,
618
SPA_VERSION_DEVICE,
619
- &impl_device, impl);
620
+ &impl_device, this);
621
622
- impl->info = SPA_DEVICE_INFO_INIT();
623
- impl->info_all = SPA_DEVICE_CHANGE_MASK_FLAGS |
624
+ this->info = SPA_DEVICE_INFO_INIT();
625
+ this->info_all = SPA_DEVICE_CHANGE_MASK_FLAGS |
626
SPA_DEVICE_CHANGE_MASK_PROPS;
627
- impl->info.flags = 0;
628
+ this->info.flags = 0;
629
630
return 0;
631
}
632
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
257
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
+ port->info.flags &= ~SPA_PORT_FLAG_CAN_ALLOC_BUFFERS;
202
+ }
203
+ port->info.change_mask |= SPA_PORT_CHANGE_MASK_FLAGS;
204
+
205
port->current_format = info;
206
port->have_format = true;
207
+
208
+ if (modifier_fixed) {
209
+ port->info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS;
210
+ port->params0.flags ^= SPA_PARAM_INFO_SERIAL;
211
+ emit_port_info(this, port, false);
212
+ return 0;
213
+ }
214
}
215
216
port->info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS;
217
218
spa_log_info(this->log, "%p: %d:%d add buffer %p", port, direction, port_id, b);
219
spa_list_append(&port->empty, &b->link);
220
}
221
- spa_vulkan_use_buffers(&this->state, &this->state.streamsport->stream_id, flags, n_buffers, buffers);
222
+ spa_vulkan_use_buffers(&this->state, &this->state.streamsport->stream_id, flags, &port->current_format.info.dsp, n_buffers, buffers);
223
port->n_buffers = n_buffers;
224
225
return 0;
226
227
228
static int impl_clear(struct spa_handle *handle)
229
{
230
+ struct impl *this;
231
+
232
+ spa_return_val_if_fail(handle != NULL, -EINVAL);
233
+
234
+ this = (struct impl *) handle;
235
+
236
+ spa_vulkan_deinit(&this->state);
237
return 0;
238
}
239
240
241
SPA_PORT_CHANGE_MASK_PARAMS |
242
SPA_PORT_CHANGE_MASK_PROPS;
243
port->info = SPA_PORT_INFO_INIT();
244
- port->info.flags = SPA_PORT_FLAG_NO_REF | SPA_PORT_FLAG_CAN_ALLOC_BUFFERS;
245
+ port->info.flags = SPA_PORT_FLAG_NO_REF;
246
port->params0 = SPA_PARAM_INFO(SPA_PARAM_EnumFormat, SPA_PARAM_INFO_READ);
247
port->params1 = SPA_PARAM_INFO(SPA_PARAM_Meta, SPA_PARAM_INFO_READ);
248
port->params2 = SPA_PARAM_INFO(SPA_PARAM_IO, SPA_PARAM_INFO_READ);
249
250
SPA_DIRECTION_OUTPUT, NULL);
251
252
this->state.n_streams = 2;
253
+ spa_vulkan_init(&this->state);
254
spa_vulkan_prepare(&this->state);
255
256
return 0;
257
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
257
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
+ } else {
202
+ port->info.flags &= ~SPA_PORT_FLAG_CAN_ALLOC_BUFFERS;
203
+ }
204
+ port->info.change_mask |= SPA_PORT_CHANGE_MASK_FLAGS;
205
+
206
port->current_format = info;
207
port->have_format = true;
208
spa_vulkan_prepare(&this->state);
209
+
210
+ if (modifier_fixed) {
211
+ port->info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS;
212
+ port->params0.flags ^= SPA_PARAM_INFO_SERIAL;
213
+ emit_port_info(this, port, false);
214
+ return 0;
215
+ }
216
}
217
218
port->info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS;
219
220
b->flags = 0;
221
b->h = spa_buffer_find_meta_data(buffersi, SPA_META_Header, sizeof(*b->h));
222
223
+ spa_log_info(this->log, "%p: %d:%d add buffer %p", port, direction, port_id, b);
224
spa_list_append(&port->empty, &b->link);
225
}
226
- spa_vulkan_use_buffers(&this->state, &this->state.streams0, flags, n_buffers, buffers);
227
+ spa_vulkan_use_buffers(&this->state, &this->state.streams0, flags, &port->current_format.info.dsp, n_buffers, buffers);
228
port->n_buffers = n_buffers;
229
230
return 0;
231
232
233
this = (struct impl *) handle;
234
235
+ spa_vulkan_deinit(&this->state);
236
+
237
if (this->data_loop)
238
spa_loop_invoke(this->data_loop, do_remove_timer, 0, NULL, 0, true, this);
239
spa_system_close(this->data_system, this->timer_source.fd);
240
241
SPA_PORT_CHANGE_MASK_PARAMS |
242
SPA_PORT_CHANGE_MASK_PROPS;
243
port->info = SPA_PORT_INFO_INIT();
244
- port->info.flags = SPA_PORT_FLAG_NO_REF | SPA_PORT_FLAG_CAN_ALLOC_BUFFERS;
245
+ port->info.flags = SPA_PORT_FLAG_NO_REF;
246
if (this->props.live)
247
port->info.flags |= SPA_PORT_FLAG_LIVE;
248
port->params0 = SPA_PARAM_INFO(SPA_PARAM_EnumFormat, SPA_PARAM_INFO_READ);
249
250
SPA_DIRECTION_OUTPUT, NULL);
251
this->state.shaderName = "spa/plugins/vulkan/shaders/main.spv";
252
this->state.n_streams = 1;
253
+ spa_vulkan_init(&this->state);
254
255
return 0;
256
}
257
pipewire-0.3.80.tar.gz/spa/plugins/vulkan/vulkan-compute-utils.c
Added
677
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
+ }
202
+ return shaderModule;
203
+}
204
+
205
+static int createComputePipeline(struct vulkan_compute_state *s, const char *shader_file)
206
+{
207
+ static const VkPushConstantRange range = {
208
+ .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
209
+ .offset = 0,
210
+ .size = sizeof(struct push_constants)
211
+ };
212
+
213
+ const VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = {
214
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
215
+ .setLayoutCount = 1,
216
+ .pSetLayouts = &s->descriptorSetLayout,
217
+ .pushConstantRangeCount = 1,
218
+ .pPushConstantRanges = &range,
219
+ };
220
+ VK_CHECK_RESULT(vkCreatePipelineLayout(s->base.device,
221
+ &pipelineLayoutCreateInfo, NULL,
222
+ &s->pipelineLayout));
223
+
224
+ s->computeShaderModule = createShaderModule(s, shader_file);
225
+ if (s->computeShaderModule == VK_NULL_HANDLE)
226
+ return -ENOENT;
227
+
228
+ const VkPipelineShaderStageCreateInfo shaderStageCreateInfo = {
229
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
230
+ .stage = VK_SHADER_STAGE_COMPUTE_BIT,
231
+ .module = s->computeShaderModule,
232
+ .pName = "main",
233
+ };
234
+ const VkComputePipelineCreateInfo pipelineCreateInfo = {
235
+ .sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,
236
+ .stage = shaderStageCreateInfo,
237
+ .layout = s->pipelineLayout,
238
+ };
239
+ VK_CHECK_RESULT(vkCreateComputePipelines(s->base.device, VK_NULL_HANDLE,
240
+ 1, &pipelineCreateInfo, NULL,
241
+ &s->pipeline));
242
+ return 0;
243
+}
244
+
245
+static int createCommandBuffer(struct vulkan_compute_state *s)
246
+{
247
+ CHECK(vulkan_commandPool_create(&s->base, &s->commandPool));
248
+ CHECK(vulkan_commandBuffer_create(&s->base, s->commandPool, &s->commandBuffer));
249
+
250
+ return 0;
251
+}
252
+
253
+static int runExportSHMBuffers(struct vulkan_compute_state *s) {
254
+ for (uint32_t i = 0; i < s->n_streams; i++) {
255
+ struct vulkan_stream *p = &s->streamsi;
256
+
257
+ if (p->direction == SPA_DIRECTION_INPUT)
258
+ continue;
259
+
260
+ if (p->spa_buffersp->current_buffer_id->datas0.type == SPA_DATA_MemPtr) {
261
+ struct spa_buffer *spa_buf = p->spa_buffersp->current_buffer_id;
262
+ struct vulkan_read_pixels_info readInfo = {
263
+ .data = spa_buf->datas0.data,
264
+ .offset = spa_buf->datas0.chunk->offset,
265
+ .stride = spa_buf->datas0.chunk->stride,
266
+ .bytes_per_pixel = 16,
267
+ .size.width = s->constants.width,
268
+ .size.height = s->constants.height,
269
+ };
270
+ CHECK(vulkan_read_pixels(&s->base, &readInfo, &p->buffersp->current_buffer_id));
271
+ }
272
+ }
273
+
274
+ return 0;
275
+}
276
+
277
+/** runCommandBuffer
278
+ * The return value of this functions means the following:
279
+ * ret < 0: Error
280
+ * ret = 0: queueSubmit was succsessful, but manual synchronization is required
281
+ * ret = 1: queueSubmit was succsessful and buffers can be released without synchronization
282
+ */
283
+static int runCommandBuffer(struct vulkan_compute_state *s)
284
+{
285
+ VULKAN_INSTANCE_FUNCTION(vkQueueSubmit2KHR);
286
+ VULKAN_INSTANCE_FUNCTION(vkGetSemaphoreFdKHR);
287
+
288
+ static const VkCommandBufferBeginInfo beginInfo = {
289
+ .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
290
+ .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
291
+ };
292
+ VK_CHECK_RESULT(vkBeginCommandBuffer(s->commandBuffer, &beginInfo));
293
+
294
+ vkCmdBindPipeline(s->commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, s->pipeline);
295
+ vkCmdPushConstants (s->commandBuffer,
296
+ s->pipelineLayout, VK_SHADER_STAGE_COMPUTE_BIT,
297
+ 0, sizeof(struct push_constants), (const void *) &s->constants);
298
+ vkCmdBindDescriptorSets(s->commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE,
299
+ s->pipelineLayout, 0, 1, &s->descriptorSet, 0, NULL);
300
+
301
+ vkCmdDispatch(s->commandBuffer,
302
+ (uint32_t)ceil(s->constants.width / (float)WORKGROUP_SIZE),
303
+ (uint32_t)ceil(s->constants.height / (float)WORKGROUP_SIZE), 1);
304
+
305
+ VkImageMemoryBarrier acquire_barriers->n_streams;
306
+ VkImageMemoryBarrier release_barriers->n_streams;
307
+ VkSemaphoreSubmitInfo semaphore_wait_infos->n_streams;
308
+ uint32_t semaphore_wait_info_len = 0;
309
+ VkSemaphoreSubmitInfo semaphore_signal_info1;
310
+ uint32_t semaphore_signal_info_len = 0;
311
+
312
+ uint32_t i;
313
+ for (i = 0; i < s->n_streams; i++) {
314
+ struct vulkan_stream *p = &s->streamsi;
315
+ struct vulkan_buffer *current_buffer = &p->buffersp->current_buffer_id;
316
+ struct spa_buffer *current_spa_buffer = p->spa_buffersp->current_buffer_id;
317
+
318
+ VkAccessFlags access_flags;
319
+ if (p->direction == SPA_DIRECTION_INPUT) {
320
+ access_flags = VK_ACCESS_SHADER_READ_BIT;
321
+ } else {
322
+ access_flags = VK_ACCESS_SHADER_WRITE_BIT;
323
+ }
324
+
325
+ acquire_barrieri= (VkImageMemoryBarrier) {
326
+ .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
327
+ .srcQueueFamilyIndex = VK_QUEUE_FAMILY_FOREIGN_EXT,
328
+ .dstQueueFamilyIndex = s->base.queueFamilyIndex,
329
+ .image = current_buffer->image,
330
+ .oldLayout = VK_IMAGE_LAYOUT_UNDEFINED,
331
+ .newLayout = VK_IMAGE_LAYOUT_GENERAL,
332
+ .srcAccessMask = 0,
333
+ .dstAccessMask = access_flags,
334
+ .subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
335
+ .subresourceRange.levelCount = 1,
336
+ .subresourceRange.layerCount = 1,
337
+ };
338
+
339
+ release_barrieri= (VkImageMemoryBarrier) {
340
+ .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
341
+ .srcQueueFamilyIndex = s->base.queueFamilyIndex,
342
+ .dstQueueFamilyIndex = VK_QUEUE_FAMILY_FOREIGN_EXT,
343
+ .image = current_buffer->image,
344
+ .oldLayout = VK_IMAGE_LAYOUT_GENERAL,
345
+ .newLayout = VK_IMAGE_LAYOUT_GENERAL,
346
+ .srcAccessMask = access_flags,
347
+ .dstAccessMask = 0,
348
+ .subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
349
+ .subresourceRange.levelCount = 1,
350
+ .subresourceRange.layerCount = 1,
351
+ };
352
+
353
+ if (current_spa_buffer->datas0.type != SPA_DATA_DmaBuf)
354
+ continue;
355
+
356
+ if (vulkan_sync_foreign_dmabuf(&s->base, current_buffer) < 0) {
357
+ spa_log_warn(s->log, "Failed to wait for foreign buffer DMA-BUF fence");
358
+ } else {
359
+ if (current_buffer->foreign_semaphore != VK_NULL_HANDLE) {
360
+ semaphore_wait_infosemaphore_wait_info_len++ = (VkSemaphoreSubmitInfo) {
361
+ .sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO,
362
+ .semaphore = current_buffer->foreign_semaphore,
363
+ .stageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
364
+ };
365
+ }
366
+ }
367
+ }
368
+
369
+ vkCmdPipelineBarrier(s->commandBuffer,
370
+ VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
371
+ VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
372
+ 0, 0, NULL, 0, NULL,
373
+ s->n_streams, acquire_barrier);
374
+
375
+ vkCmdPipelineBarrier(s->commandBuffer,
376
+ VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
377
+ VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
378
+ 0, 0, NULL, 0, NULL,
379
+ s->n_streams, release_barrier);
380
+
381
+ VK_CHECK_RESULT(vkEndCommandBuffer(s->commandBuffer));
382
+
383
+ VK_CHECK_RESULT(vkResetFences(s->base.device, 1, &s->fence));
384
+
385
+ if (s->pipelineSemaphore == VK_NULL_HANDLE) {
386
+ VkExportSemaphoreCreateInfo export_info = {
387
+ .sType = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO,
388
+ .handleTypes = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT,
389
+ };
390
+ VkSemaphoreCreateInfo semaphore_info = {
391
+ .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
392
+ .pNext = &export_info,
393
+ };
394
+ VK_CHECK_RESULT(vkCreateSemaphore(s->base.device, &semaphore_info, NULL, &s->pipelineSemaphore));
395
+ }
396
+
397
+ semaphore_signal_infosemaphore_signal_info_len++ = (VkSemaphoreSubmitInfo) {
398
+ .sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO,
399
+ .semaphore = s->pipelineSemaphore,
400
+ };
401
+
402
+ VkCommandBufferSubmitInfoKHR commandBufferInfo = {
403
+ .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO,
404
+ .commandBuffer = s->commandBuffer,
405
+ };
406
+
407
+ const VkSubmitInfo2KHR submitInfo = {
408
+ .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO_2_KHR,
409
+ .commandBufferInfoCount = 1,
410
+ .pCommandBufferInfos = &commandBufferInfo,
411
+ .waitSemaphoreInfoCount = semaphore_wait_info_len,
412
+ .pWaitSemaphoreInfos = semaphore_wait_info,
413
+ .signalSemaphoreInfoCount = semaphore_signal_info_len,
414
+ .pSignalSemaphoreInfos = semaphore_signal_info,
415
+ };
416
+ VK_CHECK_RESULT(vkQueueSubmit2KHR(s->base.queue, 1, &submitInfo, s->fence));
417
+ s->started = true;
418
+
419
+ VkSemaphoreGetFdInfoKHR get_fence_fd_info = {
420
+ .sType = VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR,
421
+ .semaphore = s->pipelineSemaphore,
422
+ .handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT,
423
+ };
424
+ int sync_file_fd = -1;
425
+ VK_CHECK_RESULT(vkGetSemaphoreFdKHR(s->base.device, &get_fence_fd_info, &sync_file_fd));
426
+
427
+ int ret = 1;
428
+ for (uint32_t i = 0; i < s->n_streams; i++) {
429
+ struct vulkan_stream *p = &s->streamsi;
430
+ struct spa_buffer *current_spa_buffer = p->spa_buffersp->current_buffer_id;
431
+
432
+ if (current_spa_buffer->datas0.type != SPA_DATA_DmaBuf)
433
+ continue;
434
+
435
+ if (!vulkan_sync_export_dmabuf(&s->base, &p->buffersp->current_buffer_id, sync_file_fd)) {
436
+ ret = 0;
437
+ }
438
+ }
439
+ close(sync_file_fd);
440
+
441
+ return ret;
442
+}
443
+
444
+static void clear_buffers(struct vulkan_compute_state *s, struct vulkan_stream *p)
445
+{
446
+ uint32_t i;
447
+
448
+ for (i = 0; i < p->n_buffers; i++) {
449
+ vulkan_buffer_clear(&s->base, &p->buffersi);
450
+ p->spa_buffersi = NULL;
451
+ }
452
+ p->n_buffers = 0;
453
+}
454
+
455
+static void clear_streams(struct vulkan_compute_state *s)
456
+{
457
+ uint32_t i;
458
+ for (i = 0; i < s->n_streams; i++) {
459
+ struct vulkan_stream *p = &s->streamsi;
460
+ clear_buffers(s, p);
461
+ }
462
+}
463
+
464
+int spa_vulkan_fixate_modifier(struct vulkan_compute_state *s, struct vulkan_stream *p, struct spa_video_info_dsp *dsp_info,
465
+ uint32_t modifierCount, uint64_t *modifiers, uint64_t *modifier)
466
+{
467
+ VkFormat format = vulkan_id_to_vkformat(dsp_info->format);
468
+ if (format == VK_FORMAT_UNDEFINED) {
469
+ return -1;
470
+ }
471
+
472
+ struct dmabuf_fixation_info fixation_info = {
473
+ .format = format,
474
+ .modifierCount = modifierCount,
475
+ .modifiers = modifiers,
476
+ .size.width = s->constants.width,
477
+ .size.height = s->constants.height,
478
+ .usage = VK_IMAGE_USAGE_STORAGE_BIT,
479
+ };
480
+ return vulkan_fixate_modifier(&s->base, &fixation_info, modifier);
481
+}
482
+
483
+int spa_vulkan_use_buffers(struct vulkan_compute_state *s, struct vulkan_stream *p, uint32_t flags,
484
+ struct spa_video_info_dsp *dsp_info, uint32_t n_buffers, struct spa_buffer **buffers)
485
+{
486
+ VkFormat format = vulkan_id_to_vkformat(dsp_info->format);
487
+ if (format == VK_FORMAT_UNDEFINED)
488
+ return -1;
489
+
490
+ vulkan_wait_idle(&s->base);
491
+ clear_buffers(s, p);
492
+
493
+ bool alloc = flags & SPA_NODE_BUFFERS_FLAG_ALLOC;
494
+ int ret;
495
+ p->n_buffers = 0;
496
+ for (uint32_t i = 0; i < n_buffers; i++) {
497
+ if (alloc) {
498
+ if (SPA_FLAG_IS_SET(buffersi->datas0.type, 1<<SPA_DATA_DmaBuf)) {
499
+ struct external_buffer_info dmabufInfo = {
500
+ .format = format,
501
+ .modifier = dsp_info->modifier,
502
+ .size.width = s->constants.width,
503
+ .size.height = s->constants.height,
504
+ .usage = p->direction == SPA_DIRECTION_OUTPUT
505
+ ? VK_IMAGE_USAGE_STORAGE_BIT
506
+ : VK_IMAGE_USAGE_SAMPLED_BIT,
507
+ .spa_buf = buffersi,
508
+ };
509
+ ret = vulkan_create_dmabuf(&s->base, &dmabufInfo, &p->buffersi);
510
+ } else {
511
+ spa_log_error(s->log, "Unsupported buffer type mask %d", buffersi->datas0.type);
512
+ return -1;
513
+ }
514
+ } else {
515
+ switch (buffersi->datas0.type) {
516
+ case SPA_DATA_DmaBuf:;
517
+ struct external_buffer_info dmabufInfo = {
518
+ .format = format,
519
+ .modifier = dsp_info->modifier,
520
+ .size.width = s->constants.width,
521
+ .size.height = s->constants.height,
522
+ .usage = p->direction == SPA_DIRECTION_OUTPUT
523
+ ? VK_IMAGE_USAGE_STORAGE_BIT
524
+ : VK_IMAGE_USAGE_SAMPLED_BIT,
525
+ .spa_buf = buffersi,
526
+ };
527
+ ret = vulkan_import_dmabuf(&s->base, &dmabufInfo, &p->buffersi);
528
+ break;
529
+ case SPA_DATA_MemPtr:;
530
+ struct external_buffer_info memptrInfo = {
531
+ .format = format,
532
+ .size.width = s->constants.width,
533
+ .size.height = s->constants.height,
534
+ .usage = p->direction == SPA_DIRECTION_OUTPUT
535
+ ? VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT
536
+ : VK_IMAGE_USAGE_SAMPLED_BIT,
537
+ .spa_buf = buffersi,
538
+ };
539
+ ret = vulkan_import_memptr(&s->base, &memptrInfo, &p->buffersi);
540
+ break;
541
+ default:
542
+ spa_log_error(s->log, "Unsupported buffer type %d", buffersi->datas0.type);
543
+ return -1;
544
+ }
545
+ }
546
+ if (ret != 0) {
547
+ spa_log_error(s->log, "Failed to use buffer %d", i);
548
+ return ret;
549
+ }
550
+ p->spa_buffersi = buffersi;
551
+ p->n_buffers++;
552
+ }
553
+
554
+ return 0;
555
+}
556
+
557
+int spa_vulkan_init_stream(struct vulkan_compute_state *s, struct vulkan_stream *stream,
558
+ enum spa_direction direction, struct spa_dict *props)
559
+{
560
+ return vulkan_stream_init(stream, direction, props);
561
+}
562
+
563
+int spa_vulkan_prepare(struct vulkan_compute_state *s)
564
+{
565
+ if (!s->prepared) {
566
+ CHECK(createFence(s));
567
+ CHECK(createDescriptors(s));
568
+ CHECK(createComputePipeline(s, s->shaderName));
569
+ CHECK(createCommandBuffer(s));
570
+ s->prepared = true;
571
+ }
572
+ return 0;
573
+}
574
+
575
+int spa_vulkan_unprepare(struct vulkan_compute_state *s)
576
+{
577
+ if (s->prepared) {
578
+ vkDestroyShaderModule(s->base.device, s->computeShaderModule, NULL);
579
+ vkDestroySampler(s->base.device, s->sampler, NULL);
580
+ vkDestroyDescriptorPool(s->base.device, s->descriptorPool, NULL);
581
+ vkDestroyDescriptorSetLayout(s->base.device, s->descriptorSetLayout, NULL);
582
+ vkDestroyPipelineLayout(s->base.device, s->pipelineLayout, NULL);
583
+ vkDestroyPipeline(s->base.device, s->pipeline, NULL);
584
+ vkDestroyCommandPool(s->base.device, s->commandPool, NULL);
585
+ vkDestroyFence(s->base.device, s->fence, NULL);
586
+ s->prepared = false;
587
+ }
588
+ return 0;
589
+}
590
+
591
+int spa_vulkan_start(struct vulkan_compute_state *s)
592
+{
593
+ uint32_t i;
594
+
595
+ for (i = 0; i < s->n_streams; i++) {
596
+ struct vulkan_stream *p = &s->streamsi;
597
+ p->current_buffer_id = SPA_ID_INVALID;
598
+ p->busy_buffer_id = SPA_ID_INVALID;
599
+ p->ready_buffer_id = SPA_ID_INVALID;
600
+ }
601
+ return 0;
602
+}
603
+
604
+int spa_vulkan_stop(struct vulkan_compute_state *s)
605
+{
606
+ VK_CHECK_RESULT(vkDeviceWaitIdle(s->base.device));
607
+ clear_streams(s);
608
+ s->started = false;
609
+ return 0;
610
+}
611
+
612
+int spa_vulkan_ready(struct vulkan_compute_state *s)
613
+{
614
+ uint32_t i;
615
+ VkResult result;
616
+
617
+ if (!s->started)
618
+ return 0;
619
+
620
+ result = vkGetFenceStatus(s->base.device, s->fence);
621
+ if (result == VK_NOT_READY)
622
+ return -EBUSY;
623
+ VK_CHECK_RESULT(result);
624
+
625
+ s->started = false;
626
+
627
+ for (i = 0; i < s->n_streams; i++) {
628
+ struct vulkan_stream *p = &s->streamsi;
629
+ p->ready_buffer_id = p->busy_buffer_id;
630
+ p->busy_buffer_id = SPA_ID_INVALID;
631
+ }
632
+ return 0;
633
+}
634
+
635
+int spa_vulkan_process(struct vulkan_compute_state *s)
636
+{
637
+ CHECK(updateDescriptors(s));
638
+ CHECK(runCommandBuffer(s));
639
+ VK_CHECK_RESULT(vkDeviceWaitIdle(s->base.device));
640
+ CHECK(runExportSHMBuffers(s));
641
+
642
+ return 0;
643
+}
644
+
645
+int spa_vulkan_get_buffer_caps(struct vulkan_compute_state *s, enum spa_direction direction)
646
+{
647
+ switch (direction) {
648
+ case SPA_DIRECTION_INPUT:
649
+ return VULKAN_BUFFER_TYPE_CAP_DMABUF;
650
+ case SPA_DIRECTION_OUTPUT:
651
+ return VULKAN_BUFFER_TYPE_CAP_DMABUF | VULKAN_BUFFER_TYPE_CAP_SHM;
652
+ }
653
+ return 0;
654
+}
655
+
656
+struct vulkan_modifier_info *spa_vulkan_get_modifier_info(struct vulkan_compute_state *s, struct spa_video_info_dsp *info) {
657
+ VkFormat vk_format = vulkan_id_to_vkformat(info->format);
658
+ return vulkan_modifierInfo_find(&s->base, vk_format, info->modifier);
659
+}
660
+
661
+int spa_vulkan_init(struct vulkan_compute_state *s)
662
+{
663
+ s->base.log = s->log;
664
+ uint32_t dsp_format = SPA_VIDEO_FORMAT_DSP_F32;
665
+ struct vulkan_base_info baseInfo = {
666
+ .queueFlags = VK_QUEUE_COMPUTE_BIT,
667
+ .formatInfo.formatCount = 1,
668
+ .formatInfo.formats = &dsp_format,
669
+ };
670
+ return vulkan_base_init(&s->base, &baseInfo);
671
+}
672
+
673
+void spa_vulkan_deinit(struct vulkan_compute_state *s)
674
+{
675
+ vulkan_base_deinit(&s->base);
676
+}
677
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
1226
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
+ VkDrmFormatModifierPropertiesListEXT modPropsList = {
202
+ .sType = VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT,
203
+ };
204
+ VkFormatProperties2 fmtProps = {
205
+ .sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2,
206
+ .pNext = &modPropsList,
207
+ };
208
+ vkGetPhysicalDeviceFormatProperties2(s->physicalDevice, format, &fmtProps);
209
210
- VkDescriptorPoolSize descriptorPoolSizes2 = {
211
- {
212
- .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
213
- .descriptorCount = 1,
214
- },
215
- {
216
- .type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
217
- .descriptorCount = s->n_streams - 1,
218
- },
219
- };
220
- const VkDescriptorPoolCreateInfo descriptorPoolCreateInfo = {
221
- .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
222
- .maxSets = s->n_streams,
223
- .poolSizeCount = s->n_streams > 1 ? 2 : 1,
224
- .pPoolSizes = descriptorPoolSizes,
225
- };
226
+ if (!modPropsList.drmFormatModifierCount)
227
+ continue;
228
229
- VK_CHECK_RESULT(vkCreateDescriptorPool(s->device,
230
- &descriptorPoolCreateInfo, NULL,
231
- &s->descriptorPool));
232
+ modPropsList.pDrmFormatModifierProperties = calloc(modPropsList.drmFormatModifierCount,
233
+ sizeof(modPropsList.pDrmFormatModifierProperties0));
234
+ if (!modPropsList.pDrmFormatModifierProperties)
235
+ continue;
236
+ vkGetPhysicalDeviceFormatProperties2(s->physicalDevice, format, &fmtProps);
237
238
- VkDescriptorSetLayoutBinding descriptorSetLayoutBindings->n_streams;
239
- descriptorSetLayoutBinding0 = (VkDescriptorSetLayoutBinding) {
240
- .binding = 0,
241
- .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
242
- .descriptorCount = 1,
243
- .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT
244
- };
245
- for (i = 1; i < s->n_streams; i++) {
246
- descriptorSetLayoutBindingi = (VkDescriptorSetLayoutBinding) {
247
- .binding = i,
248
- .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
249
- .descriptorCount = 1,
250
- .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT
251
- };
252
- };
253
- const VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCreateInfo = {
254
- .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
255
- .bindingCount = s->n_streams,
256
- .pBindings = descriptorSetLayoutBinding
257
- };
258
- VK_CHECK_RESULT(vkCreateDescriptorSetLayout(s->device,
259
- &descriptorSetLayoutCreateInfo, NULL,
260
- &s->descriptorSetLayout));
261
-
262
- const VkDescriptorSetAllocateInfo descriptorSetAllocateInfo = {
263
- .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
264
- .descriptorPool = s->descriptorPool,
265
- .descriptorSetCount = 1,
266
- .pSetLayouts = &s->descriptorSetLayout
267
- };
268
+ f_info->infos = calloc(modPropsList.drmFormatModifierCount, sizeof(f_info->infos0));
269
+ if (!f_info->infos) {
270
+ free(modPropsList.pDrmFormatModifierProperties);
271
+ continue;
272
+ }
273
274
- VK_CHECK_RESULT(vkAllocateDescriptorSets(s->device,
275
- &descriptorSetAllocateInfo,
276
- &s->descriptorSet));
277
-
278
- const VkSamplerCreateInfo samplerInfo = {
279
- .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
280
- .magFilter = VK_FILTER_LINEAR,
281
- .minFilter = VK_FILTER_LINEAR,
282
- .mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR,
283
- .addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
284
- .addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
285
- .addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
286
- .borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK,
287
- .unnormalizedCoordinates = VK_FALSE,
288
- .compareEnable = VK_FALSE,
289
- .compareOp = VK_COMPARE_OP_ALWAYS,
290
- .mipLodBias = 0.0f,
291
- .minLod = 0,
292
- .maxLod = 5,
293
- };
294
- VK_CHECK_RESULT(vkCreateSampler(s->device, &samplerInfo, NULL, &s->sampler));
295
+ for (uint32_t j = 0; j < modPropsList.drmFormatModifierCount; j++) {
296
+ VkDrmFormatModifierPropertiesEXT props = modPropsList.pDrmFormatModifierPropertiesj;
297
298
- return 0;
299
-}
300
+ if (!(props.drmFormatModifierTilingFeatures & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT))
301
+ continue;
302
303
-static int updateDescriptors(struct vulkan_state *s)
304
-{
305
- uint32_t i;
306
- VkDescriptorImageInfo descriptorImageInfos->n_streams;
307
- VkWriteDescriptorSet writeDescriptorSets->n_streams;
308
+ if (props.drmFormatModifierPlaneCount > DMABUF_MAX_PLANES)
309
+ continue;
310
311
- for (i = 0; i < s->n_streams; i++) {
312
- struct vulkan_stream *p = &s->streamsi;
313
+ VkPhysicalDeviceImageDrmFormatModifierInfoEXT modInfo = {
314
+ .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT,
315
+ .drmFormatModifier = props.drmFormatModifier,
316
+ .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
317
+ };
318
+ VkPhysicalDeviceExternalImageFormatInfo extImgFmtInfo = {
319
+ .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO,
320
+ .pNext = &modInfo,
321
+ .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
322
+ };
323
+ VkPhysicalDeviceImageFormatInfo2 imgFmtInfo = {
324
+ .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2,
325
+ .pNext = &extImgFmtInfo,
326
+ .type = VK_IMAGE_TYPE_2D,
327
+ .format = format,
328
+ .usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
329
+ .tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT,
330
+ };
331
332
- if (p->current_buffer_id == p->pending_buffer_id ||
333
- p->pending_buffer_id == SPA_ID_INVALID)
334
- continue;
335
+ VkExternalImageFormatProperties extImgFmtProps = {
336
+ .sType = VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES,
337
+ };
338
+ VkImageFormatProperties2 imgFmtProps = {
339
+ .sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2,
340
+ .pNext = &extImgFmtProps,
341
+ };
342
343
- p->current_buffer_id = p->pending_buffer_id;
344
- p->busy_buffer_id = p->current_buffer_id;
345
- p->pending_buffer_id = SPA_ID_INVALID;
346
+ VK_CHECK_RESULT_LOOP(vkGetPhysicalDeviceImageFormatProperties2(s->physicalDevice, &imgFmtInfo, &imgFmtProps))
347
348
- descriptorImageInfoi = (VkDescriptorImageInfo) {
349
- .sampler = s->sampler,
350
- .imageView = p->buffersp->current_buffer_id.view,
351
- .imageLayout = VK_IMAGE_LAYOUT_GENERAL,
352
- };
353
- writeDescriptorSeti = (VkWriteDescriptorSet) {
354
- .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
355
- .dstSet = s->descriptorSet,
356
- .dstBinding = i,
357
- .descriptorCount = 1,
358
- .descriptorType = i == 0 ?
359
- VK_DESCRIPTOR_TYPE_STORAGE_IMAGE :
360
- VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
361
- .pImageInfo = &descriptorImageInfoi,
362
- };
363
- }
364
- vkUpdateDescriptorSets(s->device, s->n_streams,
365
- writeDescriptorSet, 0, NULL);
366
+ VkExternalMemoryFeatureFlags extMemFeatures =
367
+ extImgFmtProps.externalMemoryProperties.externalMemoryFeatures;
368
+ if (!(extMemFeatures & VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT)) {
369
+ continue;
370
+ }
371
+
372
+ VkExtent3D max_extent = imgFmtProps.imageFormatProperties.maxExtent;
373
+ f_info->infosf_info->modifierCount++ = (struct vulkan_modifier_info){
374
+ .props = props,
375
+ .max_extent = { .width = max_extent.width, .height = max_extent.height },
376
+ };
377
378
+ }
379
+ free(modPropsList.pDrmFormatModifierProperties);
380
+ }
381
return 0;
382
}
383
384
-static VkShaderModule createShaderModule(struct vulkan_state *s, const char* shaderFile)
385
+static void destroyFormatInfo(struct vulkan_base *s)
386
{
387
- VkShaderModule shaderModule = VK_NULL_HANDLE;
388
- VkResult result;
389
- void *data;
390
- int fd;
391
- struct stat stat;
392
-
393
- if ((fd = open(shaderFile, 0, O_RDONLY)) == -1) {
394
- spa_log_error(s->log, "can't open %s: %m", shaderFile);
395
- return VK_NULL_HANDLE;
396
+ for (uint32_t i = 0; i < s->formatInfoCount; i++) {
397
+ free(s->formatInfosi.infos);
398
}
399
- if (fstat(fd, &stat) < 0) {
400
- spa_log_error(s->log, "can't stat %s: %m", shaderFile);
401
- close(fd);
402
- return VK_NULL_HANDLE;
403
+ free(s->formatInfos);
404
+ s->formatInfos = NULL;
405
+ s->formatInfoCount = 0;
406
+}
407
+
408
+int vulkan_read_pixels(struct vulkan_base *s, struct vulkan_read_pixels_info *info, struct vulkan_buffer *vk_buf)
409
+{
410
+ VkImageSubresource img_sub_res = {
411
+ .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
412
+ .arrayLayer = 0,
413
+ .mipLevel = 0,
414
+ };
415
+ VkSubresourceLayout img_sub_layout;
416
+ vkGetImageSubresourceLayout(s->device, vk_buf->image, &img_sub_res, &img_sub_layout);
417
+
418
+ void *v;
419
+ VK_CHECK_RESULT(vkMapMemory(s->device, vk_buf->memory, 0, VK_WHOLE_SIZE, 0, &v));
420
+
421
+ const char *d = (const char *)v + img_sub_layout.offset;
422
+ unsigned char *p = (unsigned char *)info->data + info->offset;
423
+ uint32_t bytes_per_pixel = 16;
424
+ uint32_t pack_stride = img_sub_layout.rowPitch;
425
+ if (pack_stride == info->stride) {
426
+ memcpy(p, d, info->stride * info->size.height);
427
+ } else {
428
+ for (uint32_t i = 0; i < info->size.height; i++) {
429
+ memcpy(p + i * info->stride, d + i * pack_stride, info->size.width * bytes_per_pixel);
430
+ }
431
}
432
+ vkUnmapMemory(s->device, vk_buf->memory);
433
+ return 0;
434
+}
435
436
- data = mmap(NULL, stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
437
+int vulkan_sync_foreign_dmabuf(struct vulkan_base *s, struct vulkan_buffer *vk_buf)
438
+{
439
+ VULKAN_INSTANCE_FUNCTION(vkImportSemaphoreFdKHR);
440
441
- const VkShaderModuleCreateInfo shaderModuleCreateInfo = {
442
- .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
443
- .codeSize = stat.st_size,
444
- .pCode = data,
445
- };
446
- result = vkCreateShaderModule(s->device,
447
- &shaderModuleCreateInfo, 0, &shaderModule);
448
+ if (!s->implicit_sync_interop) {
449
+ struct pollfd pollfd = {
450
+ .fd = vk_buf->fd,
451
+ .events = POLLIN,
452
+ };
453
+ int timeout_ms = 1000;
454
+ int ret = poll(&pollfd, 1, timeout_ms);
455
+ if (ret < 0) {
456
+ spa_log_error(s->log, "Failed to wait for DMA-BUF fence");
457
+ return -1;
458
+ } else if (ret == 0) {
459
+ spa_log_error(s->log, "Timed out waiting for DMA-BUF fence");
460
+ return -1;
461
+ }
462
+ return 0;
463
+ }
464
465
- munmap(data, stat.st_size);
466
- close(fd);
467
+ int sync_file_fd = dmabuf_export_sync_file(s->log, vk_buf->fd, DMA_BUF_SYNC_READ);
468
+ if (sync_file_fd < 0) {
469
+ spa_log_error(s->log, "Failed to extract for DMA-BUF fence");
470
+ return -1;
471
+ }
472
473
- if (result != VK_SUCCESS) {
474
- spa_log_error(s->log, "can't create shader %s: %m", shaderFile);
475
- return VK_NULL_HANDLE;
476
+ if (vk_buf->foreign_semaphore == VK_NULL_HANDLE) {
477
+ VkSemaphoreCreateInfo semaphore_info = {
478
+ .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
479
+ };
480
+ VK_CHECK_RESULT_WITH_CLEANUP(vkCreateSemaphore(s->device, &semaphore_info, NULL, &vk_buf->foreign_semaphore), close(sync_file_fd));
481
}
482
- return shaderModule;
483
-}
484
485
-static int createComputePipeline(struct vulkan_state *s, const char *shader_file)
486
-{
487
- static const VkPushConstantRange range = {
488
- .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
489
- .offset = 0,
490
- .size = sizeof(struct push_constants)
491
+ VkImportSemaphoreFdInfoKHR import_info = {
492
+ .sType = VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHR,
493
+ .handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT,
494
+ .flags = VK_SEMAPHORE_IMPORT_TEMPORARY_BIT_KHR,
495
+ .semaphore = vk_buf->foreign_semaphore,
496
+ .fd = sync_file_fd,
497
};
498
+ VK_CHECK_RESULT_WITH_CLEANUP(vkImportSemaphoreFdKHR(s->device, &import_info), close(sync_file_fd));
499
500
- const VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = {
501
- .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
502
- .setLayoutCount = 1,
503
- .pSetLayouts = &s->descriptorSetLayout,
504
- .pushConstantRangeCount = 1,
505
- .pPushConstantRanges = &range,
506
- };
507
- VK_CHECK_RESULT(vkCreatePipelineLayout(s->device,
508
- &pipelineLayoutCreateInfo, NULL,
509
- &s->pipelineLayout));
510
-
511
- s->computeShaderModule = createShaderModule(s, shader_file);
512
- if (s->computeShaderModule == VK_NULL_HANDLE)
513
- return -ENOENT;
514
-
515
- const VkPipelineShaderStageCreateInfo shaderStageCreateInfo = {
516
- .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
517
- .stage = VK_SHADER_STAGE_COMPUTE_BIT,
518
- .module = s->computeShaderModule,
519
- .pName = "main",
520
- };
521
- const VkComputePipelineCreateInfo pipelineCreateInfo = {
522
- .sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,
523
- .stage = shaderStageCreateInfo,
524
- .layout = s->pipelineLayout,
525
- };
526
- VK_CHECK_RESULT(vkCreateComputePipelines(s->device, VK_NULL_HANDLE,
527
- 1, &pipelineCreateInfo, NULL,
528
- &s->pipeline));
529
return 0;
530
}
531
532
-static int createCommandBuffer(struct vulkan_state *s)
533
+bool vulkan_sync_export_dmabuf(struct vulkan_base *s, struct vulkan_buffer *vk_buf, int sync_file_fd)
534
+{
535
+ if (!s->implicit_sync_interop)
536
+ return false;
537
+
538
+ return dmabuf_import_sync_file(s->log, vk_buf->fd, DMA_BUF_SYNC_WRITE, sync_file_fd);
539
+}
540
+
541
+int vulkan_commandPool_create(struct vulkan_base *s, VkCommandPool *commandPool)
542
{
543
const VkCommandPoolCreateInfo commandPoolCreateInfo = {
544
.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
545
546
};
547
VK_CHECK_RESULT(vkCreateCommandPool(s->device,
548
&commandPoolCreateInfo, NULL,
549
- &s->commandPool));
550
+ commandPool));
551
552
+ return 0;
553
+}
554
+
555
+int vulkan_commandBuffer_create(struct vulkan_base *s, VkCommandPool commandPool, VkCommandBuffer *commandBuffer)
556
+{
557
const VkCommandBufferAllocateInfo commandBufferAllocateInfo = {
558
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
559
- .commandPool = s->commandPool,
560
+ .commandPool = commandPool,
561
.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
562
.commandBufferCount = 1,
563
};
564
VK_CHECK_RESULT(vkAllocateCommandBuffers(s->device,
565
&commandBufferAllocateInfo,
566
- &s->commandBuffer));
567
+ commandBuffer));
568
569
return 0;
570
}
571
572
-static int runCommandBuffer(struct vulkan_state *s)
573
+uint32_t vulkan_memoryType_find(struct vulkan_base *s,
574
+ uint32_t memoryTypeBits, VkMemoryPropertyFlags properties)
575
{
576
- static const VkCommandBufferBeginInfo beginInfo = {
577
- .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
578
- .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
579
- };
580
- VK_CHECK_RESULT(vkBeginCommandBuffer(s->commandBuffer, &beginInfo));
581
-
582
- VkImageMemoryBarrier barriers->n_streams;
583
uint32_t i;
584
+ VkPhysicalDeviceMemoryProperties memoryProperties;
585
586
- for (i = 0; i < s->n_streams; i++) {
587
- struct vulkan_stream *p = &s->streamsi;
588
-
589
- barrieri= (VkImageMemoryBarrier) {
590
- .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
591
- .subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
592
- .subresourceRange.levelCount = 1,
593
- .subresourceRange.layerCount = 1,
594
- .oldLayout = VK_IMAGE_LAYOUT_UNDEFINED,
595
- .newLayout = VK_IMAGE_LAYOUT_GENERAL,
596
- .srcAccessMask = 0,
597
- .dstAccessMask = 0,
598
- .image = p->buffersp->current_buffer_id.image,
599
- };
600
+ vkGetPhysicalDeviceMemoryProperties(s->physicalDevice, &memoryProperties);
601
+
602
+ for (i = 0; i < memoryProperties.memoryTypeCount; i++) {
603
+ if ((memoryTypeBits & (1 << i)) &&
604
+ ((memoryProperties.memoryTypesi.propertyFlags & properties) == properties))
605
+ return i;
606
}
607
+ return -1;
608
+}
609
610
- vkCmdPipelineBarrier(s->commandBuffer,
611
- VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
612
- VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
613
- 0, 0, NULL, 0, NULL,
614
- s->n_streams, barrier);
615
+struct vulkan_format_info *vulkan_formatInfo_find(struct vulkan_base *s, VkFormat format)
616
+{
617
+ for (uint32_t i = 0; i < s->formatInfoCount; i++) {
618
+ if (s->formatInfosi.vk_format == format)
619
+ return &s->formatInfosi;
620
+ }
621
+ return NULL;
622
+}
623
624
- vkCmdBindPipeline(s->commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, s->pipeline);
625
- vkCmdPushConstants (s->commandBuffer,
626
- s->pipelineLayout, VK_SHADER_STAGE_COMPUTE_BIT,
627
- 0, sizeof(struct push_constants), (const void *) &s->constants);
628
- vkCmdBindDescriptorSets(s->commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE,
629
- s->pipelineLayout, 0, 1, &s->descriptorSet, 0, NULL);
630
+struct vulkan_modifier_info *vulkan_modifierInfo_find(struct vulkan_base *s, VkFormat format, uint64_t mod)
631
+{
632
+ struct vulkan_format_info *f_info = vulkan_formatInfo_find(s, format);
633
+ if (!f_info)
634
+ return NULL;
635
+ for (uint32_t i = 0; i < f_info->modifierCount; i++) {
636
+ if (f_info->infosi.props.drmFormatModifier == mod)
637
+ return &f_info->infosi;
638
+ }
639
+ return NULL;
640
+}
641
+
642
+void vulkan_buffer_clear(struct vulkan_base *s, struct vulkan_buffer *buffer)
643
+{
644
+ if (buffer->fd != -1)
645
+ close(buffer->fd);
646
+ vkFreeMemory(s->device, buffer->memory, NULL);
647
+ vkDestroyImage(s->device, buffer->image, NULL);
648
+ vkDestroyImageView(s->device, buffer->view, NULL);
649
+}
650
+
651
+static VkImageAspectFlagBits mem_plane_aspect(uint32_t i)
652
+{
653
+ switch (i) {
654
+ case 0: return VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT;
655
+ case 1: return VK_IMAGE_ASPECT_MEMORY_PLANE_1_BIT_EXT;
656
+ case 2: return VK_IMAGE_ASPECT_MEMORY_PLANE_2_BIT_EXT;
657
+ case 3: return VK_IMAGE_ASPECT_MEMORY_PLANE_3_BIT_EXT;
658
+ default: abort(); // unreachable
659
+ }
660
+}
661
662
- vkCmdDispatch(s->commandBuffer,
663
- (uint32_t)ceil(s->constants.width / (float)WORKGROUP_SIZE),
664
- (uint32_t)ceil(s->constants.height / (float)WORKGROUP_SIZE), 1);
665
+static int allocate_dmabuf(struct vulkan_base *s, VkFormat format, uint32_t modifierCount, uint64_t *modifiers, VkImageUsageFlags usage, struct spa_rectangle *size, struct vulkan_buffer *vk_buf)
666
+{
667
+ VkImageDrmFormatModifierListCreateInfoEXT imageDrmFormatModifierListCreateInfo = {
668
+ .sType = VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT,
669
+ .drmFormatModifierCount = modifierCount,
670
+ .pDrmFormatModifiers = modifiers,
671
+ };
672
673
- VK_CHECK_RESULT(vkEndCommandBuffer(s->commandBuffer));
674
+ VkExternalMemoryImageCreateInfo extMemoryImageCreateInfo = {
675
+ .sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO,
676
+ .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
677
+ };
678
+ extMemoryImageCreateInfo.pNext = &imageDrmFormatModifierListCreateInfo;
679
+
680
+ VkImageCreateInfo imageCreateInfo = {
681
+ .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
682
+ .imageType = VK_IMAGE_TYPE_2D,
683
+ .format = format,
684
+ .extent.width = size->width,
685
+ .extent.height = size->height,
686
+ .extent.depth = 1,
687
+ .mipLevels = 1,
688
+ .arrayLayers = 1,
689
+ .samples = VK_SAMPLE_COUNT_1_BIT,
690
+ .tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT,
691
+ .usage = usage,
692
+ .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
693
+ .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
694
+ };
695
+ imageCreateInfo.pNext = &extMemoryImageCreateInfo;
696
697
- VK_CHECK_RESULT(vkResetFences(s->device, 1, &s->fence));
698
+ VK_CHECK_RESULT(vkCreateImage(s->device,
699
+ &imageCreateInfo, NULL, &vk_buf->image));
700
701
- const VkSubmitInfo submitInfo = {
702
- .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
703
- .commandBufferCount = 1,
704
- .pCommandBuffers = &s->commandBuffer,
705
+ VkMemoryRequirements memoryRequirements = {0};
706
+ vkGetImageMemoryRequirements(s->device,
707
+ vk_buf->image, &memoryRequirements);
708
+
709
+ VkExportMemoryAllocateInfo exportAllocateInfo = {
710
+ .sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO,
711
+ .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
712
};
713
- VK_CHECK_RESULT(vkQueueSubmit(s->queue, 1, &submitInfo, s->fence));
714
- s->started = true;
715
+ VkMemoryAllocateInfo allocateInfo = {
716
+ .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
717
+ .allocationSize = memoryRequirements.size,
718
+ .memoryTypeIndex = vulkan_memoryType_find(s,
719
+ memoryRequirements.memoryTypeBits,
720
+ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT),
721
+ };
722
+ allocateInfo.pNext = &exportAllocateInfo;
723
+
724
+ VK_CHECK_RESULT(vkAllocateMemory(s->device,
725
+ &allocateInfo, NULL, &vk_buf->memory));
726
+
727
+ VK_CHECK_RESULT(vkBindImageMemory(s->device,
728
+ vk_buf->image, vk_buf->memory, 0));
729
730
return 0;
731
}
732
733
-static void clear_buffers(struct vulkan_state *s, struct vulkan_stream *p)
734
+int vulkan_fixate_modifier(struct vulkan_base *s, struct dmabuf_fixation_info *info, uint64_t *modifier)
735
{
736
- uint32_t i;
737
+ VULKAN_INSTANCE_FUNCTION(vkGetImageDrmFormatModifierPropertiesEXT);
738
739
- for (i = 0; i < p->n_buffers; i++) {
740
- if (p->buffersi.fd != -1)
741
- close(p->buffersi.fd);
742
- vkFreeMemory(s->device, p->buffersi.memory, NULL);
743
- vkDestroyImage(s->device, p->buffersi.image, NULL);
744
- vkDestroyImageView(s->device, p->buffersi.view, NULL);
745
- }
746
- p->n_buffers = 0;
747
-}
748
+ struct vulkan_buffer vk_buf;
749
+ vk_buf.fd = -1;
750
+ vk_buf.view = VK_NULL_HANDLE;
751
+ VK_CHECK_RESULT(allocate_dmabuf(s, info->format, info->modifierCount, info->modifiers, info->usage, &info->size, &vk_buf));
752
753
-static void clear_streams(struct vulkan_state *s)
754
-{
755
- uint32_t i;
756
- for (i = 0; i < s->n_streams; i++) {
757
- struct vulkan_stream *p = &s->streamsi;
758
- clear_buffers(s, p);
759
- }
760
+ VkImageDrmFormatModifierPropertiesEXT mod_prop = {
761
+ .sType = VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_PROPERTIES_EXT,
762
+ };
763
+ VK_CHECK_RESULT(vkGetImageDrmFormatModifierPropertiesEXT(s->device, vk_buf.image, &mod_prop));
764
+
765
+ *modifier = mod_prop.drmFormatModifier;
766
+
767
+ vulkan_buffer_clear(s, &vk_buf);
768
+
769
+ return 0;
770
}
771
772
-int spa_vulkan_use_buffers(struct vulkan_state *s, struct vulkan_stream *p, uint32_t flags,
773
- uint32_t n_buffers, struct spa_buffer **buffers)
774
+int vulkan_create_dmabuf(struct vulkan_base *s, struct external_buffer_info *info, struct vulkan_buffer *vk_buf)
775
{
776
- uint32_t i;
777
VULKAN_INSTANCE_FUNCTION(vkGetMemoryFdKHR);
778
779
- clear_buffers(s, p);
780
-
781
- for (i = 0; i < n_buffers; i++) {
782
- VkExternalMemoryImageCreateInfo extInfo;
783
- VkImageCreateInfo imageCreateInfo = {
784
- .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
785
- .imageType = VK_IMAGE_TYPE_2D,
786
- .format = VK_FORMAT_R32G32B32A32_SFLOAT,
787
- .extent.width = s->constants.width,
788
- .extent.height = s->constants.height,
789
- .extent.depth = 1,
790
- .mipLevels = 1,
791
- .arrayLayers = 1,
792
- .samples = VK_SAMPLE_COUNT_1_BIT,
793
- .tiling = VK_IMAGE_TILING_LINEAR,
794
- .usage = p->direction == SPA_DIRECTION_OUTPUT ?
795
- VK_IMAGE_USAGE_STORAGE_BIT:
796
- VK_IMAGE_USAGE_SAMPLED_BIT,
797
- .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
798
- .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
799
- };
800
+ if (info->spa_buf->n_datas != 1)
801
+ return -1;
802
803
- if (!(flags & SPA_NODE_BUFFERS_FLAG_ALLOC)) {
804
- extInfo = (VkExternalMemoryImageCreateInfo) {
805
- .sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO,
806
- .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
807
- };
808
- imageCreateInfo.pNext = &extInfo;
809
- }
810
+ VK_CHECK_RESULT(allocate_dmabuf(s, info->format, 1, &info->modifier, info->usage, &info->size, vk_buf));
811
812
- VK_CHECK_RESULT(vkCreateImage(s->device,
813
- &imageCreateInfo, NULL, &p->buffersi.image));
814
+ const VkMemoryGetFdInfoKHR getFdInfo = {
815
+ .sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR,
816
+ .memory = vk_buf->memory,
817
+ .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT
818
+ };
819
+ int fd = -1;
820
+ VK_CHECK_RESULT(vkGetMemoryFdKHR(s->device, &getFdInfo, &fd));
821
822
- VkMemoryRequirements memoryRequirements;
823
- vkGetImageMemoryRequirements(s->device,
824
- p->buffersi.image, &memoryRequirements);
825
+ const struct vulkan_modifier_info *modInfo = vulkan_modifierInfo_find(s, info->format, info->modifier);
826
827
- VkMemoryAllocateInfo allocateInfo = {
828
- .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
829
- .allocationSize = memoryRequirements.size,
830
- .memoryTypeIndex = findMemoryType(s,
831
- memoryRequirements.memoryTypeBits,
832
- VK_MEMORY_PROPERTY_HOST_COHERENT_BIT |
833
- VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT),
834
- };
835
+ if (info->spa_buf->n_datas != modInfo->props.drmFormatModifierPlaneCount)
836
+ return -1;
837
838
- if (flags & SPA_NODE_BUFFERS_FLAG_ALLOC) {
839
- VK_CHECK_RESULT(vkAllocateMemory(s->device,
840
- &allocateInfo, NULL, &p->buffersi.memory));
841
+ VkMemoryRequirements memoryRequirements = {0};
842
+ vkGetImageMemoryRequirements(s->device,
843
+ vk_buf->image, &memoryRequirements);
844
845
- const VkMemoryGetFdInfoKHR getFdInfo = {
846
- .sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR,
847
- .memory = p->buffersi.memory,
848
- .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT
849
- };
850
- int fd;
851
-
852
- VK_CHECK_RESULT(vkGetMemoryFdKHR(s->device, &getFdInfo, &fd));
853
-
854
- spa_log_info(s->log, "export DMABUF %zd", memoryRequirements.size);
855
-
856
-// buffersi->datas0.type = SPA_DATA_DmaBuf;
857
- buffersi->datas0.type = SPA_DATA_MemFd;
858
- buffersi->datas0.fd = fd;
859
- buffersi->datas0.flags = SPA_DATA_FLAG_READABLE;
860
- buffersi->datas0.mapoffset = 0;
861
- buffersi->datas0.maxsize = memoryRequirements.size;
862
- p->buffersi.fd = fd;
863
- } else {
864
- VkImportMemoryFdInfoKHR importInfo = {
865
- .sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR,
866
- .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
867
- .fd = fcntl(buffersi->datas0.fd, F_DUPFD_CLOEXEC, 0),
868
- };
869
- allocateInfo.pNext = &importInfo;
870
- p->buffersi.fd = -1;
871
- spa_log_info(s->log, "import DMABUF");
872
+ spa_log_info(s->log, "export DMABUF %zd", memoryRequirements.size);
873
874
- VK_CHECK_RESULT(vkAllocateMemory(s->device,
875
- &allocateInfo, NULL, &p->buffersi.memory));
876
- }
877
- VK_CHECK_RESULT(vkBindImageMemory(s->device,
878
- p->buffersi.image, p->buffersi.memory, 0));
879
-
880
- VkImageViewCreateInfo viewInfo = {
881
- .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
882
- .image = p->buffersi.image,
883
- .viewType = VK_IMAGE_VIEW_TYPE_2D,
884
- .format = VK_FORMAT_R32G32B32A32_SFLOAT,
885
- .components.r = VK_COMPONENT_SWIZZLE_R,
886
- .components.g = VK_COMPONENT_SWIZZLE_G,
887
- .components.b = VK_COMPONENT_SWIZZLE_B,
888
- .components.a = VK_COMPONENT_SWIZZLE_A,
889
- .subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
890
- .subresourceRange.levelCount = 1,
891
- .subresourceRange.layerCount = 1,
892
+ for (uint32_t i = 0; i < info->spa_buf->n_datas; i++) {
893
+ VkImageSubresource subresource = {
894
+ .aspectMask = mem_plane_aspect(i),
895
};
896
+ VkSubresourceLayout subresLayout = {0};
897
+ vkGetImageSubresourceLayout(s->device, vk_buf->image, &subresource, &subresLayout);
898
+
899
+ info->spa_buf->datasi.type = SPA_DATA_DmaBuf;
900
+ info->spa_buf->datasi.fd = fd;
901
+ info->spa_buf->datasi.flags = SPA_DATA_FLAG_READABLE;
902
+ info->spa_buf->datasi.mapoffset = 0;
903
+ info->spa_buf->datasi.chunk->offset = subresLayout.offset;
904
+ info->spa_buf->datasi.chunk->stride = subresLayout.rowPitch;
905
+ info->spa_buf->datasi.chunk->size = subresLayout.size;
906
+ info->spa_buf->datasi.maxsize = memoryRequirements.size;
907
+ }
908
+ vk_buf->fd = fd;
909
+
910
+ VkImageViewCreateInfo viewInfo = {
911
+ .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
912
+ .image = vk_buf->image,
913
+ .viewType = VK_IMAGE_VIEW_TYPE_2D,
914
+ .format = info->format,
915
+ .components.r = VK_COMPONENT_SWIZZLE_R,
916
+ .components.g = VK_COMPONENT_SWIZZLE_G,
917
+ .components.b = VK_COMPONENT_SWIZZLE_B,
918
+ .components.a = VK_COMPONENT_SWIZZLE_A,
919
+ .subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
920
+ .subresourceRange.levelCount = 1,
921
+ .subresourceRange.layerCount = 1,
922
+ };
923
+
924
+ VK_CHECK_RESULT(vkCreateImageView(s->device,
925
+ &viewInfo, NULL, &vk_buf->view));
926
+ return 0;
927
+}
928
929
- VK_CHECK_RESULT(vkCreateImageView(s->device,
930
- &viewInfo, NULL, &p->buffersi.view));
931
+int vulkan_import_dmabuf(struct vulkan_base *s, struct external_buffer_info *info, struct vulkan_buffer *vk_buf)
932
+{
933
+
934
+ if (info->spa_buf->n_datas == 0 || info->spa_buf->n_datas > DMABUF_MAX_PLANES)
935
+ return -1;
936
+
937
+ struct vulkan_modifier_info *modProps = vulkan_modifierInfo_find(s, info->format, info->modifier);
938
+ if (!modProps)
939
+ return -1;
940
+
941
+ uint32_t planeCount = info->spa_buf->n_datas;
942
+
943
+ if (planeCount != modProps->props.drmFormatModifierPlaneCount)
944
+ return -1;
945
+
946
+ if (info->size.width > modProps->max_extent.width || info->size.height > modProps->max_extent.height)
947
+ return -1;
948
+
949
+ VkSubresourceLayout planeLayoutsDMABUF_MAX_PLANES = {0};
950
+ for (uint32_t i = 0; i < planeCount; i++) {
951
+ planeLayoutsi.offset = info->spa_buf->datasi.chunk->offset;
952
+ planeLayoutsi.rowPitch = info->spa_buf->datasi.chunk->stride;
953
+ planeLayoutsi.size = 0;
954
}
955
- p->n_buffers = n_buffers;
956
957
+ VkImageDrmFormatModifierExplicitCreateInfoEXT modInfo = {
958
+ .sType = VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT,
959
+ .drmFormatModifierPlaneCount = planeCount,
960
+ .drmFormatModifier = info->modifier,
961
+ .pPlaneLayouts = planeLayouts,
962
+ };
963
+
964
+ VkExternalMemoryImageCreateInfo extInfo = {
965
+ .sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO,
966
+ .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
967
+ .pNext = &modInfo,
968
+ };
969
+
970
+ VkImageCreateInfo imageCreateInfo = {
971
+ .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
972
+ .imageType = VK_IMAGE_TYPE_2D,
973
+ .format = info->format,
974
+ .extent.width = info->size.width,
975
+ .extent.height = info->size.height,
976
+ .extent.depth = 1,
977
+ .mipLevels = 1,
978
+ .arrayLayers = 1,
979
+ .samples = VK_SAMPLE_COUNT_1_BIT,
980
+ .tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT,
981
+ .usage = info->usage,
982
+ .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
983
+ .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
984
+ .pNext = &extInfo,
985
+ };
986
+
987
+ VK_CHECK_RESULT(vkCreateImage(s->device,
988
+ &imageCreateInfo, NULL, &vk_buf->image));
989
+
990
+ VkMemoryRequirements memoryRequirements;
991
+ vkGetImageMemoryRequirements(s->device,
992
+ vk_buf->image, &memoryRequirements);
993
+
994
+ vk_buf->fd = fcntl(info->spa_buf->datas0.fd, F_DUPFD_CLOEXEC, 0);
995
+ VkImportMemoryFdInfoKHR importInfo = {
996
+ .sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR,
997
+ .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
998
+ .fd = fcntl(info->spa_buf->datas0.fd, F_DUPFD_CLOEXEC, 0),
999
+ };
1000
+
1001
+ VkMemoryAllocateInfo allocateInfo = {
1002
+ .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
1003
+ .allocationSize = memoryRequirements.size,
1004
+ .memoryTypeIndex = vulkan_memoryType_find(s,
1005
+ memoryRequirements.memoryTypeBits,
1006
+ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT),
1007
+ };
1008
+ allocateInfo.pNext = &importInfo;
1009
+
1010
+ spa_log_info(s->log, "import DMABUF");
1011
+
1012
+ VK_CHECK_RESULT(vkAllocateMemory(s->device,
1013
+ &allocateInfo, NULL, &vk_buf->memory));
1014
+ VK_CHECK_RESULT(vkBindImageMemory(s->device,
1015
+ vk_buf->image, vk_buf->memory, 0));
1016
+
1017
+ VkImageViewCreateInfo viewInfo = {
1018
+ .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
1019
+ .image = vk_buf->image,
1020
+ .viewType = VK_IMAGE_VIEW_TYPE_2D,
1021
+ .format = info->format,
1022
+ .components.r = VK_COMPONENT_SWIZZLE_R,
1023
+ .components.g = VK_COMPONENT_SWIZZLE_G,
1024
+ .components.b = VK_COMPONENT_SWIZZLE_B,
1025
+ .components.a = VK_COMPONENT_SWIZZLE_A,
1026
+ .subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
1027
+ .subresourceRange.levelCount = 1,
1028
+ .subresourceRange.layerCount = 1,
1029
+ };
1030
+
1031
+ VK_CHECK_RESULT(vkCreateImageView(s->device,
1032
+ &viewInfo, NULL, &vk_buf->view));
1033
+ return 0;
1034
+}
1035
+
1036
+int vulkan_import_memptr(struct vulkan_base *s, struct external_buffer_info *info, struct vulkan_buffer *vk_buf)
1037
+{
1038
+ VkImageCreateInfo imageCreateInfo = {
1039
+ .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
1040
+ .imageType = VK_IMAGE_TYPE_2D,
1041
+ .format = info->format,
1042
+ .extent.width = info->size.width,
1043
+ .extent.height = info->size.height,
1044
+ .extent.depth = 1,
1045
+ .mipLevels = 1,
1046
+ .arrayLayers = 1,
1047
+ .samples = VK_SAMPLE_COUNT_1_BIT,
1048
+ .tiling = VK_IMAGE_TILING_LINEAR,
1049
+ .usage = info->usage,
1050
+ .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
1051
+ .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
1052
+ };
1053
+
1054
+ VK_CHECK_RESULT(vkCreateImage(s->device,
1055
+ &imageCreateInfo, NULL, &vk_buf->image));
1056
+
1057
+ VkMemoryRequirements memoryRequirements;
1058
+ vkGetImageMemoryRequirements(s->device,
1059
+ vk_buf->image, &memoryRequirements);
1060
+
1061
+ VkMemoryAllocateInfo allocateInfo = {
1062
+ .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
1063
+ .allocationSize = memoryRequirements.size,
1064
+ .memoryTypeIndex = vulkan_memoryType_find(s,
1065
+ memoryRequirements.memoryTypeBits,
1066
+ VK_MEMORY_PROPERTY_HOST_COHERENT_BIT |
1067
+ VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT),
1068
+ };
1069
+
1070
+ vk_buf->fd = -1;
1071
+ spa_log_info(s->log, "import MemPtr");
1072
+
1073
+ VK_CHECK_RESULT(vkAllocateMemory(s->device,
1074
+ &allocateInfo, NULL, &vk_buf->memory));
1075
+ VK_CHECK_RESULT(vkBindImageMemory(s->device,
1076
+ vk_buf->image, vk_buf->memory, 0));
1077
+
1078
+ VkImageViewCreateInfo viewInfo = {
1079
+ .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
1080
+ .image = vk_buf->image,
1081
+ .viewType = VK_IMAGE_VIEW_TYPE_2D,
1082
+ .format = info->format,
1083
+ .components.r = VK_COMPONENT_SWIZZLE_R,
1084
+ .components.g = VK_COMPONENT_SWIZZLE_G,
1085
+ .components.b = VK_COMPONENT_SWIZZLE_B,
1086
+ .components.a = VK_COMPONENT_SWIZZLE_A,
1087
+ .subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
1088
+ .subresourceRange.levelCount = 1,
1089
+ .subresourceRange.layerCount = 1,
1090
+ };
1091
+
1092
+ VK_CHECK_RESULT(vkCreateImageView(s->device,
1093
+ &viewInfo, NULL, &vk_buf->view));
1094
return 0;
1095
}
1096
1097
-int spa_vulkan_init_stream(struct vulkan_state *s, struct vulkan_stream *stream,
1098
- enum spa_direction direction, struct spa_dict *props)
1099
+int vulkan_stream_init(struct vulkan_stream *stream, enum spa_direction direction,
1100
+ struct spa_dict *props)
1101
{
1102
spa_zero(*stream);
1103
stream->direction = direction;
1104
1105
return 0;
1106
}
1107
1108
-int spa_vulkan_prepare(struct vulkan_state *s)
1109
+uint32_t vulkan_vkformat_to_id(VkFormat format)
1110
{
1111
- if (!s->prepared) {
1112
- CHECK(createInstance(s));
1113
- CHECK(findPhysicalDevice(s));
1114
- CHECK(createDevice(s));
1115
- CHECK(createDescriptors(s));
1116
- CHECK(createComputePipeline(s, s->shaderName));
1117
- CHECK(createCommandBuffer(s));
1118
- s->prepared = true;
1119
+ SPA_FOR_EACH_ELEMENT_VAR(vk_video_format_convs, f) {
1120
+ if (f->format == format)
1121
+ return f->id;
1122
}
1123
- return 0;
1124
+ return SPA_VIDEO_FORMAT_UNKNOWN;
1125
}
1126
1127
-int spa_vulkan_unprepare(struct vulkan_state *s)
1128
+VkFormat vulkan_id_to_vkformat(uint32_t id)
1129
{
1130
- if (s->prepared) {
1131
- vkDestroyShaderModule(s->device, s->computeShaderModule, NULL);
1132
- vkDestroySampler(s->device, s->sampler, NULL);
1133
- vkDestroyDescriptorPool(s->device, s->descriptorPool, NULL);
1134
- vkDestroyDescriptorSetLayout(s->device, s->descriptorSetLayout, NULL);
1135
- vkDestroyPipelineLayout(s->device, s->pipelineLayout, NULL);
1136
- vkDestroyPipeline(s->device, s->pipeline, NULL);
1137
- vkDestroyCommandPool(s->device, s->commandPool, NULL);
1138
- vkDestroyFence(s->device, s->fence, NULL);
1139
- vkDestroyDevice(s->device, NULL);
1140
- vkDestroyInstance(s->instance, NULL);
1141
- s->prepared = false;
1142
+ SPA_FOR_EACH_ELEMENT_VAR(vk_video_format_convs, f) {
1143
+ if (f->id == id)
1144
+ return f->format;
1145
}
1146
- return 0;
1147
+ return VK_FORMAT_UNDEFINED;
1148
}
1149
1150
-int spa_vulkan_start(struct vulkan_state *s)
1151
+int vulkan_vkresult_to_errno(VkResult result)
1152
{
1153
- uint32_t i;
1154
+ return vkresult_to_errno(result);
1155
+}
1156
+
1157
+int vulkan_wait_fence(struct vulkan_base *s, VkFence fence)
1158
+{
1159
+ VK_CHECK_RESULT(vkWaitForFences(s->device, 1, &fence, VK_TRUE, UINT64_MAX));
1160
1161
- for (i = 0; i < s->n_streams; i++) {
1162
- struct vulkan_stream *p = &s->streamsi;
1163
- p->current_buffer_id = SPA_ID_INVALID;
1164
- p->busy_buffer_id = SPA_ID_INVALID;
1165
- p->ready_buffer_id = SPA_ID_INVALID;
1166
- }
1167
return 0;
1168
}
1169
1170
-int spa_vulkan_stop(struct vulkan_state *s)
1171
+int vulkan_wait_idle(struct vulkan_base *s)
1172
{
1173
VK_CHECK_RESULT(vkDeviceWaitIdle(s->device));
1174
- clear_streams(s);
1175
- s->started = false;
1176
+
1177
return 0;
1178
}
1179
1180
-int spa_vulkan_ready(struct vulkan_state *s)
1181
+int vulkan_base_init(struct vulkan_base *s, struct vulkan_base_info *info)
1182
{
1183
- uint32_t i;
1184
- VkResult result;
1185
-
1186
- if (!s->started)
1187
- return 0;
1188
-
1189
- result = vkGetFenceStatus(s->device, s->fence);
1190
- if (result == VK_NOT_READY)
1191
- return -EBUSY;
1192
- VK_CHECK_RESULT(result);
1193
-
1194
- s->started = false;
1195
-
1196
- for (i = 0; i < s->n_streams; i++) {
1197
- struct vulkan_stream *p = &s->streamsi;
1198
- p->ready_buffer_id = p->busy_buffer_id;
1199
- p->busy_buffer_id = SPA_ID_INVALID;
1200
+ if (!s->initialized) {
1201
+ CHECK(createInstance(s));
1202
+ CHECK(findPhysicalDevice(s));
1203
+ CHECK(createDevice(s, info));
1204
+ CHECK(queryFormatInfo(s, info));
1205
+ s->implicit_sync_interop = dmabuf_check_sync_file_import_export(s->log);
1206
+ s->initialized = true;
1207
}
1208
return 0;
1209
}
1210
1211
-int spa_vulkan_process(struct vulkan_state *s)
1212
+void vulkan_base_deinit(struct vulkan_base *s)
1213
{
1214
- CHECK(updateDescriptors(s));
1215
- CHECK(runCommandBuffer(s));
1216
- VK_CHECK_RESULT(vkDeviceWaitIdle(s->device));
1217
-
1218
- return 0;
1219
+ if (s->initialized) {
1220
+ destroyFormatInfo(s);
1221
+ vkDestroyDevice(s->device, NULL);
1222
+ vkDestroyInstance(s->instance, NULL);
1223
+ s->initialized = false;
1224
+ }
1225
}
1226
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
464
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
202
- nread = read(impl->fd, SPA_PTROFF(d->data, d->chunk->size, void), req);
203
- if (nread < 0) {
204
- const bool important = !(errno == EINTR
205
- || errno == EAGAIN
206
- || errno == EWOULDBLOCK);
207
+ pw_log_debug("avail %d %u %u", avail, index, size);
208
209
- if (important)
210
- pw_log_warn("failed to read from pipe (%s): %s",
211
- impl->filename, strerror(errno));
212
+ if (avail < (int32_t)size) {
213
+ memset(bd->data, 0, size);
214
+ if (avail > 0)
215
+ pw_log_warn("underrun %d < %u", avail, size);
216
+ impl->have_sync = false;
217
}
218
- else {
219
- d->chunk->size += nread;
220
+ if (avail > (int32_t)RINGBUFFER_SIZE) {
221
+ index += avail - impl->target_buffer;
222
+ avail = impl->target_buffer;
223
+ pw_log_warn("overrun %d > %u", avail, RINGBUFFER_SIZE);
224
}
225
-
226
- impl->leftover_count = d->chunk->size % impl->frame_size;
227
- d->chunk->size -= impl->leftover_count;
228
- memcpy(impl->leftover, SPA_PTROFF(d->data, d->chunk->size, void), impl->leftover_count);
229
+ if (avail > 0) {
230
+ avail = SPA_ROUND_DOWN(avail, impl->frame_size);
231
+ update_rate(impl, avail);
232
+
233
+ avail = SPA_MIN(size, (uint32_t)avail);
234
+ spa_ringbuffer_read_data(&impl->ring,
235
+ impl->buffer, RINGBUFFER_SIZE,
236
+ index & RINGBUFFER_MASK,
237
+ bd->data, avail);
238
+
239
+ index += avail;
240
+ spa_ringbuffer_read_update(&impl->ring, index);
241
+ }
242
+ bd->chunk->offset = 0;
243
+ bd->chunk->size = size;
244
+ bd->chunk->stride = impl->frame_size;
245
246
pw_stream_queue_buffer(impl->stream, buf);
247
}
248
249
+static void stream_io_changed(void *data, uint32_t id, void *area, uint32_t size)
250
+{
251
+ struct impl *impl = data;
252
+ switch (id) {
253
+ case SPA_IO_RateMatch:
254
+ impl->rate_match = area;
255
+ break;
256
+ case SPA_IO_Position:
257
+ impl->position = area;
258
+ break;
259
+ }
260
+}
261
+
262
static const struct pw_stream_events playback_stream_events = {
263
PW_VERSION_STREAM_EVENTS,
264
.destroy = stream_destroy,
265
266
static const struct pw_stream_events capture_stream_events = {
267
PW_VERSION_STREAM_EVENTS,
268
.destroy = stream_destroy,
269
+ .io_changed = stream_io_changed,
270
.state_changed = stream_state_changed,
271
- .process = capture_stream_process
272
+ .process = capture_stream_process,
273
};
274
275
static int create_stream(struct impl *impl)
276
277
return 0;
278
}
279
280
+static inline void
281
+set_iovec(struct spa_ringbuffer *rbuf, void *buffer, uint32_t size,
282
+ uint32_t offset, struct iovec *iov, uint32_t len)
283
+{
284
+ iov0.iov_len = SPA_MIN(len, size - offset);
285
+ iov0.iov_base = SPA_PTROFF(buffer, offset, void);
286
+ iov1.iov_len = len - iov0.iov_len;
287
+ iov1.iov_base = buffer;
288
+}
289
+
290
+static int handle_pipe_read(struct impl *impl)
291
+{
292
+ ssize_t nread;
293
+ int32_t filled;
294
+ uint32_t index;
295
+ struct iovec iov2;
296
+
297
+ filled = spa_ringbuffer_get_write_index(&impl->ring, &index);
298
+ if (!impl->have_sync) {
299
+ memset(impl->buffer, 0, RINGBUFFER_SIZE);
300
+ }
301
+
302
+ if (filled < 0) {
303
+ pw_log_warn("%p: underrun write:%u filled:%d",
304
+ impl, index, filled);
305
+ }
306
+
307
+ set_iovec(&impl->ring,
308
+ impl->buffer, RINGBUFFER_SIZE,
309
+ index & RINGBUFFER_MASK,
310
+ iov, RINGBUFFER_SIZE);
311
+
312
+ nread = read(impl->fd, iov0.iov_base, iov0.iov_len);
313
+ if (nread > 0) {
314
+ index += nread;
315
+ filled += nread;
316
+ if (nread == (ssize_t)iov0.iov_len) {
317
+ nread = read(impl->fd, iov1.iov_base, iov1.iov_len);
318
+ if (nread > 0) {
319
+ index += nread;
320
+ filled += nread;
321
+ }
322
+ }
323
+ }
324
+ if (!impl->have_sync) {
325
+ impl->ring.readindex = index - impl->target_buffer;
326
+
327
+ spa_dll_init(&impl->dll);
328
+ spa_dll_set_bw(&impl->dll, SPA_DLL_BW_MIN, 256.f, impl->info.rate);
329
+ impl->corr = 1.0f;
330
+
331
+ pw_log_info("resync");
332
+ impl->have_sync = true;
333
+ }
334
+ spa_ringbuffer_write_update(&impl->ring, index);
335
+
336
+ if (nread < 0) {
337
+ const bool important = !(errno == EINTR
338
+ || errno == EAGAIN
339
+ || errno == EWOULDBLOCK);
340
+
341
+ if (important)
342
+ pw_log_warn("failed to read from pipe (%s): %m",
343
+ impl->filename);
344
+ else
345
+ pw_log_debug("pipe (%s) underrun: %m", impl->filename);
346
+ }
347
+ pw_log_debug("filled %d %u %d", filled, index, impl->target_buffer);
348
+
349
+ return 0;
350
+}
351
+
352
+
353
+static void on_pipe_io(void *data, int fd, uint32_t mask)
354
+{
355
+ struct impl *impl = data;
356
+
357
+ if (mask & (SPA_IO_ERR | SPA_IO_HUP)) {
358
+ pw_log_warn("error:%08x", mask);
359
+ pw_loop_update_io(impl->data_loop, impl->socket, 0);
360
+ return;
361
+ }
362
+ if (mask & SPA_IO_IN)
363
+ handle_pipe_read(impl);
364
+}
365
+
366
static int create_fifo(struct impl *impl)
367
{
368
struct stat st;
369
370
371
do_unlink_fifo = true;
372
}
373
-
374
if ((fd = open(filename, O_RDWR | O_CLOEXEC | O_NONBLOCK, 0)) < 0) {
375
res = -errno;
376
pw_log_error("open('%s'): %s", filename, spa_strerror(res));
377
378
pw_log_error("'%s' is not a FIFO.", filename);
379
goto error;
380
}
381
+ impl->socket = pw_loop_add_io(impl->data_loop, fd,
382
+ 0, false, on_pipe_io, impl);
383
+ if (impl->socket == NULL) {
384
+ res = -errno;
385
+ pw_log_error("can't create socket");
386
+ goto error;
387
+ }
388
+ impl->timer = pw_loop_add_timer(impl->data_loop, on_timeout, impl);
389
+ if (impl->timer == NULL) {
390
+ res = -errno;
391
+ pw_log_error("can't create timer");
392
+ goto error;
393
+ }
394
+
395
pw_log_info("%s fifo '%s' with format:%s channels:%d rate:%d",
396
impl->direction == PW_DIRECTION_OUTPUT ? "reading from" : "writing to",
397
filename,
398
399
impl->filename = strdup(filename);
400
impl->unlink_fifo = do_unlink_fifo;
401
impl->fd = fd;
402
+
403
return 0;
404
405
error:
406
407
unlink(impl->filename);
408
free(impl->filename);
409
}
410
+ if (impl->socket)
411
+ pw_loop_destroy_source(impl->data_loop, impl->socket);
412
+ if (impl->timer)
413
+ pw_loop_destroy_source(impl->data_loop, impl->timer);
414
if (impl->fd >= 0)
415
close(impl->fd);
416
417
pw_properties_free(impl->stream_props);
418
pw_properties_free(impl->props);
419
420
- free(impl->leftover);
421
+ free(impl->buffer);
422
free(impl);
423
}
424
425
426
struct pw_properties *props = NULL;
427
struct impl *impl;
428
const char *str, *media_class = NULL;
429
+ struct pw_data_loop *data_loop;
430
int res;
431
432
PW_LOG_TOPIC_INIT(mod_topic);
433
434
435
impl->module = module;
436
impl->context = context;
437
+ data_loop = pw_context_get_data_loop(context);
438
+ impl->data_loop = pw_data_loop_get_loop(data_loop);
439
440
if ((str = pw_properties_get(props, "tunnel.mode")) == NULL)
441
str = "playback";
442
443
444
copy_props(impl, props, PW_KEY_NODE_RATE);
445
446
- impl->leftover = calloc(1, impl->frame_size);
447
- if (impl->leftover == NULL) {
448
+ impl->buffer = calloc(1, RINGBUFFER_SIZE);
449
+ if (impl->buffer == NULL) {
450
res = -errno;
451
- pw_log_error("can't alloc leftover buffer: %m");
452
+ pw_log_error("can't alloc ringbuffer: %m");
453
goto error;
454
}
455
+ spa_ringbuffer_init(&impl->ring);
456
+ impl->target_buffer = 8192 * impl->frame_size;
457
+ spa_dll_init(&impl->dll);
458
+ spa_dll_set_bw(&impl->dll, SPA_DLL_BW_MIN, 256.f, impl->info.rate);
459
+ impl->max_error = 256.0f * impl->frame_size;
460
+ impl->corr = 1.0f;
461
462
impl->core = pw_context_get_object(impl->context, PW_TYPE_INTERFACE_Core);
463
if (impl->core == NULL) {
464
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
264
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
+ if (port->destroying)
202
+ return 0;
203
+
204
+ direction = SPA_DIRECTION_REVERSE(port->direction);
205
+
206
+ spa_pod_dynamic_builder_init(&b, buffer, sizeof(buffer), 4096);
207
+ spa_tag_build_start(&b.b, &f, SPA_PARAM_Tag, direction);
208
+
209
+ if (port->direction == PW_DIRECTION_OUTPUT) {
210
+ spa_list_for_each(l, &port->links, output_link) {
211
+ other = l->input;
212
+ tag = other->tagother->direction;
213
+ if (tag) {
214
+ void *state = NULL;
215
+ while (spa_tag_parse(tag, &info, &state) == 1) {
216
+ spa_tag_build_add_info(&b.b, info.info);
217
+ count++;
218
+ }
219
+ }
220
+ }
221
+ } else {
222
+ spa_list_for_each(l, &port->links, input_link) {
223
+ other = l->output;
224
+ tag = other->tagother->direction;
225
+ if (tag) {
226
+ void *state = NULL;
227
+ while (spa_tag_parse(tag, &info, &state) == 1) {
228
+ spa_tag_build_add_info(&b.b, info.info);
229
+ count++;
230
+ }
231
+ }
232
+ }
233
+ }
234
+ param = count == 0 ? NULL : spa_tag_build_end(&b.b, &f);
235
+
236
+ old = port->tagdirection;
237
+
238
+ changed = spa_tag_compare(old, param);
239
+
240
+ pw_log_info("port %d: %p %s %s tag %p",
241
+ port->info.id, port, changed ? "set" : "keep",
242
+ pw_direction_as_string(direction), param);
243
+
244
+ if (changed) {
245
+ free(old);
246
+ port->tagdirection = param ? spa_pod_copy(param) : NULL;
247
+ if (param)
248
+ pw_log_pod(SPA_LOG_LEVEL_INFO, param);
249
+ }
250
+ spa_pod_dynamic_builder_clean(&b);
251
+
252
+ if (!changed)
253
+ return 0;
254
+
255
+ if (!port->have_tag_param)
256
+ return 0;
257
+
258
+ return pw_impl_port_set_param(port, SPA_PARAM_Tag, 0, port->tagdirection);
259
+}
260
+
261
SPA_EXPORT
262
int pw_impl_port_is_linked(struct pw_impl_port *port)
263
{
264
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
328
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
}
202
203
PW_PERMISSION_ARGS(data->permissions));
204
printf("\ttype: %s (version %d)\n", data->type, data->version);
205
206
- if (print_all) {
207
+ if (!hide_props) {
208
print_properties(info->props, MARK_CHANGE(PW_CLIENT_CHANGE_MASK_PROPS));
209
}
210
}
211
212
static void link_event_info(void *_data, const struct pw_link_info *info)
213
{
214
struct proxy_data *data = _data;
215
- bool print_all, print_mark;
216
+ bool hide_props, print_mark;
217
218
- print_all = true;
219
- if (data->info == NULL) {
220
+ hide_props = data->data->hide_props;
221
+
222
+ if (data->info == NULL) {
223
printf("added:\n");
224
print_mark = false;
225
}
226
- else {
227
+ else {
228
printf("changed:\n");
229
print_mark = true;
230
}
231
232
printf("\toutput-port-id: %u\n", info->output_port_id);
233
printf("\tinput-node-id: %u\n", info->input_node_id);
234
printf("\tinput-port-id: %u\n", info->input_port_id);
235
- if (print_all) {
236
+ if (!hide_props) {
237
with_prefix(MARK_CHANGE(PW_LINK_CHANGE_MASK_STATE)) {
238
printf("\tstate: \"%s\"",
239
pw_link_state_as_string(info->state));
240
241
static void print_device(struct proxy_data *data)
242
{
243
struct pw_device_info *info = data->info;
244
- bool print_all, print_mark;
245
+ bool hide_params, hide_props, print_mark;
246
+
247
+ hide_params = data->data->hide_params;
248
+ hide_props = data->data->hide_props;
249
250
- print_all = true;
251
- if (data->first) {
252
+ if (data->first) {
253
printf("added:\n");
254
print_mark = false;
255
data->first = false;
256
}
257
- else {
258
+ else {
259
printf("changed:\n");
260
print_mark = true;
261
}
262
263
PW_PERMISSION_ARGS(data->permissions));
264
printf("\ttype: %s (version %d)\n", data->type, data->version);
265
266
- if (print_all) {
267
- print_params(data, MARK_CHANGE(PW_DEVICE_CHANGE_MASK_PARAMS));
268
+ if (!hide_params) {
269
+ print_parameters(data, MARK_CHANGE(PW_DEVICE_CHANGE_MASK_PARAMS));
270
+ }
271
+
272
+ if (!hide_props) {
273
print_properties(info->props, MARK_CHANGE(PW_DEVICE_CHANGE_MASK_PROPS));
274
}
275
}
276
277
" --version Show version\n"
278
" -r, --remote Remote daemon name\n"
279
" -N, --no-colors disable color output\n"
280
- " -C, --color=WHEN whether to enable color support. WHEN is `never`, `always`, or `auto`\n",
281
+ " -C, --color=WHEN whether to enable color support. WHEN is `never`, `always`, or `auto`\n"
282
+ " -o, --hide-props hide node properties\n"
283
+ " -a, --hide-params hide node properties\n",
284
name);
285
}
286
287
288
struct pw_loop *l;
289
const char *opt_remote = NULL;
290
static const struct option long_options = {
291
- { "help", no_argument, NULL, 'h' },
292
- { "version", no_argument, NULL, 'V' },
293
- { "remote", required_argument, NULL, 'r' },
294
- { "no-colors", no_argument, NULL, 'N' },
295
- { "color", optional_argument, NULL, 'C' },
296
+ { "help", no_argument, NULL, 'h' },
297
+ { "version", no_argument, NULL, 'V' },
298
+ { "remote", required_argument, NULL, 'r' },
299
+ { "no-colors", no_argument, NULL, 'N' },
300
+ { "color", optional_argument, NULL, 'C' },
301
+ { "hide-props", no_argument, NULL, 'o' },
302
+ { "hide-params", no_argument, NULL, 'a' },
303
{ NULL, 0, NULL, 0}
304
};
305
int c;
306
307
if (isatty(STDOUT_FILENO) && getenv("NO_COLOR") == NULL)
308
colors = true;
309
310
- while ((c = getopt_long(argc, argv, "hVr:NC", long_options, NULL)) != -1) {
311
+ while ((c = getopt_long(argc, argv, "hVr:NCoa", long_options, NULL)) != -1) {
312
switch (c) {
313
case 'h':
314
show_help(argv0, false);
315
316
return -1;
317
}
318
break;
319
+ case 'o':
320
+ data.hide_props = true;
321
+ break;
322
+ case 'a':
323
+ data.hide_params = true;
324
+ break;
325
default:
326
show_help(argv0, true);
327
return -1;
328
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