Overview
pipewire-aptx.changes
Changed
x
1
2
-------------------------------------------------------------------
3
+Mon Apr 4 15:18:29 UTC 2022 - Bjørn Lie <zaitor@opensuse.org>
4
+
5
+- Update to version 0.3.49
6
+
7
+-------------------------------------------------------------------
8
Thu Mar 3 11:50:58 UTC 2022 - Bjørn Lie <zaitor@opensuse.org>
9
10
- Update to version 0.3.48
11
pipewire-aptx.spec
Changed
10
1
2
%define soversion 0_2
3
4
Name: pipewire-aptx
5
-Version: 0.3.48
6
+Version: 0.3.49
7
Release: 0
8
Summary: PipeWire Bluetooth aptX codec plugin
9
License: MIT
10
pipewire-0.3.48.tar.gz/.gitignore -> pipewire-0.3.49.tar.gz/.gitignore
Changed
16
1
2
+.*
3
.tarball-version
4
.version
5
.*.swp
6
7
*.tar.gz
8
*.tar.xz
9
*.o
10
-build/
11
-builddir/
12
-config.h.meson
13
cscope.out
14
cscope.in.out
15
cscope.po.out
16
pipewire-0.3.48.tar.gz/.gitlab-ci.yml -> pipewire-0.3.49.tar.gz/.gitlab-ci.yml
Changed
19
1
2
.fedora:
3
variables:
4
# Update this tag when you want to trigger a rebuild
5
- FDO_DISTRIBUTION_TAG: '2022-02-16.0'
6
+ FDO_DISTRIBUTION_TAG: '2022-03-05.0'
7
FDO_DISTRIBUTION_VERSION: '35'
8
FDO_DISTRIBUTION_PACKAGES: >-
9
alsa-lib-devel
10
11
ninja-build
12
pkgconf
13
python3-pip
14
+ pulseaudio-utils
15
+ openal-soft
16
FDO_DISTRIBUTION_EXEC: >-
17
pip3 install meson
18
19
pipewire-0.3.48.tar.gz/Makefile.in -> pipewire-0.3.49.tar.gz/Makefile.in
Changed
31
1
2
3
run: all
4
SPA_PLUGIN_DIR=$(BUILD_ROOT)/spa/plugins \
5
+ SPA_DATA_DIR=$(SOURCE_ROOT)/spa/plugins \
6
PIPEWIRE_MODULE_DIR=$(BUILD_ROOT)/src/modules \
7
PATH=$(BUILD_ROOT)/src/examples:$(PATH) \
8
PIPEWIRE_CONFIG_DIR=$(BUILD_ROOT)/src/daemon \
9
10
11
run-pulse: all
12
SPA_PLUGIN_DIR=$(BUILD_ROOT)/spa/plugins \
13
+ SPA_DATA_DIR=$(SOURCE_ROOT)/spa/plugins \
14
PIPEWIRE_MODULE_DIR=$(BUILD_ROOT)/src/modules \
15
PIPEWIRE_CONFIG_DIR=$(BUILD_ROOT)/src/daemon \
16
ACP_PATHS_DIR=$(SOURCE_ROOT)/spa/plugins/alsa/mixer/paths \
17
18
19
monitor: all
20
SPA_PLUGIN_DIR=$(BUILD_ROOT)/spa/plugins \
21
+ SPA_DATA_DIR=$(SOURCE_ROOT)/spa/plugins \
22
PIPEWIRE_MODULE_DIR=$(BUILD_ROOT)/src/modules/ \
23
$(BUILD_ROOT)/src/tools/pw-mon
24
25
cli: all
26
SPA_PLUGIN_DIR=$(BUILD_ROOT)/spa/plugins \
27
+ SPA_DATA_DIR=$(SOURCE_ROOT)/spa/plugins \
28
PIPEWIRE_MODULE_DIR=$(BUILD_ROOT)/src/modules/ \
29
$(BUILD_ROOT)/src/tools/pw-cli
30
31
pipewire-0.3.48.tar.gz/NEWS -> pipewire-0.3.49.tar.gz/NEWS
Changed
89
1
2
+# PipeWire 0.3.49 (2022-03-31)
3
+
4
+This is a bugfix release that is API and ABI compatible with previous
5
+0.3.x releases.
6
+
7
+## Highlights
8
+ - Sample rate switching should work again.
9
+ - pw-dot can now use the output of pw-dump to render a graph.
10
+ - Bluetooth A2DP streaming was improved that would reduce stuttering on
11
+ some devices.
12
+ - A JACK bug was fixed that would sometimes make it impossible to add more
13
+ tracks in Ardour. (#1714)
14
+ - Many bugfixes and improvements.
15
+
16
+## PipeWire
17
+ - Fix a potential crash when NULL params were configured.
18
+ - Add some simple functional tests to avoid some recent regressions. Improve
19
+ the test framework for this as well.
20
+ - Improvements to the poll loop to avoid some use-after-free scenarios.
21
+ - Fix samplerate switching again.
22
+ - setlocale is not called anymore from the pipewire library. This should be
23
+ called by the application. (#2223)
24
+ - pw_init() and pw_deinit() can now be nested and called multiple times.
25
+ - pw_stream will now report the resampler delay in the pw_time.queued field.
26
+
27
+## modules
28
+ - module-filter-chain now supports arbitrary many properties and will use
29
+ property hints to assign them the right type.
30
+ - The ROC modules now accept a sink/source_properties parameter.
31
+ - The module-rt can now also be built without RT-Kit support.
32
+ - module-echo-cancel can now use a fraction to specify the delay for more
33
+ precise control.
34
+
35
+## SPA
36
+ - The channelmixer will now do upmixing by default and will not use
37
+ normalization. It will also use a simple upmixing algorithm that duplicates
38
+ channels by default. A more interesting upmix method is also available (PSD)
39
+ but needs to be enabled manually. (#861)
40
+ - Add SSE optimized (de)interleave functions for 32 bits samples with and
41
+ without byteswap.
42
+ - JSON parsing of empty strings will now give an invalid number instead of
43
+ 0.
44
+ - JSON numbers are now parsed and serialized in a locale independent way so
45
+ that , and . are not mixed up.
46
+ - The resampler will now report the resample delay and queued samples as the
47
+ extra delay.
48
+
49
+## tools
50
+ - pw-cat will read more dsf files correctly and will not crash at the end.
51
+ - pw-top now has a man page.
52
+ - pw-dot can now use the output of pw-dump to render a graph.
53
+
54
+## bluetooth
55
+ - Improve interactions with oFono.
56
+ - Fix recovery with slow connections.
57
+ - Improve frame size of AptX-ll.
58
+ - A2DP can now use any quantum and will flush packets in smaller chunks
59
+ when needed to adapt. This improves stuttering in some cases.
60
+
61
+## pulse-server
62
+ - The server configuration can now be placed in pulse.properties section,
63
+ which also makes it possible to have custom overrides.
64
+ - Implement FIX_ flags for capture as well.
65
+ - Small fixes and improvements in module loading.
66
+
67
+## JACK
68
+ - Clear the last error before executing a new action or else we could end up
69
+ with error from a previous action. This causes some problems in Ardour where
70
+ adding a track would fail after some time. (#1714)
71
+
72
+
73
+Older versions:
74
+
75
+
76
# PipeWire 0.3.48 (2022-03-03)
77
78
This is a bugfix release that is API and ABI compatible with previous
79
80
- Don't try to connect HSP/HFP when no backend is available.
81
82
83
-Older versions:
84
-
85
-
86
# PipeWire 0.3.47 (2022-02-18)
87
88
This is a bugfix release that is API and ABI compatible with previous
89
pipewire-0.3.48.tar.gz/README.md -> pipewire-0.3.49.tar.gz/README.md
Changed
10
1
2
3
## Documentation
4
5
-Find tutorials and design documentation [here](doc/index.md).
6
+Find tutorials and design documentation [here](doc/index.dox).
7
8
The (incomplete) autogenerated API docs are [here](https://docs.pipewire.org).
9
10
pipewire-0.3.48.tar.gz/doc/dma-buf.dox -> pipewire-0.3.49.tar.gz/doc/dma-buf.dox
Changed
17
1
2
using a proper graphics API (such as EGL, Vulkan or VA-API) to process the
3
DMA-BUFs.
4
5
+# Size of DMA-BUFs
6
+
7
+When importing a DMA-BUF with a proper graphics API the size of a single buffer plane
8
+is no relevant property since it will be derived by the driver from the other properties.
9
+Therefore consumers should ignore the field `maxsize` of a `spa_data` and the field
10
+`size` of a `spa_chunk` struct. Producers are allowed to set both to 0.
11
+In cases where mapping a single plane is required the size should be obtained locally
12
+via the filedescriptor.
13
+
14
# v4l2
15
16
Another use case for streaming via DMA-BUFs are exporting a camera feed from v4l2
17
pipewire-0.3.48.tar.gz/man/meson.build -> pipewire-0.3.49.tar.gz/man/meson.build
Changed
9
1
2
'pw-mididump.1.rst.in',
3
'pw-mon.1.rst.in',
4
'pw-profiler.1.rst.in',
5
+ 'pw-top.1.rst.in',
6
]
7
8
if get_option('pipewire-jack').allowed()
9
pipewire-0.3.49.tar.gz/man/pw-top.1.rst.in
Added
84
1
2
+pw-top
3
+######
4
+
5
+---------------------------
6
+The PipeWire process viewer
7
+---------------------------
8
+
9
+:Manual section: 1
10
+:Manual group: General Commands Manual
11
+
12
+SYNOPSIS
13
+========
14
+
15
+| **pw-top** [*options*]
16
+
17
+DESCRIPTION
18
+===========
19
+
20
+The *pw-top* program provides a dynamic real-time view of the pipewire
21
+node and device statistics.
22
+
23
+The columns presented are as follows:
24
+
25
+S
26
+ Measurement status.
27
+ ! representing inactive - no connections
28
+
29
+ Blank representing active
30
+
31
+ID
32
+ The ID of the pipewire node/device, as found in *pw-dump*
33
+
34
+QUANT
35
+ Current quantum at which the device/node is polled.
36
+ See https://gitlab.freedesktop.org/pipewire/pipewire/-/wikis/FAQ#pipewire-buffering-explained
37
+
38
+RATE
39
+ Sample rate used for communicating with this device/node.
40
+
41
+WAIT
42
+
43
+BUSY
44
+
45
+W/Q
46
+ Ratio of WAIT / QUANT.
47
+
48
+B/Q
49
+ Ratio of BUSY / QUANT
50
+
51
+ERR
52
+ Total of Xruns and Errors
53
+
54
+NAME
55
+ Name assigned to the device/node, as found in *pw-dump* node.name
56
+
57
+ Names are prefixed by *+* when they are linked to a driver (entry above with no +)
58
+
59
+
60
+OPTIONS
61
+=======
62
+
63
+-h | --help
64
+ Show help.
65
+
66
+-r | --remote=NAME
67
+ The name the *remote* instance to monitor. If left unspecified,
68
+ a connection is made to the default PipeWire instance.
69
+
70
+--version
71
+ Show version information.
72
+
73
+
74
+AUTHORS
75
+=======
76
+
77
+The PipeWire Developers <@PACKAGE_BUGREPORT@>; PipeWire is available from @PACKAGE_URL@
78
+
79
+SEE ALSO
80
+========
81
+
82
+``pipewire(1)``,
83
+
84
pipewire-0.3.48.tar.gz/meson.build -> pipewire-0.3.49.tar.gz/meson.build
Changed
8
1
2
project('pipewire', ['c' ],
3
- version : '0.3.48',
4
+ version : '0.3.49',
5
license : [ 'MIT', 'LGPL-2.1-or-later', 'GPL-2.0-only' ],
6
meson_version : '>= 0.59.0',
7
default_options : [ 'warning_level=3',
8
pipewire-0.3.48.tar.gz/pipewire-jack/src/pipewire-jack.c -> pipewire-0.3.49.tar.gz/pipewire-jack/src/pipewire-jack.c
Changed
46
1
2
int pending_sync;
3
int last_sync;
4
int last_res;
5
- bool error;
6
7
struct spa_node_info info;
8
9
10
id, seq, res, spa_strerror(res), message);
11
12
if (id == PW_ID_CORE) {
13
- client->error = true;
14
client->last_res = res;
15
if (!client->destroyed)
16
do_callback(client, shutdown_callback, client->shutdown_arg);
17
18
pw_log_warn("sync requested from callback");
19
return 0;
20
}
21
- if (client->error)
22
- return client->last_res;
23
24
+ client->last_res = 0;
25
client->pending_sync = pw_proxy_sync((struct pw_proxy*)client->core, client->pending_sync);
26
27
while (true) {
28
29
if (in_data_thread && client->rt_locked)
30
pthread_mutex_lock(&client->rt_lock);
31
32
- if (client->error)
33
+ if (client->last_res < 0)
34
return client->last_res;
35
36
if (client->pending_sync == client->last_sync)
37
38
while (true) {
39
pw_thread_loop_wait(client->context.loop);
40
41
- if (client->error)
42
+ if (client->last_res < 0)
43
goto init_failed;
44
45
if (client->has_transport)
46
pipewire-0.3.48.tar.gz/po/pl.po -> pipewire-0.3.49.tar.gz/po/pl.po
Changed
247
1
2
# Polish translation for pipewire.
3
-# Copyright © 2008-2021 the pipewire authors.
4
+# Copyright © 2008-2022 the pipewire authors.
5
# This file is distributed under the same license as the pipewire package.
6
-# Piotr Drąg <piotrdrag@gmail.com>, 2008, 2012-2021.
7
+# Piotr Drąg <piotrdrag@gmail.com>, 2008, 2012-2022.
8
#
9
msgid ""
10
msgstr ""
11
"Project-Id-Version: pipewire\n"
12
"Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pipewire/pipewire/-/"
13
"issues\n"
14
-"POT-Creation-Date: 2021-09-21 15:31+0000\n"
15
-"PO-Revision-Date: 2021-10-09 15:35+0200\n"
16
+"POT-Creation-Date: 2022-02-13 15:33+0000\n"
17
+"PO-Revision-Date: 2022-03-13 12:05+0100\n"
18
"Last-Translator: Piotr Drąg <piotrdrag@gmail.com>\n"
19
"Language-Team: Polish <community-poland@mozilla.org>\n"
20
"Language: pl\n"
21
22
msgid "Start the PipeWire Media System"
23
msgstr "Uruchomienie systemu multimediów PipeWire"
24
25
-#: src/examples/media-session/alsa-monitor.c:656
26
-#: spa/plugins/alsa/acp/compat.c:189
27
-msgid "Built-in Audio"
28
-msgstr "Wbudowany dźwięk"
29
-
30
-#: src/examples/media-session/alsa-monitor.c:660
31
-#: spa/plugins/alsa/acp/compat.c:194
32
-msgid "Modem"
33
-msgstr "Modem"
34
-
35
-#: src/examples/media-session/alsa-monitor.c:669
36
-#: src/modules/module-zeroconf-discover.c:296
37
-msgid "Unknown device"
38
-msgstr "Nieznane urządzenie"
39
-
40
-#: src/modules/module-protocol-pulse/modules/module-tunnel-sink.c:173
41
-#: src/modules/module-protocol-pulse/modules/module-tunnel-source.c:173
42
+#: src/modules/module-protocol-pulse/modules/module-tunnel-sink.c:188
43
+#: src/modules/module-protocol-pulse/modules/module-tunnel-source.c:188
44
#, c-format
45
msgid "Tunnel to %s/%s"
46
msgstr "Tunel do %s/%s"
47
48
-#: src/modules/module-pulse-tunnel.c:534
49
+#: src/modules/module-fallback-sink.c:51
50
+msgid "Dummy Output"
51
+msgstr "Głuche wyjście"
52
+
53
+#: src/modules/module-pulse-tunnel.c:536
54
#, c-format
55
msgid "Tunnel for %s@%s"
56
msgstr "Tunel dla %s@%s"
57
58
-#: src/modules/module-zeroconf-discover.c:308
59
+#: src/modules/module-zeroconf-discover.c:332
60
+msgid "Unknown device"
61
+msgstr "Nieznane urządzenie"
62
+
63
+#: src/modules/module-zeroconf-discover.c:344
64
#, c-format
65
msgid "%s on %s@%s"
66
msgstr "%s na %s@%s"
67
68
-#: src/modules/module-zeroconf-discover.c:312
69
+#: src/modules/module-zeroconf-discover.c:348
70
#, c-format
71
msgid "%s on %s"
72
msgstr "%s na %s"
73
74
-#: src/tools/pw-cat.c:1055
75
+#: src/tools/pw-cat.c:1075
76
#, c-format
77
msgid ""
78
"%s [options] <file>\n"
79
80
" -v, --verbose Wyświetla więcej komunikatów\n"
81
"\n"
82
83
-#: src/tools/pw-cat.c:1062
84
+#: src/tools/pw-cat.c:1082
85
#, c-format
86
msgid ""
87
" -R, --remote Remote daemon name\n"
88
89
"docelowych dla --target\n"
90
"\n"
91
92
-#: src/tools/pw-cat.c:1080
93
+#: src/tools/pw-cat.c:1100
94
#, c-format
95
msgid ""
96
" --rate Sample rate (req. for rec) (default "
97
98
"(domyślnie %d)\n"
99
"\n"
100
101
-#: src/tools/pw-cat.c:1097
102
+#: src/tools/pw-cat.c:1117
103
msgid ""
104
" -p, --playback Playback mode\n"
105
" -r, --record Recording mode\n"
106
107
" -d, --dsd Tryb DSD\n"
108
"\n"
109
110
-#: src/tools/pw-cli.c:2954
111
+#: src/tools/pw-cli.c:3050
112
#, c-format
113
msgid ""
114
"%s [options] [command]\n"
115
116
" -r, --remote Nazwa zdalnej usługi\n"
117
"\n"
118
119
-#: spa/plugins/alsa/acp/acp.c:310
120
+#: spa/plugins/alsa/acp/acp.c:321
121
msgid "Pro Audio"
122
msgstr "Dźwięk w zastosowaniach profesjonalnych"
123
124
-#: spa/plugins/alsa/acp/acp.c:433 spa/plugins/alsa/acp/alsa-mixer.c:4648
125
-#: spa/plugins/bluez5/bluez5-device.c:1135
126
+#: spa/plugins/alsa/acp/acp.c:444 spa/plugins/alsa/acp/alsa-mixer.c:4648
127
+#: spa/plugins/bluez5/bluez5-device.c:1159
128
msgid "Off"
129
msgstr "Wyłączone"
130
131
132
133
#: spa/plugins/alsa/acp/alsa-mixer.c:2657
134
#: spa/plugins/alsa/acp/alsa-mixer.c:2741
135
-#: spa/plugins/bluez5/bluez5-device.c:1292
136
+#: spa/plugins/bluez5/bluez5-device.c:1328
137
msgid "Microphone"
138
msgstr "Mikrofon"
139
140
141
msgstr "Brak podbicia basów"
142
143
#: spa/plugins/alsa/acp/alsa-mixer.c:2672
144
-#: spa/plugins/bluez5/bluez5-device.c:1297
145
+#: spa/plugins/bluez5/bluez5-device.c:1333
146
msgid "Speaker"
147
msgstr "Głośnik"
148
149
150
151
#: spa/plugins/alsa/acp/alsa-mixer.c:4484
152
#: spa/plugins/alsa/acp/alsa-mixer.c:4642
153
-#: spa/plugins/bluez5/bluez5-device.c:1282
154
+#: spa/plugins/bluez5/bluez5-device.c:1318
155
msgid "Headset"
156
msgstr "Słuchawki z mikrofonem"
157
158
159
"Prawdopodobnie jest to błąd sterownika ALSA „%s”. Proszę zgłosić ten problem "
160
"programistom usługi ALSA."
161
162
-#: spa/plugins/alsa/acp/channelmap.h:466
163
+#: spa/plugins/alsa/acp/channelmap.h:464
164
msgid "(invalid)"
165
msgstr "(nieprawidłowe)"
166
167
-#: spa/plugins/bluez5/bluez5-device.c:1145
168
+#: spa/plugins/alsa/acp/compat.c:189
169
+msgid "Built-in Audio"
170
+msgstr "Wbudowany dźwięk"
171
+
172
+#: spa/plugins/alsa/acp/compat.c:194
173
+msgid "Modem"
174
+msgstr "Modem"
175
+
176
+#: spa/plugins/bluez5/bluez5-device.c:1170
177
msgid "Audio Gateway (A2DP Source & HSP/HFP AG)"
178
msgstr "Bramka dźwięku (źródło A2DP i AG HSP/HFP)"
179
180
-#: spa/plugins/bluez5/bluez5-device.c:1168
181
+#: spa/plugins/bluez5/bluez5-device.c:1195
182
#, c-format
183
msgid "High Fidelity Playback (A2DP Sink, codec %s)"
184
msgstr "Odtwarzanie o wysokiej dokładności (odpływ A2DP, kodek %s)"
185
186
-#: spa/plugins/bluez5/bluez5-device.c:1171
187
+#: spa/plugins/bluez5/bluez5-device.c:1198
188
#, c-format
189
msgid "High Fidelity Duplex (A2DP Source/Sink, codec %s)"
190
msgstr "Dupleks o wysokiej dokładności (źródło/odpływ A2DP, kodek %s)"
191
192
-#: spa/plugins/bluez5/bluez5-device.c:1178
193
+#: spa/plugins/bluez5/bluez5-device.c:1206
194
msgid "High Fidelity Playback (A2DP Sink)"
195
msgstr "Odtwarzanie o wysokiej dokładności (odpływ A2DP)"
196
197
-#: spa/plugins/bluez5/bluez5-device.c:1180
198
+#: spa/plugins/bluez5/bluez5-device.c:1208
199
msgid "High Fidelity Duplex (A2DP Source/Sink)"
200
msgstr "Dupleks o wysokiej dokładności (źródło/odpływ A2DP)"
201
202
-#: spa/plugins/bluez5/bluez5-device.c:1207
203
+#: spa/plugins/bluez5/bluez5-device.c:1236
204
#, c-format
205
msgid "Headset Head Unit (HSP/HFP, codec %s)"
206
msgstr "Jednostka główna słuchawek z mikrofonem (HSP/HFP, kodek %s)"
207
208
-#: spa/plugins/bluez5/bluez5-device.c:1211
209
+#: spa/plugins/bluez5/bluez5-device.c:1241
210
msgid "Headset Head Unit (HSP/HFP)"
211
msgstr "Jednostka główna słuchawek z mikrofonem (HSP/HFP)"
212
213
-#: spa/plugins/bluez5/bluez5-device.c:1287
214
+#: spa/plugins/bluez5/bluez5-device.c:1323
215
msgid "Handsfree"
216
msgstr "Zestaw głośnomówiący"
217
218
-#: spa/plugins/bluez5/bluez5-device.c:1302
219
+#: spa/plugins/bluez5/bluez5-device.c:1338
220
msgid "Headphone"
221
msgstr "Słuchawki"
222
223
-#: spa/plugins/bluez5/bluez5-device.c:1307
224
+#: spa/plugins/bluez5/bluez5-device.c:1343
225
msgid "Portable"
226
msgstr "Przenośne"
227
228
-#: spa/plugins/bluez5/bluez5-device.c:1312
229
+#: spa/plugins/bluez5/bluez5-device.c:1348
230
msgid "Car"
231
msgstr "Samochód"
232
233
-#: spa/plugins/bluez5/bluez5-device.c:1317
234
+#: spa/plugins/bluez5/bluez5-device.c:1353
235
msgid "HiFi"
236
msgstr "HiFi"
237
238
-#: spa/plugins/bluez5/bluez5-device.c:1322
239
+#: spa/plugins/bluez5/bluez5-device.c:1358
240
msgid "Phone"
241
msgstr "Telefon"
242
243
-#: spa/plugins/bluez5/bluez5-device.c:1328
244
+#: spa/plugins/bluez5/bluez5-device.c:1364
245
msgid "Bluetooth"
246
msgstr "Bluetooth"
247
pipewire-0.3.48.tar.gz/spa/include/spa/debug/format.h -> pipewire-0.3.49.tar.gz/spa/include/spa/debug/format.h
Changed
10
1
2
spa_debugn("%f", *(float *) body);
3
break;
4
case SPA_TYPE_Double:
5
- spa_debugn("%g", *(double *) body);
6
+ spa_debugn("%f", *(double *) body);
7
break;
8
case SPA_TYPE_String:
9
spa_debugn("%s", (char *) body);
10
pipewire-0.3.48.tar.gz/spa/include/spa/utils/hook.h -> pipewire-0.3.49.tar.gz/spa/include/spa/utils/hook.h
Changed
61
1
2
* The below (pseudo)code is a minimal example outlining the use of hooks:
3
* \code{.c}
4
* // the public interface
5
+ * #define VERSION_BAR_EVENTS 0 // version of the vtable
6
* struct bar_events {
7
- * uint32_t version;
8
+ * uint32_t version; // NOTE: an integral member named `version`
9
+ * // must be present in the vtable
10
* void (*boom)(void *data, const char *msg);
11
* };
12
*
13
14
* };
15
*
16
* void party_add_event_listener(struct party *p, struct spa_hook *listener,
17
- * struct bar_events *events, void *data)
18
+ * const struct bar_events *events, void *data)
19
* {
20
* spa_hook_list_append(&p->bar_list, listener, events, data);
21
* }
22
*
23
* static void party_on(struct party *p)
24
* {
25
- * spa_hook_list_call(&p->list, struct bar_events,
26
- * boom, // function name
27
- * 0 // hardcoded version,
28
- * "party on, wayne");
29
+ * // NOTE: this is a macro, it evaluates to an integer,
30
+ * // which is the number of hooks called
31
+ * spa_hook_list_call(&p->list,
32
+ * struct bar_events, // vtable type
33
+ * boom, // function name
34
+ * 0, // hardcoded version,
35
+ * // usually the version in which `boom`
36
+ * // has been added to the vtable
37
+ * "party on, wayne" // function argument(s)
38
+ * );
39
* }
40
* \endcode
41
*
42
43
* printf("%s", msg);
44
* }
45
*
46
- * static const struct bar_events {
47
+ * static const struct bar_events events = {
48
+ * .version = VERSION_BAR_EVENTS, // version of the implemented interface
49
* .boom = boom_cb,
50
* };
51
*
52
53
* struct spa_hook hook;
54
* struct party *p = start_the_party();
55
*
56
- * party_add_event_listener(p, &hook, boom_cb, userdata);
57
+ * party_add_event_listener(p, &hook, &events, userdata);
58
*
59
* mainloop();
60
* return 0;
61
pipewire-0.3.48.tar.gz/spa/include/spa/utils/json.h -> pipewire-0.3.49.tar.gz/spa/include/spa/utils/json.h
Changed
53
1
2
#include <stdlib.h>
3
#include <stdint.h>
4
#include <string.h>
5
+#include <math.h>
6
+#include <float.h>
7
8
#include <spa/utils/defs.h>
9
+#include <spa/utils/string.h>
10
11
/** \defgroup spa_json JSON
12
* Relaxed JSON variant parsing
13
14
static inline int spa_json_parse_float(const char *val, int len, float *result)
15
{
16
char *end;
17
- *result = strtof(val, &end);
18
- return end == val + len;
19
+ *result = spa_strtof(val, &end);
20
+ return len > 0 && end == val + len;
21
}
22
+
23
static inline bool spa_json_is_float(const char *val, int len)
24
{
25
float dummy;
26
27
return spa_json_parse_float(value, len, res);
28
}
29
30
+static inline char *spa_json_format_float(char *str, int size, float val)
31
+{
32
+ if (SPA_UNLIKELY(!isnormal(val))) {
33
+ if (val == INFINITY)
34
+ val = FLT_MAX;
35
+ else if (val == -INFINITY)
36
+ val = FLT_MIN;
37
+ else
38
+ val = 0.0f;
39
+ }
40
+ return spa_dtoa(str, size, val);
41
+}
42
+
43
/* int */
44
static inline int spa_json_parse_int(const char *val, int len, int *result)
45
{
46
char *end;
47
*result = strtol(val, &end, 0);
48
- return end == val + len;
49
+ return len > 0 && end == val + len;
50
}
51
static inline bool spa_json_is_int(const char *val, int len)
52
{
53
pipewire-0.3.48.tar.gz/spa/include/spa/utils/string.h -> pipewire-0.3.49.tar.gz/spa/include/spa/utils/string.h
Changed
103
1
2
#include <stdarg.h>
3
#include <stdbool.h>
4
#include <errno.h>
5
+#include <stdlib.h>
6
+#include <locale.h>
7
8
#include <spa/utils/defs.h>
9
10
11
}
12
13
/**
14
+ * Convert \a str to a float in the C locale.
15
+ *
16
+ * If \a endptr is not NULL, a pointer to the character after the last character
17
+ * used in the conversion is stored in the location referenced by endptr.
18
+ *
19
+ * \return the result float.
20
+ */
21
+static inline float spa_strtof(const char *str, char **endptr)
22
+{
23
+ static locale_t locale = NULL;
24
+ float v;
25
+ if (SPA_UNLIKELY(locale == NULL))
26
+ locale = newlocale(LC_ALL_MASK, "C", NULL);
27
+ if (locale != NULL)
28
+ v = strtof_l(str, endptr, locale);
29
+ else
30
+ v = strtof(str, endptr);
31
+ return v;
32
+}
33
+
34
+/**
35
* Convert \a str to a float and store the result in \a val.
36
*
37
* On failure, the value of \a val is unmodified.
38
39
40
if (!str || *str =='\0')
41
return false;
42
-
43
errno = 0;
44
- v = strtof(str, &endptr);
45
+ v = spa_strtof(str, &endptr);
46
if (errno != 0 || *endptr != '\0')
47
return false;
48
49
50
}
51
52
/**
53
+ * Convert \a str to a double in the C locale.
54
+ *
55
+ * If \a endptr is not NULL, a pointer to the character after the last character
56
+ * used in the conversion is stored in the location referenced by endptr.
57
+ *
58
+ * \return the result float.
59
+ */
60
+static inline double spa_strtod(const char *str, char **endptr)
61
+{
62
+ static locale_t locale = NULL;
63
+ double v;
64
+ if (SPA_UNLIKELY(locale == NULL))
65
+ locale = newlocale(LC_ALL_MASK, "C", NULL);
66
+ if (locale != NULL)
67
+ v = strtod_l(str, endptr, locale);
68
+ else
69
+ v = strtod(str, endptr);
70
+ return v;
71
+}
72
+
73
+/**
74
* Convert \a str to a double and store the result in \a val.
75
*
76
* On failure, the value of \a val is unmodified.
77
78
return false;
79
80
errno = 0;
81
- v = strtod(str, &endptr);
82
+ v = spa_strtod(str, &endptr);
83
if (errno != 0 || *endptr != '\0')
84
return false;
85
86
87
return true;
88
}
89
90
+static inline char *spa_dtoa(char *str, size_t size, double val)
91
+{
92
+ int i, l;
93
+ l = spa_scnprintf(str, size, "%f", val);
94
+ for (i = 0; i < l; i++)
95
+ if (str[i] == ',')
96
+ str[i] = '.';
97
+ return str;
98
+}
99
+
100
/**
101
* \}
102
*/
103
pipewire-0.3.48.tar.gz/spa/plugins/aec/aec-null.c -> pipewire-0.3.49.tar.gz/spa/plugins/aec/aec-null.c
Changed
19
1
2
return 1;
3
}
4
5
-const struct spa_handle_factory spa_aec_exaudio_factory = {
6
+const struct spa_handle_factory spa_aec_null_factory = {
7
SPA_VERSION_HANDLE_FACTORY,
8
SPA_NAME_AEC,
9
NULL,
10
11
12
switch (*index) {
13
case 0:
14
- *factory = &spa_aec_exaudio_factory;
15
+ *factory = &spa_aec_null_factory;
16
break;
17
default:
18
return 0;
19
pipewire-0.3.48.tar.gz/spa/plugins/aec/aec-webrtc.cpp -> pipewire-0.3.49.tar.gz/spa/plugins/aec/aec-webrtc.cpp
Changed
19
1
2
return 1;
3
}
4
5
-const struct spa_handle_factory spa_aec_exaudio_factory = {
6
+const struct spa_handle_factory spa_aec_webrtc_factory = {
7
SPA_VERSION_HANDLE_FACTORY,
8
SPA_NAME_AEC,
9
NULL,
10
11
12
switch (*index) {
13
case 0:
14
- *factory = &spa_aec_exaudio_factory;
15
+ *factory = &spa_aec_webrtc_factory;
16
break;
17
default:
18
return 0;
19
pipewire-0.3.48.tar.gz/spa/plugins/alsa/alsa-pcm-sink.c -> pipewire-0.3.49.tar.gz/spa/plugins/alsa/alsa-pcm-sink.c
Changed
48
1
2
SPA_TYPE_OBJECT_PropInfo, id,
3
SPA_PROP_INFO_id, SPA_POD_Id(SPA_PROP_latencyOffsetNsec),
4
SPA_PROP_INFO_description, SPA_POD_String("Latency offset (ns)"),
5
- SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Long(0LL, 0LL, INT64_MAX));
6
+ SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Long(0LL, 0LL, 2 * SPA_NSEC_PER_SEC));
7
break;
8
case 4:
9
if (!this->is_iec958 && !this->is_hdmi)
10
11
case SPA_PARAM_Props:
12
{
13
struct props *p = &this->props;
14
- struct spa_process_latency_info info;
15
struct spa_pod *iec958_codecs = NULL, *params = NULL;
16
+ int64_t lat_ns = -1;
17
18
if (param == NULL) {
19
reset_props(p);
20
return 0;
21
}
22
23
- info = this->process_latency;
24
-
25
spa_pod_parse_object(param,
26
SPA_TYPE_OBJECT_Props, NULL,
27
SPA_PROP_device, SPA_POD_OPT_Stringn(p->device, sizeof(p->device)),
28
- SPA_PROP_latencyOffsetNsec, SPA_POD_OPT_Long(&info.ns),
29
+ SPA_PROP_latencyOffsetNsec, SPA_POD_OPT_Long(&lat_ns),
30
SPA_PROP_iec958Codecs, SPA_POD_OPT_Pod(&iec958_codecs),
31
SPA_PROP_params, SPA_POD_OPT_Pod(¶ms));
32
33
34
this->port_params[PORT_EnumFormat].user++;
35
}
36
spa_alsa_parse_prop_params(this, params);
37
- handle_process_latency(this, &info);
38
-
39
+ if (lat_ns != -1) {
40
+ struct spa_process_latency_info info;
41
+ info = this->process_latency;
42
+ info.ns = lat_ns;
43
+ handle_process_latency(this, &info);
44
+ }
45
emit_node_info(this, false);
46
emit_port_info(this, false);
47
break;
48
pipewire-0.3.48.tar.gz/spa/plugins/alsa/alsa-pcm-source.c -> pipewire-0.3.49.tar.gz/spa/plugins/alsa/alsa-pcm-source.c
Changed
43
1
2
SPA_TYPE_OBJECT_PropInfo, id,
3
SPA_PROP_INFO_id, SPA_POD_Id(SPA_PROP_latencyOffsetNsec),
4
SPA_PROP_INFO_description, SPA_POD_String("Latency offset (ns)"),
5
- SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Long(0LL, 0LL, INT64_MAX));
6
+ SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Long(0LL, 0LL, 2 * SPA_NSEC_PER_SEC));
7
break;
8
default:
9
param = spa_alsa_enum_propinfo(this, result.index - 4, &b);
10
11
case SPA_PARAM_Props:
12
{
13
struct props *p = &this->props;
14
- struct spa_process_latency_info info;
15
struct spa_pod *params = NULL;
16
+ int64_t lat_ns = -1;
17
18
if (param == NULL) {
19
reset_props(p);
20
return 0;
21
}
22
23
- info = this->process_latency;
24
-
25
spa_pod_parse_object(param,
26
SPA_TYPE_OBJECT_Props, NULL,
27
SPA_PROP_device, SPA_POD_OPT_Stringn(p->device, sizeof(p->device)),
28
- SPA_PROP_latencyOffsetNsec, SPA_POD_OPT_Long(&info.ns),
29
+ SPA_PROP_latencyOffsetNsec, SPA_POD_OPT_Long(&lat_ns),
30
SPA_PROP_params, SPA_POD_OPT_Pod(¶ms));
31
32
spa_alsa_parse_prop_params(this, params);
33
- handle_process_latency(this, &info);
34
+ if (lat_ns != -1) {
35
+ struct spa_process_latency_info info;
36
+ info = this->process_latency;
37
+ info.ns = lat_ns;
38
+ handle_process_latency(this, &info);
39
+ }
40
41
emit_node_info(this, false);
42
emit_port_info(this, false);
43
pipewire-0.3.48.tar.gz/spa/plugins/alsa/alsa-pcm.c -> pipewire-0.3.49.tar.gz/spa/plugins/alsa/alsa-pcm.c
Changed
102
1
2
SPA_TYPE_OBJECT_PropInfo, SPA_PARAM_PropInfo,
3
SPA_PROP_INFO_name, SPA_POD_String("api.alsa.period-size"),
4
SPA_PROP_INFO_description, SPA_POD_String("Period Size"),
5
- SPA_PROP_INFO_type, SPA_POD_Int(state->default_period_size),
6
+ SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Int(state->default_period_size, 0, 8192),
7
SPA_PROP_INFO_params, SPA_POD_Bool(true));
8
break;
9
case 6:
10
11
SPA_TYPE_OBJECT_PropInfo, SPA_PARAM_PropInfo,
12
SPA_PROP_INFO_name, SPA_POD_String("api.alsa.period-num"),
13
SPA_PROP_INFO_description, SPA_POD_String("Number of Periods"),
14
- SPA_PROP_INFO_type, SPA_POD_Int(state->default_period_num),
15
+ SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Int(state->default_period_num, 0, 1024),
16
SPA_PROP_INFO_params, SPA_POD_Bool(true));
17
break;
18
case 7:
19
20
SPA_TYPE_OBJECT_PropInfo, SPA_PARAM_PropInfo,
21
SPA_PROP_INFO_name, SPA_POD_String("api.alsa.headroom"),
22
SPA_PROP_INFO_description, SPA_POD_String("Headroom"),
23
- SPA_PROP_INFO_type, SPA_POD_Int(state->default_headroom),
24
+ SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Int(state->default_headroom, 0, 8192),
25
SPA_PROP_INFO_params, SPA_POD_Bool(true));
26
break;
27
case 8:
28
29
SPA_TYPE_OBJECT_PropInfo, SPA_PARAM_PropInfo,
30
SPA_PROP_INFO_name, SPA_POD_String("api.alsa.start-delay"),
31
SPA_PROP_INFO_description, SPA_POD_String("Start Delay"),
32
- SPA_PROP_INFO_type, SPA_POD_Int(state->default_start_delay),
33
+ SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Int(state->default_start_delay, 0, 8192),
34
SPA_PROP_INFO_params, SPA_POD_Bool(true));
35
break;
36
case 9:
37
38
SPA_TYPE_OBJECT_PropInfo, SPA_PARAM_PropInfo,
39
SPA_PROP_INFO_name, SPA_POD_String("api.alsa.disable-mmap"),
40
SPA_PROP_INFO_description, SPA_POD_String("Disable MMAP"),
41
- SPA_PROP_INFO_type, SPA_POD_Bool(state->disable_mmap),
42
+ SPA_PROP_INFO_type, SPA_POD_CHOICE_Bool(state->disable_mmap),
43
SPA_PROP_INFO_params, SPA_POD_Bool(true));
44
break;
45
case 10:
46
47
SPA_TYPE_OBJECT_PropInfo, SPA_PARAM_PropInfo,
48
SPA_PROP_INFO_name, SPA_POD_String("api.alsa.disable-batch"),
49
SPA_PROP_INFO_description, SPA_POD_String("Disable Batch"),
50
- SPA_PROP_INFO_type, SPA_POD_Bool(state->disable_batch),
51
+ SPA_PROP_INFO_type, SPA_POD_CHOICE_Bool(state->disable_batch),
52
SPA_PROP_INFO_params, SPA_POD_Bool(true));
53
break;
54
case 11:
55
56
SPA_TYPE_OBJECT_PropInfo, SPA_PARAM_PropInfo,
57
SPA_PROP_INFO_name, SPA_POD_String("api.alsa.use-chmap"),
58
SPA_PROP_INFO_description, SPA_POD_String("Use the driver channelmap"),
59
- SPA_PROP_INFO_type, SPA_POD_Bool(state->props.use_chmap),
60
+ SPA_PROP_INFO_type, SPA_POD_CHOICE_Bool(state->props.use_chmap),
61
SPA_PROP_INFO_params, SPA_POD_Bool(true));
62
break;
63
case 12:
64
65
SPA_TYPE_OBJECT_PropInfo, SPA_PARAM_PropInfo,
66
SPA_PROP_INFO_name, SPA_POD_String("api.alsa.multi-rate"),
67
SPA_PROP_INFO_description, SPA_POD_String("Support multiple rates"),
68
- SPA_PROP_INFO_type, SPA_POD_Bool(state->multi_rate),
69
+ SPA_PROP_INFO_type, SPA_POD_CHOICE_Bool(state->multi_rate),
70
SPA_PROP_INFO_params, SPA_POD_Bool(true));
71
break;
72
case 13:
73
74
SPA_TYPE_OBJECT_PropInfo, SPA_PARAM_PropInfo,
75
SPA_PROP_INFO_name, SPA_POD_String("latency.internal.rate"),
76
SPA_PROP_INFO_description, SPA_POD_String("Internal latency in samples"),
77
- SPA_PROP_INFO_type, SPA_POD_Int(state->process_latency.rate),
78
+ SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Int(state->process_latency.rate,
79
+ 0, 65536),
80
SPA_PROP_INFO_params, SPA_POD_Bool(true));
81
break;
82
case 14:
83
84
SPA_TYPE_OBJECT_PropInfo, SPA_PARAM_PropInfo,
85
SPA_PROP_INFO_name, SPA_POD_String("latency.internal.ns"),
86
SPA_PROP_INFO_description, SPA_POD_String("Internal latency in nanoseconds"),
87
- SPA_PROP_INFO_type, SPA_POD_Long(state->process_latency.ns),
88
+ SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Long(state->process_latency.ns,
89
+ 0, 2 * SPA_NSEC_PER_SEC),
90
SPA_PROP_INFO_params, SPA_POD_Bool(true));
91
break;
92
case 15:
93
94
} else
95
continue;
96
97
- spa_log_debug(state->log, "key:'%s' val:'%s'", name, value);
98
+ spa_log_info(state->log, "key:'%s' val:'%s'", name, value);
99
alsa_set_param(state, name, value);
100
changed++;
101
}
102
pipewire-0.3.48.tar.gz/spa/plugins/alsa/test-timer.c -> pipewire-0.3.49.tar.gz/spa/plugins/alsa/test-timer.c
Changed
174
1
2
#include <stdio.h>
3
#include <stdbool.h>
4
#include <limits.h>
5
+#include <getopt.h>
6
#include <math.h>
7
#include <sys/timerfd.h>
8
9
10
#define BW_PERIOD (NSEC_PER_SEC * 3)
11
12
struct state {
13
+ const char *device;
14
+ unsigned int format;
15
unsigned int rate;
16
unsigned int channels;
17
snd_pcm_uframes_t period;
18
19
} \
20
}
21
22
+#define LOOP(type,areas,scale) { \
23
+ uint32_t i, j; \
24
+ type *samples, v; \
25
+ samples = (type*)((uint8_t*)areas[0].addr + (areas[0].first + offset*areas[0].step) / 8); \
26
+ for (i = 0; i < frames; i++) { \
27
+ state->accumulator += M_PI_M2 * 440 / state->rate; \
28
+ if (state->accumulator >= M_PI_M2) \
29
+ state->accumulator -= M_PI_M2; \
30
+ v = sin(state->accumulator) * scale; \
31
+ for (j = 0; j < state->channels; j++) \
32
+ *samples++ = v; \
33
+ } \
34
+}
35
+
36
static int write_period(struct state *state)
37
{
38
snd_pcm_uframes_t frames = state->period;
39
snd_pcm_uframes_t offset;
40
const snd_pcm_channel_area_t* areas;
41
- uint32_t i, j;
42
- int32_t *samples, v;
43
44
snd_pcm_mmap_begin(state->hndl, &areas, &offset, &frames);
45
46
- samples = (int32_t*)((uint8_t*)areas[0].addr + (areas[0].first + offset*areas[0].step) / 8);
47
-
48
- for (i = 0; i < frames; i++) {
49
- state->accumulator += M_PI_M2 * 440 / state->rate;
50
- if (state->accumulator >= M_PI_M2)
51
- state->accumulator -= M_PI_M2;
52
- v = sin(state->accumulator) * 0x7fffffff;
53
-
54
- for (j = 0; j < state->channels; j++)
55
- *samples++ = v;
56
+ switch (state->format) {
57
+ case SND_PCM_FORMAT_S32_LE:
58
+ LOOP(int32_t, areas, 0x7fffffff);
59
+ break;
60
+ case SND_PCM_FORMAT_S16_LE:
61
+ LOOP(int16_t, areas, 0x7fff);
62
+ break;
63
+ default:
64
+ break;
65
}
66
+
67
snd_pcm_mmap_commit(state->hndl, offset, frames) ;
68
69
return 0;
70
71
return 0;
72
}
73
74
+static unsigned int format_from_string(const char *str)
75
+{
76
+ if (strcmp(str, "S32_LE") == 0)
77
+ return SND_PCM_FORMAT_S32_LE;
78
+ else if (strcmp(str, "S32_BE") == 0)
79
+ return SND_PCM_FORMAT_S32_BE;
80
+ else if (strcmp(str, "S24_LE") == 0)
81
+ return SND_PCM_FORMAT_S24_LE;
82
+ else if (strcmp(str, "S24_BE") == 0)
83
+ return SND_PCM_FORMAT_S24_BE;
84
+ else if (strcmp(str, "S24_3LE") == 0)
85
+ return SND_PCM_FORMAT_S24_3LE;
86
+ else if (strcmp(str, "S24_3_BE") == 0)
87
+ return SND_PCM_FORMAT_S24_3BE;
88
+ else if (strcmp(str, "S16_LE") == 0)
89
+ return SND_PCM_FORMAT_S16_LE;
90
+ else if (strcmp(str, "S16_BE") == 0)
91
+ return SND_PCM_FORMAT_S16_BE;
92
+ return 0;
93
+}
94
+
95
+static void show_help(const char *name, bool error)
96
+{
97
+ fprintf(error ? stderr : stdout, "%s [options]\n"
98
+ " -h, --help Show this help\n"
99
+ " -D, --device device name (default %s)\n",
100
+ name, DEFAULT_DEVICE);
101
+}
102
+
103
int main(int argc, char *argv[])
104
{
105
struct state state = { 0, };
106
- const char *device = DEFAULT_DEVICE;
107
snd_pcm_hw_params_t *hparams;
108
snd_pcm_sw_params_t *sparams;
109
struct timespec now;
110
-
111
- CHECK(snd_pcm_open(&state.hndl, device, SND_PCM_STREAM_PLAYBACK, 0), "open %s failed", device);
112
-
113
+ char c;
114
+ static const struct option long_options[] = {
115
+ { "help", no_argument, NULL, 'h' },
116
+ { "device", required_argument, NULL, 'D' },
117
+ { "format", required_argument, NULL, 'f' },
118
+ { "rate", required_argument, NULL, 'r' },
119
+ { "channels", required_argument, NULL, 'c' },
120
+ { NULL, 0, NULL, 0}
121
+ };
122
+ state.device = DEFAULT_DEVICE;
123
+ state.format = SND_PCM_FORMAT_S16_LE;
124
state.rate = 44100;
125
state.channels = 2;
126
state.period = 1024;
127
128
+ while ((c = getopt_long(argc, argv, "hD:f:r:c:", long_options, NULL)) != -1) {
129
+ switch (c) {
130
+ case 'h':
131
+ show_help(argv[0], false);
132
+ return 0;
133
+ case 'D':
134
+ state.device = optarg;
135
+ break;
136
+ case 'f':
137
+ state.format = format_from_string(optarg);
138
+ break;
139
+ case 'r':
140
+ state.rate = atoi(optarg);
141
+ break;
142
+ case 'c':
143
+ state.channels = atoi(optarg);
144
+ break;
145
+ default:
146
+ show_help(argv[0], true);
147
+ return -1;
148
+ }
149
+ }
150
+
151
+ CHECK(snd_pcm_open(&state.hndl, state.device, SND_PCM_STREAM_PLAYBACK, 0),
152
+ "open %s failed", state.device);
153
+
154
/* hw params */
155
snd_pcm_hw_params_alloca(&hparams);
156
snd_pcm_hw_params_any(state.hndl, hparams);
157
CHECK(snd_pcm_hw_params_set_access(state.hndl, hparams,
158
SND_PCM_ACCESS_MMAP_INTERLEAVED), "set interleaved");
159
CHECK(snd_pcm_hw_params_set_format(state.hndl, hparams,
160
- SND_PCM_FORMAT_S32_LE), "set format");
161
+ state.format), "set format");
162
CHECK(snd_pcm_hw_params_set_channels_near(state.hndl, hparams,
163
&state.channels), "set channels");
164
CHECK(snd_pcm_hw_params_set_rate_near(state.hndl, hparams,
165
166
CHECK(snd_pcm_hw_params_get_buffer_size(hparams, &state.buffer_frames), "get_buffer_size_max");
167
168
fprintf(stdout, "opened format:%s rate:%u channels:%u\n",
169
- snd_pcm_format_name(SND_PCM_FORMAT_S32_LE),
170
+ snd_pcm_format_name(state.format),
171
state.rate, state.channels);
172
173
snd_pcm_sw_params_alloca(&sparams);
174
pipewire-0.3.48.tar.gz/spa/plugins/audioconvert/audioadapter.c -> pipewire-0.3.49.tar.gz/spa/plugins/audioconvert/audioadapter.c
Changed
9
1
2
res = spa_pod_parse_object(format,
3
SPA_TYPE_OBJECT_Format, NULL,
4
SPA_FORMAT_AUDIO_format, SPA_POD_OPT_Id(&info->format),
5
- SPA_FORMAT_AUDIO_rate, SPA_POD_OPT_Int(&info->rate),
6
SPA_FORMAT_AUDIO_channels, SPA_POD_OPT_Int(&info->channels),
7
SPA_FORMAT_AUDIO_position, SPA_POD_OPT_Pod(&position));
8
if (position == NULL ||
9
pipewire-0.3.48.tar.gz/spa/plugins/audioconvert/channelmix-ops-c.c -> pipewire-0.3.49.tar.gz/spa/plugins/audioconvert/channelmix-ops-c.c
Changed
58
1
2
for (i = 0; i < n_dst; i++)
3
memset(d[i], 0, n_samples * sizeof(float));
4
}
5
+ else if (mix->upmix == CHANNELMIX_UPMIX_SIMPLE) {
6
+ for (n = 0; n < n_samples; n++) {
7
+ float c = s[0][n] + s[1][n];
8
+ d[0][n] = s[0][n] * v0;
9
+ d[1][n] = s[1][n] * v1;
10
+ d[2][n] = c * v2;
11
+ d[3][n] = c;
12
+ }
13
+ lr4_process(&mix->lr4[3], d[3], d[3], v3, n_samples);
14
+ }
15
else if (v0 == 1.0f && v1 == 1.0f) {
16
for (n = 0; n < n_samples; n++) {
17
float c = s[0][n] + s[1][n];
18
19
for (i = 0; i < n_dst; i++)
20
memset(d[i], 0, n_samples * sizeof(float));
21
}
22
+ else if (mix->upmix == CHANNELMIX_UPMIX_SIMPLE) {
23
+ for (n = 0; n < n_samples; n++) {
24
+ float c = s[0][n] + s[1][n];
25
+ d[0][n] = s[0][n] * v0;
26
+ d[1][n] = s[1][n] * v1;
27
+ d[2][n] = c * v2;
28
+ d[3][n] = c;
29
+ d[4][n] = s[0][n] * v4;
30
+ d[5][n] = s[1][n] * v5;
31
+ }
32
+ lr4_process(&mix->lr4[3], d[3], d[3], v3, n_samples);
33
+ }
34
else if (v0 == 1.0f && v1 == 1.0f) {
35
for (n = 0; n < n_samples; n++) {
36
float c = s[0][n] + s[1][n];
37
38
for (i = 0; i < n_dst; i++)
39
memset(d[i], 0, n_samples * sizeof(float));
40
}
41
+ else if (mix->upmix == CHANNELMIX_UPMIX_SIMPLE) {
42
+ for (n = 0; n < n_samples; n++) {
43
+ float c = s[0][n] + s[1][n];
44
+ d[0][n] = s[0][n] * v0;
45
+ d[1][n] = s[1][n] * v1;
46
+ d[2][n] = c * v2;
47
+ d[3][n] = c;
48
+ d[4][n] = s[0][n] * v4;
49
+ d[5][n] = s[1][n] * v5;
50
+ d[6][n] = s[0][n] * v6;
51
+ d[7][n] = s[1][n] * v7;
52
+ }
53
+ lr4_process(&mix->lr4[3], d[3], d[3], v3, n_samples);
54
+ }
55
else if (v0 == 1.0f && v1 == 1.0f && v4 == 1.0f && v5 == 1.0f) {
56
for (n = 0; n < n_samples; n++) {
57
float c = s[0][n] + s[1][n];
58
pipewire-0.3.48.tar.gz/spa/plugins/audioconvert/channelmix-ops.c -> pipewire-0.3.49.tar.gz/spa/plugins/audioconvert/channelmix-ops.c
Changed
11
1
2
unassigned = src_mask & ~dst_mask;
3
keep = dst_mask & ~src_mask;
4
5
- if (!SPA_FLAG_IS_SET(mix->options, CHANNELMIX_OPTION_UPMIX))
6
+ if (!SPA_FLAG_IS_SET(mix->options, CHANNELMIX_OPTION_UPMIX) ||
7
+ mix->upmix == CHANNELMIX_UPMIX_NONE)
8
keep = 0;
9
10
keep |= FRONT;
11
pipewire-0.3.48.tar.gz/spa/plugins/audioconvert/channelmix-ops.h -> pipewire-0.3.49.tar.gz/spa/plugins/audioconvert/channelmix-ops.h
Changed
47
1
2
#include <stdio.h>
3
4
#include <spa/utils/defs.h>
5
+#include <spa/utils/string.h>
6
#include <spa/param/audio/raw.h>
7
8
#undef SPA_LOG_TOPIC_DEFAULT
9
10
#define CHANNELMIX_OPTION_NORMALIZE (1<<1) /**< normalize volumes */
11
#define CHANNELMIX_OPTION_UPMIX (1<<2) /**< do simple upmixing */
12
uint32_t options;
13
+#define CHANNELMIX_UPMIX_NONE (0) /**< disable upmixing */
14
+#define CHANNELMIX_UPMIX_SIMPLE (1) /**< simple upmixing */
15
+#define CHANNELMIX_UPMIX_PSD (2) /**< Passive Surround Decoding upmixing */
16
+ uint32_t upmix;
17
18
struct spa_log *log;
19
20
21
22
int channelmix_init(struct channelmix *mix);
23
24
+static const struct channelmix_upmix_info {
25
+ const char *label;
26
+ const char *description;
27
+ uint32_t upmix;
28
+} channelmix_upmix_info[] = {
29
+ [CHANNELMIX_UPMIX_NONE] = { "none", "Disabled", CHANNELMIX_UPMIX_NONE },
30
+ [CHANNELMIX_UPMIX_SIMPLE] = { "simple", "Simple upmixing", CHANNELMIX_UPMIX_SIMPLE },
31
+ [CHANNELMIX_UPMIX_PSD] = { "psd", "Passive Surround Decoding", CHANNELMIX_UPMIX_PSD }
32
+};
33
+
34
+static inline uint32_t channelmix_upmix_from_label(const char *label)
35
+{
36
+ uint32_t i;
37
+ for (i = 0; i < SPA_N_ELEMENTS(channelmix_upmix_info); i++) {
38
+ if (spa_streq(channelmix_upmix_info[i].label, label))
39
+ return channelmix_upmix_info[i].upmix;
40
+ }
41
+ return CHANNELMIX_UPMIX_NONE;
42
+}
43
+
44
#define channelmix_process(mix,...) (mix)->process(mix, __VA_ARGS__)
45
#define channelmix_set_volume(mix,...) (mix)->set_volume(mix, __VA_ARGS__)
46
#define channelmix_free(mix) (mix)->free(mix)
47
pipewire-0.3.48.tar.gz/spa/plugins/audioconvert/channelmix.c -> pipewire-0.3.49.tar.gz/spa/plugins/audioconvert/channelmix.c
Changed
142
1
2
{
3
struct volumes *vol;
4
5
- if (this->mix.set_volume == NULL)
6
+ if (this->mix.set_volume == NULL ||
7
+ this->props.disabled)
8
return;
9
10
if (this->props.have_soft_volume)
11
12
this->mix.hilbert_taps, 0, MAX_TAPS),
13
SPA_PROP_INFO_params, SPA_POD_Bool(true));
14
break;
15
+ case 17:
16
+ {
17
+ struct spa_pod_frame f[2];
18
+ uint32_t i;
19
+ spa_pod_builder_push_object(&b, &f[0],
20
+ SPA_TYPE_OBJECT_PropInfo, id);
21
+ spa_pod_builder_add(&b,
22
+ SPA_PROP_INFO_name, SPA_POD_String("channelmix.upmix-method"),
23
+ SPA_PROP_INFO_description, SPA_POD_String("Upmix Method to use"),
24
+ SPA_PROP_INFO_type, SPA_POD_String(
25
+ channelmix_upmix_info[this->mix.upmix].label),
26
+ 0);
27
+ spa_pod_builder_prop(&b, SPA_PROP_INFO_labels, 0);
28
+ spa_pod_builder_push_struct(&b, &f[1]);
29
+ for (i = 0; i < SPA_N_ELEMENTS(channelmix_upmix_info); i++) {
30
+ spa_pod_builder_string(&b, channelmix_upmix_info[i].label);
31
+ spa_pod_builder_string(&b, channelmix_upmix_info[i].description);
32
+ }
33
+ spa_pod_builder_pop(&b, &f[1]);
34
+ spa_pod_builder_add(&b,
35
+ SPA_PROP_INFO_params, SPA_POD_Bool(true),
36
+ 0);
37
+ param = spa_pod_builder_pop(&b, &f[0]);
38
+ break;
39
+ }
40
default:
41
return 0;
42
}
43
44
spa_pod_builder_float(&b, this->mix.widen);
45
spa_pod_builder_string(&b, "channelmix.hilbert-taps");
46
spa_pod_builder_int(&b, this->mix.hilbert_taps);
47
+ spa_pod_builder_string(&b, "channelmix.upmix-method");
48
+ spa_pod_builder_string(&b, channelmix_upmix_info[this->mix.upmix].label);
49
spa_pod_builder_pop(&b, &f[1]);
50
param = spa_pod_builder_pop(&b, &f[0]);
51
break;
52
53
spa_atof(s, &this->mix.widen);
54
else if (spa_streq(k, "channelmix.hilbert-taps"))
55
spa_atou32(s, &this->mix.hilbert_taps, 0);
56
+ else if (spa_streq(k, "channelmix.upmix-method"))
57
+ this->mix.upmix = channelmix_upmix_from_label(s);
58
else
59
return 0;
60
return 1;
61
62
while (true) {
63
const char *name;
64
struct spa_pod *pod;
65
- char value[512];
66
+ char value[512], buf[128];
67
68
if (spa_pod_parser_get_string(&prs, &name) < 0)
69
break;
70
71
if (spa_pod_is_string(pod)) {
72
spa_pod_copy_string(pod, sizeof(value), value);
73
} else if (spa_pod_is_float(pod)) {
74
- snprintf(value, sizeof(value), "%f",
75
- SPA_POD_VALUE(struct spa_pod_float, pod));
76
+ snprintf(value, sizeof(value), "%s",
77
+ spa_json_format_float(buf, sizeof(buf),
78
+ SPA_POD_VALUE(struct spa_pod_float, pod)));
79
} else if (spa_pod_is_int(pod)) {
80
snprintf(value, sizeof(value), "%d",
81
SPA_POD_VALUE(struct spa_pod_int, pod));
82
83
spa_log_info(this->log, "key:'%s' val:'%s'", name, value);
84
changed += channelmix_set_param(this, name, value);
85
}
86
- if (changed)
87
+ if (changed && !this->props.disabled)
88
channelmix_init(&this->mix);
89
return changed;
90
}
91
92
if (param == NULL)
93
return 0;
94
95
- if (this->props.disabled)
96
- return 0;
97
-
98
SPA_POD_OBJECT_FOREACH(obj, prop) {
99
switch (prop->key) {
100
case SPA_PROP_volume:
101
102
break;
103
}
104
}
105
+
106
if (changed) {
107
struct port *port = GET_PORT(this, this->direction, 0);
108
if (have_soft_volume)
109
110
111
if (port->have_format)
112
remap_volumes(this, &port->format);
113
+
114
set_volume(this);
115
}
116
return changed;
117
118
if (size < 3)
119
return -EINVAL;
120
121
- if (this->props.disabled)
122
- return 0;
123
-
124
if ((val[0] & 0xf0) != 0xb0 || val[1] != 7)
125
return 0;
126
127
128
129
props_reset(&this->props);
130
131
- this->mix.options = CHANNELMIX_OPTION_NORMALIZE;
132
+ this->mix.options = CHANNELMIX_OPTION_UPMIX;
133
+ this->mix.upmix = CHANNELMIX_UPMIX_SIMPLE;
134
this->mix.log = this->log;
135
+ this->mix.lfe_cutoff = 120.0f;
136
+ this->mix.fc_cutoff = 6000.0f;
137
this->mix.rear_delay = 12.0f;
138
+ this->mix.widen = 0.1f;
139
140
for (i = 0; info && i < info->n_items; i++) {
141
const char *k = info->items[i].key;
142
pipewire-0.3.48.tar.gz/spa/plugins/audioconvert/fmt-ops-sse2.c -> pipewire-0.3.49.tar.gz/spa/plugins/audioconvert/fmt-ops-sse2.c
Changed
356
1
2
}
3
4
static void
5
+conv_interleave_32_1s_sse2(void *data, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src[],
6
+ uint32_t n_channels, uint32_t n_samples)
7
+{
8
+ const int32_t *s0 = src[0];
9
+ int32_t *d = dst;
10
+ uint32_t n, unrolled;
11
+ __m128i out[4];
12
+
13
+ if (SPA_IS_ALIGNED(s0, 16))
14
+ unrolled = n_samples & ~3;
15
+ else
16
+ unrolled = 0;
17
+
18
+ for(n = 0; n < unrolled; n += 4) {
19
+ out[0] = _mm_load_si128((__m128i*)&s0[n]);
20
+ out[1] = _mm_shuffle_epi32(out[0], _MM_SHUFFLE(0, 3, 2, 1));
21
+ out[2] = _mm_shuffle_epi32(out[0], _MM_SHUFFLE(1, 0, 3, 2));
22
+ out[3] = _mm_shuffle_epi32(out[0], _MM_SHUFFLE(2, 1, 0, 3));
23
+
24
+ d[0*n_channels] = _mm_cvtsi128_si32(out[0]);
25
+ d[1*n_channels] = _mm_cvtsi128_si32(out[1]);
26
+ d[2*n_channels] = _mm_cvtsi128_si32(out[2]);
27
+ d[3*n_channels] = _mm_cvtsi128_si32(out[3]);
28
+ d += 4*n_channels;
29
+ }
30
+ for(; n < n_samples; n++) {
31
+ *d = s0[n];
32
+ d += n_channels;
33
+ }
34
+}
35
+static void
36
+conv_interleave_32_4s_sse2(void *data, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src[],
37
+ uint32_t n_channels, uint32_t n_samples)
38
+{
39
+ const float *s0 = src[0], *s1 = src[1], *s2 = src[2], *s3 = src[3];
40
+ float *d = dst;
41
+ uint32_t n, unrolled;
42
+ __m128 out[4];
43
+
44
+ if (SPA_IS_ALIGNED(s0, 16) &&
45
+ SPA_IS_ALIGNED(s1, 16) &&
46
+ SPA_IS_ALIGNED(s2, 16) &&
47
+ SPA_IS_ALIGNED(s3, 16))
48
+ unrolled = n_samples & ~3;
49
+ else
50
+ unrolled = 0;
51
+
52
+ for(n = 0; n < unrolled; n += 4) {
53
+ out[0] = _mm_load_ps(&s0[n]);
54
+ out[1] = _mm_load_ps(&s1[n]);
55
+ out[2] = _mm_load_ps(&s2[n]);
56
+ out[3] = _mm_load_ps(&s3[n]);
57
+
58
+ _MM_TRANSPOSE4_PS(out[0], out[1], out[2], out[3]);
59
+
60
+ _mm_storeu_ps((d + 0*n_channels), out[0]);
61
+ _mm_storeu_ps((d + 1*n_channels), out[1]);
62
+ _mm_storeu_ps((d + 2*n_channels), out[2]);
63
+ _mm_storeu_ps((d + 3*n_channels), out[3]);
64
+ d += 4*n_channels;
65
+ }
66
+ for(; n < n_samples; n++) {
67
+ out[0] = _mm_setr_ps(s0[n], s1[n], s2[n], s3[n]);
68
+ _mm_storeu_ps(d, out[0]);
69
+ d += n_channels;
70
+ }
71
+}
72
+
73
+void
74
+conv_interleave_32_sse2(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
75
+ uint32_t n_samples)
76
+{
77
+ int32_t *d = dst[0];
78
+ uint32_t i = 0, n_channels = conv->n_channels;
79
+
80
+ for(; i + 3 < n_channels; i += 4)
81
+ conv_interleave_32_4s_sse2(conv, &d[i], &src[i], n_channels, n_samples);
82
+ for(; i < n_channels; i++)
83
+ conv_interleave_32_1s_sse2(conv, &d[i], &src[i], n_channels, n_samples);
84
+}
85
+
86
+#define _MM_BSWAP_EPI32(x) \
87
+({ \
88
+ __m128i a = _mm_or_si128( \
89
+ _mm_slli_epi16(x, 8), \
90
+ _mm_srli_epi16(x, 8)); \
91
+ a = _mm_shufflelo_epi16(a, _MM_SHUFFLE(2, 3, 0, 1)); \
92
+ a = _mm_shufflehi_epi16(a, _MM_SHUFFLE(2, 3, 0, 1)); \
93
+})
94
+
95
+static void
96
+conv_interleave_32s_1s_sse2(void *data, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src[],
97
+ uint32_t n_channels, uint32_t n_samples)
98
+{
99
+ const int32_t *s0 = src[0];
100
+ int32_t *d = dst;
101
+ uint32_t n, unrolled;
102
+ __m128i out[4];
103
+
104
+ if (SPA_IS_ALIGNED(s0, 16))
105
+ unrolled = n_samples & ~3;
106
+ else
107
+ unrolled = 0;
108
+
109
+ for(n = 0; n < unrolled; n += 4) {
110
+ out[0] = _mm_load_si128((__m128i*)&s0[n]);
111
+ out[0] = _MM_BSWAP_EPI32(out[0]);
112
+ out[1] = _mm_shuffle_epi32(out[0], _MM_SHUFFLE(0, 3, 2, 1));
113
+ out[2] = _mm_shuffle_epi32(out[0], _MM_SHUFFLE(1, 0, 3, 2));
114
+ out[3] = _mm_shuffle_epi32(out[0], _MM_SHUFFLE(2, 1, 0, 3));
115
+
116
+ d[0*n_channels] = _mm_cvtsi128_si32(out[0]);
117
+ d[1*n_channels] = _mm_cvtsi128_si32(out[1]);
118
+ d[2*n_channels] = _mm_cvtsi128_si32(out[2]);
119
+ d[3*n_channels] = _mm_cvtsi128_si32(out[3]);
120
+ d += 4*n_channels;
121
+ }
122
+ for(; n < n_samples; n++) {
123
+ *d = bswap_32(s0[n]);
124
+ d += n_channels;
125
+ }
126
+}
127
+static void
128
+conv_interleave_32s_4s_sse2(void *data, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src[],
129
+ uint32_t n_channels, uint32_t n_samples)
130
+{
131
+ const float *s0 = src[0], *s1 = src[1], *s2 = src[2], *s3 = src[3];
132
+ float *d = dst;
133
+ uint32_t n, unrolled;
134
+ __m128 out[4];
135
+
136
+ if (SPA_IS_ALIGNED(s0, 16) &&
137
+ SPA_IS_ALIGNED(s1, 16) &&
138
+ SPA_IS_ALIGNED(s2, 16) &&
139
+ SPA_IS_ALIGNED(s3, 16))
140
+ unrolled = n_samples & ~3;
141
+ else
142
+ unrolled = 0;
143
+
144
+ for(n = 0; n < unrolled; n += 4) {
145
+ out[0] = _mm_load_ps(&s0[n]);
146
+ out[1] = _mm_load_ps(&s1[n]);
147
+ out[2] = _mm_load_ps(&s2[n]);
148
+ out[3] = _mm_load_ps(&s3[n]);
149
+
150
+ _MM_TRANSPOSE4_PS(out[0], out[1], out[2], out[3]);
151
+
152
+ out[0] = (__m128) _MM_BSWAP_EPI32((__m128i)out[0]);
153
+ out[1] = (__m128) _MM_BSWAP_EPI32((__m128i)out[1]);
154
+ out[2] = (__m128) _MM_BSWAP_EPI32((__m128i)out[2]);
155
+ out[3] = (__m128) _MM_BSWAP_EPI32((__m128i)out[3]);
156
+
157
+ _mm_storeu_ps(&d[0*n_channels], out[0]);
158
+ _mm_storeu_ps(&d[1*n_channels], out[1]);
159
+ _mm_storeu_ps(&d[2*n_channels], out[2]);
160
+ _mm_storeu_ps(&d[3*n_channels], out[3]);
161
+ d += 4*n_channels;
162
+ }
163
+ for(; n < n_samples; n++) {
164
+ out[0] = _mm_setr_ps(s0[n], s1[n], s2[n], s3[n]);
165
+ out[0] = (__m128) _MM_BSWAP_EPI32((__m128i)out[0]);
166
+ _mm_storeu_ps(d, out[0]);
167
+ d += n_channels;
168
+ }
169
+}
170
+
171
+void
172
+conv_interleave_32s_sse2(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
173
+ uint32_t n_samples)
174
+{
175
+ int32_t *d = dst[0];
176
+ uint32_t i = 0, n_channels = conv->n_channels;
177
+
178
+ for(; i + 3 < n_channels; i += 4)
179
+ conv_interleave_32s_4s_sse2(conv, &d[i], &src[i], n_channels, n_samples);
180
+ for(; i < n_channels; i++)
181
+ conv_interleave_32s_1s_sse2(conv, &d[i], &src[i], n_channels, n_samples);
182
+}
183
+
184
+static void
185
+conv_deinterleave_32_1s_sse2(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src,
186
+ uint32_t n_channels, uint32_t n_samples)
187
+{
188
+ const float *s = src;
189
+ float *d0 = dst[0];
190
+ uint32_t n, unrolled;
191
+ __m128 out;
192
+
193
+ if (SPA_IS_ALIGNED(d0, 16))
194
+ unrolled = n_samples & ~3;
195
+ else
196
+ unrolled = 0;
197
+
198
+ for(n = 0; n < unrolled; n += 4) {
199
+ out = _mm_setr_ps(s[0*n_channels],
200
+ s[1*n_channels],
201
+ s[2*n_channels],
202
+ s[3*n_channels]);
203
+ _mm_store_ps(&d0[n], out);
204
+ s += 4*n_channels;
205
+ }
206
+ for(; n < n_samples; n++) {
207
+ d0[n] = *s;
208
+ s += n_channels;
209
+ }
210
+}
211
+
212
+static void
213
+conv_deinterleave_32_4s_sse2(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src,
214
+ uint32_t n_channels, uint32_t n_samples)
215
+{
216
+ const float *s = src;
217
+ float *d0 = dst[0], *d1 = dst[1], *d2 = dst[2], *d3 = dst[3];
218
+ uint32_t n, unrolled;
219
+ __m128 out[4];
220
+
221
+ if (SPA_IS_ALIGNED(d0, 16) &&
222
+ SPA_IS_ALIGNED(d1, 16) &&
223
+ SPA_IS_ALIGNED(d2, 16) &&
224
+ SPA_IS_ALIGNED(d3, 16))
225
+ unrolled = n_samples & ~3;
226
+ else
227
+ unrolled = 0;
228
+
229
+ for(n = 0; n < unrolled; n += 4) {
230
+ out[0] = _mm_loadu_ps(&s[0 * n_channels]);
231
+ out[1] = _mm_loadu_ps(&s[1 * n_channels]);
232
+ out[2] = _mm_loadu_ps(&s[2 * n_channels]);
233
+ out[3] = _mm_loadu_ps(&s[3 * n_channels]);
234
+
235
+ _MM_TRANSPOSE4_PS(out[0], out[1], out[2], out[3]);
236
+
237
+ _mm_store_ps(&d0[n], out[0]);
238
+ _mm_store_ps(&d1[n], out[1]);
239
+ _mm_store_ps(&d2[n], out[2]);
240
+ _mm_store_ps(&d3[n], out[3]);
241
+ s += 4 * n_channels;
242
+ }
243
+ for(; n < n_samples; n++) {
244
+ d0[n] = s[0];
245
+ d1[n] = s[1];
246
+ d2[n] = s[2];
247
+ d3[n] = s[3];
248
+ s += n_channels;
249
+ }
250
+}
251
+
252
+void
253
+conv_deinterleave_32_sse2(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
254
+ uint32_t n_samples)
255
+{
256
+ const float *s = src[0];
257
+ uint32_t i = 0, n_channels = conv->n_channels;
258
+
259
+ for(; i + 3 < n_channels; i += 4)
260
+ conv_deinterleave_32_4s_sse2(conv, &dst[i], &s[i], n_channels, n_samples);
261
+ for(; i < n_channels; i++)
262
+ conv_deinterleave_32_1s_sse2(conv, &dst[i], &s[i], n_channels, n_samples);
263
+}
264
+
265
+static void
266
+conv_deinterleave_32s_1s_sse2(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src,
267
+ uint32_t n_channels, uint32_t n_samples)
268
+{
269
+ const float *s = src;
270
+ float *d0 = dst[0];
271
+ uint32_t n, unrolled;
272
+ __m128 out;
273
+
274
+ if (SPA_IS_ALIGNED(d0, 16))
275
+ unrolled = n_samples & ~3;
276
+ else
277
+ unrolled = 0;
278
+
279
+ for(n = 0; n < unrolled; n += 4) {
280
+ out = _mm_setr_ps(s[0*n_channels],
281
+ s[1*n_channels],
282
+ s[2*n_channels],
283
+ s[3*n_channels]);
284
+ out = (__m128) _MM_BSWAP_EPI32((__m128i)out);
285
+ _mm_store_ps(&d0[n], out);
286
+ s += 4*n_channels;
287
+ }
288
+ for(; n < n_samples; n++) {
289
+ d0[n] = bswap_32(*s);
290
+ s += n_channels;
291
+ }
292
+}
293
+
294
+static void
295
+conv_deinterleave_32s_4s_sse2(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src,
296
+ uint32_t n_channels, uint32_t n_samples)
297
+{
298
+ const float *s = src;
299
+ float *d0 = dst[0], *d1 = dst[1], *d2 = dst[2], *d3 = dst[3];
300
+ uint32_t n, unrolled;
301
+ __m128 out[4];
302
+
303
+ if (SPA_IS_ALIGNED(d0, 16) &&
304
+ SPA_IS_ALIGNED(d1, 16) &&
305
+ SPA_IS_ALIGNED(d2, 16) &&
306
+ SPA_IS_ALIGNED(d3, 16))
307
+ unrolled = n_samples & ~3;
308
+ else
309
+ unrolled = 0;
310
+
311
+ for(n = 0; n < unrolled; n += 4) {
312
+ out[0] = _mm_loadu_ps(&s[0 * n_channels]);
313
+ out[1] = _mm_loadu_ps(&s[1 * n_channels]);
314
+ out[2] = _mm_loadu_ps(&s[2 * n_channels]);
315
+ out[3] = _mm_loadu_ps(&s[3 * n_channels]);
316
+
317
+ _MM_TRANSPOSE4_PS(out[0], out[1], out[2], out[3]);
318
+
319
+ out[0] = (__m128) _MM_BSWAP_EPI32((__m128i)out[0]);
320
+ out[1] = (__m128) _MM_BSWAP_EPI32((__m128i)out[1]);
321
+ out[2] = (__m128) _MM_BSWAP_EPI32((__m128i)out[2]);
322
+ out[3] = (__m128) _MM_BSWAP_EPI32((__m128i)out[3]);
323
+
324
+ _mm_store_ps(&d0[n], out[0]);
325
+ _mm_store_ps(&d1[n], out[1]);
326
+ _mm_store_ps(&d2[n], out[2]);
327
+ _mm_store_ps(&d3[n], out[3]);
328
+ s += 4 * n_channels;
329
+ }
330
+ for(; n < n_samples; n++) {
331
+ d0[n] = bswap_32(s[0]);
332
+ d1[n] = bswap_32(s[1]);
333
+ d2[n] = bswap_32(s[2]);
334
+ d3[n] = bswap_32(s[3]);
335
+ s += n_channels;
336
+ }
337
+}
338
+
339
+void
340
+conv_deinterleave_32s_sse2(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
341
+ uint32_t n_samples)
342
+{
343
+ const float *s = src[0];
344
+ uint32_t i = 0, n_channels = conv->n_channels;
345
+
346
+ for(; i + 3 < n_channels; i += 4)
347
+ conv_deinterleave_32s_4s_sse2(conv, &dst[i], &s[i], n_channels, n_samples);
348
+ for(; i < n_channels; i++)
349
+ conv_deinterleave_32s_1s_sse2(conv, &dst[i], &s[i], n_channels, n_samples);
350
+}
351
+
352
+static void
353
conv_f32_to_s16_1_sse2(void *data, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src,
354
uint32_t n_samples)
355
{
356
pipewire-0.3.48.tar.gz/spa/plugins/audioconvert/fmt-ops.c -> pipewire-0.3.49.tar.gz/spa/plugins/audioconvert/fmt-ops.c
Changed
52
1
2
3
{ SPA_AUDIO_FORMAT_F32, SPA_AUDIO_FORMAT_F32, 0, 0, conv_copy32_c },
4
{ SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_F32P, 0, 0, conv_copy32d_c },
5
+#if defined (HAVE_SSE2)
6
+ { SPA_AUDIO_FORMAT_F32, SPA_AUDIO_FORMAT_F32P, 0, 0, conv_deinterleave_32_sse2 },
7
+#endif
8
{ SPA_AUDIO_FORMAT_F32, SPA_AUDIO_FORMAT_F32P, 0, 0, conv_deinterleave_32_c },
9
+#if defined (HAVE_SSE2)
10
+ { SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_F32, 0, 0, conv_interleave_32_sse2 },
11
+#endif
12
{ SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_F32, 0, 0, conv_interleave_32_c },
13
14
+#if defined (HAVE_SSE2)
15
+ { SPA_AUDIO_FORMAT_F32_OE, SPA_AUDIO_FORMAT_F32P, 0, 0, conv_deinterleave_32s_sse2 },
16
+#endif
17
{ SPA_AUDIO_FORMAT_F32_OE, SPA_AUDIO_FORMAT_F32P, 0, 0, conv_deinterleave_32s_c },
18
+#if defined (HAVE_SSE2)
19
+ { SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_F32_OE, 0, 0, conv_interleave_32s_sse2 },
20
+#endif
21
{ SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_F32_OE, 0, 0, conv_interleave_32s_c },
22
23
{ SPA_AUDIO_FORMAT_U32, SPA_AUDIO_FORMAT_F32, 0, 0, conv_u32_to_f32_c },
24
25
/* s32 */
26
{ SPA_AUDIO_FORMAT_S32, SPA_AUDIO_FORMAT_S32, 0, 0, conv_copy32_c },
27
{ SPA_AUDIO_FORMAT_S32P, SPA_AUDIO_FORMAT_S32P, 0, 0, conv_copy32d_c },
28
+#if defined (HAVE_SSE2)
29
+ { SPA_AUDIO_FORMAT_S32, SPA_AUDIO_FORMAT_S32P, 0, 0, conv_deinterleave_32_sse2 },
30
+#endif
31
{ SPA_AUDIO_FORMAT_S32, SPA_AUDIO_FORMAT_S32P, 0, 0, conv_deinterleave_32_c },
32
+#if defined (HAVE_SSE2)
33
+ { SPA_AUDIO_FORMAT_S32P, SPA_AUDIO_FORMAT_S32, 0, 0, conv_interleave_32_sse2 },
34
+#endif
35
{ SPA_AUDIO_FORMAT_S32P, SPA_AUDIO_FORMAT_S32, 0, 0, conv_interleave_32_c },
36
37
/* s24 */
38
39
/* s24_32 */
40
{ SPA_AUDIO_FORMAT_S24_32, SPA_AUDIO_FORMAT_S24_32, 0, 0, conv_copy32_c },
41
{ SPA_AUDIO_FORMAT_S24_32P, SPA_AUDIO_FORMAT_S24_32P, 0, 0, conv_copy32d_c },
42
+#if defined (HAVE_SSE2)
43
+ { SPA_AUDIO_FORMAT_S24_32, SPA_AUDIO_FORMAT_S24_32P, 0, 0, conv_deinterleave_32_sse2 },
44
+#endif
45
{ SPA_AUDIO_FORMAT_S24_32, SPA_AUDIO_FORMAT_S24_32P, 0, 0, conv_deinterleave_32_c },
46
+#if defined (HAVE_SSE2)
47
+ { SPA_AUDIO_FORMAT_S24_32P, SPA_AUDIO_FORMAT_S24_32, 0, 0, conv_interleave_32_sse2 },
48
+#endif
49
{ SPA_AUDIO_FORMAT_S24_32P, SPA_AUDIO_FORMAT_S24_32, 0, 0, conv_interleave_32_c },
50
51
/* F64 */
52
pipewire-0.3.48.tar.gz/spa/plugins/audioconvert/fmt-ops.h -> pipewire-0.3.49.tar.gz/spa/plugins/audioconvert/fmt-ops.h
Changed
12
1
2
DEFINE_FUNCTION(f32d_to_s16_2, sse2);
3
DEFINE_FUNCTION(f32d_to_s16, sse2);
4
DEFINE_FUNCTION(f32d_to_s16d, sse2);
5
+DEFINE_FUNCTION(deinterleave_32, sse2);
6
+DEFINE_FUNCTION(deinterleave_32s, sse2);
7
+DEFINE_FUNCTION(interleave_32, sse2);
8
+DEFINE_FUNCTION(interleave_32s, sse2);
9
#endif
10
#if defined(HAVE_SSSE3)
11
DEFINE_FUNCTION(s24_to_f32d, ssse3);
12
pipewire-0.3.48.tar.gz/spa/plugins/audioconvert/merger.c -> pipewire-0.3.49.tar.gz/spa/plugins/audioconvert/merger.c
Changed
127
1
2
3
case SPA_PARAM_PropInfo:
4
{
5
- struct props *p = &this->props;
6
-
7
switch (result.index) {
8
- case 0:
9
- param = spa_pod_builder_add_object(&b,
10
- SPA_TYPE_OBJECT_PropInfo, id,
11
- SPA_PROP_INFO_id, SPA_POD_Id(SPA_PROP_volume),
12
- SPA_PROP_INFO_name, SPA_POD_String("Volume"),
13
- SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Float(p->volume, 0.0, 10.0));
14
- break;
15
- case 1:
16
- param = spa_pod_builder_add_object(&b,
17
- SPA_TYPE_OBJECT_PropInfo, id,
18
- SPA_PROP_INFO_id, SPA_POD_Id(SPA_PROP_mute),
19
- SPA_PROP_INFO_name, SPA_POD_String("Mute"),
20
- SPA_PROP_INFO_type, SPA_POD_CHOICE_Bool(p->channel.mute));
21
- break;
22
- case 2:
23
- param = spa_pod_builder_add_object(&b,
24
- SPA_TYPE_OBJECT_PropInfo, id,
25
- SPA_PROP_INFO_id, SPA_POD_Id(SPA_PROP_channelVolumes),
26
- SPA_PROP_INFO_name, SPA_POD_String("Channel Volumes"),
27
- SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Float(p->volume, 0.0, 10.0),
28
- SPA_PROP_INFO_container, SPA_POD_Id(SPA_TYPE_Array));
29
- break;
30
- case 3:
31
- param = spa_pod_builder_add_object(&b,
32
- SPA_TYPE_OBJECT_PropInfo, id,
33
- SPA_PROP_INFO_id, SPA_POD_Id(SPA_PROP_channelMap),
34
- SPA_PROP_INFO_name, SPA_POD_String("Channel Map"),
35
- SPA_PROP_INFO_type, SPA_POD_Id(SPA_AUDIO_CHANNEL_UNKNOWN),
36
- SPA_PROP_INFO_container, SPA_POD_Id(SPA_TYPE_Array));
37
- break;
38
- case 4:
39
- param = spa_pod_builder_add_object(&b,
40
- SPA_TYPE_OBJECT_PropInfo, id,
41
- SPA_PROP_INFO_id, SPA_POD_Id(SPA_PROP_monitorMute),
42
- SPA_PROP_INFO_name, SPA_POD_String("Monitor Mute"),
43
- SPA_PROP_INFO_type, SPA_POD_CHOICE_Bool(p->monitor.mute));
44
- break;
45
- case 5:
46
- param = spa_pod_builder_add_object(&b,
47
- SPA_TYPE_OBJECT_PropInfo, id,
48
- SPA_PROP_INFO_id, SPA_POD_Id(SPA_PROP_monitorVolumes),
49
- SPA_PROP_INFO_name, SPA_POD_String("Monitor Volumes"),
50
- SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Float(p->volume, 0.0, 10.0),
51
- SPA_PROP_INFO_container, SPA_POD_Id(SPA_TYPE_Array));
52
- break;
53
- case 6:
54
- param = spa_pod_builder_add_object(&b,
55
- SPA_TYPE_OBJECT_PropInfo, id,
56
- SPA_PROP_INFO_id, SPA_POD_Id(SPA_PROP_softMute),
57
- SPA_PROP_INFO_name, SPA_POD_String("Soft Mute"),
58
- SPA_PROP_INFO_type, SPA_POD_CHOICE_Bool(p->soft.mute));
59
- break;
60
- case 7:
61
- param = spa_pod_builder_add_object(&b,
62
- SPA_TYPE_OBJECT_PropInfo, id,
63
- SPA_PROP_INFO_id, SPA_POD_Id(SPA_PROP_softVolumes),
64
- SPA_PROP_INFO_name, SPA_POD_String("Soft Volumes"),
65
- SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Float(p->volume, 0.0, 10.0),
66
- SPA_PROP_INFO_container, SPA_POD_Id(SPA_TYPE_Array));
67
- break;
68
- case 8:
69
- param = spa_pod_builder_add_object(&b,
70
- SPA_TYPE_OBJECT_PropInfo, id,
71
- SPA_PROP_INFO_name, SPA_POD_String("monitor.channel-volumes"),
72
- SPA_PROP_INFO_description, SPA_POD_String("Monitor channel volume"),
73
- SPA_PROP_INFO_type, SPA_POD_CHOICE_Bool(
74
- this->monitor_channel_volumes),
75
- SPA_PROP_INFO_params, SPA_POD_Bool(true));
76
- break;
77
default:
78
return 0;
79
}
80
81
82
case SPA_PARAM_Props:
83
{
84
-#if 0
85
- struct props *p = &this->props;
86
- struct spa_pod_frame f[2];
87
-#endif
88
-
89
switch (result.index) {
90
-#if 0
91
- case 0:
92
- spa_pod_builder_push_object(&b, &f[0],
93
- SPA_TYPE_OBJECT_Props, id);
94
- spa_pod_builder_add(&b,
95
- SPA_PROP_volume, SPA_POD_Float(p->volume),
96
- SPA_PROP_mute, SPA_POD_Bool(p->channel.mute),
97
- SPA_PROP_channelVolumes, SPA_POD_Array(sizeof(float),
98
- SPA_TYPE_Float,
99
- p->channel.n_volumes,
100
- p->channel.volumes),
101
- SPA_PROP_channelMap, SPA_POD_Array(sizeof(uint32_t),
102
- SPA_TYPE_Id,
103
- p->n_channels,
104
- p->channel_map),
105
- SPA_PROP_softMute, SPA_POD_Bool(p->soft.mute),
106
- SPA_PROP_softVolumes, SPA_POD_Array(sizeof(float),
107
- SPA_TYPE_Float,
108
- p->soft.n_volumes,
109
- p->soft.volumes),
110
- SPA_PROP_monitorMute, SPA_POD_Bool(p->monitor.mute),
111
- SPA_PROP_monitorVolumes, SPA_POD_Array(sizeof(float),
112
- SPA_TYPE_Float,
113
- p->monitor.n_volumes,
114
- p->monitor.volumes),
115
- 0);
116
- spa_pod_builder_prop(&b, SPA_PROP_params, 0);
117
- spa_pod_builder_push_struct(&b, &f[1]);
118
- spa_pod_builder_string(&b, "monitor.channel-volumes");
119
- spa_pod_builder_bool(&b, this->monitor_channel_volumes);
120
- spa_pod_builder_pop(&b, &f[1]);
121
- param = spa_pod_builder_pop(&b, &f[0]);
122
- break;
123
-#endif
124
default:
125
return 0;
126
}
127
pipewire-0.3.48.tar.gz/spa/plugins/audioconvert/resample.c -> pipewire-0.3.49.tar.gz/spa/plugins/audioconvert/resample.c
Changed
77
1
2
3
if (spa_pod_is_string(pod)) {
4
spa_pod_copy_string(pod, sizeof(value), value);
5
- } else if (spa_pod_is_float(pod)) {
6
- snprintf(value, sizeof(value), "%f",
7
- SPA_POD_VALUE(struct spa_pod_float, pod));
8
} else if (spa_pod_is_int(pod)) {
9
snprintf(value, sizeof(value), "%d",
10
SPA_POD_VALUE(struct spa_pod_int, pod));
11
12
static void update_rate_match(struct impl *this, bool passthrough, uint32_t out_size, uint32_t in_queued)
13
{
14
if (this->io_rate_match) {
15
- uint32_t match_size;
16
+ uint32_t delay, match_size;
17
18
if (passthrough) {
19
- this->io_rate_match->delay = 0;
20
+ delay = in_queued;
21
match_size = out_size;
22
} else {
23
if (SPA_FLAG_IS_SET(this->io_rate_match->flags, SPA_IO_RATE_MATCH_FLAG_ACTIVE))
24
25
else
26
resample_update_rate(&this->resample, this->rate_scale);
27
28
- this->io_rate_match->delay = resample_delay(&this->resample);
29
+ delay = resample_delay(&this->resample) + in_queued;
30
match_size = resample_in_len(&this->resample, out_size);
31
}
32
match_size -= SPA_MIN(match_size, in_queued);
33
this->io_rate_match->size = match_size;
34
- spa_log_trace_fp(this->log, "%p: next match %u", this, match_size);
35
+ this->io_rate_match->delay = delay;
36
+ spa_log_trace_fp(this->log, "%p: next match:%u queued:%u delay:%u", this, match_size,
37
+ in_queued, delay);
38
} else {
39
resample_update_rate(&this->resample, this->rate_scale * this->props.rate);
40
}
41
42
if (SPA_LIKELY(this->io_position)) {
43
double r = this->rate_scale;
44
45
- max = this->io_position->clock.duration;
46
+ max = this->io_position->clock.duration * sizeof(float);
47
if (this->mode == MODE_SPLIT) {
48
if (this->io_position->clock.rate.denom != this->resample.o_rate)
49
r = (double) this->io_position->clock.rate.denom / this->resample.o_rate;
50
51
}
52
}
53
else
54
- max = maxsize / sizeof(float);
55
+ max = maxsize;
56
57
switch (this->mode) {
58
case MODE_SPLIT:
59
/* in split mode we need to output exactly the size of the
60
* duration so we don't try to flush early */
61
- maxsize = SPA_MIN(maxsize, max * sizeof(float));
62
+ maxsize = SPA_MIN(maxsize, max);
63
flush_out = false;
64
break;
65
case MODE_MERGE:
66
67
spa_log_trace_fp(this->log, "%p: no output buffer", this);
68
}
69
70
- update_rate_match(this, passthrough, max - outport->offset / sizeof(float),
71
- size - inport->offset / sizeof(float));
72
+ update_rate_match(this, passthrough, (max - outport->offset) / sizeof(float),
73
+ (size - inport->offset) / sizeof(float));
74
return res;
75
}
76
77
pipewire-0.3.48.tar.gz/spa/plugins/audiotestsrc/audiotestsrc.c -> pipewire-0.3.49.tar.gz/spa/plugins/audiotestsrc/audiotestsrc.c
Changed
24
1
2
return 0;
3
}
4
5
+static int do_remove_timer(struct spa_loop *loop, bool async, uint32_t seq, const void *data, size_t size, void *user_data)
6
+{
7
+ struct impl *this = user_data;
8
+ spa_loop_remove_source(this->data_loop, &this->timer_source);
9
+ return 0;
10
+}
11
+
12
static int impl_clear(struct spa_handle *handle)
13
{
14
struct impl *this;
15
16
this = (struct impl *) handle;
17
18
if (this->data_loop)
19
- spa_loop_remove_source(this->data_loop, &this->timer_source);
20
+ spa_loop_invoke(this->data_loop, do_remove_timer, 0, NULL, 0, true, this);
21
spa_system_close(this->data_system, this->timer_source.fd);
22
23
return 0;
24
pipewire-0.3.48.tar.gz/spa/plugins/bluez5/a2dp-codec-aptx.c -> pipewire-0.3.49.tar.gz/spa/plugins/bluez5/a2dp-codec-aptx.c
Changed
10
1
2
3
if (this->hd)
4
this->max_frames = (this->mtu - sizeof(struct rtp_header)) / this->frame_length;
5
+ else if (codec_is_ll(codec))
6
+ this->max_frames = SPA_MIN(256u, this->mtu) / this->frame_length;
7
else
8
this->max_frames = this->mtu / this->frame_length;
9
10
pipewire-0.3.48.tar.gz/spa/plugins/bluez5/a2dp-codecs.h -> pipewire-0.3.49.tar.gz/spa/plugins/bluez5/a2dp-codecs.h
Changed
10
1
2
3
#define SPA_TYPE_INTERFACE_Bluez5CodecA2DP SPA_TYPE_INFO_INTERFACE_BASE "Bluez5:Codec:A2DP:Private"
4
5
-#define SPA_VERSION_BLUEZ5_CODEC_A2DP 0
6
+#define SPA_VERSION_BLUEZ5_CODEC_A2DP 1
7
8
struct spa_bluez5_codec_a2dp {
9
struct spa_interface iface;
10
pipewire-0.3.48.tar.gz/spa/plugins/bluez5/a2dp-sink.c -> pipewire-0.3.49.tar.gz/spa/plugins/bluez5/a2dp-sink.c
Changed
310
1
2
3
#define FILL_FRAMES 2
4
#define MAX_BUFFERS 32
5
+#define MIN_LATENCY 128
6
+#define MAX_LATENCY 8192
7
+#define BUFFER_SIZE (MAX_LATENCY*8)
8
9
struct buffer {
10
uint32_t id;
11
12
struct spa_source source;
13
int timerfd;
14
struct spa_source flush_source;
15
+ struct spa_source flush_timer_source;
16
+ int flush_timerfd;
17
18
struct spa_io_clock *clock;
19
struct spa_io_position *position;
20
21
22
int need_flush;
23
uint32_t block_size;
24
- uint8_t buffer[4096];
25
+ uint8_t buffer[BUFFER_SIZE];
26
uint32_t buffer_used;
27
uint32_t header_size;
28
uint32_t frame_count;
29
uint16_t seqnum;
30
uint32_t timestamp;
31
uint64_t sample_count;
32
- uint8_t tmp_buffer[4096];
33
+ uint8_t tmp_buffer[BUFFER_SIZE];
34
uint32_t tmp_buffer_used;
35
uint32_t fd_buffer_size;
36
};
37
38
39
static void reset_props(struct impl *this, struct props *props)
40
{
41
- if (this->codec->id == SPA_BLUETOOTH_AUDIO_CODEC_APTX_LL) {
42
- props->min_latency = 256;
43
- } else {
44
- props->min_latency = MIN_LATENCY;
45
- }
46
+ props->min_latency = MIN_LATENCY;
47
props->max_latency = MAX_LATENCY;
48
props->latency_offset = 0;
49
strncpy(props->clock_name, DEFAULT_CLOCK_NAME, sizeof(props->clock_name));
50
51
return written;
52
}
53
54
-static bool want_flush(struct impl *this)
55
-{
56
- return (this->frame_count * this->block_size / this->port.frame_size >= this->props.min_latency);
57
-}
58
-
59
static int encode_buffer(struct impl *this, const void *data, uint32_t size)
60
{
61
int processed;
62
63
spa_log_trace(this->log, "%p: used:%d block_size:%d", this,
64
this->buffer_used, this->block_size);
65
66
- if (this->need_flush || want_flush(this))
67
+ if (this->need_flush)
68
return send_buffer(this);
69
70
return 0;
71
72
return total;
73
}
74
75
-static void enable_flush(struct impl *this, bool enabled)
76
+static void enable_flush(struct impl *this, bool enabled, uint64_t timeout)
77
{
78
- if (SPA_FLAG_IS_SET(this->flush_source.mask, SPA_IO_OUT) != enabled) {
79
- SPA_FLAG_UPDATE(this->flush_source.mask, SPA_IO_OUT, enabled);
80
+ bool flush_enabled = enabled && (timeout == 0);
81
+ struct itimerspec ts;
82
+
83
+ if (SPA_FLAG_IS_SET(this->flush_source.mask, SPA_IO_OUT) != flush_enabled) {
84
+ SPA_FLAG_UPDATE(this->flush_source.mask, SPA_IO_OUT, flush_enabled);
85
spa_loop_update_source(this->data_loop, &this->flush_source);
86
}
87
+
88
+ if (!enabled)
89
+ timeout = 0;
90
+
91
+ ts.it_value.tv_sec = timeout / SPA_NSEC_PER_SEC;
92
+ ts.it_value.tv_nsec = timeout % SPA_NSEC_PER_SEC;
93
+ ts.it_interval.tv_sec = 0;
94
+ ts.it_interval.tv_nsec = 0;
95
+ spa_system_timerfd_settime(this->data_system,
96
+ this->flush_timerfd, 0, &ts, NULL);
97
}
98
99
static int flush_data(struct impl *this, uint64_t now_time)
100
101
uint32_t total_frames;
102
struct port *port = &this->port;
103
104
+ if (!this->flush_source.loop) {
105
+ /* I/O in error state */
106
+ return -EIO;
107
+ }
108
+
109
total_frames = 0;
110
again:
111
written = 0;
112
113
}
114
115
if (written > 0 && this->buffer_used == this->header_size) {
116
- enable_flush(this, false);
117
+ enable_flush(this, false, 0);
118
return 0;
119
}
120
121
written = flush_buffer(this);
122
+
123
if (written == -EAGAIN) {
124
- spa_log_trace(this->log, "%p: delay flush", this);
125
+ spa_log_trace(this->log, "%p: fail flush", this);
126
if (now_time - this->last_error > SPA_NSEC_PER_SEC / 2) {
127
+ spa_log_trace(this->log, "%p: reduce bitpool", this);
128
this->codec->reduce_bitpool(this->codec_data);
129
this->last_error = now_time;
130
}
131
- this->need_flush = true;
132
- enable_flush(this, true);
133
+
134
+ /*
135
+ * The socket buffer is full, and the device is not processing data
136
+ * fast enough, so should just skip this packet. There will be a sound
137
+ * glitch in any case.
138
+ */
139
+ written = this->buffer_used;
140
+ reset_buffer(this);
141
}
142
- else if (written < 0) {
143
+
144
+ if (written < 0) {
145
spa_log_trace(this->log, "%p: error flushing %s", this,
146
spa_strerror(written));
147
reset_buffer(this);
148
- enable_flush(this, false);
149
+ enable_flush(this, false, 0);
150
return written;
151
}
152
else if (written > 0) {
153
+ /*
154
+ * We cannot write all data we have at once, since this can exceed
155
+ * device buffers. We'll want a limited number of "excess"
156
+ * samples. This is an issue for the "low-latency" A2DP codecs.
157
+ *
158
+ * Flushing the rest of the data (if any) is delayed after a timeout,
159
+ * selected on an average-rate basis:
160
+ *
161
+ * npackets = quantum / packet_samples
162
+ * write_end_time = npackets * timeout
163
+ * max_excess = quantum - sample_rate * write_end_time
164
+ * packet_time = packet_samples / sample_rate
165
+ * => timeout = (quantum - max_excess)/quantum * packet_time
166
+ */
167
+ uint64_t max_excess = 2*256;
168
+ uint64_t packet_samples = this->frame_count * this->block_size / port->frame_size;
169
+ uint64_t packet_time = packet_samples * SPA_NSEC_PER_SEC / port->current_format.info.raw.rate;
170
+ uint64_t quantum = SPA_LIKELY(this->clock) ? this->clock->duration : 0;
171
+ uint64_t timeout = (quantum > max_excess) ?
172
+ (packet_time * (quantum - max_excess) / quantum) : 0;
173
+
174
reset_buffer(this);
175
if (now_time - this->last_error > SPA_NSEC_PER_SEC) {
176
- this->codec->increase_bitpool(this->codec_data);
177
+ if (get_transport_unused_size(this) == (int)this->fd_buffer_size) {
178
+ spa_log_trace(this->log, "%p: increase bitpool", this);
179
+ this->codec->increase_bitpool(this->codec_data);
180
+ }
181
this->last_error = now_time;
182
}
183
- if (!spa_list_is_empty(&port->ready))
184
- goto again;
185
-
186
- enable_flush(this, false);
187
+ if (!spa_list_is_empty(&port->ready)) {
188
+ spa_log_trace(this->log, "%p: flush after %d ns", this, (int)timeout);
189
+ if (timeout == 0)
190
+ goto again;
191
+ else
192
+ enable_flush(this, true, timeout);
193
+ } else {
194
+ enable_flush(this, false, 0);
195
+ }
196
}
197
else {
198
/* Don't want to flush yet, or failed to write anything */
199
spa_log_trace(this->log, "%p: skip flush", this);
200
- enable_flush(this, false);
201
+ enable_flush(this, false, 0);
202
}
203
return 0;
204
}
205
206
spa_loop_remove_source(this->data_loop, &this->flush_source);
207
return;
208
}
209
+
210
+ if (this->transport == NULL) {
211
+ enable_flush(this, false, 0);
212
+ return;
213
+ }
214
+
215
+ flush_data(this, this->current_time);
216
+}
217
+
218
+static void a2dp_on_flush_timeout(struct spa_source *source)
219
+{
220
+ struct impl *this = source->data;
221
+ uint64_t exp;
222
+
223
+ spa_log_trace(this->log, "%p: flush on timeout", this);
224
+
225
+ if (spa_system_timerfd_read(this->data_system, this->flush_timerfd, &exp) < 0)
226
+ spa_log_warn(this->log, "error reading timerfd: %s", strerror(errno));
227
+
228
+ if (this->transport == NULL) {
229
+ enable_flush(this, false, 0);
230
+ return;
231
+ }
232
+
233
flush_data(this, this->current_time);
234
}
235
236
237
this->source.rmask = 0;
238
spa_loop_add_source(this->data_loop, &this->source);
239
240
+ this->flush_timer_source.data = this;
241
+ this->flush_timer_source.fd = this->flush_timerfd;
242
+ this->flush_timer_source.func = a2dp_on_flush_timeout;
243
+ this->flush_timer_source.mask = SPA_IO_IN;
244
+ this->flush_timer_source.rmask = 0;
245
+ spa_loop_add_source(this->data_loop, &this->flush_timer_source);
246
+
247
this->flush_source.data = this;
248
this->flush_source.fd = this->transport->fd;
249
this->flush_source.func = a2dp_on_flush;
250
251
ts.it_interval.tv_sec = 0;
252
ts.it_interval.tv_nsec = 0;
253
spa_system_timerfd_settime(this->data_system, this->timerfd, 0, &ts, NULL);
254
+
255
if (this->flush_source.loop)
256
spa_loop_remove_source(this->data_loop, &this->flush_source);
257
258
+ if (this->flush_timer_source.loop)
259
+ spa_loop_remove_source(this->data_loop, &this->flush_timer_source);
260
+ ts.it_value.tv_sec = 0;
261
+ ts.it_value.tv_nsec = 0;
262
+ ts.it_interval.tv_sec = 0;
263
+ ts.it_interval.tv_nsec = 0;
264
+ spa_system_timerfd_settime(this->data_system, this->flush_timerfd, 0, &ts, NULL);
265
+
266
return 0;
267
}
268
269
270
271
static void emit_node_info(struct impl *this, bool full)
272
{
273
- char latency[64] = SPA_STRINGIFY(MIN_LATENCY)"/48000";
274
struct spa_dict_item node_info_items[] = {
275
{ SPA_KEY_DEVICE_API, "bluez5" },
276
{ SPA_KEY_MEDIA_CLASS, "Audio/Sink" },
277
{ SPA_KEY_NODE_DRIVER, "true" },
278
- { SPA_KEY_NODE_LATENCY, latency },
279
};
280
uint64_t old = full ? this->info.change_mask : 0;
281
if (full)
282
this->info.change_mask = this->info_all;
283
if (this->info.change_mask) {
284
- if (this->transport && this->port.have_format)
285
- snprintf(latency, sizeof(latency), "%d/%d", (int)this->props.min_latency,
286
- (int)this->port.current_format.info.raw.rate);
287
- else
288
- snprintf(latency, sizeof(latency), "%d/48000", (int)this->props.min_latency);
289
this->info.props = &SPA_DICT_INIT_ARRAY(node_info_items);
290
spa_node_emit_info(&this->hooks, &this->info);
291
this->info.change_mask = old;
292
293
if (this->transport)
294
spa_hook_remove(&this->transport_listener);
295
spa_system_close(this->data_system, this->timerfd);
296
+ spa_system_close(this->data_system, this->flush_timerfd);
297
return 0;
298
}
299
300
301
this->timerfd = spa_system_timerfd_create(this->data_system,
302
CLOCK_MONOTONIC, SPA_FD_CLOEXEC | SPA_FD_NONBLOCK);
303
304
+ this->flush_timerfd = spa_system_timerfd_create(this->data_system,
305
+ CLOCK_MONOTONIC, SPA_FD_CLOEXEC | SPA_FD_NONBLOCK);
306
+
307
return 0;
308
}
309
310
pipewire-0.3.48.tar.gz/spa/plugins/bluez5/a2dp-source.c -> pipewire-0.3.49.tar.gz/spa/plugins/bluez5/a2dp-source.c
Changed
10
1
2
3
#define FILL_FRAMES 2
4
#define MAX_BUFFERS 32
5
+#define MIN_LATENCY 512
6
+#define MAX_LATENCY 1024
7
8
struct buffer {
9
uint32_t id;
10
pipewire-0.3.48.tar.gz/spa/plugins/bluez5/backend-ofono.c -> pipewire-0.3.49.tar.gz/spa/plugins/bluez5/backend-ofono.c
Changed
281
1
2
#include <spa/support/plugin.h>
3
#include <spa/utils/string.h>
4
#include <spa/utils/type.h>
5
+#include <spa/utils/result.h>
6
#include <spa/param/audio/raw.h>
7
8
#include "defs.h"
9
10
+#define INITIAL_INTERVAL_NSEC (500 * SPA_NSEC_PER_MSEC)
11
+#define ACTION_INTERVAL_NSEC (3000 * SPA_NSEC_PER_MSEC)
12
+
13
static struct spa_log_topic log_topic = SPA_LOG_TOPIC(0, "spa.bluez5.ofono");
14
#undef SPA_LOG_TOPIC_DEFAULT
15
#define SPA_LOG_TOPIC_DEFAULT &log_topic
16
17
18
struct spa_log *log;
19
struct spa_loop *main_loop;
20
+ struct spa_system *main_system;
21
struct spa_dbus *dbus;
22
+ struct spa_loop_utils *loop_utils;
23
DBusConnection *conn;
24
25
const struct spa_bt_quirks *quirks;
26
27
+ struct spa_source *timer;
28
+
29
unsigned int filters_added:1;
30
unsigned int msbc_supported:1;
31
};
32
33
struct transport_data {
34
struct spa_source sco;
35
+ unsigned int broken:1;
36
+ unsigned int activated:1;
37
};
38
39
#define OFONO_HF_AUDIO_MANAGER_INTERFACE OFONO_SERVICE ".HandsfreeAudioManager"
40
41
42
dbus_error_init(&err);
43
44
+ /*
45
+ * XXX: We assume here oFono replies. It however can happen that the headset does
46
+ * XXX: not properly respond to the codec negotiation RFCOMM commands.
47
+ * XXX: oFono (1.34) fails to handle this condition, and will not send DBus reply
48
+ * XXX: in this case. The transport acquire API is synchronous, so we can't
49
+ * XXX: do better here right now.
50
+ */
51
r = dbus_connection_send_with_reply_and_block(backend->conn, m, -1, &err);
52
dbus_message_unref(m);
53
m = NULL;
54
55
static int ofono_audio_acquire(void *data, bool optional)
56
{
57
struct spa_bt_transport *transport = data;
58
+ struct transport_data *td = transport->user_data;
59
struct impl *backend = SPA_CONTAINER_OF(transport->backend, struct impl, this);
60
uint8_t codec;
61
int ret = 0;
62
63
if (transport->fd >= 0)
64
goto finish;
65
+ if (td->broken) {
66
+ ret = -EIO;
67
+ goto finish;
68
+ }
69
+
70
+ spa_bt_device_update_last_bluez_action_time(transport->device);
71
72
ret = _audio_acquire(backend, transport->path, &codec);
73
if (ret < 0)
74
75
transport->fd = ret;
76
77
if (transport->codec != codec) {
78
- struct spa_bt_transport *t = NULL;
79
+ struct timespec ts;
80
81
- spa_log_warn(backend->log, "Acquired codec (%d) differs from transport one (%d)",
82
- codec, transport->codec);
83
+ spa_log_info(backend->log, "transport %p: acquired codec (%d) differs from transport one (%d)",
84
+ transport, codec, transport->codec);
85
86
/* shutdown to make sure connection is dropped immediately */
87
shutdown(transport->fd, SHUT_RDWR);
88
close(transport->fd);
89
transport->fd = -1;
90
91
- /* Create a new transport which differs only for codec */
92
- t = _transport_create(backend, transport->path, transport->device,
93
- transport->profile, codec, &transport->impl);
94
-
95
- spa_bt_transport_free(transport);
96
- spa_bt_device_connect_profile(t->device, t->profile);
97
-
98
- ret = -EIO;
99
- goto finish;
100
+ /* schedule immediate profile update, from main loop */
101
+ transport->codec = codec;
102
+ td->broken = true;
103
+ ts.tv_sec = 0;
104
+ ts.tv_nsec = 1;
105
+ spa_loop_utils_update_timer(backend->loop_utils, backend->timer,
106
+ &ts, NULL, false);
107
+ return -EIO;
108
}
109
110
+ td->broken = false;
111
+
112
spa_log_debug(backend->log, "transport %p: Acquire %s, fd %d codec %d", transport,
113
transport->path, transport->fd, transport->codec);
114
115
116
.release = ofono_audio_release,
117
};
118
119
+bool activate_transport(struct spa_bt_transport *t, const void *data)
120
+{
121
+ struct impl *backend = (void *)data;
122
+ struct transport_data *td = t->user_data;
123
+ struct timespec ts;
124
+ uint64_t now, threshold;
125
+
126
+ if (t->backend != &backend->this)
127
+ return false;
128
+
129
+ /* Check device-specific rate limit */
130
+ spa_system_clock_gettime(backend->main_system, CLOCK_MONOTONIC, &ts);
131
+ now = SPA_TIMESPEC_TO_NSEC(&ts);
132
+ threshold = t->device->last_bluez_action_time + ACTION_INTERVAL_NSEC;
133
+ if (now < threshold) {
134
+ ts.tv_sec = (threshold - now) / SPA_NSEC_PER_SEC;
135
+ ts.tv_nsec = (threshold - now) % SPA_NSEC_PER_SEC;
136
+ spa_loop_utils_update_timer(backend->loop_utils, backend->timer,
137
+ &ts, NULL, false);
138
+ return false;
139
+ }
140
+
141
+ if (!td->activated) {
142
+ /* Connect profile */
143
+ spa_log_debug(backend->log, "Transport %s activated", t->path);
144
+ td->activated = true;
145
+ spa_bt_device_connect_profile(t->device, t->profile);
146
+ }
147
+
148
+ if (td->broken) {
149
+ /* Recreate the transport */
150
+ struct spa_bt_transport *t_copy;
151
+
152
+ t_copy = _transport_create(backend, t->path, t->device,
153
+ t->profile, t->codec, (struct spa_callbacks *)&ofono_transport_impl);
154
+ spa_bt_transport_free(t);
155
+
156
+ if (t_copy)
157
+ spa_bt_device_connect_profile(t_copy->device, t_copy->profile);
158
+
159
+ return true;
160
+ }
161
+
162
+ return false;
163
+}
164
+
165
+static void activate_transports(struct impl *backend)
166
+{
167
+ while (spa_bt_transport_find_full(backend->monitor, activate_transport, backend));
168
+}
169
+
170
+static void activate_timer_event(void *userdata, uint64_t expirations)
171
+{
172
+ struct impl *backend = userdata;
173
+ spa_loop_utils_update_timer(backend->loop_utils, backend->timer, NULL, NULL, false);
174
+ activate_transports(backend);
175
+}
176
+
177
static DBusHandlerResult ofono_audio_card_found(struct impl *backend, char *path, DBusMessageIter *props_i)
178
{
179
const char *remote_address = NULL;
180
const char *local_address = NULL;
181
struct spa_bt_device *d;
182
struct spa_bt_transport *t;
183
+ struct transport_data *td;
184
enum spa_bt_profile profile = SPA_BT_PROFILE_HFP_AG;
185
- uint8_t codec = HFP_AUDIO_CODEC_CVSD;
186
+ uint8_t codec = backend->msbc_supported ?
187
+ HFP_AUDIO_CODEC_MSBC : HFP_AUDIO_CODEC_CVSD;
188
189
spa_assert(backend);
190
spa_assert(path);
191
192
dbus_message_iter_next(props_i);
193
}
194
195
- /*
196
- * Acquire and close immediately to figure out the codec.
197
- * This is necessary if we are in HF mode, because we need to emit
198
- * nodes and the advertised sample rate of the node depends on the codec.
199
- * For AG mode, we delay the emission of the nodes, so it is not necessary
200
- * to know the codec in advance
201
- */
202
- if (profile == SPA_BT_PROFILE_HFP_HF) {
203
- int fd = _audio_acquire(backend, path, &codec);
204
- if (fd < 0) {
205
- spa_log_error(backend->log, "Failed to retrieve codec for %s", path);
206
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
207
- }
208
- /* shutdown to make sure connection is dropped immediately */
209
- shutdown(fd, SHUT_RDWR);
210
- close(fd);
211
- }
212
-
213
if (!remote_address || !local_address) {
214
spa_log_error(backend->log, "Missing addresses for %s", path);
215
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
216
217
spa_bt_device_add_profile(d, profile);
218
219
t = _transport_create(backend, path, d, profile, codec, (struct spa_callbacks *)&ofono_transport_impl);
220
+ if (t == NULL) {
221
+ spa_log_error(backend->log, "failed to create transport: %s", spa_strerror(-errno));
222
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
223
+ }
224
225
- spa_bt_device_connect_profile(t->device, profile);
226
+ td = t->user_data;
227
+
228
+ /*
229
+ * For HF profile, delay profile connect, so that we likely don't do it at the
230
+ * same time as the device is busy with A2DP connect. This avoids some oFono
231
+ * misbehavior (see comment in _audio_acquire above).
232
+ *
233
+ * For AG mode, we delay the emission of the nodes, so it is not necessary
234
+ * to know the codec in advance.
235
+ */
236
+ if (profile == SPA_BT_PROFILE_HFP_HF) {
237
+ struct timespec ts;
238
+ ts.tv_sec = INITIAL_INTERVAL_NSEC / SPA_NSEC_PER_SEC;
239
+ ts.tv_nsec = INITIAL_INTERVAL_NSEC % SPA_NSEC_PER_SEC;
240
+ spa_loop_utils_update_timer(backend->loop_utils, backend->timer,
241
+ &ts, NULL, false);
242
+ } else {
243
+ td->activated = true;
244
+ spa_bt_device_connect_profile(t->device, t->profile);
245
+ }
246
247
spa_log_debug(backend->log, "Transport %s available, codec %d", t->path, t->codec);
248
249
250
backend->filters_added = false;
251
}
252
253
+ if (backend->timer)
254
+ spa_loop_utils_destroy_source(backend->loop_utils, backend->timer);
255
+
256
dbus_connection_unregister_object_path(backend->conn, OFONO_AUDIO_CLIENT);
257
258
free(backend);
259
260
backend->log = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_Log);
261
backend->dbus = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_DBus);
262
backend->main_loop = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_Loop);
263
+ backend->main_system = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_System);
264
+ backend->loop_utils = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_LoopUtils);
265
backend->conn = dbus_connection;
266
if (info && (str = spa_dict_lookup(info, "bluez5.enable-msbc")))
267
backend->msbc_supported = spa_atob(str);
268
269
270
spa_log_topic_init(backend->log, &log_topic);
271
272
+ backend->timer = spa_loop_utils_add_timer(backend->loop_utils, activate_timer_event, backend);
273
+ if (backend->timer == NULL) {
274
+ free(backend);
275
+ return NULL;
276
+ }
277
+
278
if (!dbus_connection_register_object_path(backend->conn,
279
OFONO_AUDIO_CLIENT,
280
&vtable_profile, backend)) {
281
pipewire-0.3.48.tar.gz/spa/plugins/bluez5/bluez5-dbus.c -> pipewire-0.3.49.tar.gz/spa/plugins/bluez5/bluez5-dbus.c
Changed
46
1
2
return NULL;
3
}
4
5
-static void device_update_last_bluez_action_time(struct spa_bt_device *device)
6
+void spa_bt_device_update_last_bluez_action_time(struct spa_bt_device *device)
7
{
8
struct timespec ts;
9
spa_system_clock_gettime(device->monitor->main_system, CLOCK_MONOTONIC, &ts);
10
11
12
spa_list_prepend(&monitor->device_list, &d->link);
13
14
- device_update_last_bluez_action_time(d);
15
+ spa_bt_device_update_last_bluez_action_time(d);
16
17
return d;
18
}
19
20
goto next;
21
}
22
23
- device_update_last_bluez_action_time(sw->device);
24
+ spa_bt_device_update_last_bluez_action_time(sw->device);
25
26
spa_log_info(sw->device->monitor->log, "a2dp codec switch %p: trying codec %s for endpoint %s, local endpoint %s",
27
sw, codec->name, ep->path, local_endpoint);
28
29
dbus_pending_call_unref(pending);
30
sw->pending = NULL;
31
32
- device_update_last_bluez_action_time(device);
33
+ spa_bt_device_update_last_bluez_action_time(device);
34
35
if (!a2dp_codec_switch_goto_active(sw)) {
36
if (r != NULL)
37
38
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
39
}
40
41
- device_update_last_bluez_action_time(transport->device);
42
+ spa_bt_device_update_last_bluez_action_time(transport->device);
43
44
if (profile & SPA_BT_PROFILE_A2DP_SOURCE) {
45
/* PW is the rendering device so it's responsible for reporting hardware volume. */
46
pipewire-0.3.48.tar.gz/spa/plugins/bluez5/codec-loader.c -> pipewire-0.3.49.tar.gz/spa/plugins/bluez5/codec-loader.c
Changed
19
1
2
spa_log_debug(impl->log, "loading codecs from %s", factory_name);
3
4
if ((res = spa_handle_get_interface(handle, SPA_TYPE_INTERFACE_Bluez5CodecA2DP, &iface)) < 0) {
5
- spa_log_info(impl->log, "Bluetooth codec plugin %s has no codec interface",
6
+ spa_log_warn(impl->log, "Bluetooth codec plugin %s has no codec interface",
7
factory_name);
8
goto fail;
9
}
10
11
bluez5_codec_a2dp = iface;
12
13
if (bluez5_codec_a2dp->iface.version != SPA_VERSION_BLUEZ5_CODEC_A2DP) {
14
- spa_log_info(impl->log, "codec plugin %s has incompatible ABI version (%d != %d)",
15
+ spa_log_warn(impl->log, "codec plugin %s has incompatible ABI version (%d != %d)",
16
factory_name, bluez5_codec_a2dp->iface.version, SPA_VERSION_BLUEZ5_CODEC_A2DP);
17
res = -ENOENT;
18
goto fail;
19
pipewire-0.3.48.tar.gz/spa/plugins/bluez5/defs.h -> pipewire-0.3.49.tar.gz/spa/plugins/bluez5/defs.h
Changed
19
1
2
3
#define PIPEWIRE_BATTERY_PROVIDER "/org/freedesktop/pipewire/battery"
4
5
-#define MIN_LATENCY 512
6
-#define MAX_LATENCY 1024
7
-
8
#define OBJECT_MANAGER_INTROSPECT_XML \
9
DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
10
"<node>\n" \
11
12
int spa_bt_device_supports_hfp_codec(struct spa_bt_device *device, unsigned int codec);
13
int spa_bt_device_release_transports(struct spa_bt_device *device);
14
int spa_bt_device_report_battery_level(struct spa_bt_device *device, uint8_t percentage);
15
+void spa_bt_device_update_last_bluez_action_time(struct spa_bt_device *device);
16
17
#define spa_bt_device_emit(d,m,v,...) spa_hook_list_call(&(d)->listener_list, \
18
struct spa_bt_device_events, \
19
pipewire-0.3.48.tar.gz/spa/plugins/bluez5/quirks.c -> pipewire-0.3.49.tar.gz/spa/plugins/bluez5/quirks.c
Changed
20
1
2
} else {
3
char path[PATH_MAX];
4
const char *dir = getenv("SPA_DATA_DIR");
5
+ int res;
6
7
if (dir == NULL)
8
dir = SPADATADIR;
9
10
if (spa_scnprintf(path, sizeof(path), "%s/bluez5/bluez-hardware.conf", dir) >= 0)
11
- load_conf(this, path);
12
+ if ((res = load_conf(this, path)) < 0)
13
+ spa_log_warn(this->log, "failed to load '%s': %s", path,
14
+ spa_strerror(res));
15
}
16
-
17
if (!(this->kernel_rules && this->adapter_rules && this->device_rules))
18
spa_log_warn(this->log, "failed to load bluez-hardware.conf");
19
20
pipewire-0.3.48.tar.gz/spa/plugins/bluez5/sco-sink.c -> pipewire-0.3.49.tar.gz/spa/plugins/bluez5/sco-sink.c
Changed
10
1
2
};
3
4
#define MAX_BUFFERS 32
5
+#define MIN_LATENCY 512
6
+#define MAX_LATENCY 1024
7
8
struct buffer {
9
uint32_t id;
10
pipewire-0.3.48.tar.gz/spa/plugins/support/loop.c -> pipewire-0.3.49.tar.gz/spa/plugins/support/loop.c
Changed
447
1
2
uint8_t buffer_mem[DATAS_SIZE + MAX_ALIGN];
3
4
unsigned int flushing:1;
5
+ unsigned int polling:1;
6
};
7
8
struct source_impl {
9
10
struct impl *impl;
11
struct spa_list link;
12
13
- bool close;
14
union {
15
spa_source_io_func_t io;
16
spa_source_idle_func_t idle;
17
18
spa_source_timer_func_t timer;
19
spa_source_signal_func_t signal;
20
} func;
21
- bool enabled;
22
+
23
struct spa_source *fallback;
24
+
25
+ bool close;
26
+ bool enabled;
27
};
28
/** \endcond */
29
30
31
struct impl *impl = object;
32
source->loop = &impl->loop;
33
source->priv = NULL;
34
+ source->rmask = 0;
35
return spa_system_pollfd_add(impl->system, impl->poll_fd, source->fd, source->mask, source);
36
}
37
38
static int loop_update_source(void *object, struct spa_source *source)
39
{
40
struct impl *impl = object;
41
+
42
+ spa_assert(source->loop == &impl->loop);
43
+
44
return spa_system_pollfd_mod(impl->system, impl->poll_fd, source->fd, source->mask, source);
45
}
46
47
-static int loop_remove_source(void *object, struct spa_source *source)
48
+static void detach_source(struct spa_source *source)
49
{
50
- struct impl *impl = object;
51
struct spa_poll_event *e;
52
+
53
+ source->loop = NULL;
54
+ source->rmask = 0;
55
+
56
if ((e = source->priv)) {
57
/* active in an iteration of the loop, remove it from there */
58
e->data = NULL;
59
source->priv = NULL;
60
}
61
- source->loop = NULL;
62
+}
63
+
64
+static int remove_from_poll(struct impl *impl, struct spa_source *source)
65
+{
66
+ spa_assert(source->loop == &impl->loop);
67
+
68
return spa_system_pollfd_del(impl->system, impl->poll_fd, source->fd);
69
}
70
71
+static int loop_remove_source(void *object, struct spa_source *source)
72
+{
73
+ struct impl *impl = object;
74
+ spa_assert(!impl->polling);
75
+
76
+ int res = remove_from_poll(impl, source);
77
+ detach_source(source);
78
+
79
+ return res;
80
+}
81
+
82
static void flush_items(struct impl *impl)
83
{
84
uint32_t index;
85
86
item = SPA_PTROFF(impl->buffer_data, index & (DATAS_SIZE - 1), struct invoke_item);
87
block = item->block;
88
89
- spa_log_trace(impl->log, "%p: flush item %p", impl, item);
90
+ spa_log_trace_fp(impl->log, "%p: flush item %p", impl, item);
91
item->res = item->func ? item->func(&impl->loop,
92
true, item->seq, item->data, item->size,
93
item->user_data) : 0;
94
95
item->user_data = user_data;
96
item->item_size = SPA_ROUND_UP_N(sizeof(struct invoke_item) + size, ITEM_ALIGN);
97
98
- spa_log_trace(impl->log, "%p: add item %p filled:%d", impl, item, filled);
99
+ spa_log_trace_fp(impl->log, "%p: add item %p filled:%d", impl, item, filled);
100
101
if (l0 >= item->item_size) {
102
/* item + size fit in current ringbuffer idx */
103
104
105
spa_log_trace(impl->log, "%p: leave %lu", impl, impl->thread);
106
107
- if (--impl->enter_count == 0)
108
+ if (--impl->enter_count == 0) {
109
impl->thread = 0;
110
+ impl->polling = false;
111
+ }
112
+}
113
+
114
+static inline void free_source(struct source_impl *s)
115
+{
116
+ detach_source(&s->source);
117
+ free(s);
118
}
119
120
static inline void process_destroy(struct impl *impl)
121
{
122
struct source_impl *source, *tmp;
123
+
124
spa_list_for_each_safe(source, tmp, &impl->destroy_list, link)
125
- free(source);
126
+ free_source(source);
127
+
128
spa_list_init(&impl->destroy_list);
129
}
130
131
132
struct spa_poll_event ep[MAX_EP], *e;
133
int i, nfds;
134
135
+ impl->polling = true;
136
spa_loop_control_hook_before(&impl->hooks_list);
137
138
- nfds = spa_system_pollfd_wait(impl->system, impl->poll_fd, ep, MAX_EP, timeout);
139
+ nfds = spa_system_pollfd_wait(impl->system, impl->poll_fd, ep, SPA_N_ELEMENTS(ep), timeout);
140
141
spa_loop_control_hook_after(&impl->hooks_list);
142
-
143
- if (SPA_UNLIKELY(nfds < 0))
144
- return nfds;
145
+ impl->polling = false;
146
147
/* first we set all the rmasks, then call the callbacks. The reason is that
148
* some callback might also want to look at other sources it manages and
149
* can then reset the rmask to suppress the callback */
150
for (i = 0; i < nfds; i++) {
151
struct spa_source *s = ep[i].data;
152
+
153
+ spa_assert(s->loop == &impl->loop);
154
+
155
s->rmask = ep[i].events;
156
/* already active in another iteration of the loop,
157
* remove it from that iteration */
158
159
e->data = NULL;
160
s->priv = &ep[i];
161
}
162
+
163
+ if (SPA_UNLIKELY(!spa_list_is_empty(&impl->destroy_list)))
164
+ process_destroy(impl);
165
+
166
for (i = 0; i < nfds; i++) {
167
struct spa_source *s = ep[i].data;
168
- if (SPA_LIKELY(s && s->rmask && s->loop)) {
169
- s->priv = NULL;
170
+ if (SPA_LIKELY(s && s->rmask))
171
s->func(s);
172
+ }
173
+
174
+ for (i = 0; i < nfds; i++) {
175
+ struct spa_source *s = ep[i].data;
176
+ if (SPA_LIKELY(s)) {
177
+ s->rmask = 0;
178
+ s->priv = NULL;
179
}
180
}
181
- if (SPA_UNLIKELY(!spa_list_is_empty(&impl->destroy_list)))
182
- process_destroy(impl);
183
184
return nfds;
185
}
186
187
static void source_io_func(struct spa_source *source)
188
{
189
- struct source_impl *impl = SPA_CONTAINER_OF(source, struct source_impl, source);
190
- spa_log_trace_fp(impl->impl->log, "%p: io %08x", impl, source->rmask);
191
- impl->func.io(source->data, source->fd, source->rmask);
192
+ struct source_impl *s = SPA_CONTAINER_OF(source, struct source_impl, source);
193
+ spa_log_trace_fp(s->impl->log, "%p: io %08x", s, source->rmask);
194
+ s->func.io(source->data, source->fd, source->rmask);
195
}
196
197
static struct spa_source *loop_add_io(void *object,
198
199
if (source == NULL)
200
goto error_exit;
201
202
- source->source.loop = &impl->loop;
203
source->source.func = source_io_func;
204
source->source.data = data;
205
source->source.fd = fd;
206
207
struct impl *impl = object;
208
struct source_impl *s = SPA_CONTAINER_OF(source, struct source_impl, source);
209
int res;
210
+
211
+ spa_assert(s->impl == object);
212
+ spa_assert(source->func == source_io_func);
213
+
214
+ spa_log_trace(impl->log, "%p: update %08x -> %08x", s, source->mask, mask);
215
source->mask = mask;
216
- spa_log_trace(impl->log, "%p: update %08x", s, mask);
217
+
218
if (s->fallback)
219
res = spa_loop_utils_enable_idle(&impl->utils, s->fallback,
220
mask & (SPA_IO_IN | SPA_IO_OUT) ? true : false);
221
222
223
static void source_idle_func(struct spa_source *source)
224
{
225
- struct source_impl *impl = SPA_CONTAINER_OF(source, struct source_impl, source);
226
- impl->func.idle(source->data);
227
+ struct source_impl *s = SPA_CONTAINER_OF(source, struct source_impl, source);
228
+ s->func.idle(source->data);
229
}
230
231
static int loop_enable_idle(void *object, struct spa_source *source, bool enabled)
232
{
233
- struct source_impl *impl = SPA_CONTAINER_OF(source, struct source_impl, source);
234
+ struct source_impl *s = SPA_CONTAINER_OF(source, struct source_impl, source);
235
int res = 0;
236
237
- if (enabled && !impl->enabled) {
238
- if ((res = spa_system_eventfd_write(impl->impl->system, source->fd, 1)) < 0)
239
- spa_log_warn(impl->impl->log, "%p: failed to write idle fd %d: %s",
240
+ spa_assert(s->impl == object);
241
+ spa_assert(source->func == source_idle_func);
242
+
243
+ if (enabled && !s->enabled) {
244
+ if ((res = spa_system_eventfd_write(s->impl->system, source->fd, 1)) < 0)
245
+ spa_log_warn(s->impl->log, "%p: failed to write idle fd %d: %s",
246
source, source->fd, spa_strerror(res));
247
- } else if (!enabled && impl->enabled) {
248
+ } else if (!enabled && s->enabled) {
249
uint64_t count;
250
- if ((res = spa_system_eventfd_read(impl->impl->system, source->fd, &count)) < 0)
251
- spa_log_warn(impl->impl->log, "%p: failed to read idle fd %d: %s",
252
+ if ((res = spa_system_eventfd_read(s->impl->system, source->fd, &count)) < 0)
253
+ spa_log_warn(s->impl->log, "%p: failed to read idle fd %d: %s",
254
source, source->fd, spa_strerror(res));
255
}
256
- impl->enabled = enabled;
257
+ s->enabled = enabled;
258
return res;
259
}
260
261
262
if ((res = spa_system_eventfd_create(impl->system, SPA_FD_CLOEXEC | SPA_FD_NONBLOCK)) < 0)
263
goto error_exit_free;
264
265
- source->source.loop = &impl->loop;
266
source->source.func = source_idle_func;
267
source->source.data = data;
268
source->source.fd = res;
269
270
271
static void source_event_func(struct spa_source *source)
272
{
273
- struct source_impl *impl = SPA_CONTAINER_OF(source, struct source_impl, source);
274
+ struct source_impl *s = SPA_CONTAINER_OF(source, struct source_impl, source);
275
uint64_t count = 0;
276
int res;
277
278
- if ((res = spa_system_eventfd_read(impl->impl->system, source->fd, &count)) < 0)
279
- spa_log_warn(impl->impl->log, "%p: failed to read event fd %d: %s",
280
+ if ((res = spa_system_eventfd_read(s->impl->system, source->fd, &count)) < 0)
281
+ spa_log_warn(s->impl->log, "%p: failed to read event fd %d: %s",
282
source, source->fd, spa_strerror(res));
283
284
- impl->func.event(source->data, count);
285
+ s->func.event(source->data, count);
286
}
287
288
static struct spa_source *loop_add_event(void *object,
289
290
if ((res = spa_system_eventfd_create(impl->system, SPA_FD_CLOEXEC | SPA_FD_NONBLOCK)) < 0)
291
goto error_exit_free;
292
293
- source->source.loop = &impl->loop;
294
source->source.func = source_event_func;
295
source->source.data = data;
296
source->source.fd = res;
297
298
299
static int loop_signal_event(void *object, struct spa_source *source)
300
{
301
- struct source_impl *impl = SPA_CONTAINER_OF(source, struct source_impl, source);
302
+ struct source_impl *s = SPA_CONTAINER_OF(source, struct source_impl, source);
303
int res;
304
305
- if (SPA_UNLIKELY((res = spa_system_eventfd_write(impl->impl->system, source->fd, 1)) < 0))
306
- spa_log_warn(impl->impl->log, "%p: failed to write event fd %d: %s",
307
+ spa_assert(s->impl == object);
308
+ spa_assert(source->func == source_event_func);
309
+
310
+ if (SPA_UNLIKELY((res = spa_system_eventfd_write(s->impl->system, source->fd, 1)) < 0))
311
+ spa_log_warn(s->impl->log, "%p: failed to write event fd %d: %s",
312
source, source->fd, spa_strerror(res));
313
return res;
314
}
315
316
static void source_timer_func(struct spa_source *source)
317
{
318
- struct source_impl *impl = SPA_CONTAINER_OF(source, struct source_impl, source);
319
+ struct source_impl *s = SPA_CONTAINER_OF(source, struct source_impl, source);
320
uint64_t expirations = 0;
321
int res;
322
323
- if (SPA_UNLIKELY((res = spa_system_timerfd_read(impl->impl->system,
324
+ if (SPA_UNLIKELY((res = spa_system_timerfd_read(s->impl->system,
325
source->fd, &expirations)) < 0))
326
- spa_log_warn(impl->impl->log, "%p: failed to read timer fd %d: %s",
327
+ spa_log_warn(s->impl->log, "%p: failed to read timer fd %d: %s",
328
source, source->fd, spa_strerror(res));
329
330
- impl->func.timer(source->data, expirations);
331
+ s->func.timer(source->data, expirations);
332
}
333
334
static struct spa_source *loop_add_timer(void *object,
335
336
SPA_FD_CLOEXEC | SPA_FD_NONBLOCK)) < 0)
337
goto error_exit_free;
338
339
- source->source.loop = &impl->loop;
340
source->source.func = source_timer_func;
341
source->source.data = data;
342
source->source.fd = res;
343
344
loop_update_timer(void *object, struct spa_source *source,
345
struct timespec *value, struct timespec *interval, bool absolute)
346
{
347
- struct impl *impl = object;
348
+ struct source_impl *s = SPA_CONTAINER_OF(source, struct source_impl, source);
349
struct itimerspec its;
350
int flags = 0, res;
351
352
+ spa_assert(s->impl == object);
353
+ spa_assert(source->func == source_timer_func);
354
+
355
spa_zero(its);
356
if (SPA_LIKELY(value)) {
357
its.it_value = *value;
358
359
if (SPA_LIKELY(absolute))
360
flags |= SPA_FD_TIMER_ABSTIME;
361
362
- if (SPA_UNLIKELY((res = spa_system_timerfd_settime(impl->system, source->fd, flags, &its, NULL)) < 0))
363
+ if (SPA_UNLIKELY((res = spa_system_timerfd_settime(s->impl->system, source->fd, flags, &its, NULL)) < 0))
364
return res;
365
366
return 0;
367
368
369
static void source_signal_func(struct spa_source *source)
370
{
371
- struct source_impl *impl = SPA_CONTAINER_OF(source, struct source_impl, source);
372
+ struct source_impl *s = SPA_CONTAINER_OF(source, struct source_impl, source);
373
int res, signal_number = 0;
374
375
- if ((res = spa_system_signalfd_read(impl->impl->system, source->fd, &signal_number)) < 0)
376
- spa_log_warn(impl->impl->log, "%p: failed to read signal fd %d: %s",
377
+ if ((res = spa_system_signalfd_read(s->impl->system, source->fd, &signal_number)) < 0)
378
+ spa_log_warn(s->impl->log, "%p: failed to read signal fd %d: %s",
379
source, source->fd, spa_strerror(res));
380
381
- impl->func.signal(source->data, signal_number);
382
+ s->func.signal(source->data, signal_number);
383
}
384
385
static struct spa_source *loop_add_signal(void *object,
386
387
signal_number, SPA_FD_CLOEXEC | SPA_FD_NONBLOCK)) < 0)
388
goto error_exit_free;
389
390
- source->source.loop = &impl->loop;
391
source->source.func = source_signal_func;
392
source->source.data = data;
393
source->source.fd = res;
394
395
396
static void loop_destroy_source(void *object, struct spa_source *source)
397
{
398
- struct source_impl *impl = SPA_CONTAINER_OF(source, struct source_impl, source);
399
+ struct source_impl *s = SPA_CONTAINER_OF(source, struct source_impl, source);
400
+
401
+ spa_assert(s->impl == object);
402
403
- spa_log_trace(impl->impl->log, "%p ", impl);
404
+ spa_log_trace(s->impl->log, "%p ", s);
405
406
- spa_list_remove(&impl->link);
407
+ spa_list_remove(&s->link);
408
409
- if (impl->fallback)
410
- loop_destroy_source(impl->impl, impl->fallback);
411
- else if (source->loop)
412
- loop_remove_source(impl->impl, source);
413
+ if (s->fallback)
414
+ loop_destroy_source(s->impl, s->fallback);
415
+ else
416
+ remove_from_poll(s->impl, source);
417
418
- if (source->fd != -1 && impl->close) {
419
- spa_system_close(impl->impl->system, source->fd);
420
+ if (source->fd != -1 && s->close) {
421
+ spa_system_close(s->impl->system, source->fd);
422
source->fd = -1;
423
}
424
- spa_list_insert(&impl->impl->destroy_list, &impl->link);
425
+
426
+ if (!s->impl->polling)
427
+ free_source(s);
428
+ else
429
+ spa_list_insert(&s->impl->destroy_list, &s->link);
430
}
431
432
static const struct spa_loop_methods impl_loop = {
433
434
spa_log_warn(impl->log, "%p: loop is entered %d times",
435
impl, impl->enter_count);
436
437
+ spa_assert(!impl->polling);
438
+
439
spa_list_consume(source, &impl->source_list, link)
440
loop_destroy_source(impl, &source->source);
441
442
- process_destroy(impl);
443
-
444
spa_system_close(impl->system, impl->ack_fd);
445
spa_system_close(impl->system, impl->poll_fd);
446
447
pipewire-0.3.48.tar.gz/spa/plugins/support/node-driver.c -> pipewire-0.3.49.tar.gz/spa/plugins/support/node-driver.c
Changed
24
1
2
return 0;
3
}
4
5
+static int do_remove_timer(struct spa_loop *loop, bool async, uint32_t seq, const void *data, size_t size, void *user_data)
6
+{
7
+ struct impl *this = user_data;
8
+ spa_loop_remove_source(this->data_loop, &this->timer_source);
9
+ return 0;
10
+}
11
+
12
static int impl_clear(struct spa_handle *handle)
13
{
14
struct impl *this;
15
16
17
this = (struct impl *) handle;
18
19
- spa_loop_remove_source(this->data_loop, &this->timer_source);
20
+ spa_loop_invoke(this->data_loop, do_remove_timer, 0, NULL, 0, true, this);
21
spa_system_close(this->data_system, this->timer_source.fd);
22
23
return 0;
24
pipewire-0.3.48.tar.gz/spa/plugins/support/null-audio-sink.c -> pipewire-0.3.49.tar.gz/spa/plugins/support/null-audio-sink.c
Changed
24
1
2
return 0;
3
}
4
5
+static int do_remove_timer(struct spa_loop *loop, bool async, uint32_t seq, const void *data, size_t size, void *user_data)
6
+{
7
+ struct impl *this = user_data;
8
+ spa_loop_remove_source(this->data_loop, &this->timer_source);
9
+ return 0;
10
+}
11
+
12
static int impl_clear(struct spa_handle *handle)
13
{
14
struct impl *this;
15
16
17
this = (struct impl *) handle;
18
19
- spa_loop_remove_source(this->data_loop, &this->timer_source);
20
+ spa_loop_invoke(this->data_loop, do_remove_timer, 0, NULL, 0, true, this);
21
spa_system_close(this->data_system, this->timer_source.fd);
22
23
return 0;
24
pipewire-0.3.48.tar.gz/spa/plugins/test/fakesink.c -> pipewire-0.3.49.tar.gz/spa/plugins/test/fakesink.c
Changed
24
1
2
return 0;
3
}
4
5
+static int do_remove_timer(struct spa_loop *loop, bool async, uint32_t seq, const void *data, size_t size, void *user_data)
6
+{
7
+ struct impl *this = user_data;
8
+ spa_loop_remove_source(this->data_loop, &this->timer_source);
9
+ return 0;
10
+}
11
+
12
static int impl_clear(struct spa_handle *handle)
13
{
14
struct impl *this;
15
16
this = (struct impl *) handle;
17
18
if (this->data_loop)
19
- spa_loop_remove_source(this->data_loop, &this->timer_source);
20
+ spa_loop_invoke(this->data_loop, do_remove_timer, 0, NULL, 0, true, this);
21
spa_system_close(this->data_system, this->timer_source.fd);
22
23
return 0;
24
pipewire-0.3.48.tar.gz/spa/plugins/test/fakesrc.c -> pipewire-0.3.49.tar.gz/spa/plugins/test/fakesrc.c
Changed
24
1
2
return 0;
3
}
4
5
+static int do_remove_timer(struct spa_loop *loop, bool async, uint32_t seq, const void *data, size_t size, void *user_data)
6
+{
7
+ struct impl *this = user_data;
8
+ spa_loop_remove_source(this->data_loop, &this->timer_source);
9
+ return 0;
10
+}
11
+
12
static int impl_clear(struct spa_handle *handle)
13
{
14
struct impl *this;
15
16
this = (struct impl *) handle;
17
18
if (this->data_loop)
19
- spa_loop_remove_source(this->data_loop, &this->timer_source);
20
+ spa_loop_invoke(this->data_loop, do_remove_timer, 0, NULL, 0, true, this);
21
spa_system_close(this->data_system, this->timer_source.fd);
22
23
return 0;
24
pipewire-0.3.48.tar.gz/spa/plugins/videotestsrc/videotestsrc.c -> pipewire-0.3.49.tar.gz/spa/plugins/videotestsrc/videotestsrc.c
Changed
24
1
2
return 0;
3
}
4
5
+static int do_remove_timer(struct spa_loop *loop, bool async, uint32_t seq, const void *data, size_t size, void *user_data)
6
+{
7
+ struct impl *this = user_data;
8
+ spa_loop_remove_source(this->data_loop, &this->timer_source);
9
+ return 0;
10
+}
11
+
12
static int impl_clear(struct spa_handle *handle)
13
{
14
struct impl *this;
15
16
this = (struct impl *) handle;
17
18
if (this->data_loop)
19
- spa_loop_remove_source(this->data_loop, &this->timer_source);
20
+ spa_loop_invoke(this->data_loop, do_remove_timer, 0, NULL, 0, true, this);
21
spa_system_close(this->data_system, this->timer_source.fd);
22
23
return 0;
24
pipewire-0.3.48.tar.gz/spa/plugins/vulkan/vulkan-compute-source.c -> pipewire-0.3.49.tar.gz/spa/plugins/vulkan/vulkan-compute-source.c
Changed
24
1
2
return 0;
3
}
4
5
+static int do_remove_timer(struct spa_loop *loop, bool async, uint32_t seq, const void *data, size_t size, void *user_data)
6
+{
7
+ struct impl *this = user_data;
8
+ spa_loop_remove_source(this->data_loop, &this->timer_source);
9
+ return 0;
10
+}
11
+
12
static int impl_clear(struct spa_handle *handle)
13
{
14
struct impl *this;
15
16
this = (struct impl *) handle;
17
18
if (this->data_loop)
19
- spa_loop_remove_source(this->data_loop, &this->timer_source);
20
+ spa_loop_invoke(this->data_loop, do_remove_timer, 0, NULL, 0, true, this);
21
spa_system_close(this->data_system, this->timer_source.fd);
22
23
return 0;
24
pipewire-0.3.48.tar.gz/src/daemon/client-rt.conf.in -> pipewire-0.3.49.tar.gz/src/daemon/client-rt.conf.in
Changed
20
1
2
#node.latency = 1024/48000
3
#node.autoconnect = true
4
#resample.quality = 4
5
- #channelmix.normalize = true
6
+ #channelmix.normalize = false
7
#channelmix.mix-lfe = true
8
- #channelmix.upmix = false
9
- #channelmix.lfe-cutoff = 0
10
- #channelmix.fc-cutoff = 0
11
+ #channelmix.upmix = true
12
+ #channelmix.upmix-method = simple # none, psd
13
+ #channelmix.lfe-cutoff = 120
14
+ #channelmix.fc-cutoff = 6000
15
#channelmix.rear-delay = 12.0
16
- #channelmix.stereo-widen = 0.0
17
+ #channelmix.stereo-widen = 0.1
18
#channelmix.hilbert-taps = 0
19
}
20
pipewire-0.3.48.tar.gz/src/daemon/client.conf.in -> pipewire-0.3.49.tar.gz/src/daemon/client.conf.in
Changed
20
1
2
#node.latency = 1024/48000
3
#node.autoconnect = true
4
#resample.quality = 4
5
- #channelmix.normalize = true
6
+ #channelmix.normalize = false
7
#channelmix.mix-lfe = false
8
- #channelmix.upmix = false
9
- #channelmix.lfe-cutoff = 0
10
- #channelmix.fc-cutoff = 0
11
+ #channelmix.upmix = true
12
+ #channelmix.upmix-method = simple # none, psd
13
+ #channelmix.lfe-cutoff = 120
14
+ #channelmix.fc-cutoff = 6000
15
#channelmix.rear-delay = 12.0
16
- #channelmix.stereo-widen = 0.0
17
+ #channelmix.stereo-widen = 0.1
18
#channelmix.hilbert-taps = 0
19
}
20
pipewire-0.3.48.tar.gz/src/daemon/minimal.conf.in -> pipewire-0.3.49.tar.gz/src/daemon/minimal.conf.in
Changed
41
1
2
#resample.quality = 4
3
resample.disable = true
4
#monitor.channel-volumes = false
5
- #channelmix.normalize = true
6
+ #channelmix.normalize = false
7
#channelmix.mix-lfe = false
8
- #channelmix.upmix = false
9
- #channelmix.lfe-cutoff = 0
10
- #channelmix.fc-cutoff = 0
11
+ #channelmix.upmix = true
12
+ #channelmix.upmix-method = simple # none, psd
13
+ #channelmix.lfe-cutoff = 120
14
+ #channelmix.fc-cutoff = 6000
15
#channelmix.rear-delay = 12.0
16
- #channelmix.stereo-widen = 0.0
17
+ #channelmix.stereo-widen = 0.1
18
#channelmix.hilbert-taps = 0
19
channelmix.disable = true
20
#node.param.Props = {
21
22
#audio.position = "FL,FR"
23
#resample.quality = 4
24
resample.disable = true
25
- #channelmix.normalize = true
26
+ #channelmix.normalize = false
27
#channelmix.mix-lfe = false
28
- #channelmix.upmix = false
29
- #channelmix.lfe-cutoff = 0
30
- #channelmix.fc-cutoff = 0
31
+ #channelmix.upmix = true
32
+ #channelmix.upmix-method = simple # none, psd
33
+ #channelmix.lfe-cutoff = 120
34
+ #channelmix.fc-cutoff = 6000
35
#channelmix.rear-delay = 12.0
36
- #channelmix.stereo-widen = 0.0
37
+ #channelmix.stereo-widen = 0.1
38
#channelmix.hilbert-taps = 0
39
channelmix.disable = true
40
#node.param.Props = {
41
pipewire-0.3.48.tar.gz/src/daemon/pipewire-pulse.conf.in -> pipewire-0.3.49.tar.gz/src/daemon/pipewire-pulse.conf.in
Changed
88
1
2
3
{ name = libpipewire-module-protocol-pulse
4
args = {
5
- # the addresses this server listens on
6
- server.address = [
7
- "unix:native"
8
- #"unix:/tmp/something" # absolute paths may be used
9
- #"tcp:4713" # IPv4 and IPv6 on all addresses
10
- #"tcp:[::]:9999" # IPv6 on all addresses
11
- #"tcp:127.0.0.1:8888" # IPv4 on a single address
12
- #
13
- #{ address = "tcp:4713" # address
14
- # max-clients = 64 # maximum number of clients
15
- # listen-backlog = 32 # backlog in the server listen queue
16
- # client.access = "restricted" # permissions for clients
17
- #}
18
- ]
19
- #pulse.min.req = 256/48000 # 5ms
20
- #pulse.default.req = 960/48000 # 20 milliseconds
21
- #pulse.min.frag = 256/48000 # 5ms
22
- #pulse.default.frag = 96000/48000 # 2 seconds
23
- #pulse.default.tlength = 96000/48000 # 2 seconds
24
- #pulse.min.quantum = 256/48000 # 5ms
25
- #pulse.default.format = F32
26
- #pulse.default.position = [ FL FR ]
27
- # These overrides are only applied when running in a vm.
28
- vm.overrides = {
29
- pulse.min.quantum = 1024/48000 # 22ms
30
- }
31
+ # contents of pulse.properties can also be placed here
32
+ # to have config per server.
33
}
34
}
35
]
36
37
#node.latency = 1024/48000
38
#node.autoconnect = true
39
#resample.quality = 4
40
- #channelmix.normalize = true
41
+ #channelmix.normalize = false
42
#channelmix.mix-lfe = false
43
- #channelmix.upmix = false
44
- #channelmix.lfe-cutoff = 0
45
- #channelmix.fc-cutoff = 0
46
+ #channelmix.upmix = true
47
+ #channelmix.upmix-method = simple # none, psd
48
+ #channelmix.lfe-cutoff = 120
49
+ #channelmix.fc-cutoff = 6000
50
#channelmix.rear-delay = 12.0
51
- #channelmix.stereo-widen = 0.0
52
+ #channelmix.stereo-widen = 0.1
53
#channelmix.hilbert-taps = 0
54
}
55
56
+pulse.properties = {
57
+ # the addresses this server listens on
58
+ server.address = [
59
+ "unix:native"
60
+ #"unix:/tmp/something" # absolute paths may be used
61
+ #"tcp:4713" # IPv4 and IPv6 on all addresses
62
+ #"tcp:[::]:9999" # IPv6 on all addresses
63
+ #"tcp:127.0.0.1:8888" # IPv4 on a single address
64
+ #
65
+ #{ address = "tcp:4713" # address
66
+ # max-clients = 64 # maximum number of clients
67
+ # listen-backlog = 32 # backlog in the server listen queue
68
+ # client.access = "restricted" # permissions for clients
69
+ #}
70
+ ]
71
+ #pulse.min.req = 256/48000 # 5ms
72
+ #pulse.default.req = 960/48000 # 20 milliseconds
73
+ #pulse.min.frag = 256/48000 # 5ms
74
+ #pulse.default.frag = 96000/48000 # 2 seconds
75
+ #pulse.default.tlength = 96000/48000 # 2 seconds
76
+ #pulse.min.quantum = 256/48000 # 5ms
77
+ #pulse.default.format = F32
78
+ #pulse.default.position = [ FL FR ]
79
+ # These overrides are only applied when running in a vm.
80
+ vm.overrides = {
81
+ pulse.min.quantum = 1024/48000 # 22ms
82
+ }
83
+}
84
+
85
# client/stream specific properties
86
pulse.rules = [
87
{
88
pipewire-0.3.48.tar.gz/src/daemon/pipewire.c -> pipewire-0.3.49.tar.gz/src/daemon/pipewire.c
Changed
17
1
2
#include <signal.h>
3
#include <getopt.h>
4
#include <libgen.h>
5
+#include <locale.h>
6
7
#include <spa/utils/result.h>
8
#include <pipewire/pipewire.h>
9
10
snprintf(path, sizeof(path), "%s.conf", argv[0]);
11
config_name = basename(path);
12
13
+ setlocale(LC_ALL, "");
14
pw_init(&argc, &argv);
15
16
while ((c = getopt_long(argc, argv, "hVc:v", long_options, NULL)) != -1) {
17
pipewire-0.3.48.tar.gz/src/gst/gstpipewiredeviceprovider.c -> pipewire-0.3.49.tar.gz/src/gst/gstpipewiredeviceprovider.c
Changed
133
1
2
enum
3
{
4
PROP_ID = 1,
5
+ PROP_SERIAL,
6
};
7
8
static GstElement *
9
10
{
11
GstPipeWireDevice *pipewire_dev = GST_PIPEWIRE_DEVICE (device);
12
GstElement *elem;
13
- gchar *str;
14
+ gchar *id_str, *serial_str;
15
16
elem = gst_element_factory_make (pipewire_dev->element, name);
17
- str = g_strdup_printf ("%u", pipewire_dev->id);
18
- g_object_set (elem, "path", str, NULL);
19
- g_free (str);
20
+
21
+ /* XXX: eventually only add target-object here */
22
+ id_str = g_strdup_printf ("%u", pipewire_dev->id);
23
+ serial_str = g_strdup_printf ("%"PRIu64, pipewire_dev->serial);
24
+ g_object_set (elem, "path", id_str, "target-object", serial_str, NULL);
25
+ g_free (id_str);
26
+ g_free (serial_str);
27
28
return elem;
29
}
30
31
gst_pipewire_device_reconfigure_element (GstDevice * device, GstElement * element)
32
{
33
GstPipeWireDevice *pipewire_dev = GST_PIPEWIRE_DEVICE (device);
34
- gchar *str;
35
+ gchar *id_str, *serial_str;
36
37
if (spa_streq(pipewire_dev->element, "pipewiresrc")) {
38
if (!GST_IS_PIPEWIRE_SRC (element))
39
40
g_assert_not_reached ();
41
}
42
43
- str = g_strdup_printf ("%u", pipewire_dev->id);
44
- g_object_set (element, "path", str, NULL);
45
- g_free (str);
46
+ /* XXX: eventually only add target-object here */
47
+ id_str = g_strdup_printf ("%u", pipewire_dev->id);
48
+ serial_str = g_strdup_printf ("%"PRIu64, pipewire_dev->serial);
49
+ g_object_set (element, "path", id_str, "target-object", serial_str, NULL);
50
+ g_free (id_str);
51
+ g_free (serial_str);
52
53
return TRUE;
54
}
55
56
case PROP_ID:
57
g_value_set_uint (value, device->id);
58
break;
59
+ case PROP_SERIAL:
60
+ g_value_set_uint64 (value, device->serial);
61
+ break;
62
default:
63
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
64
break;
65
66
case PROP_ID:
67
device->id = g_value_get_uint (value);
68
break;
69
+ case PROP_SERIAL:
70
+ device->serial = g_value_get_uint64 (value);
71
+ break;
72
default:
73
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
74
break;
75
76
g_param_spec_uint ("id", "Id",
77
"The internal id of the PipeWire device", 0, G_MAXUINT32, SPA_ID_INVALID,
78
G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
79
+
80
+ g_object_class_install_property (object_class, PROP_SERIAL,
81
+ g_param_spec_uint64 ("serial", "Serial",
82
+ "The internal serial of the PipeWire device", 0, G_MAXUINT64, SPA_ID_INVALID,
83
+ G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
84
}
85
86
static void
87
88
struct pw_node *proxy;
89
struct spa_hook proxy_listener;
90
uint32_t id;
91
+ uint64_t serial;
92
struct spa_hook node_listener;
93
struct pw_node_info *info;
94
GstCaps *caps;
95
96
struct pw_port *proxy;
97
struct spa_hook proxy_listener;
98
uint32_t id;
99
+ uint64_t serial;
100
struct spa_hook port_listener;
101
};
102
103
104
105
gstdev = g_object_new (GST_TYPE_PIPEWIRE_DEVICE,
106
"display-name", name, "caps", data->caps, "device-class", klass,
107
- "id", data->id, "properties", props, NULL);
108
+ "id", data->id, "serial", data->serial, "properties", props, NULL);
109
110
gstdev->id = data->id;
111
+ gstdev->serial = data->serial;
112
gstdev->type = type;
113
gstdev->element = element;
114
if (props)
115
116
nd->self = self;
117
nd->proxy = node;
118
nd->id = id;
119
+ if (!props || !spa_atou64(spa_dict_lookup(props, PW_KEY_OBJECT_SERIAL), &nd->serial, 0))
120
+ nd->serial = SPA_ID_INVALID;
121
spa_list_append(&rd->nodes, &nd->link);
122
pw_node_add_listener(node, &nd->node_listener, &node_events, nd);
123
pw_proxy_add_listener((struct pw_proxy*)node, &nd->proxy_listener, &proxy_node_events, nd);
124
125
pd->node_data = nd;
126
pd->proxy = port;
127
pd->id = id;
128
+ if (!props || !spa_atou64(spa_dict_lookup(props, PW_KEY_OBJECT_SERIAL), &pd->serial, 0))
129
+ pd->serial = SPA_ID_INVALID;
130
pw_port_add_listener(port, &pd->port_listener, &port_events, pd);
131
pw_proxy_add_listener((struct pw_proxy*)port, &pd->proxy_listener, &proxy_port_events, pd);
132
resync(self);
133
pipewire-0.3.48.tar.gz/src/gst/gstpipewiredeviceprovider.h -> pipewire-0.3.49.tar.gz/src/gst/gstpipewiredeviceprovider.h
Changed
9
1
2
3
GstPipeWireDeviceType type;
4
uint32_t id;
5
+ uint64_t serial;
6
const gchar *element;
7
};
8
9
pipewire-0.3.48.tar.gz/src/gst/gstpipewiresink.c -> pipewire-0.3.49.tar.gz/src/gst/gstpipewiresink.c
Changed
96
1
2
{
3
PROP_0,
4
PROP_PATH,
5
+ PROP_TARGET_OBJECT,
6
PROP_CLIENT_NAME,
7
PROP_STREAM_PROPERTIES,
8
PROP_MODE,
9
10
if (pwsink->properties)
11
gst_structure_free (pwsink->properties);
12
g_free (pwsink->path);
13
+ g_free (pwsink->target_object);
14
g_free (pwsink->client_name);
15
16
G_OBJECT_CLASS (parent_class)->finalize (object);
17
18
"The sink path to connect to (NULL = default)",
19
NULL,
20
G_PARAM_READWRITE |
21
+ G_PARAM_STATIC_STRINGS |
22
+ G_PARAM_DEPRECATED));
23
+
24
+ g_object_class_install_property (gobject_class,
25
+ PROP_TARGET_OBJECT,
26
+ g_param_spec_string ("target-object",
27
+ "Target object",
28
+ "The sink name/serial to connect to (NULL = default)",
29
+ NULL,
30
+ G_PARAM_READWRITE |
31
G_PARAM_STATIC_STRINGS));
32
33
g_object_class_install_property (gobject_class,
34
35
pwsink->path = g_value_dup_string (value);
36
break;
37
38
+ case PROP_TARGET_OBJECT:
39
+ g_free (pwsink->target_object);
40
+ pwsink->target_object = g_value_dup_string (value);
41
+ break;
42
+
43
case PROP_CLIENT_NAME:
44
g_free (pwsink->client_name);
45
pwsink->client_name = g_value_dup_string (value);
46
47
g_value_set_string (value, pwsink->path);
48
break;
49
50
+ case PROP_TARGET_OBJECT:
51
+ g_value_set_string (value, pwsink->target_object);
52
+ break;
53
+
54
case PROP_CLIENT_NAME:
55
g_value_set_string (value, pwsink->client_name);
56
break;
57
58
59
if (state == PW_STREAM_STATE_UNCONNECTED) {
60
enum pw_stream_flags flags = 0;
61
+ uint32_t target_id;
62
63
if (pwsink->mode != GST_PIPEWIRE_SINK_MODE_PROVIDE)
64
flags |= PW_STREAM_FLAG_AUTOCONNECT;
65
else
66
flags |= PW_STREAM_FLAG_DRIVER;
67
68
+ target_id = pwsink->path ? (uint32_t)atoi(pwsink->path) : PW_ID_ANY;
69
+
70
+ if (pwsink->target_object) {
71
+ struct spa_dict_item items[2] = {
72
+ SPA_DICT_ITEM_INIT(PW_KEY_TARGET_OBJECT, pwsink->target_object),
73
+ SPA_DICT_ITEM_INIT(PW_KEY_NODE_TARGET, NULL),
74
+ };
75
+ struct spa_dict dict = SPA_DICT_INIT_ARRAY(items);
76
+ uint64_t serial;
77
+
78
+ /* If target.object is a name, set it also to node.target */
79
+ if (spa_atou64(pwsink->target_object, &serial, 0)) {
80
+ dict.n_items = 1;
81
+ } else {
82
+ target_id = PW_ID_ANY;
83
+ items[1].value = pwsink->target_object;
84
+ }
85
+
86
+ pw_stream_update_properties (pwsink->stream, &dict);
87
+ }
88
+
89
pw_stream_connect (pwsink->stream,
90
PW_DIRECTION_OUTPUT,
91
- pwsink->path ? (uint32_t)atoi(pwsink->path) : PW_ID_ANY,
92
+ target_id,
93
flags,
94
(const struct spa_pod **) possible->pdata,
95
possible->len);
96
pipewire-0.3.48.tar.gz/src/gst/gstpipewiresink.h -> pipewire-0.3.49.tar.gz/src/gst/gstpipewiresink.h
Changed
9
1
2
3
/*< private >*/
4
gchar *path;
5
+ gchar *target_object;
6
gchar *client_name;
7
int fd;
8
9
pipewire-0.3.48.tar.gz/src/gst/gstpipewiresrc.c -> pipewire-0.3.49.tar.gz/src/gst/gstpipewiresrc.c
Changed
101
1
2
{
3
PROP_0,
4
PROP_PATH,
5
+ PROP_TARGET_OBJECT,
6
PROP_CLIENT_NAME,
7
PROP_STREAM_PROPERTIES,
8
PROP_ALWAYS_COPY,
9
10
pwsrc->path = g_value_dup_string (value);
11
break;
12
13
+ case PROP_TARGET_OBJECT:
14
+ g_free (pwsrc->target_object);
15
+ pwsrc->target_object = g_value_dup_string (value);
16
+ break;
17
+
18
case PROP_CLIENT_NAME:
19
g_free (pwsrc->client_name);
20
pwsrc->client_name = g_value_dup_string (value);
21
22
g_value_set_string (value, pwsrc->path);
23
break;
24
25
+ case PROP_TARGET_OBJECT:
26
+ g_value_set_string (value, pwsrc->target_object);
27
+ break;
28
+
29
case PROP_CLIENT_NAME:
30
g_value_set_string (value, pwsrc->client_name);
31
break;
32
33
if (pwsrc->clock)
34
gst_object_unref (pwsrc->clock);
35
g_free (pwsrc->path);
36
+ g_free (pwsrc->target_object);
37
g_free (pwsrc->client_name);
38
g_object_unref(pwsrc->pool);
39
40
41
"The source path to connect to (NULL = default)",
42
NULL,
43
G_PARAM_READWRITE |
44
+ G_PARAM_STATIC_STRINGS |
45
+ G_PARAM_DEPRECATED));
46
+
47
+ g_object_class_install_property (gobject_class,
48
+ PROP_TARGET_OBJECT,
49
+ g_param_spec_string ("target-object",
50
+ "Target object",
51
+ "The source name/serial to connect to (NULL = default)",
52
+ NULL,
53
+ G_PARAM_READWRITE |
54
G_PARAM_STATIC_STRINGS));
55
56
g_object_class_install_property (gobject_class,
57
58
GPtrArray *possible;
59
const char *error = NULL;
60
struct timespec abstime;
61
+ uint32_t target_id;
62
63
/* first see what is possible on our source pad */
64
thiscaps = gst_pad_query_caps (GST_BASE_SRC_PAD (basesrc), NULL);
65
66
}
67
}
68
69
- GST_DEBUG_OBJECT (basesrc, "connect capture with path %s", pwsrc->path);
70
+ target_id = pwsrc->path ? (uint32_t)atoi(pwsrc->path) : PW_ID_ANY;
71
+
72
+ if (pwsrc->target_object) {
73
+ struct spa_dict_item items[2] = {
74
+ SPA_DICT_ITEM_INIT(PW_KEY_TARGET_OBJECT, pwsrc->target_object),
75
+ SPA_DICT_ITEM_INIT(PW_KEY_NODE_TARGET, NULL),
76
+ };
77
+ struct spa_dict dict = SPA_DICT_INIT_ARRAY(items);
78
+ uint64_t serial;
79
+
80
+ /* If target.object is a name, set it also to node.target */
81
+ if (spa_atou64(pwsrc->target_object, &serial, 0)) {
82
+ dict.n_items = 1;
83
+ } else {
84
+ target_id = PW_ID_ANY;
85
+ items[1].value = pwsrc->target_object;
86
+ }
87
+
88
+ pw_stream_update_properties (pwsrc->stream, &dict);
89
+ }
90
+
91
+ GST_DEBUG_OBJECT (basesrc, "connect capture with path %s, target-object %s",
92
+ pwsrc->path, pwsrc->target_object);
93
pwsrc->negotiated = FALSE;
94
pw_stream_connect (pwsrc->stream,
95
PW_DIRECTION_INPUT,
96
- pwsrc->path ? (uint32_t)atoi(pwsrc->path) : PW_ID_ANY,
97
+ target_id,
98
PW_STREAM_FLAG_AUTOCONNECT | PW_STREAM_FLAG_DONT_RECONNECT,
99
(const struct spa_pod **)possible->pdata,
100
possible->len);
101
pipewire-0.3.48.tar.gz/src/gst/gstpipewiresrc.h -> pipewire-0.3.49.tar.gz/src/gst/gstpipewiresrc.h
Changed
9
1
2
3
/*< private >*/
4
gchar *path;
5
+ gchar *target_object;
6
gchar *client_name;
7
gboolean always_copy;
8
gint min_buffers;
9
pipewire-0.3.48.tar.gz/src/modules/meson.build -> pipewire-0.3.49.tar.gz/src/modules/meson.build
Changed
29
1
2
dependencies : [spa_dep, mathlib, dl_lib, pipewire_dep],
3
)
4
5
-build_module_rt = dbus_dep.found()
6
-if build_module_rt
7
pipewire_module_rt = shared_library('pipewire-module-rt', [ 'module-rt.c' ],
8
include_directories : [configinc],
9
install : true,
10
11
install_rpath: modules_install_dir,
12
dependencies : [dbus_dep, mathlib, dl_lib, pipewire_dep],
13
)
14
+
15
+build_module_rtkit = dbus_dep.found()
16
+if build_module_rtkit
17
# TODO: This serves as a temporary alias to prevent breaking existing setups
18
# while `module-rtkit` is being migrated to `module-rt`
19
pipewire_module_rtkit = shared_library('pipewire-module-rtkit', [ 'module-rt.c' ],
20
21
dependencies : [dbus_dep, mathlib, dl_lib, pipewire_dep],
22
)
23
endif
24
-summary({'rt': build_module_rt}, bool_yn: true, section: 'Optional Modules')
25
+summary({'rt': '@0@ RTKit'.format(build_module_rtkit ? 'with' : 'without')}, section: 'Optional Modules')
26
27
build_module_portal = dbus_dep.found()
28
if build_module_portal
29
pipewire-0.3.48.tar.gz/src/modules/module-client-node/remote-node.c -> pipewire-0.3.49.tar.gz/src/modules/module-client-node/remote-node.c
Changed
13
1
2
{
3
struct link *link = user_data;
4
struct spa_system *data_system = link->data->context->data_system;
5
- struct timespec ts;
6
+ struct timespec ts = { 0, 0 };
7
8
- pw_log_trace("link %p: signal", link);
9
+ pw_log_trace_fp("link %p: signal", link);
10
11
spa_system_clock_gettime(data_system, CLOCK_MONOTONIC, &ts);
12
link->target.activation->status = PW_NODE_ACTIVATION_TRIGGERED;
13
pipewire-0.3.48.tar.gz/src/modules/module-echo-cancel.c -> pipewire-0.3.49.tar.gz/src/modules/module-echo-cancel.c
Changed
74
1
2
* - `source.props = {}`: properties to be passed to the source stream
3
* - `sink.props = {}`: properties to be passed to the sink stream
4
* - `library.name = <str>`: the echo cancellation library Currently supported:
5
- * `aec/libspa-aec-exaudio`. Leave unset to use the default method (`aec/libspa-aec-exaudio`).
6
+ * `aec/libspa-aec-webrtc`. Leave unset to use the default method (`aec/libspa-aec-webrtc`).
7
* - `aec.args = <str>`: arguments to pass to the echo cancellation method
8
*
9
* ## General options
10
11
* context.modules = [
12
* { name = libpipewire-module-echo-cancel
13
* args = {
14
- * # library.name = aec/libspa-aec-exaudio
15
+ * # library.name = aec/libspa-aec-webrtc
16
* # node.latency = 1024/48000
17
* source.props = {
18
* node.name = "Echo Cancellation Source"
19
20
"[ audio.channels=<number of channels> ] "
21
"[ audio.position=<channel map> ] "
22
"[ buffer.max_size=<max buffer size in ms> ] "
23
- "[ buffer.play_delay=<play delay in ms> ] "
24
+ "[ buffer.play_delay=<delay as fraction> ] "
25
"[ library.name =<library name> ] "
26
"[ aec.args=<aec arguments> ] "
27
"[ source.props=<properties> ] "
28
29
return res;
30
31
impl->rec_ringsize = sizeof(float) * impl->max_buffer_size * impl->info.rate / 1000;
32
- impl->play_ringsize = sizeof(float) * (impl->max_buffer_size + impl->buffer_delay) * impl->info.rate / 1000;
33
+ impl->play_ringsize = sizeof(float) * ((impl->max_buffer_size * impl->info.rate / 1000) + impl->buffer_delay);
34
impl->out_ringsize = sizeof(float) * impl->max_buffer_size * impl->info.rate / 1000;
35
for (i = 0; i < impl->info.channels; i++) {
36
impl->rec_buffer[i] = malloc(impl->rec_ringsize);
37
38
spa_ringbuffer_init(&impl->out_ring);
39
40
spa_ringbuffer_get_write_index(&impl->play_ring, &index);
41
- spa_ringbuffer_write_update(&impl->play_ring, index + (sizeof(float) * (impl->buffer_delay) * impl->info.rate / 1000));
42
+ spa_ringbuffer_write_update(&impl->play_ring, index + (sizeof(float) * (impl->buffer_delay)));
43
spa_ringbuffer_get_read_index(&impl->play_ring, &index);
44
- spa_ringbuffer_read_update(&impl->play_ring, index + (sizeof(float) * (impl->buffer_delay) * impl->info.rate / 1000));
45
+ spa_ringbuffer_read_update(&impl->play_ring, index + (sizeof(float) * (impl->buffer_delay)));
46
47
return 0;
48
}
49
50
copy_props(impl, props, PW_KEY_NODE_LATENCY);
51
52
impl->max_buffer_size = pw_properties_get_uint32(props,"buffer.max_size", MAX_BUFSIZE_MS);
53
- impl->buffer_delay = pw_properties_get_uint32(props,"buffer.play_delay", DELAY_MS);
54
+
55
+ if ((str = pw_properties_get(props, "buffer.play_delay")) != NULL) {
56
+ int req_num, req_denom;
57
+ if (sscanf(str, "%u/%u", &req_num, &req_denom) == 2) {
58
+ if (req_denom != 0) {
59
+ impl->buffer_delay = (impl->info.rate*req_num)/req_denom;
60
+ } else {
61
+ impl->buffer_delay = DELAY_MS * impl->info.rate / 1000;
62
+ pw_log_warn("Sample rate for buffer.play_delay is 0 using default");
63
+ }
64
+ } else {
65
+ impl->buffer_delay = DELAY_MS * impl->info.rate / 1000;
66
+ pw_log_warn("Wrong value/format for buffer.play_delay using default");
67
+ }
68
+ } else {
69
+ impl->buffer_delay = DELAY_MS * impl->info.rate / 1000;
70
+ }
71
72
pw_properties_free(props);
73
74
pipewire-0.3.48.tar.gz/src/modules/module-filter-chain.c -> pipewire-0.3.49.tar.gz/src/modules/module-filter-chain.c
Changed
104
1
2
SPA_PROP_INFO_name, SPA_POD_String(name),
3
0);
4
spa_pod_builder_prop(b, SPA_PROP_INFO_type, 0);
5
- if (min == max) {
6
- spa_pod_builder_float(b, def);
7
+ if (p->hint & FC_HINT_BOOLEAN) {
8
+ if (min == max) {
9
+ spa_pod_builder_bool(b, def <= 0.0 ? false : true);
10
+ } else {
11
+ spa_pod_builder_push_choice(b, &f[1], SPA_CHOICE_Enum, 0);
12
+ spa_pod_builder_bool(b, def <= 0.0 ? false : true);
13
+ spa_pod_builder_bool(b, false);
14
+ spa_pod_builder_bool(b, true);
15
+ spa_pod_builder_pop(b, &f[1]);
16
+ }
17
+ } else if (p->hint & FC_HINT_INTEGER) {
18
+ if (min == max) {
19
+ spa_pod_builder_int(b, def);
20
+ } else {
21
+ spa_pod_builder_push_choice(b, &f[1], SPA_CHOICE_Range, 0);
22
+ spa_pod_builder_int(b, def);
23
+ spa_pod_builder_int(b, min);
24
+ spa_pod_builder_int(b, max);
25
+ spa_pod_builder_pop(b, &f[1]);
26
+ }
27
} else {
28
- spa_pod_builder_push_choice(b, &f[1], SPA_CHOICE_Range, 0);
29
- spa_pod_builder_float(b, def);
30
- spa_pod_builder_float(b, min);
31
- spa_pod_builder_float(b, max);
32
- spa_pod_builder_pop(b, &f[1]);
33
+ if (min == max) {
34
+ spa_pod_builder_float(b, def);
35
+ } else {
36
+ spa_pod_builder_push_choice(b, &f[1], SPA_CHOICE_Range, 0);
37
+ spa_pod_builder_float(b, def);
38
+ spa_pod_builder_float(b, min);
39
+ spa_pod_builder_float(b, max);
40
+ spa_pod_builder_pop(b, &f[1]);
41
+ }
42
}
43
spa_pod_builder_prop(b, SPA_PROP_INFO_params, 0);
44
spa_pod_builder_bool(b, true);
45
46
snprintf(name, sizeof(name), "%s", p->name);
47
48
spa_pod_builder_string(b, name);
49
- spa_pod_builder_float(b, port->control_data);
50
+ if (p->hint & FC_HINT_BOOLEAN) {
51
+ spa_pod_builder_bool(b, port->control_data <= 0.0 ? false : true);
52
+ } else if (p->hint & FC_HINT_INTEGER) {
53
+ spa_pod_builder_int(b, port->control_data);
54
+ } else {
55
+ spa_pod_builder_float(b, port->control_data);
56
+ }
57
}
58
spa_pod_builder_pop(b, &f[1]);
59
return spa_pod_builder_pop(b, &f[0]);
60
61
while (true) {
62
const char *name;
63
float value, *val = NULL;
64
+ bool bool_val;
65
+ int32_t int_val;
66
67
if (spa_pod_parser_get_string(&prs, &name) < 0)
68
break;
69
- if (spa_pod_parser_get_float(&prs, &value) >= 0)
70
+ if (spa_pod_parser_get_float(&prs, &value) >= 0) {
71
val = &value;
72
-
73
+ } else if (spa_pod_parser_get_int(&prs, &int_val) >= 0) {
74
+ value = int_val;
75
+ val = &value;
76
+ } else if (spa_pod_parser_get_bool(&prs, &bool_val) >= 0) {
77
+ value = bool_val ? 1.0f : 0.0f;
78
+ val = &value;
79
+ } else {
80
+ struct spa_pod *pod;
81
+ spa_pod_parser_get_pod(&prs, &pod);
82
+ }
83
changed += set_control_value(def_node, name, val);
84
}
85
return changed;
86
87
}
88
if (changed > 0) {
89
uint8_t buffer[1024];
90
- struct spa_pod_builder b;
91
+ struct spa_pod_dynamic_builder b;
92
const struct spa_pod *params[1];
93
94
- spa_pod_builder_init(&b, buffer, sizeof(buffer));
95
- params[0] = get_props_param(graph, &b);
96
+ spa_pod_dynamic_builder_init(&b, buffer, sizeof(buffer), 4096);
97
+ params[0] = get_props_param(graph, &b.b);
98
99
pw_stream_update_params(impl->capture, params, 1);
100
+ spa_pod_dynamic_builder_clean(&b);
101
}
102
}
103
104
pipewire-0.3.48.tar.gz/src/modules/module-filter-chain/plugin.h -> pipewire-0.3.49.tar.gz/src/modules/module-filter-chain/plugin.h
Changed
11
1
2
#define FC_PORT_AUDIO (1ULL << 3)
3
uint64_t flags;
4
5
+#define FC_HINT_BOOLEAN (1ULL << 2)
6
#define FC_HINT_SAMPLE_RATE (1ULL << 3)
7
+#define FC_HINT_INTEGER (1ULL << 5)
8
uint64_t hint;
9
float def;
10
float min;
11
pipewire-0.3.48.tar.gz/src/modules/module-protocol-pulse/extensions/ext-stream-restore.c -> pipewire-0.3.49.tar.gz/src/modules/module-protocol-pulse/extensions/ext-stream-restore.c
Changed
20
1
2
FILE *f;
3
char *ptr;
4
size_t size;
5
- char key[1024];
6
+ char key[1024], buf[128];
7
8
spa_zero(map);
9
spa_zero(vol);
10
11
if (vol.channels > 0) {
12
fprintf(f, ", \"volumes\": [");
13
for (i = 0; i < vol.channels; i++)
14
- fprintf(f, "%s%f", (i == 0 ? " ":", "), vol.values[i]);
15
+ fprintf(f, "%s%s", (i == 0 ? " ":", "),
16
+ spa_json_format_float(buf, sizeof(buf), vol.values[i]));
17
fprintf(f, " ]");
18
}
19
if (map.channels > 0) {
20
pipewire-0.3.48.tar.gz/src/modules/module-protocol-pulse/manager.c -> pipewire-0.3.49.tar.gz/src/modules/module-protocol-pulse/manager.c
Changed
10
1
2
struct manager *m = SPA_CONTAINER_OF(manager, struct manager, this);
3
struct object *o;
4
5
+ spa_hook_list_clean(&m->hooks);
6
+
7
spa_hook_remove(&m->core_listener);
8
9
spa_list_consume(o, &m->this.object_list, this.link)
10
pipewire-0.3.48.tar.gz/src/modules/module-protocol-pulse/module.c -> pipewire-0.3.49.tar.gz/src/modules/module-protocol-pulse/module.c
Changed
21
1
2
if (module == NULL)
3
return NULL;
4
5
+ module->index = SPA_ID_INVALID;
6
module->impl = impl;
7
module->methods = methods;
8
spa_hook_list_init(&module->listener_list);
9
10
if (module->index != SPA_ID_INVALID)
11
pw_map_remove(&impl->modules, module->index & MODULE_INDEX_MASK);
12
13
+ if (module->unloading)
14
+ pw_work_queue_cancel(impl->work_queue, module, SPA_ID_INVALID);
15
+
16
spa_hook_list_clean(&module->listener_list);
17
- pw_work_queue_cancel(impl->work_queue, module, SPA_ID_INVALID);
18
pw_properties_free(module->props);
19
20
free((char*)module->name);
21
pipewire-0.3.48.tar.gz/src/modules/module-protocol-pulse/modules/module-combine-sink.c -> pipewire-0.3.49.tar.gz/src/modules/module-protocol-pulse/modules/module-combine-sink.c
Changed
11
1
2
pw_stream_queue_buffer(data->streams[i].stream, out);
3
}
4
5
- if (in != NULL)
6
- pw_stream_queue_buffer(data->sink, in);
7
+ pw_stream_queue_buffer(data->sink, in);
8
}
9
10
static void check_initialized(struct module_combine_sink_data *data)
11
pipewire-0.3.48.tar.gz/src/modules/module-protocol-pulse/modules/module-roc-sink.c -> pipewire-0.3.49.tar.gz/src/modules/module-protocol-pulse/modules/module-roc-sink.c
Changed
29
1
2
3
fprintf(f, "{");
4
pw_properties_serialize_dict(f, &data->roc_props->dict, 0);
5
- fprintf(f, " } sink.props = {");
6
+ fprintf(f, " sink.props = {");
7
pw_properties_serialize_dict(f, &data->sink_props->dict, 0);
8
fprintf(f, " } }");
9
fclose(f);
10
11
{ PW_KEY_MODULE_AUTHOR, "Sanchayan Maity <sanchayan@asymptotic.io>" },
12
{ PW_KEY_MODULE_DESCRIPTION, "roc sink" },
13
{ PW_KEY_MODULE_USAGE, "sink_name=<name for the sink> "
14
+ "sink_properties=<properties for the sink> "
15
"local_ip=<local sender ip> "
16
"remote_ip=<remote receiver ip> "
17
"remote_source_port=<remote receiver port for source packets> "
18
19
pw_properties_set(sink_props, PW_KEY_NODE_NAME, str);
20
pw_properties_set(props, "sink_name", NULL);
21
}
22
+ if ((str = pw_properties_get(props, "sink_properties")) != NULL) {
23
+ module_args_add_props(sink_props, str);
24
+ pw_properties_set(props, "sink_properties", NULL);
25
+ }
26
27
if ((str = pw_properties_get(props, PW_KEY_MEDIA_CLASS)) == NULL) {
28
pw_properties_set(props, PW_KEY_MEDIA_CLASS, "Audio/Sink");
29
pipewire-0.3.48.tar.gz/src/modules/module-protocol-pulse/modules/module-roc-source.c -> pipewire-0.3.49.tar.gz/src/modules/module-protocol-pulse/modules/module-roc-source.c
Changed
29
1
2
3
fprintf(f, "{");
4
pw_properties_serialize_dict(f, &data->roc_props->dict, 0);
5
- fprintf(f, " } source.props = {");
6
+ fprintf(f, " source.props = {");
7
pw_properties_serialize_dict(f, &data->source_props->dict, 0);
8
fprintf(f, " } }");
9
fclose(f);
10
11
{ PW_KEY_MODULE_AUTHOR, "Sanchayan Maity <sanchayan@asymptotic.io>" },
12
{ PW_KEY_MODULE_DESCRIPTION, "roc source" },
13
{ PW_KEY_MODULE_USAGE, "source_name=<name for the source> "
14
+ "source_properties=<properties for the source> "
15
"resampler_profile=<empty>|disable|high|medium|low "
16
"sess_latency_msec=<target network latency in milliseconds> "
17
"local_ip=<local receiver ip> "
18
19
pw_properties_set(source_props, PW_KEY_NODE_NAME, str);
20
pw_properties_set(props, "source_name", NULL);
21
}
22
+ if ((str = pw_properties_get(props, "source_properties")) != NULL) {
23
+ module_args_add_props(source_props, str);
24
+ pw_properties_set(props, "source_properties", NULL);
25
+ }
26
27
if ((str = pw_properties_get(props, PW_KEY_MEDIA_CLASS)) == NULL) {
28
pw_properties_set(props, PW_KEY_MEDIA_CLASS, "Audio/Source");
29
pipewire-0.3.48.tar.gz/src/modules/module-protocol-pulse/pulse-server.c -> pipewire-0.3.49.tar.gz/src/modules/module-protocol-pulse/pulse-server.c
Changed
19
1
2
n_valid_formats++;
3
}
4
}
5
- if (n_params < MAX_FORMATS &&
6
+ else if (n_params < MAX_FORMATS &&
7
(params[n_params] = format_build_param(&b,
8
SPA_PARAM_EnumFormat, &ss,
9
ss.channels > 0 ? &map : NULL)) != NULL) {
10
11
support = pw_context_get_support(context, &n_support);
12
cpu = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_CPU);
13
14
+ pw_context_conf_update_props(context, "pulse.properties", props);
15
+
16
if ((str = pw_properties_get(props, "vm.overrides")) != NULL) {
17
if (cpu != NULL && spa_cpu_get_vm_type(cpu) != SPA_CPU_VM_NONE)
18
pw_properties_update_string(props, str, strlen(str));
19
pipewire-0.3.48.tar.gz/src/modules/module-protocol-pulse/sample-play.c -> pipewire-0.3.49.tar.gz/src/modules/module-protocol-pulse/sample-play.c
Changed
10
1
2
if (p->stream)
3
pw_stream_destroy(p->stream);
4
5
+ spa_hook_list_clean(&p->hooks);
6
+
7
free(p);
8
}
9
10
pipewire-0.3.48.tar.gz/src/modules/module-rt.c -> pipewire-0.3.49.tar.gz/src/modules/module-rt.c
Changed
568
1
2
/* PipeWire
3
*
4
- * Copyright © 2018 Wim Taymans
5
+ * Copyright © 2022 Wim Taymans
6
*
7
* Permission is hereby granted, free of charge, to any person obtaining a
8
* copy of this software and associated documentation files (the "Software"),
9
10
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
11
* DEALINGS IN THE SOFTWARE.
12
*/
13
+/***
14
+ Copyright 2009 Lennart Poettering
15
+ Copyright 2010 David Henningsson <diwic@ubuntu.com>
16
+
17
+ Permission is hereby granted, free of charge, to any person
18
+ obtaining a copy of this software and associated documentation files
19
+ (the "Software"), to deal in the Software without restriction,
20
+ including without limitation the rights to use, copy, modify, merge,
21
+ publish, distribute, sublicense, and/or sell copies of the Software,
22
+ and to permit persons to whom the Software is furnished to do so,
23
+ subject to the following conditions:
24
+
25
+ The above copyright notice and this permission notice shall be
26
+ included in all copies or substantial portions of the Software.
27
+
28
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
29
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
30
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
31
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
32
+ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
33
+ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
34
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
35
+ SOFTWARE.
36
+***/
37
38
#include <stdlib.h>
39
#include <stdbool.h>
40
41
#include <unistd.h>
42
#include <pthread.h>
43
#include <sys/resource.h>
44
+#include <sys/syscall.h>
45
46
#include "config.h"
47
48
-#include <spa/support/dbus.h>
49
#include <spa/utils/result.h>
50
#include <spa/utils/string.h>
51
52
#include <pipewire/impl.h>
53
#include <pipewire/thread.h>
54
55
+#ifdef HAVE_DBUS
56
+#include <spa/support/dbus.h>
57
+#include <dbus/dbus.h>
58
+#endif
59
+
60
/** \page page_module_rt PipeWire Module: RT
61
*
62
* The `rt` module uses the operating system's scheduler to enable realtime
63
64
{ PW_KEY_MODULE_VERSION, PACKAGE_VERSION },
65
};
66
67
-struct pw_rtkit_bus;
68
+#ifdef HAVE_DBUS
69
+#define RTKIT_SERVICE_NAME "org.freedesktop.RealtimeKit1"
70
+#define RTKIT_OBJECT_PATH "/org/freedesktop/RealtimeKit1"
71
+
72
+/** \cond */
73
+struct pw_rtkit_bus {
74
+ DBusConnection *bus;
75
+};
76
+/** \endcond */
77
78
struct thread {
79
struct impl *impl;
80
81
void *(*start)(void*);
82
void *arg;
83
};
84
+#endif /* HAVE_DBUS */
85
86
struct impl {
87
struct pw_context *context;
88
89
90
struct spa_hook module_listener;
91
92
+#ifdef HAVE_DBUS
93
bool use_rtkit;
94
struct pw_rtkit_bus *system_bus;
95
96
97
pthread_mutex_t lock;
98
pthread_cond_t cond;
99
struct spa_list threads_list;
100
+#endif
101
};
102
103
-/***
104
- Copyright 2009 Lennart Poettering
105
- Copyright 2010 David Henningsson <diwic@ubuntu.com>
106
-
107
- Permission is hereby granted, free of charge, to any person
108
- obtaining a copy of this software and associated documentation files
109
- (the "Software"), to deal in the Software without restriction,
110
- including without limitation the rights to use, copy, modify, merge,
111
- publish, distribute, sublicense, and/or sell copies of the Software,
112
- and to permit persons to whom the Software is furnished to do so,
113
- subject to the following conditions:
114
-
115
- The above copyright notice and this permission notice shall be
116
- included in all copies or substantial portions of the Software.
117
-
118
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
119
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
120
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
121
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
122
- BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
123
- ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
124
- CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
125
- SOFTWARE.
126
-***/
127
-
128
-#include <dbus/dbus.h>
129
-
130
-#include "config.h"
131
-
132
-#include <sys/syscall.h>
133
-
134
-#define RTKIT_SERVICE_NAME "org.freedesktop.RealtimeKit1"
135
-#define RTKIT_OBJECT_PATH "/org/freedesktop/RealtimeKit1"
136
-
137
#ifndef RLIMIT_RTTIME
138
#define RLIMIT_RTTIME 15
139
#endif
140
141
-/** \cond */
142
-struct pw_rtkit_bus {
143
- DBusConnection *bus;
144
-};
145
-/** \endcond */
146
+static pid_t _gettid(void)
147
+{
148
+#if defined(HAVE_GETTID)
149
+ return (pid_t) gettid();
150
+#elif defined(__linux__)
151
+ return syscall(SYS_gettid);
152
+#elif defined(__FreeBSD__)
153
+ long pid;
154
+ thr_self(&pid);
155
+ return (pid_t)pid;
156
+#else
157
+#error "No gettid impl"
158
+#endif
159
+}
160
161
+#ifdef HAVE_DBUS
162
struct pw_rtkit_bus *pw_rtkit_bus_get_system(void)
163
{
164
struct pw_rtkit_bus *bus;
165
166
free(system_bus);
167
}
168
169
-static pid_t _gettid(void)
170
-{
171
-#if defined(HAVE_GETTID)
172
- return (pid_t) gettid();
173
-#elif defined(__linux__)
174
- return syscall(SYS_gettid);
175
-#elif defined(__FreeBSD__)
176
- long pid;
177
- thr_self(&pid);
178
- return (pid_t)pid;
179
-#else
180
-#error "No gettid impl"
181
-#endif
182
-}
183
-
184
static int translate_error(const char *name)
185
{
186
pw_log_warn("RTKit error: %s", name);
187
188
189
return ret;
190
}
191
+#endif /* HAVE_DBUS */
192
193
static void module_destroy(void *data)
194
{
195
196
pw_thread_utils_set(NULL);
197
spa_hook_remove(&impl->module_listener);
198
199
+#ifdef HAVE_DBUS
200
if (impl->system_bus)
201
pw_rtkit_bus_free(impl->system_bus);
202
+#endif
203
+
204
free(impl);
205
}
206
207
208
* Check if the current user has permissions to use realtime scheduling at the
209
* specified priority.
210
*/
211
-static bool check_realtime_priviliges(rlim_t priority)
212
+static bool check_realtime_privileges(rlim_t priority)
213
{
214
int old_policy;
215
struct sched_param old_sched_params;
216
217
}
218
}
219
220
+static int sched_set_nice(int nice_level)
221
+{
222
+ if (setpriority(PRIO_PROCESS, _gettid(), nice_level) == 0)
223
+ return 0;
224
+ else
225
+ return -errno;
226
+}
227
+
228
static int set_nice(struct impl *impl, int nice_level)
229
{
230
int res = 0;
231
- pid_t tid;
232
233
- if (impl->use_rtkit) {
234
- if ((res = pw_rtkit_make_high_priority(impl->system_bus, 0, nice_level)) < 0) {
235
- pw_log_warn("could not set nice-level to %d: %s",
236
- nice_level, spa_strerror(res));
237
- } else {
238
- pw_log_info("main thread nice level set to %d", nice_level);
239
- }
240
+#ifdef HAVE_DBUS
241
+ if (impl->use_rtkit)
242
+ res = pw_rtkit_make_high_priority(impl->system_bus, 0, nice_level);
243
+ else
244
+ res = sched_set_nice(nice_level);
245
+#else
246
+ res = sched_set_nice(nice_level);
247
+#endif
248
+
249
+ if (res < 0) {
250
+ pw_log_warn("could not set nice-level to %d: %s",
251
+ nice_level, spa_strerror(res));
252
} else {
253
- tid = _gettid();
254
- if (setpriority(PRIO_PROCESS, tid, nice_level) == 0) {
255
- pw_log_info("main thread nice level set to %d",
256
- nice_level);
257
- } else {
258
- res = -errno;
259
- pw_log_warn("could not set nice-level to %d: %s",
260
- nice_level, spa_strerror(res));
261
- }
262
+ pw_log_info("main thread nice level set to %d",
263
+ nice_level);
264
}
265
266
return res;
267
268
static int set_rlimit(struct impl *impl)
269
{
270
struct rlimit rl;
271
- long long rttime;
272
int res = 0;
273
274
spa_zero(rl);
275
rl.rlim_cur = impl->rt_time_soft;
276
rl.rlim_max = impl->rt_time_hard;
277
278
+#ifdef HAVE_DBUS
279
if (impl->use_rtkit) {
280
+ long long rttime;
281
rttime = pw_rtkit_get_rttime_usec_max(impl->system_bus);
282
if (rttime >= 0) {
283
if ((rlim_t)rttime < rl.rlim_cur) {
284
285
rl.rlim_max = SPA_MIN(rl.rlim_max, (rlim_t)rttime);
286
}
287
}
288
+#endif
289
290
if (setrlimit(RLIMIT_RTTIME, &rl) < 0)
291
res = -errno;
292
293
return res;
294
}
295
296
+static int impl_acquire_rt_sched(struct spa_thread *thread, int priority)
297
+{
298
+ int err;
299
+ struct sched_param sp;
300
+ pthread_t pt = (pthread_t)thread;
301
+
302
+ if (priority < sched_get_priority_min(REALTIME_POLICY) ||
303
+ priority > sched_get_priority_max(REALTIME_POLICY)) {
304
+ pw_log_warn("invalid priority %d for policy %d", priority, REALTIME_POLICY);
305
+ return -EINVAL;
306
+ }
307
+
308
+ spa_zero(sp);
309
+ sp.sched_priority = priority;
310
+ if ((err = pthread_setschedparam(pt, REALTIME_POLICY | PW_SCHED_RESET_ON_FORK, &sp)) != 0) {
311
+ pw_log_warn("could not make thread %p realtime: %s", thread, strerror(err));
312
+ return -err;
313
+ }
314
+
315
+ pw_log_info("acquired realtime priority %d for thread %p", priority, thread);
316
+ return 0;
317
+}
318
+
319
+static int impl_drop_rt_generic(void *data, struct spa_thread *thread)
320
+{
321
+ struct sched_param sp;
322
+ pthread_t pt = (pthread_t)thread;
323
+ int err;
324
+
325
+ spa_zero(sp);
326
+ if ((err = pthread_setschedparam(pt, SCHED_OTHER | PW_SCHED_RESET_ON_FORK, &sp)) != 0) {
327
+ pw_log_debug("thread %p: SCHED_OTHER|SCHED_RESET_ON_FORK failed: %s",
328
+ thread, strerror(err));
329
+ return -err;
330
+ }
331
+ pw_log_info("thread %p dropped realtime priority", thread);
332
+ return 0;
333
+}
334
+
335
+#ifdef HAVE_DBUS
336
static struct thread *find_thread_by_pt(struct impl *impl, pthread_t pt)
337
{
338
struct thread *t;
339
340
341
if ((err = pw_rtkit_make_realtime(impl->system_bus, pid, priority)) < 0) {
342
pw_log_warn("could not make thread %d realtime using RTKit: %s", pid, spa_strerror(err));
343
- } else {
344
- pw_log_info("acquired realtime priority %d for thread %d using RTKit", priority, pid);
345
+ return err;
346
}
347
+
348
+ pw_log_info("acquired realtime priority %d for thread %d using RTKit", priority, pid);
349
+ return 0;
350
} else {
351
- if (priority < sched_get_priority_min(REALTIME_POLICY) ||
352
- priority > sched_get_priority_max(REALTIME_POLICY)) {
353
- pw_log_warn("invalid priority %d for policy %d", priority, REALTIME_POLICY);
354
- return -EINVAL;
355
- }
356
+ return impl_acquire_rt_sched(thread, priority);
357
+ }
358
+}
359
360
- spa_zero(sp);
361
- sp.sched_priority = priority;
362
- if ((err = pthread_setschedparam(pt, REALTIME_POLICY | PW_SCHED_RESET_ON_FORK, &sp)) != 0) {
363
- pw_log_warn("could not make thread %p realtime: %s", thread, strerror(err));
364
- return -err;
365
- }
366
- pw_log_info("acquired realtime priority %d for thread %p", priority, thread);
367
+static const struct spa_thread_utils_methods impl_thread_utils = {
368
+ SPA_VERSION_THREAD_UTILS_METHODS,
369
+ .create = impl_create,
370
+ .join = impl_join,
371
+ .get_rt_range = impl_get_rt_range,
372
+ .acquire_rt = impl_acquire_rt,
373
+ .drop_rt = impl_drop_rt_generic,
374
+};
375
+
376
+#else /* HAVE_DBUS */
377
+
378
+static struct spa_thread *impl_create(void *data, const struct spa_dict *props,
379
+ void *(*start_routine)(void*), void *arg)
380
+{
381
+ pthread_t pt;
382
+ int err;
383
+
384
+ err = pthread_create(&pt, NULL, start_routine, arg);
385
+ if (err != 0) {
386
+ errno = err;
387
+ return NULL;
388
}
389
+ return (struct spa_thread*)pt;
390
+}
391
+
392
+static int impl_join(void *data, struct spa_thread *thread, void **retval)
393
+{
394
+ return pthread_join((pthread_t)thread, retval);
395
+}
396
397
+static int impl_get_rt_range(void *data, const struct spa_dict *props,
398
+ int *min, int *max)
399
+{
400
+ if (min)
401
+ *min = sched_get_priority_min(REALTIME_POLICY);
402
+ if (max)
403
+ *max = sched_get_priority_max(REALTIME_POLICY);
404
return 0;
405
}
406
407
-static int impl_drop_rt(void *data, struct spa_thread *thread)
408
+static int impl_acquire_rt(void *data, struct spa_thread *thread, int priority)
409
{
410
- struct sched_param sp;
411
- pthread_t pt = (pthread_t)thread;
412
- int err;
413
+ struct impl *impl = data;
414
415
- spa_zero(sp);
416
- if ((err = pthread_setschedparam(pt, SCHED_OTHER | PW_SCHED_RESET_ON_FORK, &sp)) != 0) {
417
- pw_log_debug("thread %p: SCHED_OTHER|SCHED_RESET_ON_FORK failed: %s",
418
- thread, strerror(err));
419
- return -err;
420
+ /* See the docstring on `spa_thread_utils_methods::acquire_rt` */
421
+ if (priority == -1) {
422
+ priority = impl->rt_prio;
423
}
424
- pw_log_info("thread %p dropped realtime priority", thread);
425
- return 0;
426
+
427
+ return impl_acquire_rt_sched(thread, priority);
428
}
429
430
static const struct spa_thread_utils_methods impl_thread_utils = {
431
432
.join = impl_join,
433
.get_rt_range = impl_get_rt_range,
434
.acquire_rt = impl_acquire_rt,
435
- .drop_rt = impl_drop_rt,
436
+ .drop_rt = impl_drop_rt_generic,
437
};
438
+#endif /* HAVE_DBUS */
439
+
440
+
441
+#ifdef HAVE_DBUS
442
+static int should_use_rtkit(struct impl *impl, struct pw_context *context, bool *use_rtkit)
443
+{
444
+ const struct pw_properties *context_props;
445
+ const char *str;
446
+
447
+ *use_rtkit = true;
448
449
+ if ((context_props = pw_context_get_properties(context)) != NULL &&
450
+ (str = pw_properties_get(context_props, "support.dbus")) != NULL &&
451
+ !pw_properties_parse_bool(str))
452
+ *use_rtkit = false;
453
+
454
+ /* If the user has permissions to use regular realtime scheduling, then
455
+ * we'll use that instead of RTKit */
456
+ if (check_realtime_privileges(impl->rt_prio)) {
457
+ *use_rtkit = false;
458
+ } else {
459
+ if (!(*use_rtkit)) {
460
+ pw_log_warn("neither regular realtime scheduling nor RTKit are available");
461
+ return -ENOTSUP;
462
+ }
463
+
464
+ /* TODO: Should this be pw_log_warn or pw_log_debug instead? */
465
+ pw_log_info("could not use realtime scheduling, falling back to using RTKit instead");
466
+ }
467
+
468
+ return 0;
469
+}
470
+#endif /* HAVE_DBUS */
471
472
SPA_EXPORT
473
int pipewire__module_init(struct pw_impl_module *module, const char *args)
474
{
475
struct pw_context *context = pw_impl_module_get_context(module);
476
struct impl *impl;
477
- const struct pw_properties *context_props;
478
struct pw_properties *props;
479
- const char *str;
480
- bool use_rtkit = true;
481
int res = 0;
482
483
PW_LOG_TOPIC_INIT(mod_topic);
484
485
- if ((context_props = pw_context_get_properties(context)) != NULL &&
486
- (str = pw_properties_get(context_props, "support.dbus")) != NULL &&
487
- !pw_properties_parse_bool(str))
488
- use_rtkit = false;
489
-
490
impl = calloc(1, sizeof(struct impl));
491
if (impl == NULL)
492
return -ENOMEM;
493
494
- spa_list_init(&impl->threads_list);
495
- pthread_mutex_init(&impl->lock, NULL);
496
- pthread_cond_init(&impl->cond, NULL);
497
-
498
pw_log_debug("module %p: new", impl);
499
500
props = args ? pw_properties_new_string(args) : pw_properties_new(NULL, NULL);
501
502
impl->rt_time_soft = pw_properties_get_int32(props, "rt.time.soft", DEFAULT_RT_TIME_SOFT);
503
impl->rt_time_hard = pw_properties_get_int32(props, "rt.time.hard", DEFAULT_RT_TIME_HARD);
504
505
- /* If the user has permissions to use regular realtime scheduling, then
506
- * we'll use that instead of RTKit */
507
- if (check_realtime_priviliges(impl->rt_prio)) {
508
- use_rtkit = false;
509
- } else {
510
- if (!use_rtkit) {
511
- res = -ENOTSUP;
512
- pw_log_warn("neither regular realtime scheduling nor RTKit are available");
513
- goto error;
514
- }
515
+#ifdef HAVE_DBUS
516
+ spa_list_init(&impl->threads_list);
517
+ pthread_mutex_init(&impl->lock, NULL);
518
+ pthread_cond_init(&impl->cond, NULL);
519
520
- /* TODO: Should this be pw_log_warn or pw_log_debug instead? */
521
- pw_log_info("could not use realtime scheduling, falling back to using RTKit instead");
522
+ if ((res = should_use_rtkit(impl, context, &impl->use_rtkit)) < 0) {
523
+ goto error;
524
}
525
526
- impl->use_rtkit = use_rtkit;
527
if (impl->use_rtkit) {
528
impl->system_bus = pw_rtkit_bus_get_system();
529
if (impl->system_bus == NULL) {
530
531
goto error;
532
}
533
}
534
+#else
535
+ if (!check_realtime_privileges(impl->rt_prio)) {
536
+ res = -ENOTSUP;
537
+ pw_log_warn("regular realtime scheduling not available (RTKit fallback disabled)");
538
+ goto error;
539
+ }
540
+#endif
541
542
if (IS_VALID_NICE_LEVEL(impl->nice_level))
543
set_nice(impl, impl->nice_level);
544
545
pw_impl_module_update_properties(module, &SPA_DICT_INIT_ARRAY(module_props));
546
pw_impl_module_update_properties(module, &props->dict);
547
548
+#ifdef HAVE_DBUS
549
if (impl->use_rtkit) {
550
pw_log_debug("initialized using RTKit");
551
} else {
552
pw_log_debug("initialized using regular realtime scheduling");
553
}
554
+#else
555
+ pw_log_debug("initialized using regular realtime scheduling");
556
+#endif
557
+
558
goto done;
559
560
error:
561
+#ifdef HAVE_DBUS
562
if (impl->system_bus)
563
pw_rtkit_bus_free(impl->system_bus);
564
+#endif
565
free(impl);
566
done:
567
pw_properties_free(props);
568
pipewire-0.3.48.tar.gz/src/modules/module-zeroconf-discover/avahi-poll.c -> pipewire-0.3.49.tar.gz/src/modules/module-zeroconf-discover/avahi-poll.c
Changed
39
1
2
AvahiWatchEvent events;
3
AvahiWatchCallback callback;
4
void *userdata;
5
+ unsigned int dispatching;
6
};
7
8
struct AvahiTimeout {
9
10
{
11
AvahiWatch *w = data;
12
13
+ w->dispatching += 1;
14
+
15
w->events = from_pw_events(mask);
16
w->callback(w, fd, w->events, w->userdata);
17
w->events = 0;
18
+
19
+ if (--w->dispatching == 0 && !w->source)
20
+ free(w);
21
}
22
23
static AvahiWatch* watch_new(const AvahiPoll *api, int fd, AvahiWatchEvent event,
24
25
26
static void watch_free(AvahiWatch *w)
27
{
28
- struct impl *impl = w->impl;
29
- pw_loop_destroy_source(impl->loop, w->source);
30
- free(w);
31
+ pw_loop_destroy_source(w->impl->loop, w->source);
32
+ w->source = NULL;
33
+
34
+ if (!w->dispatching)
35
+ free(w);
36
}
37
38
static void timeout_callback(void *data, uint64_t expirations)
39
pipewire-0.3.48.tar.gz/src/pipewire/filter.c -> pipewire-0.3.49.tar.gz/src/pipewire/filter.c
Changed
10
1
2
clear_params(impl, port, id);
3
} else {
4
for (i = 0; i < n_params; i++) {
5
- if (!spa_pod_is_object(params[i]))
6
+ if (params[i] == NULL || !spa_pod_is_object(params[i]))
7
continue;
8
clear_params(impl, port, SPA_POD_OBJECT_ID(params[i]));
9
}
10
pipewire-0.3.48.tar.gz/src/pipewire/pipewire.c -> pipewire-0.3.49.tar.gz/src/pipewire/pipewire.c
Changed
65
1
2
struct spa_interface i18n_iface;
3
struct spa_support support[MAX_SUPPORT];
4
uint32_t n_support;
5
- unsigned int initialized:1;
6
+ uint32_t init_count;
7
unsigned int in_valgrind:1;
8
unsigned int no_color:1;
9
unsigned int no_config:1;
10
11
12
static void init_i18n(struct support *support)
13
{
14
- /* Load locale from the environment. */
15
- setlocale(LC_ALL, "");
16
- /* Set LC_NUMERIC to C so that floating point strings are consistently
17
- * formatted and parsed across locales. */
18
- setlocale(LC_NUMERIC, "C");
19
+ /* XXX: we should remove this setlocale() call, after wireplumber
20
+ * XXX: starts setting the locale */
21
+ setlocale(LC_MESSAGES, "");
22
bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR);
23
bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
24
pw_set_domain(GETTEXT_PACKAGE);
25
26
char level[32];
27
28
pthread_mutex_lock(&init_lock);
29
- if (support->initialized)
30
+ if (support->init_count > 0)
31
goto done;
32
33
pthread_mutex_lock(&support_lock);
34
35
add_i18n(support);
36
37
pw_log_info("version %s", pw_get_library_version());
38
- support->initialized = true;
39
pthread_mutex_unlock(&support_lock);
40
done:
41
+ support->init_count++;
42
pthread_mutex_unlock(&init_lock);
43
}
44
45
46
struct plugin *p;
47
48
pthread_mutex_lock(&init_lock);
49
+ if (support->init_count == 0)
50
+ goto done;
51
+ if (--support->init_count > 0)
52
+ goto done;
53
+
54
pthread_mutex_lock(&support_lock);
55
pw_log_set(NULL);
56
spa_list_consume(p, ®istry->plugins, link) {
57
58
free(support->i18n_domain);
59
spa_zero(global_support);
60
pthread_mutex_unlock(&support_lock);
61
+done:
62
pthread_mutex_unlock(&init_lock);
63
64
}
65
pipewire-0.3.48.tar.gz/src/pipewire/stream.c -> pipewire-0.3.49.tar.gz/src/pipewire/stream.c
Changed
261
1
2
struct spa_io_clock *clock;
3
struct spa_io_position *position;
4
struct spa_io_buffers *io;
5
+ struct spa_io_rate_match *rate_match;
6
+ uint32_t rate_queued;
7
struct {
8
struct spa_io_position *position;
9
} rt;
10
11
clear_params(impl, id);
12
} else {
13
for (i = 0; i < n_params; i++) {
14
- if (!spa_pod_is_object(params[i]))
15
+ if (params[i] == NULL || !spa_pod_is_object(params[i]))
16
continue;
17
clear_params(impl, SPA_POD_OBJECT_ID(params[i]));
18
}
19
20
{
21
struct stream *impl = user_data;
22
struct pw_stream *stream = &impl->this;
23
- pw_log_trace("%p: do process", stream);
24
+ pw_log_trace_fp("%p: do process", stream);
25
pw_stream_emit_process(stream);
26
return 0;
27
}
28
29
static void call_process(struct stream *impl)
30
{
31
- pw_log_trace("%p: call process rt:%u", impl, impl->process_rt);
32
+ pw_log_trace_fp("%p: call process rt:%u", impl, impl->process_rt);
33
if (impl->process_rt)
34
spa_callbacks_call(&impl->rt_callbacks, struct pw_stream_events, process, 0);
35
else
36
37
{
38
struct stream *impl = user_data;
39
struct pw_stream *stream = &impl->this;
40
- pw_log_trace("%p: drained", stream);
41
+ pw_log_trace_fp("%p: drained", stream);
42
pw_stream_emit_drained(stream);
43
return 0;
44
}
45
46
{
47
struct stream *impl = user_data;
48
struct pw_stream *stream = &impl->this;
49
- pw_log_trace("%p: trigger_done", stream);
50
+ pw_log_trace_fp("%p: trigger_done", stream);
51
pw_stream_emit_trigger_done(stream);
52
return 0;
53
}
54
55
else
56
impl->io = NULL;
57
break;
58
+ case SPA_IO_RateMatch:
59
+ if (data && size >= sizeof(struct spa_io_rate_match))
60
+ impl->rate_match = data;
61
+ else
62
+ impl->rate_match = NULL;
63
+ break;
64
}
65
pw_stream_emit_io_changed(stream, id, data, size);
66
67
68
static inline void copy_position(struct stream *impl, int64_t queued)
69
{
70
struct spa_io_position *p = impl->rt.position;
71
- if (SPA_UNLIKELY(p != NULL)) {
72
- SEQ_WRITE(impl->seq);
73
+
74
+ SEQ_WRITE(impl->seq);
75
+ if (SPA_LIKELY(p != NULL)) {
76
impl->time.now = p->clock.nsec;
77
impl->time.rate = p->clock.rate;
78
if (SPA_UNLIKELY(impl->clock_id != p->clock.id)) {
79
80
impl->time.delay = 0;
81
impl->time.queued = queued;
82
impl->quantum = p->clock.duration;
83
- SEQ_WRITE(impl->seq);
84
}
85
+ if (SPA_LIKELY(impl->rate_match != NULL))
86
+ impl->rate_queued = impl->rate_match->delay;
87
+ SEQ_WRITE(impl->seq);
88
}
89
90
static int impl_node_process_input(void *object)
91
92
struct spa_io_buffers *io = impl->io;
93
struct buffer *b;
94
95
- pw_log_trace("%p: process in status:%d id:%d ticks:%"PRIu64" delay:%"PRIi64,
96
+ pw_log_trace_fp("%p: process in status:%d id:%d ticks:%"PRIu64" delay:%"PRIi64,
97
stream, io->status, io->buffer_id, impl->time.ticks, impl->time.delay);
98
99
if (io->status == SPA_STATUS_HAVE_DATA &&
100
101
if (io->status != SPA_STATUS_NEED_DATA) {
102
/* pop buffer to recycle */
103
if ((b = pop_queue(impl, &impl->queued))) {
104
- pw_log_trace("%p: recycle buffer %d", stream, b->id);
105
+ pw_log_trace_fp("%p: recycle buffer %d", stream, b->id);
106
} else if (io->status == -EPIPE)
107
return io->status;
108
io->buffer_id = b ? b->id : SPA_ID_INVALID;
109
110
struct buffer *b;
111
int res;
112
uint32_t index;
113
+ bool recycled;
114
115
again:
116
- pw_log_trace("%p: process out status:%d id:%d", stream,
117
+ pw_log_trace_fp("%p: process out status:%d id:%d", stream,
118
io->status, io->buffer_id);
119
120
+ recycled = false;
121
if ((res = io->status) != SPA_STATUS_HAVE_DATA) {
122
/* recycle old buffer */
123
if ((b = get_buffer(stream, io->buffer_id)) != NULL) {
124
- pw_log_trace("%p: recycle buffer %d", stream, b->id);
125
+ pw_log_trace_fp("%p: recycle buffer %d", stream, b->id);
126
push_queue(impl, &impl->dequeued, b);
127
+ recycled = true;
128
}
129
130
/* pop new buffer */
131
132
impl->drained = false;
133
io->buffer_id = b->id;
134
res = io->status = SPA_STATUS_HAVE_DATA;
135
- pw_log_trace("%p: pop %d %p", stream, b->id, io);
136
+ pw_log_trace_fp("%p: pop %d %p", stream, b->id, io);
137
} else if (impl->draining || impl->drained) {
138
impl->draining = true;
139
impl->drained = true;
140
io->buffer_id = SPA_ID_INVALID;
141
res = io->status = SPA_STATUS_DRAINED;
142
- pw_log_trace("%p: draining", stream);
143
+ pw_log_trace_fp("%p: draining", stream);
144
} else {
145
io->buffer_id = SPA_ID_INVALID;
146
res = io->status = SPA_STATUS_NEED_DATA;
147
- pw_log_trace("%p: no more buffers %p", stream, io);
148
+ pw_log_trace_fp("%p: no more buffers %p", stream, io);
149
}
150
}
151
152
153
if (!impl->draining && !impl->driving) {
154
/* we're not draining, not a driver check if we need to get
155
* more buffers */
156
- if (!impl->process_rt) {
157
+ if (!impl->process_rt && (recycled || res == SPA_STATUS_NEED_DATA)) {
158
/* not realtime and we have a free buffer, trigger process so that we have
159
* data in the next round. */
160
if (spa_ringbuffer_get_read_index(&impl->dequeued.ring, &index) > 0)
161
call_process(impl);
162
- } else if (io->status == SPA_STATUS_NEED_DATA) {
163
+ } else if (res == SPA_STATUS_NEED_DATA) {
164
/* realtime and we don't have a buffer, trigger process and try
165
* again when there is something in the queue now */
166
call_process(impl);
167
168
}
169
}
170
171
- pw_log_trace("%p: res %d", stream, res);
172
+ pw_log_trace_fp("%p: res %d", stream, res);
173
174
if (impl->driving && impl->using_trigger && res != SPA_STATUS_HAVE_DATA)
175
call_trigger_done(impl);
176
177
{
178
struct stream *impl = SPA_CONTAINER_OF(stream, struct stream, this);
179
uintptr_t seq1, seq2;
180
+ uint32_t rate_queued;
181
182
do {
183
seq1 = SEQ_READ(impl->seq);
184
*time = impl->time;
185
+ rate_queued = impl->rate_queued;
186
seq2 = SEQ_READ(impl->seq);
187
} while (!SEQ_READ_SUCCESS(seq1, seq2));
188
189
190
else
191
time->queued = (int64_t)(impl->queued.incount - time->queued);
192
193
+ time->queued += rate_queued;
194
+
195
time->delay += ((impl->latency.min_quantum + impl->latency.max_quantum) / 2) * impl->quantum;
196
time->delay += (impl->latency.min_rate + impl->latency.max_rate) / 2;
197
time->delay += ((impl->latency.min_ns + impl->latency.max_ns) / 2) * time->rate.denom / SPA_NSEC_PER_SEC;
198
199
- pw_log_trace("%p: %"PRIi64" %"PRIi64" %"PRIu64" %d/%d %"PRIu64" %"
200
+ pw_log_trace_fp("%p: %"PRIi64" %"PRIi64" %"PRIu64" %d/%d %"PRIu64" %"
201
PRIu64" %"PRIu64" %"PRIu64" %"PRIu64, stream,
202
time->now, time->delay, time->ticks,
203
time->rate.num, time->rate.denom, time->queued,
204
205
206
if ((b = pop_queue(impl, &impl->dequeued)) == NULL) {
207
res = -errno;
208
- pw_log_trace("%p: no more buffers: %m", stream);
209
+ pw_log_trace_fp("%p: no more buffers: %m", stream);
210
errno = -res;
211
return NULL;
212
}
213
- pw_log_trace("%p: dequeue buffer %d", stream, b->id);
214
+ pw_log_trace_fp("%p: dequeue buffer %d size:%"PRIu64, stream, b->id, b->this.size);
215
216
if (b->busy && impl->direction == SPA_DIRECTION_OUTPUT) {
217
if (ATOMIC_INC(b->busy->count) > 1) {
218
ATOMIC_DEC(b->busy->count);
219
push_queue(impl, &impl->dequeued, b);
220
- pw_log_trace("%p: buffer busy", stream);
221
+ pw_log_trace_fp("%p: buffer busy", stream);
222
errno = EBUSY;
223
return NULL;
224
}
225
226
if (b->busy)
227
ATOMIC_DEC(b->busy->count);
228
229
- pw_log_trace("%p: queue buffer %d", stream, b->id);
230
+ pw_log_trace_fp("%p: queue buffer %d", stream, b->id);
231
if ((res = push_queue(impl, &impl->queued, b)) < 0)
232
return res;
233
234
235
struct stream *impl = user_data;
236
struct buffer *b;
237
238
- pw_log_trace("%p: flush", impl);
239
+ pw_log_trace_fp("%p: flush", impl);
240
do {
241
b = pop_queue(impl, &impl->queued);
242
if (b != NULL)
243
244
bool async, uint32_t seq, const void *data, size_t size, void *user_data)
245
{
246
struct stream *impl = user_data;
247
- pw_log_trace("%p", impl);
248
+ pw_log_trace_fp("%p", impl);
249
impl->draining = true;
250
impl->drained = false;
251
return 0;
252
253
struct stream *impl = SPA_CONTAINER_OF(stream, struct stream, this);
254
int res = 0;
255
256
- pw_log_trace("%p", impl);
257
+ pw_log_trace_fp("%p", impl);
258
259
/* flag to check for old or new behaviour */
260
impl->using_trigger = true;
261
pipewire-0.3.48.tar.gz/src/pipewire/stream.h -> pipewire-0.3.49.tar.gz/src/pipewire/stream.h
Changed
38
1
2
3
/** A time structure */
4
struct pw_time {
5
- int64_t now; /**< the monotonic time in nanoseconds */
6
- struct spa_fraction rate; /**< the rate of \a ticks and delay */
7
+ int64_t now; /**< the monotonic time in nanoseconds. This is the time
8
+ * when this time report was updated. It is usually
9
+ * updated every graph cycle. You can use the current
10
+ * monotonic time to calculate the elapsed time between
11
+ * this report and the current state and calculate
12
+ * updated ticks and delay values. */
13
+ struct spa_fraction rate; /**< the rate of \a ticks and delay. This is usually
14
+ * expressed in 1/<samplerate>. */
15
uint64_t ticks; /**< the ticks at \a now. This is the current time that
16
* the remote end is reading/writing. */
17
- int64_t delay; /**< delay to device, add to ticks to get the time of the
18
- * device. Positive for INPUT streams and
19
- * negative for OUTPUT streams. */
20
+ int64_t delay; /**< delay to device. This is the time it will take for
21
+ * the next sample in the stream to be presented by
22
+ * the playback device or the time a sample traveled
23
+ * from the capture device. This delay includes the
24
+ * delay introduced by all filters on the path between
25
+ * the stream and the device. The delay is normally
26
+ * constant in a graph and can change when the topology
27
+ * of the graph or the quantum changes. */
28
uint64_t queued; /**< data queued in the stream, this is the sum
29
* of the size fields in the pw_buffer that are
30
- * currently queued */
31
+ * currently queued and, for audio streams, the extra
32
+ * data queued in the resampler. For audio streams, it
33
+ * is thus highly recommended to use the buffer size
34
+ * field as the sample count in the buffer. */
35
};
36
37
#include <pipewire/port.h>
38
pipewire-0.3.48.tar.gz/src/tools/dsffile.c -> pipewire-0.3.49.tar.gz/src/tools/dsffile.c
Changed
64
1
2
dsf_file_read(struct dsf_file *f, void *data, size_t samples, const struct dsf_layout *layout)
3
{
4
uint8_t *d = data;
5
- const uint8_t *s;
6
- uint32_t i, j, k, total, stride, bytes;
7
- int32_t interleave = layout->interleave;
8
+ int step = SPA_ABS(layout->interleave);
9
bool rev = layout->lsb != f->info.lsb;
10
-
11
- stride = layout->channels * layout->interleave;
12
- bytes = samples * stride;
13
- bytes -= bytes % f->info.blocksize;
14
-
15
- for (total = 0; total < bytes; total += layout->channels * f->info.blocksize) {
16
- s = f->p + f->offset;
17
-
18
- for (i = 0; i < f->info.blocksize; i += interleave) {
19
- for (j = 0; j < layout->channels; j++) {
20
- const uint8_t *c = &s[f->info.blocksize * j + i];
21
- if (interleave > 0) {
22
- for (k = 0; k < (uint32_t)interleave; k++)
23
- *d++ = rev ? bitrev[c[k]] : c[k];
24
- } else {
25
- for (k = -interleave; k > 0; k--)
26
- *d++ = rev ? bitrev[c[k-1]] : c[k-1];
27
- }
28
+ size_t total, block, offset, pos;
29
+
30
+ block = f->offset / f->info.blocksize;
31
+ offset = block * f->info.blocksize * f->info.channels;
32
+ pos = f->offset % f->info.blocksize;
33
+
34
+ for (total = 0; total < samples && offset + pos < f->info.length; total++) {
35
+ const uint8_t *s = f->p + offset + pos;
36
+ uint32_t i;
37
+
38
+ for (i = 0; i < layout->channels; i++) {
39
+ const uint8_t *c = &s[f->info.blocksize * i];
40
+ int j;
41
+
42
+ if (layout->interleave > 0) {
43
+ for (j = 0; j < step; j++)
44
+ *d++ = rev ? bitrev[c[j]] : c[j];
45
+ } else {
46
+ for (j = step-1; j >= 0; j--)
47
+ *d++ = rev ? bitrev[c[j]] : c[j];
48
}
49
}
50
- f->offset += f->info.channels * f->info.blocksize;
51
+ pos += step;
52
+ if (pos == f->info.blocksize) {
53
+ pos = 0;
54
+ offset += f->info.blocksize * f->info.channels;
55
+ }
56
}
57
- return total / stride;
58
+ f->offset += total * step;
59
+
60
+ return total;
61
}
62
63
int dsf_file_close(struct dsf_file *f)
64
pipewire-0.3.48.tar.gz/src/tools/pw-cat.c -> pipewire-0.3.49.tar.gz/src/tools/pw-cat.c
Changed
43
1
2
#include <unistd.h>
3
#include <assert.h>
4
#include <ctype.h>
5
+#include <locale.h>
6
7
#include <sndfile.h>
8
9
10
data->dsf.layout.channels = info.info.dsd.channels;
11
data->dsf.layout.lsb = info.info.dsd.bitorder == SPA_PARAM_BITORDER_lsb;
12
13
- data->stride = data->dsf.info.channels * SPA_ABS(data->dsf.layout.interleave);
14
+ data->stride = data->dsf.layout.channels * SPA_ABS(data->dsf.layout.interleave);
15
16
if (data->verbose) {
17
printf("DSD out: channels:%d bitorder:%s interleave:%d\n",
18
19
}
20
21
if (data->verbose)
22
- printf("opened file \"%s\" channels:%d rate:%d bitorder:%s\n",
23
+ printf("opened file \"%s\" channels:%d rate:%d samples:%"PRIu64" bitorder:%s\n",
24
data->filename,
25
data->dsf.info.channels, data->dsf.info.rate,
26
+ data->dsf.info.samples,
27
data->dsf.info.lsb ? "lsb" : "msb");
28
29
data->fill = dsf_play;
30
-;
31
+
32
return 0;
33
}
34
35
36
int exit_code = EXIT_FAILURE, c, ret;
37
enum pw_stream_flags flags = 0;
38
39
+ setlocale(LC_ALL, "");
40
pw_init(&argc, &argv);
41
42
flags |= PW_STREAM_FLAG_AUTOCONNECT;
43
pipewire-0.3.48.tar.gz/src/tools/pw-cli.c -> pipewire-0.3.49.tar.gz/src/tools/pw-cli.c
Changed
17
1
2
#include <fnmatch.h>
3
#include <readline/readline.h>
4
#include <readline/history.h>
5
+#include <locale.h>
6
7
#if !defined(FNM_EXTMATCH)
8
#define FNM_EXTMATCH 0
9
10
11
setlinebuf(stdout);
12
13
+ setlocale(LC_ALL, "");
14
pw_init(&argc, &argv);
15
16
while ((c = getopt_long(argc, argv, "hVdr:", long_options, NULL)) != -1) {
17
pipewire-0.3.48.tar.gz/src/tools/pw-dot.c -> pipewire-0.3.49.tar.gz/src/tools/pw-dot.c
Changed
600
1
2
#include <stdio.h>
3
#include <signal.h>
4
#include <getopt.h>
5
+#include <unistd.h>
6
+#include <sys/types.h>
7
+#include <sys/stat.h>
8
+#include <sys/mman.h>
9
+#include <fcntl.h>
10
+#include <locale.h>
11
12
#include <spa/utils/result.h>
13
#include <spa/utils/string.h>
14
+#include <spa/utils/json.h>
15
#include <spa/debug/pod.h>
16
#include <spa/debug/format.h>
17
#include <spa/debug/types.h>
18
19
#define INTERFACE_Module 5
20
#define INTERFACE_Factory 6
21
uint32_t type;
22
- struct pw_properties *props;
23
void *info;
24
25
pw_destroy_t info_destroy;
26
27
}
28
}
29
30
-static SPA_PRINTF_FUNC(7,0) void draw_vlabel(char **str, const char *name, uint32_t id, bool detail,
31
- const struct spa_dict *info_p, const struct spa_dict *p,
32
- const char *fmt, va_list varargs)
33
+static SPA_PRINTF_FUNC(6,0) void draw_vlabel(char **str, const char *name, uint32_t id, bool detail,
34
+ const struct spa_dict *props, const char *fmt, va_list varargs)
35
{
36
/* draw the label header */
37
dot_str_add(str, "%s_%u [label=\"", name, id);
38
39
/* draw the label body */
40
dot_str_vadd(str, fmt, varargs);
41
42
- if (detail) {
43
- draw_dict(str, "info_props", info_p);
44
- draw_dict(str, "properties", p);
45
- }
46
+ if (detail)
47
+ draw_dict(str, "properties", props);
48
49
/*draw the label footer */
50
dot_str_add(str, "%s", "\"];\n");
51
}
52
53
-static SPA_PRINTF_FUNC(7,8) void draw_label(char **str, const char *name, uint32_t id, bool detail,
54
- const struct spa_dict *info_p, const struct spa_dict *p,
55
- const char *fmt, ...)
56
+static SPA_PRINTF_FUNC(6,7) void draw_label(char **str, const char *name, uint32_t id, bool detail,
57
+ const struct spa_dict *props, const char *fmt, ...)
58
{
59
va_list varargs;
60
va_start(varargs, fmt);
61
- draw_vlabel(str, name, id, detail, info_p, p, fmt, varargs);
62
+ draw_vlabel(str, name, id, detail, props, fmt, varargs);
63
va_end(varargs);
64
}
65
66
67
68
/* draw the label */
69
draw_label(dot_str,
70
- "port", g->id, g->data->show_detail, info->props, &g->props->dict,
71
+ "port", g->id, g->data->show_detail, info->props,
72
"port_id: %u\\lname: %s\\ldirection: %s\\l",
73
g->id,
74
spa_dict_lookup(info->props, PW_KEY_PORT_NAME),
75
76
g->id,
77
spa_dict_lookup(info->props, PW_KEY_NODE_NAME),
78
spa_dict_lookup(info->props, PW_KEY_MEDIA_CLASS));
79
- if (g->data->show_detail) {
80
- draw_dict(dot_str, "info_props", info->props);
81
- draw_dict(dot_str, "properties", &g->props->dict);
82
- }
83
+
84
+ if (g->data->show_detail)
85
+ draw_dict(dot_str, "properties", info->props);
86
87
/*draw the label footer */
88
dot_str_add(dot_str, "%s", "\"\n");
89
90
struct global *p;
91
const char *prop_node_id;
92
spa_list_for_each(p, &g->data->globals, link) {
93
+ struct pw_port_info *pinfo;
94
if (p->info == NULL)
95
continue;
96
if (p->type != INTERFACE_Port)
97
continue;
98
- prop_node_id = pw_properties_get(p->props, PW_KEY_NODE_ID);
99
+ pinfo = p->info;
100
+ prop_node_id = spa_dict_lookup(pinfo->props, PW_KEY_NODE_ID);
101
if (!prop_node_id || (uint32_t)atoi(prop_node_id) != g->id)
102
continue;
103
if (p->draw)
104
105
106
/* draw the label */
107
draw_label(dot_str,
108
- "link", g->id, g->data->show_detail, info->props, &g->props->dict,
109
+ "link", g->id, g->data->show_detail, info->props,
110
"link_id: %u\\loutput_node_id: %u\\linput_node_id: %u\\loutput_port_id: %u\\linput_port_id: %u\\lstate: %s\\l",
111
g->id,
112
info->output_node_id,
113
114
115
/* draw the label */
116
draw_label(dot_str,
117
- "client", g->id, g->data->show_detail, info->props, &g->props->dict,
118
+ "client", g->id, g->data->show_detail, info->props,
119
"client_id: %u\\lname: %s\\lpid: %s\\l",
120
g->id,
121
spa_dict_lookup(info->props, PW_KEY_APP_NAME),
122
123
124
/* draw the label */
125
draw_label(dot_str,
126
- "device", g->id, g->data->show_detail, info->props, &g->props->dict,
127
+ "device", g->id, g->data->show_detail, info->props,
128
"device_id: %u\\lname: %s\\lmedia_class: %s\\lapi: %s\\lpath: %s\\l",
129
g->id,
130
spa_dict_lookup(info->props, PW_KEY_DEVICE_NAME),
131
132
133
/* draw the label */
134
draw_label(dot_str,
135
- "factory", g->id, g->data->show_detail, info->props, &g->props->dict,
136
+ "factory", g->id, g->data->show_detail, info->props,
137
"factory_id: %u\\lname: %s\\lmodule_id: %u\\l",
138
g->id, info->name, module_id
139
);
140
141
142
/* draw the label */
143
draw_label(dot_str,
144
- "module", g->id, g->data->show_detail, info->props, &g->props->dict,
145
+ "module", g->id, g->data->show_detail, info->props,
146
"module_id: %u\\lname: %s\\l",
147
g->id, info->name
148
);
149
150
struct global *g = user_data;
151
spa_hook_remove(&g->object_listener);
152
spa_hook_remove(&g->proxy_listener);
153
- pw_properties_free(g->props);
154
- if (g->info)
155
- g->info_destroy(g->info);
156
}
157
158
static const struct pw_proxy_events proxy_events = {
159
160
return;
161
}
162
163
- proxy = pw_registry_bind(d->registry, id, type,
164
- client_version,
165
- sizeof(struct global));
166
+ proxy = pw_registry_bind(d->registry, id, type, client_version, 0);
167
if (proxy == NULL)
168
return;
169
170
/* set the global data */
171
- g = pw_proxy_get_user_data(proxy);
172
+ g = calloc(1, sizeof(struct global));
173
g->data = d;
174
g->proxy = proxy;
175
176
g->id = id;
177
g->type = object_type;
178
- g->props = props ? pw_properties_new_dict(props) : NULL;
179
g->info = NULL;
180
181
g->info_destroy = info_destroy;
182
183
pw_main_loop_quit(d->loop);
184
}
185
186
+static int get_data_from_pipewire(struct data *data, const char *opt_remote)
187
+{
188
+ struct pw_loop *l;
189
+ struct global *g;
190
+
191
+ data->loop = pw_main_loop_new(NULL);
192
+ if (data->loop == NULL) {
193
+ fprintf(stderr, "can't create main loop: %m\n");
194
+ return -1;
195
+ }
196
+
197
+ l = pw_main_loop_get_loop(data->loop);
198
+ pw_loop_add_signal(l, SIGINT, do_quit, &data);
199
+ pw_loop_add_signal(l, SIGTERM, do_quit, &data);
200
+
201
+ data->context = pw_context_new(l, NULL, 0);
202
+ if (data->context == NULL) {
203
+ fprintf(stderr, "can't create context: %m\n");
204
+ pw_main_loop_destroy(data->loop);
205
+ return -1;
206
+ }
207
+
208
+ data->core = pw_context_connect(data->context,
209
+ pw_properties_new(
210
+ PW_KEY_REMOTE_NAME, opt_remote,
211
+ NULL),
212
+ 0);
213
+ if (data->core == NULL) {
214
+ fprintf(stderr, "can't connect: %m\n");
215
+ pw_context_destroy(data->context);
216
+ pw_main_loop_destroy(data->loop);
217
+ return -1;
218
+ }
219
+
220
+ pw_core_add_listener(data->core,
221
+ &data->core_listener,
222
+ &core_events, data);
223
+
224
+ data->registry = pw_core_get_registry(data->core,
225
+ PW_VERSION_REGISTRY, 0);
226
+ pw_registry_add_listener(data->registry,
227
+ &data->registry_listener,
228
+ ®istry_events, data);
229
+
230
+ pw_main_loop_run(data->loop);
231
+
232
+ spa_hook_remove(&data->registry_listener);
233
+ pw_proxy_destroy((struct pw_proxy*)data->registry);
234
+ spa_list_for_each(g, &data->globals, link)
235
+ pw_proxy_destroy(g->proxy);
236
+ spa_hook_remove(&data->core_listener);
237
+ pw_context_destroy(data->context);
238
+ pw_main_loop_destroy(data->loop);
239
+
240
+ return 0;
241
+}
242
+
243
+static void handle_json_obj(struct data *data, struct pw_properties *obj)
244
+{
245
+ struct global *g;
246
+ struct pw_properties *info, *props;
247
+ const char *str;
248
+
249
+ str = pw_properties_get(obj, "type");
250
+ if (!str) {
251
+ fprintf(stderr, "invalid object without type\n");
252
+ return;
253
+ }
254
+
255
+ g = calloc(1, sizeof (struct global));
256
+ g->data = data;
257
+
258
+ if (spa_streq(str, PW_TYPE_INTERFACE_Port)) {
259
+ g->info_destroy = (pw_destroy_t)pw_port_info_free;
260
+ g->draw = draw_port;
261
+ g->type = INTERFACE_Port;
262
+ }
263
+ else if (spa_streq(str, PW_TYPE_INTERFACE_Node)) {
264
+ g->info_destroy = (pw_destroy_t)pw_node_info_free;
265
+ g->draw = draw_node;
266
+ g->type = INTERFACE_Node;
267
+ }
268
+ else if (spa_streq(str, PW_TYPE_INTERFACE_Link)) {
269
+ g->info_destroy = (pw_destroy_t)pw_link_info_free;
270
+ g->draw = draw_link;
271
+ g->type = INTERFACE_Link;
272
+ }
273
+ else if (spa_streq(str, PW_TYPE_INTERFACE_Client)) {
274
+ g->info_destroy = (pw_destroy_t)pw_client_info_free;
275
+ g->draw = draw_client;
276
+ g->type = INTERFACE_Client;
277
+ }
278
+ else if (spa_streq(str, PW_TYPE_INTERFACE_Device)) {
279
+ g->info_destroy = (pw_destroy_t)pw_device_info_free;
280
+ g->draw = draw_device;
281
+ g->type = INTERFACE_Device;
282
+ }
283
+ else if (spa_streq(str, PW_TYPE_INTERFACE_Factory)) {
284
+ g->info_destroy = (pw_destroy_t)pw_factory_info_free;
285
+ g->draw = draw_factory;
286
+ g->type = INTERFACE_Factory;
287
+ }
288
+ else if (spa_streq(str, PW_TYPE_INTERFACE_Module)) {
289
+ g->info_destroy = (pw_destroy_t)pw_module_info_free;
290
+ g->draw = draw_module;
291
+ g->type = INTERFACE_Module;
292
+ }
293
+ else {
294
+ free(g);
295
+ return;
296
+ }
297
+
298
+ g->id = pw_properties_get_uint32(obj, "id", 0);
299
+
300
+ str = pw_properties_get(obj, "info");
301
+ info = pw_properties_new_string(str);
302
+
303
+ str = pw_properties_get(info, "props");
304
+ props = str ? pw_properties_new_string(str) : NULL;
305
+
306
+ switch (g->type) {
307
+ case INTERFACE_Port: {
308
+ struct pw_port_info pinfo = {0};
309
+ pinfo.id = g->id;
310
+ str = pw_properties_get(info, "direction");
311
+ pinfo.direction = spa_streq(str, "output") ?
312
+ PW_DIRECTION_OUTPUT : PW_DIRECTION_INPUT;
313
+ pinfo.props = props ? &props->dict : NULL;
314
+ pinfo.change_mask = PW_PORT_CHANGE_MASK_PROPS;
315
+ g->info = pw_port_info_update(NULL, &pinfo);
316
+ break;
317
+ }
318
+ case INTERFACE_Node: {
319
+ struct pw_node_info ninfo = {0};
320
+ ninfo.id = g->id;
321
+ ninfo.max_input_ports =
322
+ pw_properties_get_uint32(info, "max-input-ports", 0);
323
+ ninfo.max_output_ports =
324
+ pw_properties_get_uint32(info, "max-output-ports", 0);
325
+ ninfo.n_input_ports =
326
+ pw_properties_get_uint32(info, "n-input-ports", 0);
327
+ ninfo.n_output_ports =
328
+ pw_properties_get_uint32(info, "n-output-ports", 0);
329
+
330
+ str = pw_properties_get(info, "state");
331
+ if (spa_streq(str, "running"))
332
+ ninfo.state = PW_NODE_STATE_RUNNING;
333
+ else if (spa_streq(str, "idle"))
334
+ ninfo.state = PW_NODE_STATE_IDLE;
335
+ else if (spa_streq(str, "suspended"))
336
+ ninfo.state = PW_NODE_STATE_SUSPENDED;
337
+ else if (spa_streq(str, "creating"))
338
+ ninfo.state = PW_NODE_STATE_CREATING;
339
+ else
340
+ ninfo.state = PW_NODE_STATE_ERROR;
341
+ ninfo.error = pw_properties_get(info, "error");
342
+
343
+ ninfo.props = props ? &props->dict : NULL;
344
+ ninfo.change_mask = PW_NODE_CHANGE_MASK_INPUT_PORTS |
345
+ PW_NODE_CHANGE_MASK_OUTPUT_PORTS |
346
+ PW_NODE_CHANGE_MASK_STATE |
347
+ PW_NODE_CHANGE_MASK_PROPS;
348
+ g->info = pw_node_info_update(NULL, &ninfo);
349
+ break;
350
+ }
351
+ case INTERFACE_Link: {
352
+ struct pw_link_info linfo = {0};
353
+ linfo.id = g->id;
354
+ linfo.output_node_id =
355
+ pw_properties_get_uint32(info, "output-node-id", 0);
356
+ linfo.output_port_id =
357
+ pw_properties_get_uint32(info, "output-port-id", 0);
358
+ linfo.input_node_id =
359
+ pw_properties_get_uint32(info, "input-node-id", 0);
360
+ linfo.input_port_id =
361
+ pw_properties_get_uint32(info, "input-port-id", 0);
362
+
363
+ str = pw_properties_get(info, "state");
364
+ if (spa_streq(str, "active"))
365
+ linfo.state = PW_LINK_STATE_ACTIVE;
366
+ else if (spa_streq(str, "paused"))
367
+ linfo.state = PW_LINK_STATE_PAUSED;
368
+ else if (spa_streq(str, "allocating"))
369
+ linfo.state = PW_LINK_STATE_ALLOCATING;
370
+ else if (spa_streq(str, "negotiating"))
371
+ linfo.state = PW_LINK_STATE_NEGOTIATING;
372
+ else if (spa_streq(str, "init"))
373
+ linfo.state = PW_LINK_STATE_INIT;
374
+ else if (spa_streq(str, "unlinked"))
375
+ linfo.state = PW_LINK_STATE_UNLINKED;
376
+ else
377
+ linfo.state = PW_LINK_STATE_ERROR;
378
+ linfo.error = pw_properties_get(info, "error");
379
+
380
+ linfo.props = props ? &props->dict : NULL;
381
+ linfo.change_mask = PW_LINK_CHANGE_MASK_STATE |
382
+ PW_LINK_CHANGE_MASK_PROPS;
383
+ g->info = pw_link_info_update(NULL, &linfo);
384
+ break;
385
+ }
386
+ case INTERFACE_Client: {
387
+ struct pw_client_info cinfo = {0};
388
+ cinfo.id = g->id;
389
+ cinfo.props = props ? &props->dict : NULL;
390
+ cinfo.change_mask = PW_CLIENT_CHANGE_MASK_PROPS;
391
+ g->info = pw_client_info_update(NULL, &cinfo);
392
+ break;
393
+ }
394
+ case INTERFACE_Device: {
395
+ struct pw_device_info dinfo = {0};
396
+ dinfo.id = g->id;
397
+ dinfo.props = props ? &props->dict : NULL;
398
+ dinfo.change_mask = PW_DEVICE_CHANGE_MASK_PROPS;
399
+ g->info = pw_device_info_update(NULL, &dinfo);
400
+ break;
401
+ }
402
+ case INTERFACE_Factory: {
403
+ struct pw_factory_info finfo = {0};
404
+ finfo.id = g->id;
405
+ finfo.name = pw_properties_get(info, "name");
406
+ finfo.type = pw_properties_get(info, "type");
407
+ finfo.version = pw_properties_get_uint32(info, "version", 0);
408
+ finfo.props = props ? &props->dict : NULL;
409
+ finfo.change_mask = PW_FACTORY_CHANGE_MASK_PROPS;
410
+ g->info = pw_factory_info_update(NULL, &finfo);
411
+ break;
412
+ }
413
+ case INTERFACE_Module: {
414
+ struct pw_module_info minfo = {0};
415
+ minfo.id = g->id;
416
+ minfo.name = pw_properties_get(info, "name");
417
+ minfo.filename = pw_properties_get(info, "filename");
418
+ minfo.args = pw_properties_get(info, "args");
419
+ minfo.props = props ? &props->dict : NULL;
420
+ minfo.change_mask = PW_MODULE_CHANGE_MASK_PROPS;
421
+ g->info = pw_module_info_update(NULL, &minfo);
422
+ break;
423
+ }
424
+ default:
425
+ break;
426
+ }
427
+
428
+ pw_properties_free(info);
429
+ pw_properties_free(props);
430
+
431
+ /* add the global to the list */
432
+ spa_list_insert(&data->globals, &g->link);
433
+}
434
+
435
+static int get_data_from_json(struct data *data, const char *json_path)
436
+{
437
+ int fd, len;
438
+ void *json;
439
+ struct stat sbuf;
440
+ struct spa_json it[2];
441
+ const char *value;
442
+
443
+ if ((fd = open(json_path, O_CLOEXEC | O_RDONLY)) < 0) {
444
+ fprintf(stderr, "error opening file '%s': %m\n", json_path);
445
+ return -1;
446
+ }
447
+ if (fstat(fd, &sbuf) < 0) {
448
+ fprintf(stderr, "error statting file '%s': %m\n", json_path);
449
+ close(fd);
450
+ return -1;
451
+ }
452
+ if ((json = mmap(NULL, sbuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED) {
453
+ fprintf(stderr, "error mmapping file '%s': %m\n", json_path);
454
+ close(fd);
455
+ return -1;
456
+ }
457
+
458
+ close(fd);
459
+ spa_json_init(&it[0], json, sbuf.st_size);
460
+
461
+ if (spa_json_enter_array(&it[0], &it[1]) <= 0) {
462
+ fprintf(stderr, "expected top-level array in JSON file '%s'\n", json_path);
463
+ munmap(json, sbuf.st_size);
464
+ return -1;
465
+ }
466
+
467
+ while ((len = spa_json_next(&it[1], &value)) > 0 && spa_json_is_object(value, len)) {
468
+ struct pw_properties *obj;
469
+ obj = pw_properties_new(NULL, NULL);
470
+ len = spa_json_container_len(&it[1], value, len);
471
+ pw_properties_update_string(obj, value, len);
472
+ handle_json_obj(data, obj);
473
+ pw_properties_free(obj);
474
+ }
475
+
476
+ munmap(json, sbuf.st_size);
477
+ return 0;
478
+}
479
+
480
static void show_help(const char *name, bool error)
481
{
482
fprintf(error ? stderr : stdout, "%s [options]\n"
483
484
" -r, --remote Remote daemon name\n"
485
" -o, --output Output file (Default %s)\n"
486
" -L, --lr Use left-right rank direction\n"
487
- " -9, --90 Use orthogonal edges\n",
488
+ " -9, --90 Use orthogonal edges\n"
489
+ " -j, --json Read objects from pw-dump JSON file\n",
490
name,
491
DEFAULT_DOT_PATH);
492
}
493
494
int main(int argc, char *argv[])
495
{
496
struct data data = { 0 };
497
- struct pw_loop *l;
498
+ struct global *g;
499
const char *opt_remote = NULL;
500
const char *dot_path = DEFAULT_DOT_PATH;
501
+ const char *json_path = NULL;
502
static const struct option long_options[] = {
503
{ "help", no_argument, NULL, 'h' },
504
{ "version", no_argument, NULL, 'V' },
505
506
{ "output", required_argument, NULL, 'o' },
507
{ "lr", no_argument, NULL, 'L' },
508
{ "90", no_argument, NULL, '9' },
509
+ { "json", required_argument, NULL, 'j' },
510
{ NULL, 0, NULL, 0}
511
};
512
int c;
513
514
+ setlocale(LC_ALL, "");
515
pw_init(&argc, &argv);
516
517
- while ((c = getopt_long(argc, argv, "hVasdr:o:L9", long_options, NULL)) != -1) {
518
+ while ((c = getopt_long(argc, argv, "hVasdr:o:L9j:", long_options, NULL)) != -1) {
519
switch (c) {
520
case 'h' :
521
show_help(argv[0], false);
522
523
data.dot_orthoedges = true;
524
fprintf(stderr, "orthogonal edges enabled\n");
525
break;
526
+ case 'j' :
527
+ json_path = optarg;
528
+ fprintf(stderr, "Using JSON file %s as input\n", json_path);
529
+ break;
530
default:
531
show_help(argv[0], true);
532
return -1;
533
}
534
}
535
536
- data.loop = pw_main_loop_new(NULL);
537
- if (data.loop == NULL) {
538
- fprintf(stderr, "can't create main loop: %m\n");
539
+ if (!(data.dot_str = dot_str_new()))
540
return -1;
541
- }
542
543
- l = pw_main_loop_get_loop(data.loop);
544
- pw_loop_add_signal(l, SIGINT, do_quit, &data);
545
- pw_loop_add_signal(l, SIGTERM, do_quit, &data);
546
-
547
- data.context = pw_context_new(l, NULL, 0);
548
- if (data.context == NULL) {
549
- fprintf(stderr, "can't create context: %m\n");
550
- return -1;
551
- }
552
+ spa_list_init(&data.globals);
553
554
- data.core = pw_context_connect(data.context,
555
- pw_properties_new(
556
- PW_KEY_REMOTE_NAME, opt_remote,
557
- NULL),
558
- 0);
559
- if (data.core == NULL) {
560
- fprintf(stderr, "can't connect: %m\n");
561
+ if (!json_path && get_data_from_pipewire(&data, opt_remote) < 0)
562
return -1;
563
- }
564
-
565
- data.dot_str = dot_str_new();
566
- if (data.dot_str == NULL)
567
+ else if (json_path && get_data_from_json(&data, json_path) < 0)
568
return -1;
569
570
- spa_list_init(&data.globals);
571
-
572
- pw_core_add_listener(data.core,
573
- &data.core_listener,
574
- &core_events, &data);
575
- data.registry = pw_core_get_registry(data.core,
576
- PW_VERSION_REGISTRY, 0);
577
- pw_registry_add_listener(data.registry,
578
- &data.registry_listener,
579
- ®istry_events, &data);
580
-
581
- pw_main_loop_run(data.loop);
582
-
583
draw_graph(&data, dot_path);
584
585
dot_str_clear(&data.dot_str);
586
- spa_hook_remove(&data.registry_listener);
587
- pw_proxy_destroy((struct pw_proxy*)data.registry);
588
- spa_hook_remove(&data.core_listener);
589
- pw_context_destroy(data.context);
590
- pw_main_loop_destroy(data.loop);
591
+ spa_list_consume(g, &data.globals, link) {
592
+ if (g->info && g->info_destroy)
593
+ g->info_destroy(g->info);
594
+ spa_list_remove(&g->link);
595
+ free(g);
596
+ }
597
pw_deinit();
598
599
return 0;
600
pipewire-0.3.48.tar.gz/src/tools/pw-dump.c -> pipewire-0.3.49.tar.gz/src/tools/pw-dump.c
Changed
46
1
2
#include <limits.h>
3
#include <math.h>
4
#include <fnmatch.h>
5
+#include <locale.h>
6
7
#if !defined(FNM_EXTMATCH)
8
#define FNM_EXTMATCH 0
9
10
11
static void put_double(struct data *d, const char *key, double val)
12
{
13
- put_fmt(d, key, "%s%f%s", NUMBER, val, NORMAL);
14
+ char buf[128];
15
+ put_fmt(d, key, "%s%s%s", NUMBER,
16
+ spa_json_format_float(buf, sizeof(buf), val), NORMAL);
17
}
18
19
static void put_value(struct data *d, const char *key, const char *val)
20
{
21
int64_t li;
22
- double dv;
23
+ float fv;
24
25
if (val == NULL)
26
put_literal(d, key, "null");
27
28
put_literal(d, key, val);
29
else if (spa_atoi64(val, &li, 10))
30
put_int(d, key, li);
31
- else if (spa_atod(val, &dv))
32
- put_double(d, key, dv);
33
+ else if (spa_json_parse_float(val, strlen(val), &fv))
34
+ put_double(d, key, fv);
35
else
36
put_string(d, key, val);
37
}
38
39
};
40
int c;
41
42
+ setlocale(LC_ALL, "");
43
pw_init(&argc, &argv);
44
45
data.out = stdout;
46
pipewire-0.3.48.tar.gz/src/tools/pw-link.c -> pipewire-0.3.49.tar.gz/src/tools/pw-link.c
Changed
17
1
2
#include <math.h>
3
#include <getopt.h>
4
#include <regex.h>
5
+#include <locale.h>
6
7
#include <spa/utils/result.h>
8
#include <spa/utils/string.h>
9
10
{ NULL, 0, NULL, 0}
11
};
12
13
+ setlocale(LC_ALL, "");
14
pw_init(&argc, &argv);
15
spa_list_init(&data.objects);
16
17
pipewire-0.3.48.tar.gz/src/tools/pw-loopback.c -> pipewire-0.3.49.tar.gz/src/tools/pw-loopback.c
Changed
17
1
2
#include <getopt.h>
3
#include <limits.h>
4
#include <math.h>
5
+#include <locale.h>
6
7
#include <spa/utils/result.h>
8
#include <spa/pod/builder.h>
9
10
};
11
int c, res = -1;
12
13
+ setlocale(LC_ALL, "");
14
pw_init(&argc, &argv);
15
16
data.channels = DEFAULT_CHANNELS;
17
pipewire-0.3.48.tar.gz/src/tools/pw-metadata.c -> pipewire-0.3.49.tar.gz/src/tools/pw-metadata.c
Changed
17
1
2
#include <signal.h>
3
#include <math.h>
4
#include <getopt.h>
5
+#include <locale.h>
6
7
#include <spa/utils/result.h>
8
#include <spa/utils/string.h>
9
10
11
setlinebuf(stdout);
12
13
+ setlocale(LC_ALL, "");
14
pw_init(&argc, &argv);
15
16
data.opt_name = "default";
17
pipewire-0.3.48.tar.gz/src/tools/pw-mididump.c -> pipewire-0.3.49.tar.gz/src/tools/pw-mididump.c
Changed
17
1
2
#include <signal.h>
3
#include <math.h>
4
#include <getopt.h>
5
+#include <locale.h>
6
7
#include <spa/utils/result.h>
8
#include <spa/utils/defs.h>
9
10
{ NULL, 0, NULL, 0}
11
};
12
13
+ setlocale(LC_ALL, "");
14
pw_init(&argc, &argv);
15
16
setlinebuf(stdout);
17
pipewire-0.3.48.tar.gz/src/tools/pw-mon.c -> pipewire-0.3.49.tar.gz/src/tools/pw-mon.c
Changed
17
1
2
#include <signal.h>
3
#include <getopt.h>
4
#include <unistd.h>
5
+#include <locale.h>
6
7
#include <spa/utils/result.h>
8
#include <spa/utils/string.h>
9
10
int c;
11
bool colors = false;
12
13
+ setlocale(LC_ALL, "");
14
pw_init(&argc, &argv);
15
16
setlinebuf(stdout);
17
pipewire-0.3.48.tar.gz/src/tools/pw-profiler.c -> pipewire-0.3.49.tar.gz/src/tools/pw-profiler.c
Changed
17
1
2
#include <stdio.h>
3
#include <signal.h>
4
#include <getopt.h>
5
+#include <locale.h>
6
7
#include <spa/utils/result.h>
8
#include <spa/utils/string.h>
9
10
};
11
int c;
12
13
+ setlocale(LC_ALL, "");
14
pw_init(&argc, &argv);
15
16
while ((c = getopt_long(argc, argv, "hVr:o:", long_options, NULL)) != -1) {
17
pipewire-0.3.48.tar.gz/src/tools/pw-reserve.c -> pipewire-0.3.49.tar.gz/src/tools/pw-reserve.c
Changed
17
1
2
3
#include <getopt.h>
4
#include <signal.h>
5
+#include <locale.h>
6
7
#include <dbus/dbus.h>
8
9
10
11
setlinebuf(stdout);
12
13
+ setlocale(LC_ALL, "");
14
pw_init(&argc, &argv);
15
16
while ((c = getopt_long(argc, argv, "hVn:a:p:m", long_options, NULL)) != -1) {
17
pipewire-0.3.48.tar.gz/test/meson.build -> pipewire-0.3.49.tar.gz/test/meson.build
Changed
30
1
2
link_with: pwtest_lib)
3
)
4
5
+openal_info = find_program('openal-info', required: false)
6
+if openal_info.found()
7
+ cdata.set_quoted('OPENAL_INFO_PATH', openal_info.full_path())
8
+endif
9
+summary({'openal-info': openal_info.found()}, bool_yn: true, section: 'Functional test programs')
10
+
11
+pactl = find_program('pactl', required: false)
12
+if pactl.found()
13
+ cdata.set_quoted('PACTL_PATH', pactl.full_path())
14
+endif
15
+summary({'pactl': pactl.found()}, bool_yn: true, section: 'Functional test programs')
16
+
17
+if default_sm == 'media-session' or default_sm == 'wireplumber'
18
+ test('test-functional',
19
+ executable('test-functional',
20
+ 'test-functional.c',
21
+ include_directories: pwtest_inc,
22
+ dependencies: [ spa_dep ],
23
+ link_with: pwtest_lib)
24
+ )
25
+endif
26
+
27
valgrind = find_program('valgrind', required: false)
28
summary({'valgrind (test setup)': valgrind.found()}, bool_yn: true, section: 'Optional programs')
29
if valgrind.found()
30
pipewire-0.3.48.tar.gz/test/pwtest.c -> pipewire-0.3.49.tar.gz/test/pwtest.c
Changed
369
1
2
struct spa_list suites;
3
unsigned int timeout;
4
bool no_fork;
5
+ bool terminate;
6
+ struct spa_list cleanup_pids;
7
8
const char *test_filter;
9
bool has_iteration_filter;
10
11
char *xdg_dir;
12
};
13
14
+struct cleanup_pid {
15
+ struct spa_list link;
16
+ pid_t pid;
17
+};
18
+
19
struct pwtest_context *pwtest_get_context(struct pwtest_test *t)
20
{
21
return ctx;
22
23
}
24
}
25
26
+static int add_cleanup_pid(struct pwtest_context *ctx, pid_t pid)
27
+{
28
+ struct cleanup_pid *cpid;
29
+
30
+ if (pid == 0)
31
+ return -EINVAL;
32
+
33
+ cpid = calloc(1, sizeof(struct cleanup_pid));
34
+ if (cpid == NULL)
35
+ return -errno;
36
+
37
+ cpid->pid = pid;
38
+ spa_list_append(&ctx->cleanup_pids, &cpid->link);
39
+
40
+ return 0;
41
+}
42
+
43
+static void remove_cleanup_pid(struct pwtest_context *ctx, pid_t pid)
44
+{
45
+ struct cleanup_pid *cpid, *t;
46
+
47
+ spa_list_for_each_safe(cpid, t, &ctx->cleanup_pids, link) {
48
+ if (cpid->pid == pid) {
49
+ spa_list_remove(&cpid->link);
50
+ free(cpid);
51
+ }
52
+ }
53
+}
54
+
55
+static void terminate_cleanup_pids(struct pwtest_context *ctx)
56
+{
57
+ struct cleanup_pid *cpid;
58
+ spa_list_for_each(cpid, &ctx->cleanup_pids, link) {
59
+ /* Don't free here, to be signal-safe */
60
+ if (cpid->pid != 0) {
61
+ kill(cpid->pid, SIGTERM);
62
+ cpid->pid = 0;
63
+ }
64
+ }
65
+}
66
+
67
+static void free_cleanup_pids(struct pwtest_context *ctx)
68
+{
69
+ struct cleanup_pid *cpid;
70
+ spa_list_consume(cpid, &ctx->cleanup_pids, link) {
71
+ spa_list_remove(&cpid->link);
72
+ free(cpid);
73
+ }
74
+}
75
+
76
static void pwtest_backtrace(pid_t p)
77
{
78
#ifdef HAVE_GSTACK
79
80
pwtest_error_with_msg("Unable to create temporary file: %s", strerror(errno));
81
}
82
83
+int
84
+pwtest_spawn(const char *file, char *const argv[])
85
+{
86
+ int r;
87
+ int status = -1;
88
+ pid_t pid;
89
+ const int fail_code = 121;
90
+
91
+ pid = fork();
92
+ if (pid == 0) {
93
+ /* child process */
94
+ execvp(file, (char **)argv);
95
+ exit(fail_code);
96
+ } else if (pid < 0)
97
+ pwtest_error_with_msg("Unable to fork: %s", strerror(errno));
98
+
99
+ add_cleanup_pid(ctx, pid);
100
+ r = waitpid(pid, &status, 0);
101
+ remove_cleanup_pid(ctx, pid);
102
+ if (r <= 0)
103
+ pwtest_error_with_msg("waitpid failed: %s", strerror(errno));
104
+
105
+ if (WEXITSTATUS(status) == fail_code)
106
+ pwtest_error_with_msg("exec %s failed", file);
107
+
108
+ return status;
109
+}
110
+
111
void _pwtest_add(struct pwtest_context *ctx, struct pwtest_suite *suite,
112
const char *funcname, const void *func, ...)
113
{
114
115
pw_properties_set(t->args.env, key, value);
116
break;
117
case PWTEST_ARG_DAEMON:
118
+ if (RUNNING_ON_VALGRIND)
119
+ t->result = PWTEST_SKIP;
120
t->args.pw_daemon = true;
121
break;
122
}
123
124
{
125
struct pwtest_suite *c, *tmp;
126
127
+ terminate_cleanup_pids(ctx);
128
+ free_cleanup_pids(ctx);
129
+
130
spa_list_for_each_safe(c, tmp, &ctx->suites, link) {
131
free_suite(c);
132
}
133
134
sigaction(signal, &act, NULL);
135
136
pwtest_backtrace(0);
137
+ terminate_cleanup_pids(ctx);
138
raise(signal);
139
}
140
141
static inline void log_append(struct pw_array *buffer, int fd)
142
{
143
int r = 0;
144
- const int sz = 1024;
145
+ const int sz = 65536;
146
147
while (true) {
148
r = pw_array_ensure_size(buffer, sz);
149
150
pid_t pid;
151
char pw_remote[64];
152
int status;
153
+ int r;
154
155
spa_scnprintf(pw_remote, sizeof(pw_remote), "pwtest-pw-%u\n", count++);
156
replace_env(t, "PIPEWIRE_REMOTE", pw_remote);
157
158
pid = fork();
159
if (pid == 0) {
160
/* child */
161
+ setpgid(0, 0);
162
+
163
setenv("PIPEWIRE_CORE", pw_remote, 1);
164
+ setenv("PIPEWIRE_DEBUG", "4", 0);
165
+ setenv("WIREPLUMBER_DEBUG", "4", 0);
166
+
167
+ r = dup2(stderr_fd, STDERR_FILENO);
168
+ spa_assert_se(r != -1);
169
+ r = dup2(stderr_fd, STDOUT_FILENO);
170
+ spa_assert_se(r != -1);
171
172
- dup2(stderr_fd, STDERR_FILENO);
173
- setlinebuf(stderr);
174
execl(daemon, daemon, (char*)NULL);
175
return -errno;
176
177
+ } else if (pid < 0) {
178
+ return pid;
179
}
180
181
+ add_cleanup_pid(ctx, -pid);
182
+
183
/* parent */
184
sleep(1); /* FIXME how to wait for pw to be ready? */
185
if (waitpid(pid, &status, WNOHANG) > 0) {
186
187
replace_env(t, "TMPDIR", xdg_runtime_dir);
188
189
replace_env(t, "SPA_PLUGIN_DIR", BUILD_ROOT "/spa/plugins");
190
+ replace_env(t, "SPA_DATA_DIR", SOURCE_ROOT "/spa/plugins");
191
replace_env(t, "PIPEWIRE_CONFIG_DIR", BUILD_ROOT "/src/daemon");
192
replace_env(t, "PIPEWIRE_MODULE_DIR", BUILD_ROOT "/src/modules");
193
replace_env(t, "ACP_PATHS_DIR", SOURCE_ROOT "/spa/plugins/alsa/mixer/paths");
194
195
static void close_pipes(int fds[_FD_LAST])
196
{
197
for (int i = 0; i < _FD_LAST; i++) {
198
- close(fds[i]);
199
+ if (fds[i] >= 0)
200
+ close(fds[i]);
201
fds[i] = -1;
202
}
203
}
204
205
{
206
int r;
207
int i;
208
+ int pipe_max_size = 4194304;
209
210
for (i = 0; i < _FD_LAST; i++) {
211
read_fds[i] = -1;
212
write_fds[i] = -1;
213
}
214
215
+#ifdef __linux__
216
+ {
217
+ FILE *f;
218
+ f = fopen("/proc/sys/fs/pipe-max-size", "r");
219
+ if (f) {
220
+ if (fscanf(f, "%d", &r) == 1)
221
+ pipe_max_size = SPA_MIN(r, pipe_max_size);
222
+ fclose(f);
223
+ }
224
+ }
225
+#endif
226
+
227
for (i = 0; i < _FD_LAST; i++) {
228
int pipe[2];
229
230
- r = pipe2(pipe, O_NONBLOCK);
231
+ r = pipe2(pipe, O_CLOEXEC | O_NONBLOCK);
232
if (r < 0)
233
goto error;
234
read_fds[i] = pipe[0];
235
write_fds[i] = pipe[1];
236
+#ifdef __linux__
237
+ /* Max pipe buffers, to avoid scrambling if reading lags.
238
+ * Can't use blocking write fds, since reading too slow
239
+ * then affects execution.
240
+ */
241
+ fcntl(write_fds[i], F_SETPIPE_SZ, pipe_max_size);
242
+#endif
243
}
244
245
return 0;
246
247
248
close_pipes(read_fds);
249
250
+ /* Reset cleanup pid list */
251
+ free_cleanup_pids(ctx);
252
+
253
/* Catch any crashers so we can insert a backtrace */
254
sigemptyset(&act.sa_mask);
255
act.sa_flags = 0;
256
257
errno = -r;
258
goto error;
259
}
260
+ add_cleanup_pid(ctx, pid);
261
262
r = monitor_test_forked(t, pid, read_fds);
263
if (r < 0) {
264
errno = -r;
265
goto error;
266
}
267
+ remove_cleanup_pid(ctx, pid);
268
}
269
270
errno = 0;
271
272
if (errno)
273
t->sig_or_errno = -errno;
274
275
+ if (ctx->terminate) {
276
+ char *buf = pw_array_add(&t->logs[FD_LOG], 64);
277
+ spa_scnprintf(buf, 64, "pwtest: tests terminated by signal\n");
278
+ t->result = PWTEST_SYSTEM_ERROR;
279
+ }
280
+
281
for (size_t i = 0; i < SPA_N_ELEMENTS(read_fds); i++) {
282
log_append(&t->logs[i], read_fds[i]);
283
}
284
285
if (pw_daemon > 0) {
286
int status;
287
288
- kill(pw_daemon, SIGTERM);
289
- r = waitpid(pw_daemon, &status, 0);
290
+ kill(-pw_daemon, SIGTERM);
291
+ remove_cleanup_pid(ctx, -pw_daemon);
292
+
293
+ /* blocking read. the other end closes when done */
294
+ close_pipes(write_fds);
295
+ fcntl(read_fds[FD_DAEMON], F_SETFL, O_CLOEXEC);
296
+ do {
297
+ log_append(&t->logs[FD_DAEMON], read_fds[FD_DAEMON]);
298
+ } while ((r = waitpid(pw_daemon, &status, WNOHANG)) == 0);
299
+
300
if (r > 0) {
301
/* write_fds are closed in the parent process, so we append directly */
302
char *buf = pw_array_add(&t->logs[FD_DAEMON], 64);
303
304
r = EXIT_FAILURE;
305
break;
306
}
307
+
308
+ if (ctx->terminate) {
309
+ r = EXIT_FAILURE;
310
+ return r;
311
+ }
312
}
313
}
314
}
315
316
" -h, --help Show this help\n"
317
" --verbose Verbose output\n"
318
" --list List all available suites and tests\n"
319
- " --timeout=N Set the test timeout to N seconds (default: 30)\n"
320
+ " --timeout=N Set the test timeout to N seconds (default: 15)\n"
321
" --filter-test=glob Run only tests matching the given glob\n"
322
" --filter-suites=glob Run only suites matching the given glob\n"
323
" --filter-iteration=N Run only iteration N\n"
324
325
progname);
326
}
327
328
+static void sigterm_handler(int signo)
329
+{
330
+ terminate_cleanup_pids(ctx);
331
+ ctx->terminate = true;
332
+ if (ctx->no_fork) {
333
+ signal(SIGTERM, SIG_DFL);
334
+ signal(SIGINT, SIG_DFL);
335
+ raise(signo);
336
+ }
337
+}
338
+
339
int main(int argc, char **argv)
340
{
341
int r = EXIT_SUCCESS;
342
343
};
344
struct pwtest_context test_ctx = {
345
.suites = SPA_LIST_INIT(&test_ctx.suites),
346
- .timeout = 30,
347
+ .timeout = 15,
348
.has_iteration_filter = false,
349
};
350
enum {
351
352
} mode = MODE_TEST;
353
const char *suite_filter = NULL;
354
355
+ spa_list_init(&test_ctx.cleanup_pids);
356
+
357
ctx = &test_ctx;
358
359
while (1) {
360
361
break;
362
case MODE_TEST:
363
setrlimit(RLIMIT_CORE, &((struct rlimit){0, 0}));
364
+ signal(SIGTERM, sigterm_handler);
365
+ signal(SIGINT, sigterm_handler);
366
r = run_tests(ctx);
367
break;
368
}
369
pipewire-0.3.48.tar.gz/test/pwtest.h -> pipewire-0.3.49.tar.gz/test/pwtest.h
Changed
13
1
2
*/
3
void pwtest_mkstemp(char path[PATH_MAX]);
4
5
+/**
6
+ * Run a command and wait for it to return.
7
+ */
8
+int pwtest_spawn(const char *file, char *const argv[]);
9
+
10
11
/**
12
* \}
13
pipewire-0.3.49.tar.gz/test/test-functional.c
Added
64
1
2
+/* PipeWire
3
+ *
4
+ * Copyright © 2019 Wim Taymans
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a
7
+ * copy of this software and associated documentation files (the "Software"),
8
+ * to deal in the Software without restriction, including without limitation
9
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
+ * and/or sell copies of the Software, and to permit persons to whom the
11
+ * Software is furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice (including the next
14
+ * paragraph) shall be included in all copies or substantial portions of the
15
+ * Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23
+ * DEALINGS IN THE SOFTWARE.
24
+ */
25
+
26
+
27
+#include "config.h"
28
+
29
+#include "pwtest.h"
30
+
31
+PWTEST(openal_info_test)
32
+{
33
+ int status;
34
+
35
+#ifdef OPENAL_INFO_PATH
36
+ status = pwtest_spawn(OPENAL_INFO_PATH, (char *[]){ "openal-info", NULL });
37
+ pwtest_int_eq(WEXITSTATUS(status), 0);
38
+ return PWTEST_PASS;
39
+#else
40
+ return PWTEST_SKIP;
41
+#endif
42
+}
43
+
44
+PWTEST(pactl_test)
45
+{
46
+ int status;
47
+
48
+#ifdef PACTL_PATH
49
+ status = pwtest_spawn(PACTL_PATH, (char *[]){ "pactl", "info", NULL });
50
+ pwtest_int_eq(WEXITSTATUS(status), 0);
51
+ return PWTEST_PASS;
52
+#else
53
+ return PWTEST_SKIP;
54
+#endif
55
+}
56
+
57
+PWTEST_SUITE(pw_array)
58
+{
59
+ pwtest_add(pactl_test, PWTEST_ARG_DAEMON);
60
+ pwtest_add(openal_info_test, PWTEST_ARG_DAEMON);
61
+
62
+ return PWTEST_PASS;
63
+}
64
pipewire-0.3.48.tar.gz/test/test-lib.c -> pipewire-0.3.49.tar.gz/test/test-lib.c
Changed
23
1
2
return PWTEST_PASS;
3
}
4
5
+PWTEST(init_deinit)
6
+{
7
+ pw_init(0, NULL);
8
+ pw_deinit();
9
+ pw_init(0, NULL);
10
+ pw_init(0, NULL);
11
+ pw_deinit();
12
+ pw_deinit();
13
+ return PWTEST_PASS;
14
+}
15
+
16
PWTEST_SUITE(properties)
17
{
18
pwtest_add(library_version, PWTEST_NOARG);
19
+ pwtest_add(init_deinit, PWTEST_NOARG);
20
21
return PWTEST_PASS;
22
}
23
pipewire-0.3.48.tar.gz/test/test-loop.c -> pipewire-0.3.49.tar.gz/test/test-loop.c
Changed
246
1
2
int count;
3
};
4
5
+static inline void write_eventfd(int evfd)
6
+{
7
+ uint64_t value = 1;
8
+ ssize_t r = write(evfd, &value, sizeof(value));
9
+ pwtest_errno_ok(r);
10
+ pwtest_int_eq(r, (ssize_t) sizeof(value));
11
+}
12
+
13
+static inline void read_eventfd(int evfd)
14
+{
15
+ uint64_t value = 0;
16
+ ssize_t r = read(evfd, &value, sizeof(value));
17
+ pwtest_errno_ok(r);
18
+ pwtest_int_eq(r, (ssize_t) sizeof(value));
19
+}
20
+
21
static void on_event(struct spa_source *source)
22
{
23
struct data *d = source->data;
24
25
pw_loop_add_source(data.l, &data.a->source);
26
pw_loop_add_source(data.l, &data.b->source);
27
28
- write(data.a->source.fd, &(uint64_t){1}, sizeof(uint64_t));
29
- write(data.b->source.fd, &(uint64_t){1}, sizeof(uint64_t));
30
+ write_eventfd(data.a->source.fd);
31
+ write_eventfd(data.b->source.fd);
32
33
pw_main_loop_run(data.ml);
34
pw_main_loop_destroy(data.ml);
35
36
{
37
static bool first = true;
38
struct data *d = source->data;
39
- uint64_t val;
40
41
++d->count;
42
pwtest_int_lt(d->count, 3);
43
44
- read(source->fd, &val, sizeof(val));
45
+ read_eventfd(source->fd);
46
47
if (first) {
48
first = false;
49
50
pw_loop_add_source(data.l, &data.a->source);
51
pw_loop_add_source(data.l, &data.b->source);
52
53
- write(data.a->source.fd, &(uint64_t){1}, sizeof(uint64_t));
54
- write(data.b->source.fd, &(uint64_t){1}, sizeof(uint64_t));
55
+ write_eventfd(data.a->source.fd);
56
+ write_eventfd(data.b->source.fd);
57
58
pw_main_loop_run(data.ml);
59
pw_main_loop_destroy(data.ml);
60
61
{
62
static bool first = true;
63
struct data *d = source->data;
64
- uint64_t val;
65
66
++d->count;
67
pwtest_int_lt(d->count, 3);
68
69
- read(source->fd, &val, sizeof(val));
70
+ read_eventfd(source->fd);
71
72
if (first) {
73
first = false;
74
75
pw_loop_add_source(data.l, &data.a->source);
76
pw_loop_add_source(data.l, &data.b->source);
77
78
- write(data.a->source.fd, &(uint64_t){1}, sizeof(uint64_t));
79
- write(data.b->source.fd, &(uint64_t){1}, sizeof(uint64_t));
80
+ write_eventfd(data.a->source.fd);
81
+ write_eventfd(data.b->source.fd);
82
83
pw_main_loop_run(data.ml);
84
pw_main_loop_destroy(data.ml);
85
86
return PWTEST_PASS;
87
}
88
89
-PWTEST(thread_loop_destroy_between_poll_and_lock)
90
+static void
91
+on_event_fail_if_called(void *data, int fd, uint32_t mask)
92
+{
93
+ pwtest_fail_if_reached();
94
+}
95
+
96
+struct dmsbd_data {
97
+ struct pw_loop *l;
98
+ struct pw_main_loop *ml;
99
+ struct spa_source *source;
100
+ struct spa_hook hook;
101
+};
102
+
103
+static void dmsbd_after(void *data)
104
+{
105
+ struct dmsbd_data *d = data;
106
+
107
+ pw_loop_destroy_source(d->l, d->source);
108
+ pw_main_loop_quit(d->ml);
109
+}
110
+
111
+static const struct spa_loop_control_hooks dmsbd_hooks = {
112
+ SPA_VERSION_LOOP_CONTROL_HOOKS,
113
+ .after = dmsbd_after,
114
+};
115
+
116
+PWTEST(destroy_managed_source_before_dispatch)
117
{
118
pw_init(NULL, NULL);
119
120
- struct pw_thread_loop *thread_loop = pw_thread_loop_new("uaf", NULL);
121
- pwtest_ptr_notnull(thread_loop);
122
+ struct dmsbd_data data = {0};
123
+
124
+ data.ml = pw_main_loop_new(NULL);
125
+ pwtest_ptr_notnull(data.ml);
126
+
127
+ data.l = pw_main_loop_get_loop(data.ml);
128
+ pwtest_ptr_notnull(data.l);
129
+
130
+ data.source = pw_loop_add_io(data.l, eventfd(0, 0), SPA_IO_IN, true, on_event_fail_if_called, NULL);
131
+ pwtest_ptr_notnull(data.source);
132
133
- struct pw_loop *loop = pw_thread_loop_get_loop(thread_loop);
134
- pwtest_ptr_notnull(loop);
135
+ pw_loop_add_hook(data.l, &data.hook, &dmsbd_hooks, &data);
136
137
- int evfd = eventfd(0, 0);
138
- pwtest_errno_ok(evfd);
139
+ write_eventfd(data.source->fd);
140
141
- struct spa_source *source = pw_loop_add_io(loop, evfd, SPA_IO_IN, true, NULL, NULL);
142
- pwtest_ptr_notnull(source);
143
+ pw_main_loop_run(data.ml);
144
+ pw_main_loop_destroy(data.ml);
145
146
- pw_thread_loop_start(thread_loop);
147
+ pw_deinit();
148
149
- pw_thread_loop_lock(thread_loop);
150
- {
151
- write(evfd, &(uint64_t){1}, sizeof(uint64_t));
152
- sleep(1);
153
- pw_loop_destroy_source(loop, source);
154
+ return PWTEST_PASS;
155
+}
156
+
157
+struct dmsbd_recurse_data {
158
+ struct pw_loop *l;
159
+ struct pw_main_loop *ml;
160
+ struct spa_source *a, *b;
161
+ struct spa_hook hook;
162
+ bool first;
163
+};
164
+
165
+static void dmsbd_recurse_on_event(void *data, int fd, uint32_t mask)
166
+{
167
+ struct dmsbd_recurse_data *d = data;
168
+
169
+ read_eventfd(fd);
170
+
171
+ pw_loop_enter(d->l);
172
+ pw_loop_iterate(d->l, 0);
173
+ pw_loop_leave(d->l);
174
+
175
+ pw_main_loop_quit(d->ml);
176
+}
177
+
178
+static void dmswp_recurse_before(void *data)
179
+{
180
+ struct dmsbd_recurse_data *d = data;
181
+
182
+ if (d->first) {
183
+ write_eventfd(d->a->fd);
184
+ write_eventfd(d->b->fd);
185
}
186
- pw_thread_loop_unlock(thread_loop);
187
+}
188
+
189
+static void dmsbd_recurse_after(void *data)
190
+{
191
+ struct dmsbd_recurse_data *d = data;
192
+
193
+ if (d->first) {
194
+ pw_loop_destroy_source(d->l, d->b);
195
+
196
+ d->first = false;
197
+ }
198
+}
199
+
200
+static const struct spa_loop_control_hooks dmsbd_recurse_hooks = {
201
+ SPA_VERSION_LOOP_CONTROL_HOOKS,
202
+ .before = dmswp_recurse_before,
203
+ .after = dmsbd_recurse_after,
204
+};
205
+
206
+PWTEST(destroy_managed_source_before_dispatch_recurse)
207
+{
208
+ pw_init(NULL, NULL);
209
+
210
+ struct dmsbd_recurse_data data = {
211
+ .first = true,
212
+ };
213
+
214
+ data.ml = pw_main_loop_new(NULL);
215
+ pwtest_ptr_notnull(data.ml);
216
+
217
+ data.l = pw_main_loop_get_loop(data.ml);
218
+ pwtest_ptr_notnull(data.l);
219
+
220
+ data.l = pw_main_loop_get_loop(data.ml);
221
+ pwtest_ptr_notnull(data.l);
222
223
- pw_thread_loop_destroy(thread_loop);
224
+ data.a = pw_loop_add_io(data.l, eventfd(0, 0), SPA_IO_IN, true, dmsbd_recurse_on_event, &data);
225
+ data.b = pw_loop_add_io(data.l, eventfd(0, 0), SPA_IO_IN, true, on_event_fail_if_called, NULL);
226
+ pwtest_ptr_notnull(data.a);
227
+ pwtest_ptr_notnull(data.b);
228
+
229
+ pw_loop_add_hook(data.l, &data.hook, &dmsbd_recurse_hooks, &data);
230
+
231
+ pw_main_loop_run(data.ml);
232
+ pw_main_loop_destroy(data.ml);
233
234
pw_deinit();
235
236
237
pwtest_add(pwtest_loop_destroy2, PWTEST_NOARG);
238
pwtest_add(pwtest_loop_recurse1, PWTEST_NOARG);
239
pwtest_add(pwtest_loop_recurse2, PWTEST_NOARG);
240
- pwtest_add(thread_loop_destroy_between_poll_and_lock, PWTEST_NOARG);
241
+ pwtest_add(destroy_managed_source_before_dispatch, PWTEST_NOARG);
242
+ pwtest_add(destroy_managed_source_before_dispatch_recurse, PWTEST_NOARG);
243
244
return PWTEST_PASS;
245
}
246
pipewire-0.3.48.tar.gz/test/test-spa-json.c -> pipewire-0.3.49.tar.gz/test/test-spa-json.c
Changed
83
1
2
* DEALINGS IN THE SOFTWARE.
3
*/
4
5
+#include <locale.h>
6
+
7
#include "pwtest.h"
8
9
#include <spa/utils/defs.h>
10
11
return PWTEST_PASS;
12
}
13
14
+PWTEST(json_float)
15
+{
16
+ struct {
17
+ const char *str;
18
+ double val;
19
+ } val[] = {
20
+ { "0.0", 0.0f },
21
+ { ".0", 0.0f },
22
+ { ".0E0", 0.0E0f },
23
+ { "1.0", 1.0f },
24
+ { "1.011", 1.011f },
25
+ { "176543.123456", 176543.123456f },
26
+ { "-176543.123456", -176543.123456f },
27
+ { "-5678.5432E10", -5678.5432E10f },
28
+ { "-5678.5432e10", -5678.5432e10f },
29
+ { "-5678.5432e-10", -5678.5432e-10f },
30
+ { "5678.5432e+10", 5678.5432e+10f },
31
+ { "00.000100", 00.000100f },
32
+ { "-0.000100", -0.000100f },
33
+ };
34
+ float v;
35
+ unsigned i;
36
+ char buf1[128], buf2[128], *b1 = buf1, *b2 = buf2;
37
+
38
+ pwtest_int_eq(spa_json_parse_float("", 0, &v), 0);
39
+
40
+ setlocale(LC_NUMERIC, "C");
41
+ for (i = 0; i < SPA_N_ELEMENTS(val); i++) {
42
+ pwtest_int_gt(spa_json_parse_float(val[i].str, strlen(val[i].str), &v), 0);
43
+ pwtest_double_eq(v, val[i].val);
44
+ }
45
+ setlocale(LC_NUMERIC, "fr_FR");
46
+ for (i = 0; i < SPA_N_ELEMENTS(val); i++) {
47
+ pwtest_int_gt(spa_json_parse_float(val[i].str, strlen(val[i].str), &v), 0);
48
+ pwtest_double_eq(v, val[i].val);
49
+ }
50
+ pwtest_ptr_eq(spa_json_format_float(buf1, sizeof(buf1), 0.0f), b1);
51
+ pwtest_str_eq(buf1, "0.000000");
52
+ pwtest_ptr_eq(spa_json_format_float(buf1, sizeof(buf1), NAN), b1);
53
+ pwtest_str_eq(buf1, "0.000000");
54
+ pwtest_ptr_eq(spa_json_format_float(buf1, sizeof(buf1), INFINITY), b1);
55
+ pwtest_ptr_eq(spa_json_format_float(buf2, sizeof(buf2), FLT_MAX), b2);
56
+ pwtest_str_eq(buf1, buf2);
57
+ pwtest_ptr_eq(spa_json_format_float(buf1, sizeof(buf1), -INFINITY), b1);
58
+ pwtest_ptr_eq(spa_json_format_float(buf2, sizeof(buf2), FLT_MIN), b2);
59
+ pwtest_str_eq(buf1, buf2);
60
+
61
+ return PWTEST_PASS;
62
+}
63
+
64
+PWTEST(json_int)
65
+{
66
+ int v;
67
+ pwtest_int_eq(spa_json_parse_int("", 0, &v), 0);
68
+ return PWTEST_PASS;
69
+}
70
+
71
PWTEST_SUITE(spa_json)
72
{
73
pwtest_add(json_abi, PWTEST_NOARG);
74
75
pwtest_add(json_encode, PWTEST_NOARG);
76
pwtest_add(json_array, PWTEST_NOARG);
77
pwtest_add(json_overflow, PWTEST_NOARG);
78
+ pwtest_add(json_float, PWTEST_NOARG);
79
+ pwtest_add(json_int, PWTEST_NOARG);
80
81
return PWTEST_PASS;
82
}
83
Refresh
No build results available
Refresh
No rpmlint results available
Login required, please
login
or
signup
in order to comment
Request History
zaitor created request about 3 years ago
New upstream release
zaitor accepted request about 3 years ago
Xin