Overview
pipewire-aptx.changes
Changed
x
1
2
-------------------------------------------------------------------
3
+Mon Mar 13 12:30:13 UTC 2023 - Bjørn Lie <zaitor@opensuse.org>
4
+
5
+- Update to version 0.3.66
6
+
7
+-------------------------------------------------------------------
8
Thu Jan 26 20:45:06 UTC 2023 - Bjørn Lie <zaitor@opensuse.org>
9
10
- Update to version 0.3.65
11
pipewire-aptx.spec
Changed
10
1
2
%define soversion 0_2
3
4
Name: pipewire-aptx
5
-Version: 0.3.65
6
+Version: 0.3.66
7
Release: 0
8
Summary: PipeWire Bluetooth aptX codec plugin
9
License: MIT
10
pipewire-0.3.65.tar.gz/spa/plugins/libcamera/libcamera-client.c
Deleted
249
1
2
-/* Spa libcamera client
3
- *
4
- * Copyright (C) 2020, Collabora Ltd.
5
- * Author: Raghavendra Rao Sidlagatta <raghavendra.rao@collabora.com>
6
- *
7
- * libcamera-client.c
8
- *
9
- * Permission is hereby granted, free of charge, to any person obtaining a
10
- * copy of this software and associated documentation files (the "Software"),
11
- * to deal in the Software without restriction, including without limitation
12
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13
- * and/or sell copies of the Software, and to permit persons to whom the
14
- * Software is furnished to do so, subject to the following conditions:
15
- *
16
- * The above copyright notice and this permission notice (including the next
17
- * paragraph) shall be included in all copies or substantial portions of the
18
- * Software.
19
- *
20
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26
- * DEALINGS IN THE SOFTWARE.
27
- */
28
-
29
-#include <errno.h>
30
-#include <stddef.h>
31
-#include <stdio.h>
32
-#include <sys/types.h>
33
-#include <sys/stat.h>
34
-#include <fcntl.h>
35
-
36
-#include <spa/support/log.h>
37
-#include <spa/support/loop.h>
38
-#include <spa/support/plugin.h>
39
-#include <spa/utils/type.h>
40
-#include <spa/utils/keys.h>
41
-#include <spa/utils/names.h>
42
-#include <spa/utils/string.h>
43
-#include <spa/monitor/device.h>
44
-#include <spa/monitor/utils.h>
45
-
46
-#include "libcamera.h"
47
-
48
-struct impl {
49
- struct spa_handle handle;
50
- struct spa_device device;
51
-
52
- struct spa_log *log;
53
- struct spa_loop *main_loop;
54
-
55
- struct spa_hook_list hooks;
56
-
57
- uint64_t info_all;
58
- struct spa_device_info info;
59
-
60
- struct spa_source source;
61
-};
62
-
63
-static int emit_object_info(struct impl *this, uint32_t id)
64
-{
65
- struct spa_device_object_info info;
66
- struct spa_dict_item items20;
67
- uint32_t n_items = 0;
68
-
69
- info = SPA_DEVICE_OBJECT_INFO_INIT();
70
-
71
- info.type = SPA_TYPE_INTERFACE_Device;
72
- info.factory_name = SPA_NAME_API_LIBCAMERA_DEVICE;
73
- info.change_mask = (SPA_DEVICE_OBJECT_CHANGE_MASK_FLAGS |
74
- SPA_DEVICE_OBJECT_CHANGE_MASK_PROPS);
75
- info.flags = 0;
76
-
77
- itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_ENUM_API,"libcamera-client");
78
- itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_API, "libcamera");
79
- itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_MEDIA_CLASS, "Video/Device");
80
-
81
- info.props = &SPA_DICT_INIT(items, n_items);
82
- spa_device_emit_object_info(&this->hooks, id, &info);
83
-
84
- return 1;
85
-}
86
-
87
-static const struct spa_dict_item device_info_items = {
88
- { SPA_KEY_DEVICE_API, "libcamera" },
89
- { SPA_KEY_DEVICE_NICK, "libcamera-client" },
90
- { SPA_KEY_API_UDEV_MATCH, "libcamera" },
91
-};
92
-
93
-
94
-static void emit_device_info(struct impl *this, bool full)
95
-{
96
- uint64_t old = full ? this->info.change_mask : 0;
97
- if (full)
98
- this->info.change_mask = this->info_all;
99
- if (this->info.change_mask) {
100
- this->info.props = &SPA_DICT_INIT_ARRAY(device_info_items);
101
- spa_device_emit_info(&this->hooks, &this->info);
102
- this->info.change_mask = old;
103
- }
104
-}
105
-
106
-static void impl_hook_removed(struct spa_hook *hook)
107
-{
108
- return;
109
-}
110
-
111
-static int
112
-impl_device_add_listener(void *object, struct spa_hook *listener,
113
- const struct spa_device_events *events, void *data)
114
-{
115
- struct impl *this = object;
116
- struct spa_hook_list save;
117
-
118
- spa_return_val_if_fail(this != NULL, -EINVAL);
119
- spa_return_val_if_fail(events != NULL, -EINVAL);
120
-
121
- spa_hook_list_isolate(&this->hooks, &save, listener, events, data);
122
-
123
- emit_device_info(this, true);
124
-
125
- emit_object_info(this, 0);
126
-
127
- spa_hook_list_join(&this->hooks, &save);
128
-
129
- listener->removed = impl_hook_removed;
130
- listener->priv = this;
131
-
132
- return 0;
133
-}
134
-
135
-static const struct spa_device_methods impl_device = {
136
- SPA_VERSION_DEVICE_METHODS,
137
- .add_listener = impl_device_add_listener,
138
-};
139
-
140
-static int impl_get_interface(struct spa_handle *handle, const char *type, void **interface)
141
-{
142
- struct impl *this;
143
-
144
- spa_return_val_if_fail(handle != NULL, -EINVAL);
145
- spa_return_val_if_fail(interface != NULL, -EINVAL);
146
-
147
- this = (struct impl *) handle;
148
-
149
- if (spa_streq(type, SPA_TYPE_INTERFACE_Device))
150
- *interface = &this->device;
151
- else
152
- return -ENOENT;
153
-
154
- return 0;
155
-}
156
-
157
-static int impl_clear(struct spa_handle *handle)
158
-{
159
- struct impl *this = (struct impl *) handle;
160
-
161
- if(this->dev.camera) {
162
- deleteLibCamera(this->dev.camera);
163
- this->dev.camera = NULL;
164
- }
165
- return 0;
166
-}
167
-
168
-static size_t
169
-impl_get_size(const struct spa_handle_factory *factory,
170
- const struct spa_dict *params)
171
-{
172
- return sizeof(struct impl);
173
-}
174
-
175
-static int
176
-impl_init(const struct spa_handle_factory *factory,
177
- struct spa_handle *handle,
178
- const struct spa_dict *info,
179
- const struct spa_support *support,
180
- uint32_t n_support)
181
-{
182
- struct impl *this;
183
-
184
- spa_return_val_if_fail(factory != NULL, -EINVAL);
185
- spa_return_val_if_fail(handle != NULL, -EINVAL);
186
-
187
- handle->get_interface = impl_get_interface;
188
- handle->clear = impl_clear;
189
-
190
- this = (struct impl *) handle;
191
-
192
- this->log = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_Log);
193
- libcamera_log_topic_init(this->log);
194
-
195
- this->main_loop = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_Loop);
196
-
197
- if (this->main_loop == NULL) {
198
- spa_log_error(this->log, "a main-loop is needed");
199
- return -EINVAL;
200
- }
201
- spa_hook_list_init(&this->hooks);
202
-
203
- this->device.iface = SPA_INTERFACE_INIT(
204
- SPA_TYPE_INTERFACE_Device,
205
- SPA_VERSION_DEVICE,
206
- &impl_device, this);
207
-
208
- this->info = SPA_DEVICE_INFO_INIT();
209
- this->info_all = SPA_DEVICE_CHANGE_MASK_FLAGS |
210
- SPA_DEVICE_CHANGE_MASK_PROPS;
211
- this->info.flags = 0;
212
-
213
- if(this->dev.camera == NULL)
214
- this->dev.camera = (LibCamera*)newLibCamera();
215
- if(this->dev.camera != NULL)
216
- libcamera_set_log(this->dev.camera, this->dev.log);
217
-
218
- return 0;
219
-}
220
-
221
-static const struct spa_interface_info impl_interfaces = {
222
- {SPA_TYPE_INTERFACE_Device,},
223
-};
224
-
225
-static int
226
-impl_enum_interface_info(const struct spa_handle_factory *factory,
227
- const struct spa_interface_info **info,
228
- uint32_t *index)
229
-{
230
- spa_return_val_if_fail(factory != NULL, -EINVAL);
231
- spa_return_val_if_fail(info != NULL, -EINVAL);
232
- spa_return_val_if_fail(index != NULL, -EINVAL);
233
-
234
- if (*index >= SPA_N_ELEMENTS(impl_interfaces))
235
- return 0;
236
-
237
- *info = &impl_interfaces(*index)++;
238
- return 1;
239
-}
240
-
241
-const struct spa_handle_factory spa_libcamera_client_factory = {
242
- SPA_VERSION_HANDLE_FACTORY,
243
- SPA_NAME_API_LIBCAMERA_ENUM_CLIENT,
244
- NULL,
245
- impl_get_size,
246
- impl_init,
247
- impl_enum_interface_info,
248
-};
249
pipewire-0.3.65.tar.gz/.gitignore -> pipewire-0.3.66.tar.gz/.gitignore
Changed
13
1
2
subprojects/wireplumber
3
subprojects/media-session
4
subprojects/packagecache
5
+subprojects/googletest*
6
+subprojects/gtest.wrap
7
+subprojects/libyaml.wrap
8
+subprojects/libyaml
9
+subprojects/libcamera
10
11
# Created by https://www.gitignore.io/api/vim
12
13
pipewire-0.3.65.tar.gz/.gitlab-ci.yml -> pipewire-0.3.66.tar.gz/.gitlab-ci.yml
Changed
18
1
2
.fedora:
3
variables:
4
# Update this tag when you want to trigger a rebuild
5
- FDO_DISTRIBUTION_TAG: '2022-11-07.0'
6
+ FDO_DISTRIBUTION_TAG: '2023-01-18.0'
7
FDO_DISTRIBUTION_VERSION: '35'
8
FDO_DISTRIBUTION_PACKAGES: >-
9
alsa-lib-devel
10
11
jack-audio-connection-kit-devel
12
libcanberra-devel
13
libldac-devel
14
+ libmysofa-devel
15
libsndfile-devel
16
libusb-devel
17
lilv-devel
18
pipewire-0.3.65.tar.gz/NEWS -> pipewire-0.3.66.tar.gz/NEWS
Changed
93
1
2
+# PipeWire 0.3.66 (2023-02-16)
3
+
4
+This is a bugfix release that is API and ABI compatible with previous
5
+0.3.x releases.
6
+
7
+## Highlights
8
+ - Fix a regression in the pulseaudio module-combine-stream because the new
9
+ module-combine-stream was not installed.
10
+ - PipeWire can now generate a limits.d config file with our recommended
11
+ settings for priorities and memlock.
12
+
13
+
14
+## PipeWire
15
+ - Avoid rate switches when the graph is idle.
16
+ - The rate selection algorithm was improved. This ensures minimal performance
17
+ and quality loss when resampling.
18
+ - The default min.quantum was set to 32 again after it got erronously changed
19
+ to (the too low) 16 in version 0.3.45.
20
+ - Fix compilation issues with rust bindings because of macros in defines.
21
+ Work around it for now. (#2952)
22
+ - Invalid file mappings are now refused (#2617 #2914 #3007)
23
+ - Modules, exec and objects can now be loaded depending on conditions. One
24
+ example is the X11-bell module that can now be disabled with a custom
25
+ property override.
26
+ - Filter now also supports _trigger_process() to drive the graph.
27
+ - TID is now added to the journald log.
28
+ - PipeWire generates and installs */etc/security/limits.d/25-pw-rlimits.conf*
29
+ that by default contains project's recommended settings. Creation of the
30
+ pipewire group is left to the distro or user ( `groupadd -r pipewire` ).
31
+ See the rlimits-* Meson options for controlling this behavior.
32
+ - Additionally there is now by default disabled Meson option that will
33
+ install */etc/security/limits.d/20-pw-defaults.conf* with the current Linux
34
+ default memlock value. Distros with only kernels >=5.16 or always using
35
+ systemd v251 or newer do not need this. But all other builds should set the
36
+ `-Dpam-defaults-install=true` Meson option to ensure that the memlock value
37
+ is always large enough. Thanks to Rickie Schroeder for pointing out that
38
+ the default Linux memlock value has been somewhat recently increased.
39
+
40
+## modules
41
+ - Install module-combine-stream.
42
+ - RTP source now has support for custom channel names.
43
+ - RTP source will now stop when inactive.
44
+ - There is now
45
+ - Filter-chain has a new mysofa based spacializer plugin.
46
+ - The RTP modules can now use direct clock timestamps to send and receive
47
+ packets. This makes it possible to synchronize sender and receiver with
48
+ a PTP clock, for example.
49
+ - Filter-chain now has an invert plugin to invert the polarity of a
50
+ signal. (#3008)
51
+
52
+## SPA
53
+ - There is now an option to set the channels used for probing Pro Audio
54
+ devices. This could unlock more samplerates for some devices when they are
55
+ probed with fewer channels. (#2990)
56
+ - Support was added for other clocks than the MONOTONIC clock in the
57
+ driver nodes. This can be used to synchronize the graph to a PTP clock,
58
+ for example.
59
+ - The ALSA source has some more headroom when rate matching to avoid
60
+ stuttering when following another driver.
61
+ - libcamera controls are now mapped to standard PipeWire property values.
62
+ - The channelmixer has seen some improvements. MONO and undefined channel
63
+ layouts are now upmixed and downmixed more correctly. (#3010)
64
+
65
+## Bluetooth
66
+ - Many BAP support fixes.
67
+
68
+## GStreamer
69
+ - The gstreamer elements now support buffer video metadata so that strides
70
+ are correctly handled.
71
+ - pipewiresrc will now error out correctly in more cases. (#2935)
72
+
73
+## JACK
74
+ - The frame to/from time functions are improved to also work with negative
75
+ time and frame offsets.
76
+
77
+Older versions:
78
+
79
+
80
# PipeWire 0.3.65 (2023-01-26)
81
82
This is a bugfix release that is API and ABI compatible with previous
83
84
this.
85
- pipewiresrc will now always be a live source unless told otherwise.
86
87
-Older versions:
88
-
89
-
90
# PipeWire 0.3.64 (2023-01-12)
91
92
This is a bugfix release that is API and ABI compatible with previous
93
pipewire-0.3.65.tar.gz/meson.build -> pipewire-0.3.66.tar.gz/meson.build
Changed
18
1
2
project('pipewire', 'c' ,
3
- version : '0.3.65',
4
+ version : '0.3.66',
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
9
sndfile_dep = dependency('sndfile', version : '>= 1.0.20', required : get_option('sndfile'))
10
summary({'sndfile': sndfile_dep.found()}, bool_yn: true, section: 'pw-cat/pw-play/pw-dump/filter-chain')
11
cdata.set('HAVE_SNDFILE', sndfile_dep.found())
12
+libmysofa_dep = dependency('libmysofa', required : get_option('libmysofa'))
13
+summary({'libmysofa': libmysofa_dep.found()}, bool_yn: true, section: 'filter-chain')
14
+cdata.set('HAVE_LIBMYSOFA', libmysofa_dep.found())
15
pulseaudio_dep = dependency('libpulse', required : get_option('libpulse'))
16
summary({'libpulse': pulseaudio_dep.found()}, bool_yn: true, section: 'Streaming between daemons')
17
avahi_dep = dependency('avahi-client', required : get_option('avahi'))
18
pipewire-0.3.65.tar.gz/meson_options.txt -> pipewire-0.3.66.tar.gz/meson_options.txt
Changed
49
1
2
description: 'Enable code that depends on libsndfile',
3
type: 'feature',
4
value: 'auto')
5
+option('libmysofa',
6
+ description: 'Enable code that depends on libmysofa',
7
+ type: 'feature',
8
+ value: 'auto')
9
option('libpulse',
10
description: 'Enable code that depends on libpulse',
11
type: 'feature',
12
13
description: 'Enable ALSA Compress-Offload support',
14
type: 'feature',
15
value: 'disabled')
16
+option('pam-defaults-install',
17
+ description: 'Install limits.d file modifying defaults for all PAM users. Only for old kernels/systemd!',
18
+ type: 'boolean',
19
+ value: 'false')
20
+option('pam-memlock-default',
21
+ description : 'The default memlock value for any PAM user in kilobytes. Multiples of 64 recommended.',
22
+ type : 'integer',
23
+ min: 640,
24
+ value: 8192)
25
+option('rlimits-install',
26
+ description: 'Install PAM limits.d file. Voids all following rlimits-* options, if false',
27
+ type: 'boolean',
28
+ value: 'true')
29
+option('rlimits-match',
30
+ description : 'PAM match rule for the generated limits.d file. @<name> denotes matching a group.',
31
+ type : 'string',
32
+ value: '@pipewire')
33
+option('rlimits-rtprio',
34
+ description : 'RR and FIFO scheduler priority permitted for realtime threads of the matching user(s)',
35
+ type : 'integer',
36
+ min: 11,
37
+ max: 99,
38
+ value: 95)
39
+option('rlimits-memlock',
40
+ description : 'kB of memory each process of the user matched by the rule can lock. Can be unlimited .',
41
+ type : 'string',
42
+ value: '4194304')
43
+option('rlimits-nice',
44
+ description : 'Not niceness permitted for non-realtime threads of the matching user(s)',
45
+ type : 'integer',
46
+ min: -20,
47
+ max: -1,
48
+ value: -19)
49
pipewire-0.3.65.tar.gz/pipewire-jack/src/pipewire-jack.c -> pipewire-0.3.66.tar.gz/pipewire-jack/src/pipewire-jack.c
Changed
46
1
2
{
3
struct client *c = (struct client *) client;
4
struct spa_io_position *pos;
5
- double df;
6
7
spa_return_val_if_fail(c != NULL, -EINVAL);
8
9
- if (SPA_UNLIKELY((pos = c->rt.position) == NULL))
10
+ if (SPA_UNLIKELY((pos = c->rt.position) == NULL) || c->buffer_frames == 0)
11
return 0;
12
13
- df = (frames - pos->clock.position) * (double)SPA_NSEC_PER_SEC / c->sample_rate;
14
- return (pos->clock.nsec + (int64_t)rint(df)) / SPA_NSEC_PER_USEC;
15
+ uint32_t nf = (uint32_t)pos->clock.position;
16
+ uint64_t w = pos->clock.nsec/SPA_NSEC_PER_USEC;
17
+ uint64_t nw = pos->clock.next_nsec/SPA_NSEC_PER_USEC;
18
+ int32_t df = frames - nf;
19
+ int64_t dp = nw - w;
20
+ return w + (int64_t)rint((double) df * (double) dp / c->buffer_frames);
21
}
22
23
SPA_EXPORT
24
25
{
26
struct client *c = (struct client *) client;
27
struct spa_io_position *pos;
28
- double du;
29
30
spa_return_val_if_fail(c != NULL, -EINVAL);
31
32
if (SPA_UNLIKELY((pos = c->rt.position) == NULL))
33
return 0;
34
35
- du = (usecs - pos->clock.nsec/SPA_NSEC_PER_USEC) * (double)c->sample_rate / SPA_USEC_PER_SEC;
36
- return pos->clock.position + (int32_t)rint(du);
37
+ uint32_t nf = (uint32_t)pos->clock.position;
38
+ uint64_t w = pos->clock.nsec/SPA_NSEC_PER_USEC;
39
+ uint64_t nw = pos->clock.next_nsec/SPA_NSEC_PER_USEC;
40
+ int64_t du = usecs - w;
41
+ int64_t dp = nw - w;
42
+ return nf + (int32_t)rint((double)du / (double)dp * c->buffer_frames);
43
}
44
45
SPA_EXPORT
46
pipewire-0.3.65.tar.gz/po/oc.po -> pipewire-0.3.66.tar.gz/po/oc.po
Changed
850
1
2
-# French translation of pipewire.
3
+# Occitan translation of pipewire.
4
# Copyright (C) 2006-2008 Lennart Poettering
5
# This file is distributed under the same license as the pipewire package.
6
# Robert-André Mauchin <zebob.m@pengzone.org>, 2008.
7
8
# Thomas Canniot <mrtom@fedoraproject.org>, 2009, 2012.
9
# Cédric Valmary (Tot en Òc) <cvalmary@yahoo.fr>, 2015.
10
# Cédric Valmary (totenoc.eu) <cvalmary@yahoo.fr>, 2016.
11
+# Quentin PAGÈS, 2023.
12
msgid ""
13
msgstr ""
14
"Project-Id-Version: pipewire trunk\n"
15
"Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pipewire/pipewire/"
16
"issues/new\n"
17
-"POT-Creation-Date: 2021-04-18 16:54+0800\n"
18
-"PO-Revision-Date: 2016-10-12 22:20+0200\n"
19
-"Last-Translator: Cédric Valmary (totenoc.eu) <cvalmary@yahoo.fr>\n"
20
+"POT-Creation-Date: 2022-06-30 12:50+0200\n"
21
+"PO-Revision-Date: 2023-02-11 00:11+0100\n"
22
+"Last-Translator: Quentin PAGÈS\n"
23
"Language-Team: Tot En Òc\n"
24
"Language: oc\n"
25
"MIME-Version: 1.0\n"
26
"Content-Type: text/plain; charset=UTF-8\n"
27
"Content-Transfer-Encoding: 8bit\n"
28
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
29
-"X-Generator: Virtaal 0.7.1\n"
30
+"X-Generator: Poedit 3.2.2\n"
31
"X-Launchpad-Export-Date: 2016-10-12 20:12+0000\n"
32
33
-#: src/daemon/pipewire.c:43
34
+#: src/daemon/pipewire.c:46
35
#, c-format
36
msgid ""
37
"%s options\n"
38
39
" --version Show version\n"
40
" -c, --config Load config (Default %s)\n"
41
msgstr ""
42
+"%s opcions\n"
43
+" -h, --help Afichar aquesta ajuda\n"
44
+" --version Afichar la version\n"
45
+" -c, --config Cargar la conf. (Defaut %s)\n"
46
47
-#: src/daemon/pipewire.desktop.in:4
48
-msgid "PipeWire Media System"
49
-msgstr ""
50
-
51
-#: src/daemon/pipewire.desktop.in:5
52
-msgid "Start the PipeWire Media System"
53
-msgstr ""
54
+#: src/modules/module-protocol-pulse/modules/module-tunnel-sink.c:180
55
+#: src/modules/module-protocol-pulse/modules/module-tunnel-source.c:180
56
+#, c-format
57
+msgid "Tunnel to %s/%s"
58
+msgstr "Tunèl cap a %s/%s"
59
60
-#: src/examples/media-session/alsa-monitor.c:526
61
-#: spa/plugins/alsa/acp/compat.c:187
62
-msgid "Built-in Audio"
63
-msgstr "Àudio integrat"
64
+#: src/modules/module-fallback-sink.c:51
65
+msgid "Dummy Output"
66
+msgstr "Sortida factícia"
67
68
-#: src/examples/media-session/alsa-monitor.c:530
69
-#: spa/plugins/alsa/acp/compat.c:192
70
-msgid "Modem"
71
-msgstr "Modèm"
72
+#: src/modules/module-pulse-tunnel.c:662
73
+#, c-format
74
+msgid "Tunnel for %s@%s"
75
+msgstr "Tunèl per %s@%s"
76
77
-#: src/examples/media-session/alsa-monitor.c:539
78
+#: src/modules/module-zeroconf-discover.c:332
79
msgid "Unknown device"
80
-msgstr ""
81
+msgstr "Periferic desconegut"
82
+
83
+#: src/modules/module-zeroconf-discover.c:344
84
+#, c-format
85
+msgid "%s on %s@%s"
86
+msgstr "%s sus %s@%s"
87
88
-#: src/tools/pw-cat.c:991
89
+#: src/modules/module-zeroconf-discover.c:348
90
+#, c-format
91
+msgid "%s on %s"
92
+msgstr "%s sus %s"
93
+
94
+#: src/tools/pw-cat.c:784
95
#, c-format
96
msgid ""
97
-"%s options <file>\n"
98
+"%s options <file>|-\n"
99
" -h, --help Show this help\n"
100
" --version Show version\n"
101
" -v, --verbose Enable verbose operations\n"
102
"\n"
103
msgstr ""
104
+"%s opcions <file>|-\n"
105
+" -h, --help Afichar aquesta ajuda\n"
106
+" --version Afichar la version\n"
107
+" -v, --verbose Activar las operacions verbosas\n"
108
+"\n"
109
110
-#: src/tools/pw-cat.c:998
111
+#: src/tools/pw-cat.c:791
112
#, c-format
113
msgid ""
114
" -R, --remote Remote daemon name\n"
115
116
" or direct samples (256)\n"
117
" the rate is the one of the source "
118
"file\n"
119
-" --list-targets List available targets for --target\n"
120
+" -P --properties Set node properties\n"
121
"\n"
122
msgstr ""
123
124
-#: src/tools/pw-cat.c:1016
125
+#: src/tools/pw-cat.c:809
126
#, c-format
127
msgid ""
128
" --rate Sample rate (req. for rec) (default "
129
130
"\n"
131
msgstr ""
132
133
-#: src/tools/pw-cat.c:1033
134
+#: src/tools/pw-cat.c:826
135
msgid ""
136
" -p, --playback Playback mode\n"
137
" -r, --record Recording mode\n"
138
" -m, --midi Midi mode\n"
139
+" -d, --dsd DSD mode\n"
140
"\n"
141
msgstr ""
142
+" -p, --playback Mòde lectura\n"
143
+" -r, --record Mòde enregistrament\n"
144
+" -m, --midi Mòde Midi\n"
145
+" -d, --dsd Mòde DSD\n"
146
+"\n"
147
148
-#: src/tools/pw-cli.c:2932
149
+#: src/tools/pw-cli.c:2250
150
#, c-format
151
msgid ""
152
"%s options command\n"
153
154
" -r, --remote Remote daemon name\n"
155
"\n"
156
msgstr ""
157
+"%s opcions comanda\n"
158
+" -h, --help Afichar aquesta ajuda\n"
159
+" --version Afichar la version\n"
160
+" -d, --daemon Aviar coma demòni (Per defaut "
161
+"false)\n"
162
+" -r, --remote Remote daemon name\n"
163
+"\n"
164
165
-#: spa/plugins/alsa/acp/acp.c:290
166
+#: spa/plugins/alsa/acp/acp.c:321
167
msgid "Pro Audio"
168
msgstr ""
169
170
-#: spa/plugins/alsa/acp/acp.c:411 spa/plugins/alsa/acp/alsa-mixer.c:4704
171
-#: spa/plugins/bluez5/bluez5-device.c:1000
172
+#: spa/plugins/alsa/acp/acp.c:444 spa/plugins/alsa/acp/alsa-mixer.c:4648
173
+#: spa/plugins/bluez5/bluez5-device.c:1236
174
msgid "Off"
175
msgstr "Atudat"
176
177
-#: spa/plugins/alsa/acp/channelmap.h:466
178
-msgid "(invalid)"
179
-msgstr "(invalid)"
180
-
181
-#: spa/plugins/alsa/acp/alsa-mixer.c:2709
182
+#: spa/plugins/alsa/acp/alsa-mixer.c:2652
183
msgid "Input"
184
msgstr "Entrada"
185
186
-#: spa/plugins/alsa/acp/alsa-mixer.c:2710
187
+#: spa/plugins/alsa/acp/alsa-mixer.c:2653
188
msgid "Docking Station Input"
189
msgstr "Entrada de l'estacion d'acuèlh"
190
191
-#: spa/plugins/alsa/acp/alsa-mixer.c:2711
192
+#: spa/plugins/alsa/acp/alsa-mixer.c:2654
193
msgid "Docking Station Microphone"
194
msgstr "Microfòn de l'estacion d'acuèlh"
195
196
-#: spa/plugins/alsa/acp/alsa-mixer.c:2712
197
+#: spa/plugins/alsa/acp/alsa-mixer.c:2655
198
msgid "Docking Station Line In"
199
msgstr "Entrada linha de l'estacion d'acuèlh"
200
201
-#: spa/plugins/alsa/acp/alsa-mixer.c:2713
202
-#: spa/plugins/alsa/acp/alsa-mixer.c:2804
203
+#: spa/plugins/alsa/acp/alsa-mixer.c:2656
204
+#: spa/plugins/alsa/acp/alsa-mixer.c:2747
205
msgid "Line In"
206
msgstr "Entrada linha"
207
208
-#: spa/plugins/alsa/acp/alsa-mixer.c:2714
209
-#: spa/plugins/alsa/acp/alsa-mixer.c:2798
210
-#: spa/plugins/bluez5/bluez5-device.c:1145
211
+#: spa/plugins/alsa/acp/alsa-mixer.c:2657
212
+#: spa/plugins/alsa/acp/alsa-mixer.c:2741
213
+#: spa/plugins/bluez5/bluez5-device.c:1454
214
msgid "Microphone"
215
-msgstr "Micrò"
216
+msgstr "Microfòn"
217
218
-#: spa/plugins/alsa/acp/alsa-mixer.c:2715
219
-#: spa/plugins/alsa/acp/alsa-mixer.c:2799
220
+#: spa/plugins/alsa/acp/alsa-mixer.c:2658
221
+#: spa/plugins/alsa/acp/alsa-mixer.c:2742
222
msgid "Front Microphone"
223
msgstr "Microfòn avant"
224
225
-#: spa/plugins/alsa/acp/alsa-mixer.c:2716
226
-#: spa/plugins/alsa/acp/alsa-mixer.c:2800
227
+#: spa/plugins/alsa/acp/alsa-mixer.c:2659
228
+#: spa/plugins/alsa/acp/alsa-mixer.c:2743
229
msgid "Rear Microphone"
230
msgstr "Microfòn arrièr"
231
232
-#: spa/plugins/alsa/acp/alsa-mixer.c:2717
233
+#: spa/plugins/alsa/acp/alsa-mixer.c:2660
234
msgid "External Microphone"
235
msgstr "Microfòn extèrne"
236
237
-#: spa/plugins/alsa/acp/alsa-mixer.c:2718
238
-#: spa/plugins/alsa/acp/alsa-mixer.c:2802
239
+#: spa/plugins/alsa/acp/alsa-mixer.c:2661
240
+#: spa/plugins/alsa/acp/alsa-mixer.c:2745
241
msgid "Internal Microphone"
242
msgstr "Microfòn intèrne"
243
244
-#: spa/plugins/alsa/acp/alsa-mixer.c:2719
245
-#: spa/plugins/alsa/acp/alsa-mixer.c:2805
246
+#: spa/plugins/alsa/acp/alsa-mixer.c:2662
247
+#: spa/plugins/alsa/acp/alsa-mixer.c:2748
248
msgid "Radio"
249
msgstr "Ràdio"
250
251
-#: spa/plugins/alsa/acp/alsa-mixer.c:2720
252
-#: spa/plugins/alsa/acp/alsa-mixer.c:2806
253
+#: spa/plugins/alsa/acp/alsa-mixer.c:2663
254
+#: spa/plugins/alsa/acp/alsa-mixer.c:2749
255
msgid "Video"
256
msgstr "Vidèo"
257
258
-#: spa/plugins/alsa/acp/alsa-mixer.c:2721
259
+#: spa/plugins/alsa/acp/alsa-mixer.c:2664
260
msgid "Automatic Gain Control"
261
msgstr "Contraròtle automatic del ganh"
262
263
-#: spa/plugins/alsa/acp/alsa-mixer.c:2722
264
+#: spa/plugins/alsa/acp/alsa-mixer.c:2665
265
msgid "No Automatic Gain Control"
266
msgstr "Pas de contraròtle automatic del ganh"
267
268
-#: spa/plugins/alsa/acp/alsa-mixer.c:2723
269
+#: spa/plugins/alsa/acp/alsa-mixer.c:2666
270
msgid "Boost"
271
msgstr "Boost"
272
273
-#: spa/plugins/alsa/acp/alsa-mixer.c:2724
274
+#: spa/plugins/alsa/acp/alsa-mixer.c:2667
275
msgid "No Boost"
276
msgstr "Sens boost"
277
278
-#: spa/plugins/alsa/acp/alsa-mixer.c:2725
279
+#: spa/plugins/alsa/acp/alsa-mixer.c:2668
280
msgid "Amplifier"
281
msgstr "Amplificador"
282
283
-#: spa/plugins/alsa/acp/alsa-mixer.c:2726
284
+#: spa/plugins/alsa/acp/alsa-mixer.c:2669
285
msgid "No Amplifier"
286
msgstr "Pas d'amplificador"
287
288
-#: spa/plugins/alsa/acp/alsa-mixer.c:2727
289
+#: spa/plugins/alsa/acp/alsa-mixer.c:2670
290
msgid "Bass Boost"
291
msgstr "Amplificacion bassas"
292
293
-#: spa/plugins/alsa/acp/alsa-mixer.c:2728
294
+#: spa/plugins/alsa/acp/alsa-mixer.c:2671
295
msgid "No Bass Boost"
296
msgstr "Pas d'amplificacion de las bassas"
297
298
-#: spa/plugins/alsa/acp/alsa-mixer.c:2729
299
-#: spa/plugins/bluez5/bluez5-device.c:1150
300
+#: spa/plugins/alsa/acp/alsa-mixer.c:2672
301
+#: spa/plugins/bluez5/bluez5-device.c:1460
302
msgid "Speaker"
303
msgstr "Nautparlaire"
304
305
-#: spa/plugins/alsa/acp/alsa-mixer.c:2730
306
-#: spa/plugins/alsa/acp/alsa-mixer.c:2808
307
+#: spa/plugins/alsa/acp/alsa-mixer.c:2673
308
+#: spa/plugins/alsa/acp/alsa-mixer.c:2751
309
msgid "Headphones"
310
msgstr "Escotadors"
311
312
-#: spa/plugins/alsa/acp/alsa-mixer.c:2797
313
+#: spa/plugins/alsa/acp/alsa-mixer.c:2740
314
msgid "Analog Input"
315
msgstr "Entrada analogica"
316
317
-#: spa/plugins/alsa/acp/alsa-mixer.c:2801
318
+#: spa/plugins/alsa/acp/alsa-mixer.c:2744
319
msgid "Dock Microphone"
320
msgstr "Microfòn de l'estacion d'acuèlh"
321
322
-#: spa/plugins/alsa/acp/alsa-mixer.c:2803
323
+#: spa/plugins/alsa/acp/alsa-mixer.c:2746
324
msgid "Headset Microphone"
325
msgstr "Micro-casc"
326
327
-#: spa/plugins/alsa/acp/alsa-mixer.c:2807
328
+#: spa/plugins/alsa/acp/alsa-mixer.c:2750
329
msgid "Analog Output"
330
msgstr "Sortida analogica"
331
332
-#: spa/plugins/alsa/acp/alsa-mixer.c:2809
333
-#, fuzzy
334
+#: spa/plugins/alsa/acp/alsa-mixer.c:2752
335
msgid "Headphones 2"
336
-msgstr "Escotadors"
337
+msgstr "Casc àudio 2"
338
339
-#: spa/plugins/alsa/acp/alsa-mixer.c:2810
340
-#, fuzzy
341
+#: spa/plugins/alsa/acp/alsa-mixer.c:2753
342
msgid "Headphones Mono Output"
343
-msgstr "Sortida Analogica Monò"
344
+msgstr "Sortida casc àudio analogica mono"
345
346
-#: spa/plugins/alsa/acp/alsa-mixer.c:2811
347
+#: spa/plugins/alsa/acp/alsa-mixer.c:2754
348
msgid "Line Out"
349
msgstr "Sortida linha"
350
351
-#: spa/plugins/alsa/acp/alsa-mixer.c:2812
352
+#: spa/plugins/alsa/acp/alsa-mixer.c:2755
353
msgid "Analog Mono Output"
354
-msgstr "Sortida Analogica Monò"
355
+msgstr "Sortida analogica mono"
356
357
-#: spa/plugins/alsa/acp/alsa-mixer.c:2813
358
+#: spa/plugins/alsa/acp/alsa-mixer.c:2756
359
msgid "Speakers"
360
msgstr "Nauts parlaires"
361
362
-#: spa/plugins/alsa/acp/alsa-mixer.c:2814
363
+#: spa/plugins/alsa/acp/alsa-mixer.c:2757
364
msgid "HDMI / DisplayPort"
365
msgstr "HDMI / DisplayPort"
366
367
-#: spa/plugins/alsa/acp/alsa-mixer.c:2815
368
+#: spa/plugins/alsa/acp/alsa-mixer.c:2758
369
msgid "Digital Output (S/PDIF)"
370
msgstr "Sortida numerica (S/PDIF)"
371
372
-#: spa/plugins/alsa/acp/alsa-mixer.c:2816
373
+#: spa/plugins/alsa/acp/alsa-mixer.c:2759
374
msgid "Digital Input (S/PDIF)"
375
msgstr "Entrada numerica (S/PDIF)"
376
377
-#: spa/plugins/alsa/acp/alsa-mixer.c:2817
378
+#: spa/plugins/alsa/acp/alsa-mixer.c:2760
379
msgid "Multichannel Input"
380
-msgstr ""
381
+msgstr "Entrada multicanal"
382
383
-#: spa/plugins/alsa/acp/alsa-mixer.c:2818
384
+#: spa/plugins/alsa/acp/alsa-mixer.c:2761
385
msgid "Multichannel Output"
386
-msgstr ""
387
+msgstr "Sortida multicanal"
388
389
-#: spa/plugins/alsa/acp/alsa-mixer.c:2819
390
-#, fuzzy
391
+#: spa/plugins/alsa/acp/alsa-mixer.c:2762
392
msgid "Game Output"
393
-msgstr "%s Sortida"
394
+msgstr "Sortida jòc"
395
396
-#: spa/plugins/alsa/acp/alsa-mixer.c:2820
397
-#: spa/plugins/alsa/acp/alsa-mixer.c:2821
398
-#, fuzzy
399
+#: spa/plugins/alsa/acp/alsa-mixer.c:2763
400
+#: spa/plugins/alsa/acp/alsa-mixer.c:2764
401
msgid "Chat Output"
402
-msgstr "%s Sortida"
403
+msgstr "Sortida messatjariá"
404
405
-#: spa/plugins/alsa/acp/alsa-mixer.c:2822
406
-#, fuzzy
407
+#: spa/plugins/alsa/acp/alsa-mixer.c:2765
408
msgid "Chat Input"
409
-msgstr "%s Entrada"
410
+msgstr "Entrada messatjariá"
411
412
-#: spa/plugins/alsa/acp/alsa-mixer.c:2823
413
-#, fuzzy
414
+#: spa/plugins/alsa/acp/alsa-mixer.c:2766
415
msgid "Virtual Surround 7.1"
416
-msgstr "Collector ambiofonic virtual"
417
+msgstr "Surround 7.1 virtual"
418
419
-#: spa/plugins/alsa/acp/alsa-mixer.c:4527
420
+#: spa/plugins/alsa/acp/alsa-mixer.c:4471
421
msgid "Analog Mono"
422
-msgstr "Monò analogic"
423
+msgstr "Mono analogic"
424
425
-#: spa/plugins/alsa/acp/alsa-mixer.c:4528
426
-#, fuzzy
427
+#: spa/plugins/alsa/acp/alsa-mixer.c:4472
428
msgid "Analog Mono (Left)"
429
-msgstr "Monò analogic"
430
+msgstr "Mono analogic (esquèrra)"
431
432
-#: spa/plugins/alsa/acp/alsa-mixer.c:4529
433
-#, fuzzy
434
+#: spa/plugins/alsa/acp/alsa-mixer.c:4473
435
msgid "Analog Mono (Right)"
436
-msgstr "Monò analogic"
437
+msgstr "Mono analogic (drecha)"
438
439
#. Note: Not translated to "Analog Stereo Input", because the source
440
#. * name gets "Input" appended to it automatically, so adding "Input"
441
#. * here would lead to the source name to become "Analog Stereo Input
442
#. * Input". The same logic applies to analog-stereo-output,
443
#. * multichannel-input and multichannel-output.
444
-#: spa/plugins/alsa/acp/alsa-mixer.c:4530
445
-#: spa/plugins/alsa/acp/alsa-mixer.c:4538
446
-#: spa/plugins/alsa/acp/alsa-mixer.c:4539
447
+#: spa/plugins/alsa/acp/alsa-mixer.c:4474
448
+#: spa/plugins/alsa/acp/alsa-mixer.c:4482
449
+#: spa/plugins/alsa/acp/alsa-mixer.c:4483
450
msgid "Analog Stereo"
451
-msgstr "Esterèo analogic"
452
+msgstr "Estereo analogic"
453
454
-#: spa/plugins/alsa/acp/alsa-mixer.c:4531
455
+#: spa/plugins/alsa/acp/alsa-mixer.c:4475
456
msgid "Mono"
457
msgstr "Mono"
458
459
-#: spa/plugins/alsa/acp/alsa-mixer.c:4532
460
+#: spa/plugins/alsa/acp/alsa-mixer.c:4476
461
msgid "Stereo"
462
-msgstr "Esterèo"
463
+msgstr "Estereo"
464
465
-#: spa/plugins/alsa/acp/alsa-mixer.c:4540
466
-#: spa/plugins/alsa/acp/alsa-mixer.c:4698
467
-#: spa/plugins/bluez5/bluez5-device.c:1135
468
+#: spa/plugins/alsa/acp/alsa-mixer.c:4484
469
+#: spa/plugins/alsa/acp/alsa-mixer.c:4642
470
+#: spa/plugins/bluez5/bluez5-device.c:1442
471
msgid "Headset"
472
msgstr "Casc àudio"
473
474
-#: spa/plugins/alsa/acp/alsa-mixer.c:4541
475
-#: spa/plugins/alsa/acp/alsa-mixer.c:4699
476
-#, fuzzy
477
+#: spa/plugins/alsa/acp/alsa-mixer.c:4485
478
+#: spa/plugins/alsa/acp/alsa-mixer.c:4643
479
msgid "Speakerphone"
480
msgstr "Nautparlaire"
481
482
-#: spa/plugins/alsa/acp/alsa-mixer.c:4542
483
-#: spa/plugins/alsa/acp/alsa-mixer.c:4543
484
+#: spa/plugins/alsa/acp/alsa-mixer.c:4486
485
+#: spa/plugins/alsa/acp/alsa-mixer.c:4487
486
msgid "Multichannel"
487
-msgstr ""
488
+msgstr "Multicanal"
489
490
-#: spa/plugins/alsa/acp/alsa-mixer.c:4544
491
+#: spa/plugins/alsa/acp/alsa-mixer.c:4488
492
msgid "Analog Surround 2.1"
493
msgstr "Surround analogic 2.1"
494
495
-#: spa/plugins/alsa/acp/alsa-mixer.c:4545
496
+#: spa/plugins/alsa/acp/alsa-mixer.c:4489
497
msgid "Analog Surround 3.0"
498
msgstr "Surround analogic 3.0"
499
500
-#: spa/plugins/alsa/acp/alsa-mixer.c:4546
501
+#: spa/plugins/alsa/acp/alsa-mixer.c:4490
502
msgid "Analog Surround 3.1"
503
msgstr "Surround analogic 3.1"
504
505
-#: spa/plugins/alsa/acp/alsa-mixer.c:4547
506
+#: spa/plugins/alsa/acp/alsa-mixer.c:4491
507
msgid "Analog Surround 4.0"
508
msgstr "Surround analogic 4.0"
509
510
-#: spa/plugins/alsa/acp/alsa-mixer.c:4548
511
+#: spa/plugins/alsa/acp/alsa-mixer.c:4492
512
msgid "Analog Surround 4.1"
513
msgstr "Surround analogic 4.1"
514
515
-#: spa/plugins/alsa/acp/alsa-mixer.c:4549
516
+#: spa/plugins/alsa/acp/alsa-mixer.c:4493
517
msgid "Analog Surround 5.0"
518
msgstr "Surround analogic 5.0"
519
520
-#: spa/plugins/alsa/acp/alsa-mixer.c:4550
521
+#: spa/plugins/alsa/acp/alsa-mixer.c:4494
522
msgid "Analog Surround 5.1"
523
msgstr "Surround analogic 5.1"
524
525
-#: spa/plugins/alsa/acp/alsa-mixer.c:4551
526
+#: spa/plugins/alsa/acp/alsa-mixer.c:4495
527
msgid "Analog Surround 6.0"
528
msgstr "Surround analogic 6.0"
529
530
-#: spa/plugins/alsa/acp/alsa-mixer.c:4552
531
+#: spa/plugins/alsa/acp/alsa-mixer.c:4496
532
msgid "Analog Surround 6.1"
533
msgstr "Surround analogic 6.1"
534
535
-#: spa/plugins/alsa/acp/alsa-mixer.c:4553
536
+#: spa/plugins/alsa/acp/alsa-mixer.c:4497
537
msgid "Analog Surround 7.0"
538
msgstr "Surround analogic 7.0"
539
540
-#: spa/plugins/alsa/acp/alsa-mixer.c:4554
541
+#: spa/plugins/alsa/acp/alsa-mixer.c:4498
542
msgid "Analog Surround 7.1"
543
msgstr "Surround analogic 7.1"
544
545
-#: spa/plugins/alsa/acp/alsa-mixer.c:4555
546
+#: spa/plugins/alsa/acp/alsa-mixer.c:4499
547
msgid "Digital Stereo (IEC958)"
548
-msgstr "Esterèo numeric (IEC958)"
549
+msgstr "Estereo numeric (IEC958)"
550
551
-#: spa/plugins/alsa/acp/alsa-mixer.c:4556
552
+#: spa/plugins/alsa/acp/alsa-mixer.c:4500
553
msgid "Digital Surround 4.0 (IEC958/AC3)"
554
msgstr "Surround numeric 4.0 (IEC958/AC3)"
555
556
-#: spa/plugins/alsa/acp/alsa-mixer.c:4557
557
+#: spa/plugins/alsa/acp/alsa-mixer.c:4501
558
msgid "Digital Surround 5.1 (IEC958/AC3)"
559
msgstr "Surround numeric 5.1 (IEC958/AC3)"
560
561
-#: spa/plugins/alsa/acp/alsa-mixer.c:4558
562
+#: spa/plugins/alsa/acp/alsa-mixer.c:4502
563
msgid "Digital Surround 5.1 (IEC958/DTS)"
564
msgstr "Digital Surround 5.1 (IEC958/DTS)"
565
566
-#: spa/plugins/alsa/acp/alsa-mixer.c:4559
567
+#: spa/plugins/alsa/acp/alsa-mixer.c:4503
568
msgid "Digital Stereo (HDMI)"
569
-msgstr "Esterèo numeric (HDMI)"
570
+msgstr "Estereo numeric (HDMI)"
571
572
-#: spa/plugins/alsa/acp/alsa-mixer.c:4560
573
+#: spa/plugins/alsa/acp/alsa-mixer.c:4504
574
msgid "Digital Surround 5.1 (HDMI)"
575
msgstr "Digital Surround 5.1 (HDMI)"
576
577
-#: spa/plugins/alsa/acp/alsa-mixer.c:4561
578
+#: spa/plugins/alsa/acp/alsa-mixer.c:4505
579
msgid "Chat"
580
-msgstr ""
581
+msgstr "Messatjariá instantanèa"
582
583
-#: spa/plugins/alsa/acp/alsa-mixer.c:4562
584
+#: spa/plugins/alsa/acp/alsa-mixer.c:4506
585
msgid "Game"
586
-msgstr ""
587
+msgstr "Jòc"
588
589
-#: spa/plugins/alsa/acp/alsa-mixer.c:4696
590
+#: spa/plugins/alsa/acp/alsa-mixer.c:4640
591
msgid "Analog Mono Duplex"
592
msgstr "Duplèx Mono analogic"
593
594
-#: spa/plugins/alsa/acp/alsa-mixer.c:4697
595
+#: spa/plugins/alsa/acp/alsa-mixer.c:4641
596
msgid "Analog Stereo Duplex"
597
msgstr "Duplèx esterèo analogic"
598
599
-#: spa/plugins/alsa/acp/alsa-mixer.c:4700
600
+#: spa/plugins/alsa/acp/alsa-mixer.c:4644
601
msgid "Digital Stereo Duplex (IEC958)"
602
msgstr "Duplèx estèreo numeric (IEC958)"
603
604
-#: spa/plugins/alsa/acp/alsa-mixer.c:4701
605
+#: spa/plugins/alsa/acp/alsa-mixer.c:4645
606
msgid "Multichannel Duplex"
607
-msgstr ""
608
+msgstr "Duplèx multicanal"
609
610
-#: spa/plugins/alsa/acp/alsa-mixer.c:4702
611
-#, fuzzy
612
+#: spa/plugins/alsa/acp/alsa-mixer.c:4646
613
msgid "Stereo Duplex"
614
-msgstr "Duplèx esterèo analogic"
615
+msgstr "Duplèx estereo"
616
617
-#: spa/plugins/alsa/acp/alsa-mixer.c:4703
618
+#: spa/plugins/alsa/acp/alsa-mixer.c:4647
619
msgid "Mono Chat + 7.1 Surround"
620
-msgstr ""
621
+msgstr "Messatjariá mono + Surround 7.1"
622
623
-#: spa/plugins/alsa/acp/alsa-mixer.c:4806
624
+#: spa/plugins/alsa/acp/alsa-mixer.c:4754
625
#, c-format
626
msgid "%s Output"
627
msgstr "%s Sortida"
628
629
-#: spa/plugins/alsa/acp/alsa-mixer.c:4813
630
+#: spa/plugins/alsa/acp/alsa-mixer.c:4761
631
#, c-format
632
msgid "%s Input"
633
msgstr "%s Entrada"
634
635
-#: spa/plugins/alsa/acp/alsa-util.c:1175 spa/plugins/alsa/acp/alsa-util.c:1269
636
-#, fuzzy, c-format
637
+#: spa/plugins/alsa/acp/alsa-util.c:1187 spa/plugins/alsa/acp/alsa-util.c:1281
638
+#, c-format
639
msgid ""
640
"snd_pcm_avail() returned a value that is exceptionally large: %lu byte (%lu "
641
"ms).\n"
642
643
"Most likely this is a bug in the ALSA driver '%s'. Please report this issue "
644
"to the ALSA developers."
645
msgstr0 ""
646
-"snd_pcm_avail() a tornat una valor qu'es excepcionalament larga : %lu octets "
647
+"snd_pcm_avail() a tornat una valor qu'es excepcionalament larga : %lu octet "
648
"(%lu ms).\n"
649
-"S'agís fòrt probablament d'un bug dins lo pilòt ALSA « %s ». Raportatz "
650
-"aqueste problèma als desvolopaires d'ALSA."
651
+"Es fòrt probablament un bug dins lo pilòt ALSA « %s ». Senhalatz-lo als "
652
+"desvolopaires d’ALSA."
653
msgstr1 ""
654
"snd_pcm_avail() a tornat una valor qu'es excepcionalament larga : %lu octets "
655
"(%lu ms).\n"
656
-"S'agís fòrt probablament d'un bug dins lo pilòt ALSA « %s ». Raportatz "
657
-"aqueste problèma als desvolopaires d'ALSA."
658
+"Es fòrt probablament un bug dins lo pilòt ALSA « %s ». Senhalatz-lo als "
659
+"desvolopaires d’ALSA."
660
661
-#: spa/plugins/alsa/acp/alsa-util.c:1241
662
-#, fuzzy, c-format
663
+#: spa/plugins/alsa/acp/alsa-util.c:1253
664
+#, c-format
665
msgid ""
666
"snd_pcm_delay() returned a value that is exceptionally large: %li byte (%s"
667
"%lu ms).\n"
668
669
"Most likely this is a bug in the ALSA driver '%s'. Please report this issue "
670
"to the ALSA developers."
671
msgstr0 ""
672
-"snd_pcm_delay() a tornat una valor qu'es excepcionalament larga : %li octets "
673
+"snd_pcm_delay() a tornat una valor qu'es excepcionalament larga : %li octet "
674
"%s%lu ms).\n"
675
-"S'agís fòrt probablament d'un bug dins lo pilòt ALSA « %s ». Raportatz "
676
-"aqueste problèma als desvolopaires d'ALSA."
677
+"Es fòrt probablament un bug dins lo pilòt ALSA « %s ». Senhalatz-lo als "
678
+"desvolopaires d’ALSA."
679
msgstr1 ""
680
"snd_pcm_delay() a tornat una valor qu'es excepcionalament larga : %li octets "
681
"%s%lu ms).\n"
682
-"S'agís fòrt probablament d'un bug dins lo pilòt ALSA « %s ». Raportatz "
683
-"aqueste problèma als desvolopaires d'ALSA."
684
+"Es fòrt probablament un bug dins lo pilòt ALSA « %s ». Senhalatz-lo als "
685
+"desvolopaires d’ALSA."
686
687
-#: spa/plugins/alsa/acp/alsa-util.c:1288
688
+#: spa/plugins/alsa/acp/alsa-util.c:1300
689
#, c-format
690
msgid ""
691
"snd_pcm_avail_delay() returned strange values: delay %lu is less than avail "
692
693
msgstr ""
694
"snd_pcm_avail_delay() a tornat de resultats anormals : lo relambi %lu es mai "
695
"pichon que %lu.\n"
696
-"Es fòrt probablament un bug dins lo pilòt ALSA '%s'. Senhalatz-lo als "
697
-"desvolopaires d'ALSA."
698
+"Es fòrt probablament un bug dins lo pilòt ALSA « %s ». Senhalatz-lo als "
699
+"desvolopaires d’ALSA."
700
701
-#: spa/plugins/alsa/acp/alsa-util.c:1331
702
-#, fuzzy, c-format
703
+#: spa/plugins/alsa/acp/alsa-util.c:1343
704
+#, c-format
705
msgid ""
706
"snd_pcm_mmap_begin() returned a value that is exceptionally large: %lu byte "
707
"(%lu ms).\n"
708
709
"to the ALSA developers."
710
msgstr0 ""
711
"snd_pcm_mmap_begin() a tornat una valor qu'es excepcionalament larga : %lu "
712
-"octets (%lu·ms)..\n"
713
-"S'agís fòrt probablament d'un bug dins lo pilòt ALSA « %s ». Raportatz "
714
-"aqueste problèma als desvolopaires d'ALSA."
715
+"octet (%lu ms).\n"
716
+"Es fòrt probablament un bug dins lo pilòt ALSA « %s ». Senhalatz-lo als "
717
+"desvolopaires d’ALSA."
718
msgstr1 ""
719
"snd_pcm_mmap_begin() a tornat una valor qu'es excepcionalament larga : %lu "
720
-"octets (%lu·ms)..\n"
721
-"S'agís fòrt probablament d'un bug dins lo pilòt ALSA « %s ». Raportatz "
722
-"aqueste problèma als desvolopaires d'ALSA."
723
+"octet (%lu ms).\n"
724
+"Es fòrt probablament un bug dins lo pilòt ALSA « %s ». Senhalatz-lo als "
725
+"desvolopaires d’ALSA."
726
+
727
+#: spa/plugins/alsa/acp/channelmap.h:457
728
+msgid "(invalid)"
729
+msgstr "(invalid)"
730
+
731
+#: spa/plugins/alsa/acp/compat.c:189
732
+msgid "Built-in Audio"
733
+msgstr "Àudio integrat"
734
+
735
+#: spa/plugins/alsa/acp/compat.c:194
736
+msgid "Modem"
737
+msgstr "Modèm"
738
739
-#: spa/plugins/bluez5/bluez5-device.c:1010
740
+#: spa/plugins/bluez5/bluez5-device.c:1247
741
msgid "Audio Gateway (A2DP Source & HSP/HFP AG)"
742
-msgstr ""
743
+msgstr "Palanca àudio (Font A2DP & HSP/HFP AG)"
744
745
-#: spa/plugins/bluez5/bluez5-device.c:1033
746
+#: spa/plugins/bluez5/bluez5-device.c:1272
747
#, c-format
748
msgid "High Fidelity Playback (A2DP Sink, codec %s)"
749
-msgstr ""
750
+msgstr "Lectura nauta fidelitat (A2DP Sink, codec %s)"
751
752
-#: spa/plugins/bluez5/bluez5-device.c:1035
753
+#: spa/plugins/bluez5/bluez5-device.c:1275
754
#, c-format
755
msgid "High Fidelity Duplex (A2DP Source/Sink, codec %s)"
756
-msgstr ""
757
+msgstr "Duplèx nauta fidelitat (A2DP Source/Sink, codec %s)"
758
759
-#: spa/plugins/bluez5/bluez5-device.c:1041
760
+#: spa/plugins/bluez5/bluez5-device.c:1283
761
msgid "High Fidelity Playback (A2DP Sink)"
762
-msgstr ""
763
+msgstr "Lectura nauta fidelitat (A2DP Sink)"
764
765
-#: spa/plugins/bluez5/bluez5-device.c:1043
766
+#: spa/plugins/bluez5/bluez5-device.c:1285
767
msgid "High Fidelity Duplex (A2DP Source/Sink)"
768
-msgstr ""
769
+msgstr "Duplèx nauta fidelitat (A2DP Source/Sink)"
770
+
771
+#: spa/plugins/bluez5/bluez5-device.c:1322
772
+#, c-format
773
+msgid "High Fidelity Playback (BAP Sink, codec %s)"
774
+msgstr "Lectura nauta fidelitat (A2DP Sink, codec %s)"
775
776
-#: spa/plugins/bluez5/bluez5-device.c:1070
777
+#: spa/plugins/bluez5/bluez5-device.c:1326
778
+#, c-format
779
+msgid "High Fidelity Input (BAP Source, codec %s)"
780
+msgstr "Duplèx nauta fidelitat (Font BAP, codec %s)"
781
+
782
+#: spa/plugins/bluez5/bluez5-device.c:1330
783
+#, c-format
784
+msgid "High Fidelity Duplex (BAP Source/Sink, codec %s)"
785
+msgstr "Duplèx nauta fidelitat (Font BAP/Sink, codec %s)"
786
+
787
+#: spa/plugins/bluez5/bluez5-device.c:1359
788
#, c-format
789
msgid "Headset Head Unit (HSP/HFP, codec %s)"
790
msgstr ""
791
792
-#: spa/plugins/bluez5/bluez5-device.c:1074
793
+#: spa/plugins/bluez5/bluez5-device.c:1364
794
msgid "Headset Head Unit (HSP/HFP)"
795
msgstr ""
796
797
-#: spa/plugins/bluez5/bluez5-device.c:1140
798
+#: spa/plugins/bluez5/bluez5-device.c:1443
799
+#: spa/plugins/bluez5/bluez5-device.c:1448
800
+#: spa/plugins/bluez5/bluez5-device.c:1455
801
+#: spa/plugins/bluez5/bluez5-device.c:1461
802
+#: spa/plugins/bluez5/bluez5-device.c:1467
803
+#: spa/plugins/bluez5/bluez5-device.c:1473
804
+#: spa/plugins/bluez5/bluez5-device.c:1479
805
+#: spa/plugins/bluez5/bluez5-device.c:1485
806
+#: spa/plugins/bluez5/bluez5-device.c:1491
807
msgid "Handsfree"
808
msgstr "Mans liuras"
809
810
-#: spa/plugins/bluez5/bluez5-device.c:1155
811
+#: spa/plugins/bluez5/bluez5-device.c:1449
812
+msgid "Handsfree (HFP)"
813
+msgstr "Mans liuras (HFP)"
814
+
815
+#: spa/plugins/bluez5/bluez5-device.c:1466
816
msgid "Headphone"
817
-msgstr "Escotadors"
818
+msgstr "Escotador"
819
820
-#: spa/plugins/bluez5/bluez5-device.c:1160
821
+#: spa/plugins/bluez5/bluez5-device.c:1472
822
msgid "Portable"
823
msgstr "Portable"
824
825
-#: spa/plugins/bluez5/bluez5-device.c:1165
826
+#: spa/plugins/bluez5/bluez5-device.c:1478
827
msgid "Car"
828
msgstr "Telefòn de veitura"
829
830
-#: spa/plugins/bluez5/bluez5-device.c:1170
831
+#: spa/plugins/bluez5/bluez5-device.c:1484
832
msgid "HiFi"
833
msgstr "HiFi"
834
835
-#: spa/plugins/bluez5/bluez5-device.c:1175
836
+#: spa/plugins/bluez5/bluez5-device.c:1490
837
msgid "Phone"
838
msgstr "Telefòn"
839
840
-#: spa/plugins/bluez5/bluez5-device.c:1181
841
-#, fuzzy
842
+#: spa/plugins/bluez5/bluez5-device.c:1497
843
msgid "Bluetooth"
844
-msgstr "Entrada Bluetooth"
845
+msgstr "Bluetooth"
846
+
847
+#: spa/plugins/bluez5/bluez5-device.c:1498
848
+msgid "Bluetooth (HFP)"
849
+msgstr "Bluetooth (HFP)"
850
pipewire-0.3.65.tar.gz/po/uk.po -> pipewire-0.3.66.tar.gz/po/uk.po
Changed
381
1
2
# Copyright (C) 2009 Free Software Foundation, Inc.
3
# This file is distributed under the same license as the pipewire package.
4
#
5
-# Yuri Chornoivan <yurchor@ukr.net>, 2009-2021, 2022.
6
+# Yuri Chornoivan <yurchor@ukr.net>, 2009-2021, 2022, 2023.
7
msgid ""
8
msgstr ""
9
"Project-Id-Version: pipewire\n"
10
-"Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pipewire/pipewire/-/issue"
11
-"s\n"
12
-"POT-Creation-Date: 2022-05-20 15:26+0000\n"
13
-"PO-Revision-Date: 2022-06-18 13:07+0300\n"
14
+"Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pipewire/pipewire/-/issu"
15
+"es\n"
16
+"POT-Creation-Date: 2023-02-06 15:27+0000\n"
17
+"PO-Revision-Date: 2023-02-11 17:42+0200\n"
18
"Last-Translator: Yuri Chornoivan <yurchor@ukr.net>\n"
19
"Language-Team: Ukrainian <trans-uk@lists.fedoraproject.org>\n"
20
"Language: uk\n"
21
22
msgid "Start the PipeWire Media System"
23
msgstr "Запустити мультимедійну систему PipeWire"
24
25
-#: src/modules/module-protocol-pulse/modules/module-tunnel-sink.c:183
26
-#: src/modules/module-protocol-pulse/modules/module-tunnel-source.c:183
27
+#: src/modules/module-protocol-pulse/modules/module-tunnel-sink.c:179
28
+#: src/modules/module-protocol-pulse/modules/module-tunnel-source.c:179
29
#, c-format
30
msgid "Tunnel to %s/%s"
31
msgstr "Тунель до %s/%s"
32
33
msgid "Dummy Output"
34
msgstr "Фіктивний вихід"
35
36
-#: src/modules/module-pulse-tunnel.c:639
37
+#: src/modules/module-pulse-tunnel.c:695
38
#, c-format
39
msgid "Tunnel for %s@%s"
40
msgstr "Тунель для %s@%s"
41
42
-#: src/modules/module-zeroconf-discover.c:332
43
+#: src/modules/module-zeroconf-discover.c:335
44
msgid "Unknown device"
45
msgstr "Невідомий пристрій"
46
47
-#: src/modules/module-zeroconf-discover.c:344
48
+#: src/modules/module-zeroconf-discover.c:347
49
#, c-format
50
msgid "%s on %s@%s"
51
msgstr "%s на %s@%s"
52
53
-#: src/modules/module-zeroconf-discover.c:348
54
+#: src/modules/module-zeroconf-discover.c:351
55
#, c-format
56
msgid "%s on %s"
57
msgstr "%s на %s"
58
59
-#: src/tools/pw-cat.c:872
60
+#: src/tools/pw-cat.c:940
61
#, c-format
62
-#| msgid ""
63
-#| "%s options <file>\n"
64
-#| " -h, --help Show this help\n"
65
-#| " --version Show version\n"
66
-#| " -v, --verbose Enable verbose operations\n"
67
-#| "\n"
68
msgid ""
69
"%s options <file>|-\n"
70
" -h, --help Show this help\n"
71
72
"інформації\n"
73
"\n"
74
75
-#: src/tools/pw-cat.c:879
76
+#: src/tools/pw-cat.c:947
77
#, c-format
78
#| msgid ""
79
#| " -R, --remote Remote daemon name\n"
80
81
#| " or direct samples (256)\n"
82
#| " the rate is the one of the "
83
#| "source file\n"
84
+#| " -P --properties Set node properties\n"
85
#| "\n"
86
msgid ""
87
" -R, --remote Remote daemon name\n"
88
" --media-type Set media type (default %s)\n"
89
" --media-category Set media category (default %s)\n"
90
" --media-role Set media role (default %s)\n"
91
-" --target Set node target (default %s)\n"
92
+" --target Set node target serial or name "
93
+"(default %s)\n"
94
" 0 means don't link\n"
95
" --latency Set node latency (default %s)\n"
96
" Xunit (unit = s, ms, us, ns)\n"
97
98
"(типово, %s)\n"
99
" --media-role встановити роль мультимедіа (типово, "
100
"%s)\n"
101
-" --target встановити ціль вузла (типово, %s)\n"
102
+" --target встановити назву або серійний номер"
103
+" цілі вузла (типово, %s)\n"
104
" 0 — не пов'язувати\n"
105
" --latency встановити затримку вузла (типово, "
106
"%s)\n"
107
108
" -P --properties встановити властивості вузла\n"
109
"\n"
110
111
-#: src/tools/pw-cat.c:897
112
+#: src/tools/pw-cat.c:965
113
#, c-format
114
msgid ""
115
" --rate Sample rate (req. for rec) (default "
116
117
"(типово, %d)\n"
118
"\n"
119
120
-#: src/tools/pw-cat.c:914
121
+#: src/tools/pw-cat.c:982
122
+#| msgid ""
123
+#| " -p, --playback Playback mode\n"
124
+#| " -r, --record Recording mode\n"
125
+#| " -m, --midi Midi mode\n"
126
+#| " -d, --dsd DSD mode\n"
127
+#| "\n"
128
msgid ""
129
" -p, --playback Playback mode\n"
130
" -r, --record Recording mode\n"
131
" -m, --midi Midi mode\n"
132
" -d, --dsd DSD mode\n"
133
+" -o, --encoded\t\t\t Encoded mode\n"
134
"\n"
135
msgstr ""
136
" -p, --playback режим відтворення\n"
137
" -r, --record режим запису\n"
138
" -m, --midi режим MIDI\n"
139
" -d, --dsd режим DSD\n"
140
+" -o, --encoded\t\t\t закодований режим\n"
141
"\n"
142
143
-#: src/tools/pw-cli.c:3139
144
+#: src/tools/pw-cli.c:2236
145
#, c-format
146
+#| msgid ""
147
+#| "%s options command\n"
148
+#| " -h, --help Show this help\n"
149
+#| " --version Show version\n"
150
+#| " -d, --daemon Start as daemon (Default false)\n"
151
+#| " -r, --remote Remote daemon name\n"
152
+#| "\n"
153
msgid ""
154
"%s options command\n"
155
" -h, --help Show this help\n"
156
" --version Show version\n"
157
" -d, --daemon Start as daemon (Default false)\n"
158
" -r, --remote Remote daemon name\n"
159
+" -m, --monitor Monitor activity\n"
160
"\n"
161
msgstr ""
162
"%s параметри команда\n"
163
164
" -d, --daemon запустити як фонову службу (типово, "
165
"false)\n"
166
" -r, --remote назва віддаленої фонової служби\n"
167
+" -m, --monitor спостерігати за діями\n"
168
"\n"
169
170
-#: spa/plugins/alsa/acp/acp.c:321
171
+#: spa/plugins/alsa/acp/acp.c:323
172
msgid "Pro Audio"
173
msgstr "Професійний звук"
174
175
-#: spa/plugins/alsa/acp/acp.c:444 spa/plugins/alsa/acp/alsa-mixer.c:4648
176
-#: spa/plugins/bluez5/bluez5-device.c:1161
177
+#: spa/plugins/alsa/acp/acp.c:447 spa/plugins/alsa/acp/alsa-mixer.c:4648
178
+#: spa/plugins/bluez5/bluez5-device.c:1303
179
msgid "Off"
180
msgstr "Вимкнено"
181
182
183
184
#: spa/plugins/alsa/acp/alsa-mixer.c:2657
185
#: spa/plugins/alsa/acp/alsa-mixer.c:2741
186
-#: spa/plugins/bluez5/bluez5-device.c:1330
187
+#: spa/plugins/bluez5/bluez5-device.c:1536
188
msgid "Microphone"
189
msgstr "Мікрофон"
190
191
192
msgstr "Без підсилення"
193
194
#: spa/plugins/alsa/acp/alsa-mixer.c:2672
195
-#: spa/plugins/bluez5/bluez5-device.c:1335
196
+#: spa/plugins/bluez5/bluez5-device.c:1542
197
msgid "Speaker"
198
msgstr "Динамік"
199
200
201
202
#: spa/plugins/alsa/acp/alsa-mixer.c:4484
203
#: spa/plugins/alsa/acp/alsa-mixer.c:4642
204
-#: spa/plugins/bluez5/bluez5-device.c:1320
205
+#: spa/plugins/bluez5/bluez5-device.c:1524
206
msgid "Headset"
207
msgstr "Гарнітура"
208
209
210
msgid "%s Input"
211
msgstr "%s-вхід"
212
213
-#: spa/plugins/alsa/acp/alsa-util.c:1173 spa/plugins/alsa/acp/alsa-util.c:1267
214
+#: spa/plugins/alsa/acp/alsa-util.c:1187 spa/plugins/alsa/acp/alsa-util.c:1281
215
#, c-format
216
msgid ""
217
"snd_pcm_avail() returned a value that is exceptionally large: %lu byte (%lu "
218
219
"Ймовірно, ви натрапили на помилку у драйвері ALSA «%s». Будь ласка, "
220
"повідомте про цю помилку розробникам ALSA."
221
222
-#: spa/plugins/alsa/acp/alsa-util.c:1239
223
+#: spa/plugins/alsa/acp/alsa-util.c:1253
224
#, c-format
225
msgid ""
226
"snd_pcm_delay() returned a value that is exceptionally large: %li byte (%s"
227
228
"Ймовірно, ви натрапили на помилку у драйвері ALSA «%s». Будь ласка, "
229
"повідомте про цю помилку розробникам ALSA."
230
231
-#: spa/plugins/alsa/acp/alsa-util.c:1286
232
+#: spa/plugins/alsa/acp/alsa-util.c:1300
233
#, c-format
234
msgid ""
235
"snd_pcm_avail_delay() returned strange values: delay %lu is less than avail "
236
237
"Ймовірно, це пов’язано з помилкою у драйвері ALSA «%s». Будь ласка, "
238
"повідомте про цю помилку розробникам ALSA."
239
240
-#: spa/plugins/alsa/acp/alsa-util.c:1329
241
+#: spa/plugins/alsa/acp/alsa-util.c:1343
242
#, c-format
243
msgid ""
244
"snd_pcm_mmap_begin() returned a value that is exceptionally large: %lu byte "
245
246
"Ймовірно, ви натрапили на помилку у драйвері ALSA «%s». Будь ласка, "
247
"повідомте про цю помилку розробникам ALSA."
248
249
-#: spa/plugins/alsa/acp/channelmap.h:464
250
+#: spa/plugins/alsa/acp/channelmap.h:457
251
msgid "(invalid)"
252
msgstr "(некоректний)"
253
254
255
msgid "Modem"
256
msgstr "Модем"
257
258
-#: spa/plugins/bluez5/bluez5-device.c:1172
259
+#: spa/plugins/bluez5/bluez5-device.c:1314
260
msgid "Audio Gateway (A2DP Source & HSP/HFP AG)"
261
msgstr "Звуковий шлюз (джерело A2DP і HSP/HFP AG)"
262
263
-#: spa/plugins/bluez5/bluez5-device.c:1197
264
+#: spa/plugins/bluez5/bluez5-device.c:1339
265
#, c-format
266
msgid "High Fidelity Playback (A2DP Sink, codec %s)"
267
msgstr "Високоточне відтворення (приймач A2DP, кодек %s)"
268
269
-#: spa/plugins/bluez5/bluez5-device.c:1200
270
+#: spa/plugins/bluez5/bluez5-device.c:1342
271
#, c-format
272
msgid "High Fidelity Duplex (A2DP Source/Sink, codec %s)"
273
msgstr "Двобічний високоточний обмін (джерело/приймач A2DP, кодек %s)"
274
275
-#: spa/plugins/bluez5/bluez5-device.c:1208
276
+#: spa/plugins/bluez5/bluez5-device.c:1350
277
msgid "High Fidelity Playback (A2DP Sink)"
278
msgstr "Високоточне відтворення (приймач A2DP)"
279
280
-#: spa/plugins/bluez5/bluez5-device.c:1210
281
+#: spa/plugins/bluez5/bluez5-device.c:1352
282
msgid "High Fidelity Duplex (A2DP Source/Sink)"
283
msgstr "Двобічний високоточний обмін (джерело/приймач A2DP)"
284
285
-#: spa/plugins/bluez5/bluez5-device.c:1238
286
+#: spa/plugins/bluez5/bluez5-device.c:1391
287
+#, c-format
288
+#| msgid "High Fidelity Playback (A2DP Sink, codec %s)"
289
+msgid "High Fidelity Playback (BAP Sink, codec %s)"
290
+msgstr "Високоточне відтворення (приймач BAP, кодек %s)"
291
+
292
+#: spa/plugins/bluez5/bluez5-device.c:1395
293
+#, c-format
294
+#| msgid "High Fidelity Duplex (A2DP Source/Sink, codec %s)"
295
+msgid "High Fidelity Input (BAP Source, codec %s)"
296
+msgstr "Двобічний високоточний вхід (джерело BAP, кодек %s)"
297
+
298
+#: spa/plugins/bluez5/bluez5-device.c:1399
299
+#, c-format
300
+#| msgid "High Fidelity Duplex (A2DP Source/Sink, codec %s)"
301
+msgid "High Fidelity Duplex (BAP Source/Sink, codec %s)"
302
+msgstr "Двобічний високоточний обмін (джерело/приймач BAP, кодек %s)"
303
+
304
+#: spa/plugins/bluez5/bluez5-device.c:1407
305
+#| msgid "High Fidelity Playback (A2DP Sink)"
306
+msgid "High Fidelity Playback (BAP Sink)"
307
+msgstr "Високоточне відтворення (приймач BAP)"
308
+
309
+#: spa/plugins/bluez5/bluez5-device.c:1410
310
+#| msgid "High Fidelity Duplex (A2DP Source/Sink)"
311
+msgid "High Fidelity Input (BAP Source)"
312
+msgstr "Двобічний високоточний вхід (джерело BAP)"
313
+
314
+#: spa/plugins/bluez5/bluez5-device.c:1413
315
+#| msgid "High Fidelity Duplex (A2DP Source/Sink)"
316
+msgid "High Fidelity Duplex (BAP Source/Sink)"
317
+msgstr "Двобічний високоточний обмін (джерело/приймач BAP)"
318
+
319
+#: spa/plugins/bluez5/bluez5-device.c:1441
320
#, c-format
321
msgid "Headset Head Unit (HSP/HFP, codec %s)"
322
msgstr "Головний модуль гарнітури (HSP/HFP, кодек %s)"
323
324
-#: spa/plugins/bluez5/bluez5-device.c:1243
325
+#: spa/plugins/bluez5/bluez5-device.c:1446
326
msgid "Headset Head Unit (HSP/HFP)"
327
msgstr "Головний модуль гарнітури (HSP/HFP)"
328
329
-#: spa/plugins/bluez5/bluez5-device.c:1325
330
+#: spa/plugins/bluez5/bluez5-device.c:1525
331
+#: spa/plugins/bluez5/bluez5-device.c:1530
332
+#: spa/plugins/bluez5/bluez5-device.c:1537
333
+#: spa/plugins/bluez5/bluez5-device.c:1543
334
+#: spa/plugins/bluez5/bluez5-device.c:1549
335
+#: spa/plugins/bluez5/bluez5-device.c:1555
336
+#: spa/plugins/bluez5/bluez5-device.c:1561
337
+#: spa/plugins/bluez5/bluez5-device.c:1567
338
+#: spa/plugins/bluez5/bluez5-device.c:1573
339
msgid "Handsfree"
340
msgstr "Hands-Free пристрій"
341
342
-#: spa/plugins/bluez5/bluez5-device.c:1340
343
+#: spa/plugins/bluez5/bluez5-device.c:1531
344
+#| msgid "Handsfree"
345
+msgid "Handsfree (HFP)"
346
+msgstr "Hands-Free пристрій (HFP)"
347
+
348
+#: spa/plugins/bluez5/bluez5-device.c:1548
349
msgid "Headphone"
350
msgstr "Навушники"
351
352
-#: spa/plugins/bluez5/bluez5-device.c:1345
353
+#: spa/plugins/bluez5/bluez5-device.c:1554
354
msgid "Portable"
355
msgstr "Портативна акустика"
356
357
-#: spa/plugins/bluez5/bluez5-device.c:1350
358
+#: spa/plugins/bluez5/bluez5-device.c:1560
359
msgid "Car"
360
msgstr "Автомобільна акустика"
361
362
-#: spa/plugins/bluez5/bluez5-device.c:1355
363
+#: spa/plugins/bluez5/bluez5-device.c:1566
364
msgid "HiFi"
365
msgstr "Hi-Fi"
366
367
-#: spa/plugins/bluez5/bluez5-device.c:1360
368
+#: spa/plugins/bluez5/bluez5-device.c:1572
369
msgid "Phone"
370
msgstr "Телефон"
371
372
-#: spa/plugins/bluez5/bluez5-device.c:1366
373
+#: spa/plugins/bluez5/bluez5-device.c:1579
374
msgid "Bluetooth"
375
msgstr "Bluetooth"
376
+
377
+#: spa/plugins/bluez5/bluez5-device.c:1580
378
+#| msgid "Bluetooth"
379
+msgid "Bluetooth (HFP)"
380
+msgstr "Bluetooth (HFP)"
381
pipewire-0.3.65.tar.gz/spa/include/spa/param/port-config.h -> pipewire-0.3.66.tar.gz/spa/include/spa/param/port-config.h
Changed
10
1
2
/** properties for SPA_TYPE_OBJECT_ParamPortConfig */
3
enum spa_param_port_config {
4
SPA_PARAM_PORT_CONFIG_START,
5
- SPA_PARAM_PORT_CONFIG_direction, /**< direction, input/output (Id enum spa_direction) */
6
+ SPA_PARAM_PORT_CONFIG_direction, /**< (Id enum spa_direction) direction */
7
SPA_PARAM_PORT_CONFIG_mode, /**< (Id enum spa_param_port_config_mode) mode */
8
SPA_PARAM_PORT_CONFIG_monitor, /**< (Bool) enable monitor output ports on input ports */
9
SPA_PARAM_PORT_CONFIG_control, /**< (Bool) enable control ports */
10
pipewire-0.3.65.tar.gz/spa/include/spa/utils/defs.h -> pipewire-0.3.66.tar.gz/spa/include/spa/utils/defs.h
Changed
10
1
2
for ((ptr) = arr; (void*)(ptr) < SPA_PTROFF(arr, sizeof(arr), void); (ptr)++)
3
4
#define SPA_FOR_EACH_ELEMENT_VAR(arr, var) \
5
- for (__typeof__((arr)0)* (var) = arr; (void*)(var) < SPA_PTROFF(arr, sizeof(arr), void); (var)++)
6
+ for (__typeof__((arr)0)* var = arr; (void*)(var) < SPA_PTROFF(arr, sizeof(arr), void); (var)++)
7
8
#define SPA_ABS(a) \
9
({ \
10
pipewire-0.3.65.tar.gz/spa/meson.build -> pipewire-0.3.66.tar.gz/spa/meson.build
Changed
28
1
2
# plugin-specific dependencies
3
alsa_dep = dependency('alsa', required: get_option('alsa'))
4
summary({'ALSA': alsa_dep.found()}, bool_yn: true, section: 'Backend')
5
+
6
bluez_dep = dependency('bluez', version : '>= 4.101', required: get_option('bluez5'))
7
gio_dep = dependency('gio-2.0', required : get_option('bluez5'))
8
gio_unix_dep = dependency('gio-unix-2.0', required : get_option('bluez5'))
9
- bluez_deps_found = bluez_dep.found() and gio_dep.found() and gio_unix_dep.found()
10
+ bluez_glib2_dep = dependency('glib-2.0', required : get_option('bluez5'))
11
+ sbc_dep = dependency('sbc', required: get_option('bluez5'))
12
+ summary({'SBC': sbc_dep.found()}, bool_yn: true, section: 'Bluetooth audio codecs')
13
+ bluez5_deps = mathlib, dbus_dep, sbc_dep, bluez_dep, bluez_glib2_dep, gio_dep, gio_unix_dep
14
+ bluez_deps_found = get_option('bluez5').allowed()
15
+ foreach dep: bluez5_deps
16
+ if get_option('bluez5').enabled() and not dep.found()
17
+ error('bluez5 enabled, but dependency not found: ' + dep.name())
18
+ endif
19
+ bluez_deps_found = bluez_deps_found and dep.found()
20
+ endforeach
21
summary({'Bluetooth audio': bluez_deps_found}, bool_yn: true, section: 'Backend')
22
if bluez_deps_found
23
- sbc_dep = dependency('sbc', required: get_option('bluez5'))
24
- summary({'SBC': sbc_dep.found()}, bool_yn: true, section: 'Bluetooth audio codecs')
25
ldac_dep = dependency('ldacBT-enc', required : get_option('bluez5-codec-ldac'))
26
summary({'LDAC': ldac_dep.found()}, bool_yn: true, section: 'Bluetooth audio codecs')
27
ldac_abr_dep = dependency('ldacBT-abr', required : get_option('bluez5-codec-ldac'))
28
pipewire-0.3.65.tar.gz/spa/plugins/alsa/acp/acp.c -> pipewire-0.3.66.tar.gz/spa/plugins/alsa/acp/acp.c
Changed
27
1
2
3
ss.format = PA_SAMPLE_S32LE;
4
ss.rate = impl->rate;
5
- ss.channels = 64;
6
+ ss.channels = impl->pro_channels;
7
8
ap = pa_xnew0(pa_alsa_profile, 1);
9
ap->profile_set = ps;
10
11
impl->auto_port = true;
12
impl->ignore_dB = false;
13
impl->rate = DEFAULT_RATE;
14
+ impl->pro_channels = 64;
15
16
if (props) {
17
if ((s = acp_dict_lookup(props, "api.alsa.use-ucm")) != NULL)
18
19
impl->auto_port = spa_atob(s);
20
if ((s = acp_dict_lookup(props, "api.acp.probe-rate")) != NULL)
21
impl->rate = atoi(s);
22
+ if ((s = acp_dict_lookup(props, "api.acp.pro-channels")) != NULL)
23
+ impl->pro_channels = atoi(s);
24
}
25
26
impl->ucm.default_sample_spec.format = PA_SAMPLE_S16NE;
27
pipewire-0.3.65.tar.gz/spa/plugins/alsa/acp/card.h -> pipewire-0.3.66.tar.gz/spa/plugins/alsa/acp/card.h
Changed
9
1
2
bool auto_port;
3
bool ignore_dB;
4
uint32_t rate;
5
+ uint32_t pro_channels;
6
7
pa_alsa_ucm_config ucm;
8
pa_alsa_profile_set *profile_set;
9
pipewire-0.3.65.tar.gz/spa/plugins/alsa/alsa-pcm.c -> pipewire-0.3.66.tar.gz/spa/plugins/alsa/alsa-pcm.c
Changed
10
1
2
} else {
3
*delay = avail;
4
*target = SPA_MAX(*target, state->read_size);
5
+ if (state->matching)
6
+ *target += 32;
7
}
8
*target = SPA_CLAMP(*target, state->min_delay, state->buffer_frames);
9
return 0;
10
pipewire-0.3.65.tar.gz/spa/plugins/audioconvert/channelmix-ops.c -> pipewire-0.3.66.tar.gz/spa/plugins/audioconvert/channelmix-ops.c
Changed
623
1
2
#define MATRIX_DOLBY 1
3
#define MATRIX_DPLII 2
4
5
-#define _CH(ch) ((SPA_AUDIO_CHANNEL_ ## ch)-3)
6
+#define _SH 2
7
+#define _CH(ch) ((SPA_AUDIO_CHANNEL_ ## ch)-_SH)
8
#define _MASK(ch) (1ULL << _CH(ch))
9
#define FRONT (_MASK(FC))
10
#define STEREO (_MASK(FL)|_MASK(FR))
11
#define REAR (_MASK(RL)|_MASK(RR))
12
#define SIDE (_MASK(SL)|_MASK(SR))
13
14
+static uint32_t mask_to_ch(struct channelmix *mix, uint64_t mask)
15
+{
16
+ uint32_t ch = 0;
17
+ while (mask > 1) {
18
+ ch++;
19
+ mask >>= 1;
20
+ }
21
+ return ch;
22
+}
23
+
24
+static void distribute_mix(struct channelmix *mix,
25
+ float matrixSPA_AUDIO_MAX_CHANNELSSPA_AUDIO_MAX_CHANNELS,
26
+ uint64_t mask)
27
+{
28
+ uint32_t i, ch = mask_to_ch(mix, mask);
29
+ for (i = 0; i < SPA_AUDIO_MAX_CHANNELS; i++)
30
+ matrixich= 1.0f;
31
+}
32
+static void average_mix(struct channelmix *mix,
33
+ float matrixSPA_AUDIO_MAX_CHANNELSSPA_AUDIO_MAX_CHANNELS,
34
+ uint64_t mask)
35
+{
36
+ uint32_t i, ch = mask_to_ch(mix, mask);
37
+ for (i = 0; i < SPA_AUDIO_MAX_CHANNELS; i++)
38
+ matrixchi= 1.0f;
39
+}
40
+static void pair_mix(float matrixSPA_AUDIO_MAX_CHANNELSSPA_AUDIO_MAX_CHANNELS)
41
+{
42
+ uint32_t i;
43
+ for (i = 0; i < SPA_AUDIO_MAX_CHANNELS; i++)
44
+ matrixii= 1.0f;
45
+}
46
+static bool match_mix(struct channelmix *mix,
47
+ float matrixSPA_AUDIO_MAX_CHANNELSSPA_AUDIO_MAX_CHANNELS,
48
+ uint64_t src_mask, uint64_t dst_mask)
49
+{
50
+ bool matched = false;
51
+ uint32_t i;
52
+ for (i = 0; i < SPA_AUDIO_MAX_CHANNELS; i++) {
53
+ if ((src_mask & dst_mask & (1ULL << i))) {
54
+ spa_log_info(mix->log, "matched channel %u (%f)", i, 1.0f);
55
+ matrixii = 1.0f;
56
+ matched = true;
57
+ }
58
+ }
59
+ return matched;
60
+}
61
+
62
static int make_matrix(struct channelmix *mix)
63
{
64
float matrixSPA_AUDIO_MAX_CHANNELSSPA_AUDIO_MAX_CHANNELS = {{ 0.0f }};
65
- uint64_t src_mask = mix->src_mask;
66
- uint64_t dst_mask = mix->dst_mask;
67
+ uint64_t src_mask = mix->src_mask, src_paired;
68
+ uint64_t dst_mask = mix->dst_mask, dst_paired;
69
uint32_t src_chan = mix->src_chan;
70
uint32_t dst_chan = mix->dst_chan;
71
uint64_t unassigned, keep;
72
73
float slev = SQRT1_2;
74
float llev = 0.5f;
75
float maxsum = 0.0f;
76
- bool filter_fc = false, filter_lfe = false;
77
+ bool filter_fc = false, filter_lfe = false, matched = false, normalize;
78
#define _MATRIX(s,d) matrix_CH(s)_CH(d)
79
80
+ normalize = SPA_FLAG_IS_SET(mix->options, CHANNELMIX_OPTION_NORMALIZE);
81
+
82
spa_log_debug(mix->log, "src-mask:%08"PRIx64" dst-mask:%08"PRIx64
83
" options:%08x", src_mask, dst_mask, mix->options);
84
85
- /* move the MONO mask to FRONT so that the lower bits can be shifted
86
- * away. */
87
- if ((src_mask & (1Ull << SPA_AUDIO_CHANNEL_MONO)) != 0) {
88
- if (src_chan == 1)
89
- src_mask = 0;
90
- else
91
- src_mask |= (1ULL << SPA_AUDIO_CHANNEL_FC);
92
- }
93
- if ((dst_mask & (1Ull << SPA_AUDIO_CHANNEL_MONO)) != 0)
94
- dst_mask |= (1ULL << SPA_AUDIO_CHANNEL_FC);
95
+ /* shift so that bit 0 is MONO */
96
+ src_mask >>= _SH;
97
+ dst_mask >>= _SH;
98
99
- /* shift so that bit 0 is FL */
100
- src_mask >>= 3;
101
- dst_mask >>= 3;
102
+ if (src_chan > 1 && (src_mask & _MASK(MONO)))
103
+ src_mask = 0;
104
+ if (dst_chan > 1 && (dst_mask & _MASK(MONO)))
105
+ dst_mask = 0;
106
107
- /* unknown channels or just 1 channel */
108
+ src_paired = src_mask;
109
+ dst_paired = dst_mask;
110
+
111
+ /* unknown channels */
112
if (src_mask == 0 || dst_mask == 0) {
113
if (src_chan == 1) {
114
- /* one FC/MONO src goes everywhere */
115
- spa_log_debug(mix->log, "distribute FC/MONO (%f)", 1.0f);
116
- for (i = 0; i < SPA_AUDIO_MAX_CHANNELS; i++)
117
- matrixi0= 1.0f;
118
+ /* one src channel goes everywhere */
119
+ spa_log_info(mix->log, "distribute UNK (%f) %"PRIu64, 1.0f, src_mask);
120
+ distribute_mix(mix, matrix, src_mask);
121
} else if (dst_chan == 1) {
122
- /* one FC/MONO dst get average of everything */
123
- spa_log_debug(mix->log, "average FC/MONO (%f)", 1.0f / src_chan);
124
- for (i = 0; i < SPA_AUDIO_MAX_CHANNELS; i++)
125
- matrix0i= 1.0f / src_chan;
126
+ /* one dst channel get average of everything */
127
+ spa_log_info(mix->log, "average UNK (%f) %"PRIu64, 1.0f / src_chan, dst_mask);
128
+ average_mix(mix, matrix, dst_mask);
129
+ normalize = true;
130
} else {
131
/* just pair channels */
132
- spa_log_debug(mix->log, "pairing channels (%f)", 1.0f);
133
- for (i = 0; i < SPA_AUDIO_MAX_CHANNELS; i++)
134
- matrixii= 1.0f;
135
+ spa_log_info(mix->log, "pairing UNK channels (%f)", 1.0f);
136
+ if (src_mask == 0)
137
+ src_paired = dst_mask;
138
+ else if (dst_mask == 0)
139
+ dst_paired = src_mask;
140
+ pair_mix(matrix);
141
}
142
- if (dst_mask & FRONT)
143
- filter_fc = true;
144
- if (dst_mask & _MASK(LFE))
145
- filter_lfe = true;
146
- src_mask = dst_mask = ~0LU;
147
goto done;
148
} else {
149
spa_log_debug(mix->log, "matching channels");
150
- for (i = 0; i < SPA_AUDIO_MAX_CHANNELS; i++) {
151
- if ((src_mask & dst_mask & (1ULL << i))) {
152
- spa_log_debug(mix->log, "matched channel %u (%f)", i, 1.0f);
153
- matrixii= 1.0f;
154
- }
155
- }
156
+ matched = match_mix(mix, matrix, src_mask, dst_mask);
157
}
158
159
unassigned = src_mask & ~dst_mask;
160
keep = dst_mask & ~src_mask;
161
162
if (!SPA_FLAG_IS_SET(mix->options, CHANNELMIX_OPTION_UPMIX)) {
163
+ /* upmix completely disabled */
164
keep = 0;
165
} else {
166
+ /* some upmixing (FC and LFE) enabled. */
167
if (mix->upmix == CHANNELMIX_UPMIX_NONE)
168
keep = 0;
169
- keep |= FRONT;
170
+ if (mix->fc_cutoff > 0.0f)
171
+ keep |= FRONT;
172
+ else
173
+ keep &= ~FRONT;
174
if (mix->lfe_cutoff > 0.0f)
175
keep |= _MASK(LFE);
176
else
177
keep &= ~_MASK(LFE);
178
}
179
+ /* if we have no channel matched, try to upmix or keep the stereo
180
+ * pair or else we might end up with silence. */
181
+ if (dst_mask & STEREO && !matched)
182
+ keep |= STEREO;
183
+
184
+ spa_log_info(mix->log, "unassigned downmix %08" PRIx64 " %08" PRIx64, unassigned, keep);
185
+
186
+ if (unassigned & _MASK(MONO)) {
187
+ if ((dst_mask & STEREO) == STEREO) {
188
+ spa_log_info(mix->log, "assign MONO to STEREO (%f)", 1.0f);
189
+ _MATRIX(FL,MONO) += 1.0f;
190
+ _MATRIX(FR,MONO) += 1.0f;
191
+ keep &= ~STEREO;
192
+ } else if ((dst_mask & FRONT) == FRONT) {
193
+ spa_log_info(mix->log, "assign MONO to FRONT (%f)", 1.0f);
194
+ _MATRIX(FC,MONO) += 1.0f;
195
+ normalize = true;
196
+ } else {
197
+ spa_log_warn(mix->log, "can't assign MONO");
198
+ }
199
+ }
200
201
- spa_log_debug(mix->log, "unassigned downmix %08" PRIx64 " %08" PRIx64, unassigned, keep);
202
-
203
- if (unassigned & FRONT){
204
+ if (unassigned & FRONT) {
205
if ((dst_mask & STEREO) == STEREO){
206
- if(src_mask & STEREO) {
207
- spa_log_debug(mix->log, "assign FC to STEREO (%f)", clev);
208
+ if (src_mask & STEREO) {
209
+ spa_log_info(mix->log, "assign FC to STEREO (%f)", clev);
210
_MATRIX(FL,FC) += clev;
211
_MATRIX(FR,FC) += clev;
212
} else {
213
- spa_log_debug(mix->log, "assign FC to STEREO (%f)", SQRT1_2);
214
+ spa_log_info(mix->log, "assign FC to STEREO (%f)", SQRT1_2);
215
_MATRIX(FL,FC) += SQRT1_2;
216
_MATRIX(FR,FC) += SQRT1_2;
217
}
218
+ keep &= ~STEREO;
219
+ } else if (dst_mask & _MASK(MONO)){
220
+ spa_log_info(mix->log, "assign FC to MONO (%f)", 1.0f);
221
+ for (i = 0; i < SPA_AUDIO_MAX_CHANNELS; i++)
222
+ matrixi_CH(FC)= 1.0f;
223
+ normalize = true;
224
} else {
225
spa_log_warn(mix->log, "can't assign FC");
226
}
227
228
229
if (unassigned & STEREO){
230
if (dst_mask & FRONT) {
231
- spa_log_debug(mix->log, "assign STEREO to FC (%f)", SQRT1_2);
232
+ spa_log_info(mix->log, "assign STEREO to FC (%f)", SQRT1_2);
233
_MATRIX(FC,FL) += SQRT1_2;
234
_MATRIX(FC,FR) += SQRT1_2;
235
if (src_mask & FRONT) {
236
- spa_log_debug(mix->log, "assign FC to FC (%f)", clev * SQRT2);
237
+ spa_log_info(mix->log, "assign FC to FC (%f)", clev * SQRT2);
238
_MATRIX(FC,FC) = clev * SQRT2;
239
}
240
keep &= ~FRONT;
241
+ } else if ((dst_mask & _MASK(MONO))){
242
+ spa_log_info(mix->log, "assign STEREO to MONO (%f)", 1.0f);
243
+ for (i = 0; i < SPA_AUDIO_MAX_CHANNELS; i++) {
244
+ matrixi_CH(FL)= 1.0f;
245
+ matrixi_CH(FR)= 1.0f;
246
+ }
247
+ normalize = true;
248
} else {
249
spa_log_warn(mix->log, "can't assign STEREO");
250
}
251
252
253
if (unassigned & _MASK(RC)) {
254
if (dst_mask & REAR){
255
- spa_log_debug(mix->log, "assign RC to RL+RR (%f)", SQRT1_2);
256
+ spa_log_info(mix->log, "assign RC to RL+RR (%f)", SQRT1_2);
257
_MATRIX(RL,RC) += SQRT1_2;
258
_MATRIX(RR,RC) += SQRT1_2;
259
} else if (dst_mask & SIDE) {
260
- spa_log_debug(mix->log, "assign RC to SL+SR (%f)", SQRT1_2);
261
+ spa_log_info(mix->log, "assign RC to SL+SR (%f)", SQRT1_2);
262
_MATRIX(SL,RC) += SQRT1_2;
263
_MATRIX(SR,RC) += SQRT1_2;
264
} else if(dst_mask & STEREO) {
265
- spa_log_debug(mix->log, "assign RC to FL+FR");
266
+ spa_log_info(mix->log, "assign RC to FL+FR");
267
if (matrix_encoding == MATRIX_DOLBY ||
268
matrix_encoding == MATRIX_DPLII) {
269
if (unassigned & (_MASK(RL)|_MASK(RR))) {
270
271
_MATRIX(FR,RC) += slev * SQRT1_2;
272
}
273
} else if (dst_mask & FRONT) {
274
- spa_log_debug(mix->log, "assign RC to FC (%f)", slev * SQRT1_2);
275
+ spa_log_info(mix->log, "assign RC to FC (%f)", slev * SQRT1_2);
276
_MATRIX(FC,RC) += slev * SQRT1_2;
277
+ } else if (dst_mask & _MASK(MONO)){
278
+ spa_log_info(mix->log, "assign RC to MONO (%f)", 1.0f);
279
+ for (i = 0; i < SPA_AUDIO_MAX_CHANNELS; i++)
280
+ matrixi_CH(RC)= 1.0f;
281
+ normalize = true;
282
} else {
283
spa_log_warn(mix->log, "can't assign RC");
284
}
285
286
287
if (unassigned & REAR) {
288
if (dst_mask & _MASK(RC)) {
289
- spa_log_debug(mix->log, "assign RL+RR to RC");
290
+ spa_log_info(mix->log, "assign RL+RR to RC");
291
_MATRIX(RC,RL) += SQRT1_2;
292
_MATRIX(RC,RR) += SQRT1_2;
293
} else if (dst_mask & SIDE) {
294
- spa_log_debug(mix->log, "assign RL+RR to SL+SR");
295
+ spa_log_info(mix->log, "assign RL+RR to SL+SR");
296
if (src_mask & SIDE) {
297
_MATRIX(SL,RL) += SQRT1_2;
298
_MATRIX(SR,RR) += SQRT1_2;
299
300
}
301
keep &= ~SIDE;
302
} else if (dst_mask & STEREO) {
303
- spa_log_debug(mix->log, "assign RL+RR to FL+FR (%f)", slev);
304
+ spa_log_info(mix->log, "assign RL+RR to FL+FR (%f)", slev);
305
if (matrix_encoding == MATRIX_DOLBY) {
306
_MATRIX(FL,RL) -= slev * SQRT1_2;
307
_MATRIX(FL,RR) -= slev * SQRT1_2;
308
309
_MATRIX(FR,RR) += slev;
310
}
311
} else if (dst_mask & FRONT) {
312
- spa_log_debug(mix->log, "assign RL+RR to FC (%f)",
313
+ spa_log_info(mix->log, "assign RL+RR to FC (%f)",
314
slev * SQRT1_2);
315
_MATRIX(FC,RL)+= slev * SQRT1_2;
316
_MATRIX(FC,RR)+= slev * SQRT1_2;
317
+ } else if (dst_mask & _MASK(MONO)){
318
+ spa_log_info(mix->log, "assign RL+RR to MONO (%f)", 1.0f);
319
+ for (i = 0; i < SPA_AUDIO_MAX_CHANNELS; i++) {
320
+ matrixi_CH(RL)= 1.0f;
321
+ matrixi_CH(RR)= 1.0f;
322
+ }
323
+ normalize = true;
324
} else {
325
spa_log_warn(mix->log, "can't assign RL");
326
}
327
328
if (unassigned & SIDE) {
329
if (dst_mask & REAR) {
330
if (src_mask & _MASK(RL)) {
331
- spa_log_debug(mix->log, "assign SL+SR to RL+RR (%f)", SQRT1_2);
332
+ spa_log_info(mix->log, "assign SL+SR to RL+RR (%f)", SQRT1_2);
333
_MATRIX(RL,SL) += SQRT1_2;
334
_MATRIX(RR,SR) += SQRT1_2;
335
} else {
336
- spa_log_debug(mix->log, "assign SL+SR to RL+RR (%f)", 1.0f);
337
+ spa_log_info(mix->log, "assign SL+SR to RL+RR (%f)", 1.0f);
338
_MATRIX(RL,SL) += 1.0f;
339
_MATRIX(RR,SR) += 1.0f;
340
}
341
keep &= ~REAR;
342
} else if (dst_mask & _MASK(RC)) {
343
- spa_log_debug(mix->log, "assign SL+SR to RC (%f)", SQRT1_2);
344
+ spa_log_info(mix->log, "assign SL+SR to RC (%f)", SQRT1_2);
345
_MATRIX(RC,SL)+= SQRT1_2;
346
_MATRIX(RC,SR)+= SQRT1_2;
347
} else if (dst_mask & STEREO) {
348
if (matrix_encoding == MATRIX_DOLBY) {
349
- spa_log_debug(mix->log, "assign SL+SR to FL+FR (%f)",
350
+ spa_log_info(mix->log, "assign SL+SR to FL+FR (%f)",
351
slev * SQRT1_2);
352
_MATRIX(FL,SL) -= slev * SQRT1_2;
353
_MATRIX(FL,SR) -= slev * SQRT1_2;
354
_MATRIX(FR,SL) += slev * SQRT1_2;
355
_MATRIX(FR,SR) += slev * SQRT1_2;
356
} else if (matrix_encoding == MATRIX_DPLII) {
357
- spa_log_debug(mix->log, "assign SL+SR to FL+FR (%f / %f)",
358
+ spa_log_info(mix->log, "assign SL+SR to FL+FR (%f / %f)",
359
slev * SQRT3_2, slev * SQRT1_2);
360
_MATRIX(FL,SL) -= slev * SQRT3_2;
361
_MATRIX(FL,SR) -= slev * SQRT1_2;
362
_MATRIX(FR,SL) += slev * SQRT1_2;
363
_MATRIX(FR,SR) += slev * SQRT3_2;
364
} else {
365
- spa_log_debug(mix->log, "assign SL+SR to FL+FR (%f)", slev);
366
+ spa_log_info(mix->log, "assign SL+SR to FL+FR (%f)", slev);
367
_MATRIX(FL,SL) += slev;
368
_MATRIX(FR,SR) += slev;
369
}
370
} else if (dst_mask & FRONT) {
371
- spa_log_debug(mix->log, "assign SL+SR to FC (%f)", slev * SQRT1_2);
372
+ spa_log_info(mix->log, "assign SL+SR to FC (%f)", slev * SQRT1_2);
373
_MATRIX(FC,SL) += slev * SQRT1_2;
374
_MATRIX(FC,SR) += slev * SQRT1_2;
375
+ } else if (dst_mask & _MASK(MONO)){
376
+ spa_log_info(mix->log, "assign SL+SR to MONO (%f)", 1.0f);
377
+ for (i = 0; i < SPA_AUDIO_MAX_CHANNELS; i++) {
378
+ matrixi_CH(SL)= 1.0f;
379
+ matrixi_CH(SR)= 1.0f;
380
+ }
381
+ normalize = true;
382
} else {
383
spa_log_warn(mix->log, "can't assign SL");
384
}
385
386
387
if (unassigned & _MASK(FLC)) {
388
if (dst_mask & STEREO) {
389
- spa_log_debug(mix->log, "assign FLC+FRC to FL+FR (%f)", 1.0f);
390
+ spa_log_info(mix->log, "assign FLC+FRC to FL+FR (%f)", 1.0f);
391
_MATRIX(FL,FLC)+= 1.0f;
392
_MATRIX(FR,FRC)+= 1.0f;
393
} else if(dst_mask & FRONT) {
394
- spa_log_debug(mix->log, "assign FLC+FRC to FC (%f)", SQRT1_2);
395
+ spa_log_info(mix->log, "assign FLC+FRC to FC (%f)", SQRT1_2);
396
_MATRIX(FC,FLC)+= SQRT1_2;
397
_MATRIX(FC,FRC)+= SQRT1_2;
398
+ } else if (dst_mask & _MASK(MONO)){
399
+ spa_log_info(mix->log, "assign FLC+FRC to MONO (%f)", 1.0f);
400
+ for (i = 0; i < SPA_AUDIO_MAX_CHANNELS; i++) {
401
+ matrixi_CH(FLC)= 1.0f;
402
+ matrixi_CH(FRC)= 1.0f;
403
+ }
404
+ normalize = true;
405
} else {
406
spa_log_warn(mix->log, "can't assign FLC");
407
}
408
409
if (unassigned & _MASK(LFE) &&
410
SPA_FLAG_IS_SET(mix->options, CHANNELMIX_OPTION_MIX_LFE)) {
411
if (dst_mask & FRONT) {
412
- spa_log_debug(mix->log, "assign LFE to FC (%f)", llev);
413
+ spa_log_info(mix->log, "assign LFE to FC (%f)", llev);
414
_MATRIX(FC,LFE) += llev;
415
} else if (dst_mask & STEREO) {
416
- spa_log_debug(mix->log, "assign LFE to FL+FR (%f)",
417
+ spa_log_info(mix->log, "assign LFE to FL+FR (%f)",
418
llev * SQRT1_2);
419
_MATRIX(FL,LFE) += llev * SQRT1_2;
420
_MATRIX(FR,LFE) += llev * SQRT1_2;
421
+ } else if ((dst_mask & _MASK(MONO))){
422
+ spa_log_info(mix->log, "assign LFE to MONO (%f)", 1.0f);
423
+ for (i = 0; i < SPA_AUDIO_MAX_CHANNELS; i++)
424
+ matrixi_CH(LFE)= 1.0f;
425
+ normalize = true;
426
} else {
427
spa_log_warn(mix->log, "can't assign LFE");
428
}
429
430
431
unassigned = dst_mask & ~src_mask & keep;
432
433
- spa_log_debug(mix->log, "unassigned upmix %08"PRIx64" lfe:%f",
434
+ spa_log_info(mix->log, "unassigned upmix %08"PRIx64" lfe:%f",
435
unassigned, mix->lfe_cutoff);
436
437
if (unassigned & STEREO) {
438
if ((src_mask & FRONT) == FRONT) {
439
- spa_log_debug(mix->log, "produce STEREO from FC (%f)", clev);
440
+ spa_log_info(mix->log, "produce STEREO from FC (%f)", clev);
441
_MATRIX(FL,FC) += clev;
442
_MATRIX(FR,FC) += clev;
443
+ } else if (src_mask & _MASK(MONO)) {
444
+ spa_log_info(mix->log, "produce STEREO from MONO (%f)", 1.0f);
445
+ _MATRIX(FL,MONO) += 1.0f;
446
+ _MATRIX(FR,MONO) += 1.0f;
447
} else {
448
spa_log_warn(mix->log, "can't produce STEREO");
449
}
450
}
451
if (unassigned & FRONT) {
452
if ((src_mask & STEREO) == STEREO) {
453
- spa_log_debug(mix->log, "produce FC from STEREO (%f)", clev);
454
+ spa_log_info(mix->log, "produce FC from STEREO (%f)", clev);
455
_MATRIX(FC,FL) += clev;
456
_MATRIX(FC,FR) += clev;
457
filter_fc = true;
458
+ } else if (src_mask & _MASK(MONO)) {
459
+ spa_log_info(mix->log, "produce FC from MONO (%f)", 1.0f);
460
+ _MATRIX(FC,MONO) += 1.0f;
461
+ filter_fc = true;
462
} else {
463
spa_log_warn(mix->log, "can't produce FC");
464
}
465
}
466
if (unassigned & _MASK(LFE)) {
467
if ((src_mask & STEREO) == STEREO) {
468
- spa_log_debug(mix->log, "produce LFE from STEREO (%f)", llev);
469
+ spa_log_info(mix->log, "produce LFE from STEREO (%f)", llev);
470
_MATRIX(LFE,FL) += llev;
471
_MATRIX(LFE,FR) += llev;
472
filter_lfe = true;
473
} else if ((src_mask & FRONT) == FRONT) {
474
- spa_log_debug(mix->log, "produce LFE from FC (%f)", llev);
475
+ spa_log_info(mix->log, "produce LFE from FC (%f)", llev);
476
_MATRIX(LFE,FC) += llev;
477
filter_lfe = true;
478
+ } else if (src_mask & _MASK(MONO)) {
479
+ spa_log_info(mix->log, "produce LFE from MONO (%f)", 1.0f);
480
+ _MATRIX(LFE,MONO) += 1.0f;
481
+ filter_lfe = true;
482
} else {
483
spa_log_warn(mix->log, "can't produce LFE");
484
}
485
}
486
if (unassigned & SIDE) {
487
if ((src_mask & REAR) == REAR) {
488
- spa_log_debug(mix->log, "produce SIDE from REAR (%f)", 1.0f);
489
+ spa_log_info(mix->log, "produce SIDE from REAR (%f)", 1.0f);
490
_MATRIX(SL,RL) += 1.0f;
491
_MATRIX(SR,RR) += 1.0f;
492
} else if ((src_mask & STEREO) == STEREO) {
493
- spa_log_debug(mix->log, "produce SIDE from STEREO (%f)", slev);
494
+ spa_log_info(mix->log, "produce SIDE from STEREO (%f)", slev);
495
_MATRIX(SL,FL) += slev;
496
_MATRIX(SR,FR) += slev;
497
} else if ((src_mask & FRONT) == FRONT &&
498
mix->upmix == CHANNELMIX_UPMIX_SIMPLE) {
499
- spa_log_debug(mix->log, "produce SIDE from FC (%f)", clev);
500
+ spa_log_info(mix->log, "produce SIDE from FC (%f)", clev);
501
_MATRIX(SL,FC) += clev;
502
_MATRIX(SR,FC) += clev;
503
+ } else if (src_mask & _MASK(MONO) &&
504
+ mix->upmix == CHANNELMIX_UPMIX_SIMPLE) {
505
+ spa_log_info(mix->log, "produce SIDE from MONO (%f)", 1.0f);
506
+ _MATRIX(SL,MONO) += 1.0f;
507
+ _MATRIX(SR,MONO) += 1.0f;
508
} else {
509
- spa_log_debug(mix->log, "won't produce SIDE");
510
+ spa_log_info(mix->log, "won't produce SIDE");
511
}
512
}
513
if (unassigned & REAR) {
514
if ((src_mask & SIDE) == SIDE) {
515
- spa_log_debug(mix->log, "produce REAR from SIDE (%f)", 1.0f);
516
+ spa_log_info(mix->log, "produce REAR from SIDE (%f)", 1.0f);
517
_MATRIX(RL,SL) += 1.0f;
518
_MATRIX(RR,SR) += 1.0f;
519
} else if ((src_mask & STEREO) == STEREO) {
520
- spa_log_debug(mix->log, "produce REAR from STEREO (%f)", slev);
521
+ spa_log_info(mix->log, "produce REAR from STEREO (%f)", slev);
522
_MATRIX(RL,FL) += slev;
523
_MATRIX(RR,FR) += slev;
524
} else if ((src_mask & FRONT) == FRONT &&
525
mix->upmix == CHANNELMIX_UPMIX_SIMPLE) {
526
- spa_log_debug(mix->log, "produce REAR from FC (%f)", clev);
527
+ spa_log_info(mix->log, "produce REAR from FC (%f)", clev);
528
_MATRIX(RL,FC) += clev;
529
_MATRIX(RR,FC) += clev;
530
+ } else if (src_mask & _MASK(MONO) &&
531
+ mix->upmix == CHANNELMIX_UPMIX_SIMPLE) {
532
+ spa_log_info(mix->log, "produce REAR from MONO (%f)", 1.0f);
533
+ _MATRIX(RL,MONO) += 1.0f;
534
+ _MATRIX(RR,MONO) += 1.0f;
535
} else {
536
- spa_log_debug(mix->log, "won't produce SIDE");
537
+ spa_log_info(mix->log, "won't produce SIDE");
538
}
539
}
540
if (unassigned & _MASK(RC)) {
541
if ((src_mask & REAR) == REAR) {
542
- spa_log_debug(mix->log, "produce RC from REAR (%f)", 0.5f);
543
+ spa_log_info(mix->log, "produce RC from REAR (%f)", 0.5f);
544
_MATRIX(RC,RL) += 0.5f;
545
_MATRIX(RC,RR) += 0.5f;
546
} else if ((src_mask & SIDE) == SIDE) {
547
- spa_log_debug(mix->log, "produce RC from SIDE (%f)", 0.5f);
548
+ spa_log_info(mix->log, "produce RC from SIDE (%f)", 0.5f);
549
_MATRIX(RC,SL) += 0.5f;
550
_MATRIX(RC,SR) += 0.5f;
551
} else if ((src_mask & STEREO) == STEREO) {
552
- spa_log_debug(mix->log, "produce RC from STEREO (%f)", 0.5f);
553
+ spa_log_info(mix->log, "produce RC from STEREO (%f)", 0.5f);
554
_MATRIX(RC,FL) += 0.5f;
555
_MATRIX(RC,FR) += 0.5f;
556
} else if ((src_mask & FRONT) == FRONT &&
557
mix->upmix == CHANNELMIX_UPMIX_SIMPLE) {
558
- spa_log_debug(mix->log, "produce RC from FC (%f)", slev);
559
+ spa_log_info(mix->log, "produce RC from FC (%f)", slev);
560
_MATRIX(RC,FC) += slev;
561
+ } else if (src_mask & _MASK(MONO) &&
562
+ mix->upmix == CHANNELMIX_UPMIX_SIMPLE) {
563
+ spa_log_info(mix->log, "produce RC from MONO (%f)", 1.0f);
564
+ _MATRIX(RC,MONO) += 1.0f;
565
} else {
566
- spa_log_debug(mix->log, "won't produce RC");
567
+ spa_log_info(mix->log, "won't produce RC");
568
}
569
}
570
571
done:
572
+ if (dst_paired == 0)
573
+ dst_paired = ~0LU;
574
+ if (src_paired == 0)
575
+ src_paired = ~0LU;
576
+
577
for (jc = 0, ic = 0, i = 0; i < SPA_AUDIO_MAX_CHANNELS; i++) {
578
float sum = 0.0f;
579
char str1024, str21024;
580
int idx = 0, idx2 = 0;
581
- if ((dst_mask & (1UL << i)) == 0)
582
+ if ((dst_paired & (1UL << i)) == 0)
583
continue;
584
for (jc = 0, j = 0; j < SPA_AUDIO_MAX_CHANNELS; j++) {
585
- if ((src_mask & (1UL << j)) == 0)
586
+ if ((src_paired & (1UL << j)) == 0)
587
continue;
588
if (ic >= dst_chan || jc >= src_chan)
589
continue;
590
591
if (ic == 0)
592
idx2 += snprintf(str2 + idx2, sizeof(str2) - idx2, "%-4.4s ",
593
- src_mask == ~0LU ? "MONO" :
594
- spa_debug_type_find_short_name(spa_type_audio_channel, j + 3));
595
+ src_mask == 0 ? "UNK" :
596
+ spa_debug_type_find_short_name(spa_type_audio_channel, j + _SH));
597
598
mix->matrix_origicjc++ = matrixij;
599
sum += fabs(matrixij);
600
601
spa_log_info(mix->log, " %s", str2);
602
if (idx > 0) {
603
spa_log_info(mix->log, "%-4.4s %s %f",
604
- dst_mask == ~0LU ? "MONO" :
605
- spa_debug_type_find_short_name(spa_type_audio_channel, i + 3),
606
+ dst_mask == 0 ? "UNK" :
607
+ spa_debug_type_find_short_name(spa_type_audio_channel, i + _SH),
608
str, sum);
609
}
610
611
612
}
613
ic++;
614
}
615
- if (SPA_FLAG_IS_SET(mix->options, CHANNELMIX_OPTION_NORMALIZE) &&
616
- maxsum > 1.0f) {
617
- spa_log_debug(mix->log, "normalize %f", maxsum);
618
+ if (normalize && maxsum > 1.0f) {
619
+ spa_log_info(mix->log, "normalize %f", maxsum);
620
for (i = 0; i < dst_chan; i++)
621
for (j = 0; j < src_chan; j++)
622
mix->matrix_origij /= maxsum;
623
pipewire-0.3.65.tar.gz/spa/plugins/audioconvert/test-audioconvert.c -> pipewire-0.3.66.tar.gz/spa/plugins/audioconvert/test-audioconvert.c
Changed
22
1
2
#include <spa/node/node.h>
3
#include <spa/node/io.h>
4
#include <spa/debug/mem.h>
5
+#include <spa/debug/log.h>
6
#include <spa/support/log-impl.h>
7
8
SPA_LOG_IMPL(logger);
9
10
res = memcmp(b->datasj.data, out_data->datak, out_data->size);
11
if (res != 0) {
12
fprintf(stderr, "error port %d plane %d\n", i, j);
13
- spa_debug_mem(0, b->datasj.data, out_data->size);
14
- spa_debug_mem(0, out_data->datak, out_data->size);
15
+ spa_debug_log_mem(&logger.log, SPA_LOG_LEVEL_WARN,
16
+ 0, b->datasj.data, out_data->size);
17
+ spa_debug_log_mem(&logger.log, SPA_LOG_LEVEL_WARN,
18
+ 2, out_data->datak, out_data->size);
19
}
20
spa_assert_se(res == 0);
21
22
pipewire-0.3.65.tar.gz/spa/plugins/audioconvert/test-channelmix.c -> pipewire-0.3.66.tar.gz/spa/plugins/audioconvert/test-channelmix.c
Changed
135
1
2
mix.src_mask = src_mask;
3
mix.dst_mask = dst_mask;
4
mix.log = &logger.log;
5
+ mix.fc_cutoff = 120.0f;
6
+ mix.lfe_cutoff = 12000.0f;
7
8
spa_assert_se(channelmix_init(&mix) == 0);
9
channelmix_set_volume(&mix, 1.0f, false, 0, NULL);
10
11
test_mix(1, _M(MONO), 2, _M(FL)|_M(FR), 0,
12
MATRIX(1.0, 1.0));
13
test_mix(1, _M(MONO), 3, _M(FL)|_M(FR)|_M(LFE), 0,
14
+ MATRIX(1.0, 1.0, 0.0));
15
+ test_mix(1, _M(MONO), 3, _M(FL)|_M(FR)|_M(LFE), CHANNELMIX_OPTION_UPMIX,
16
MATRIX(1.0, 1.0, 1.0));
17
test_mix(1, _M(MONO), 4, _M(FL)|_M(FR)|_M(LFE)|_M(FC), 0,
18
+ MATRIX(1.0, 1.0, 0.0, 0.0));
19
+ test_mix(1, _M(MONO), 4, _M(FL)|_M(FR)|_M(LFE)|_M(FC), CHANNELMIX_OPTION_UPMIX,
20
MATRIX(1.0, 1.0, 1.0, 1.0));
21
test_mix(1, _M(MONO), 4, _M(FL)|_M(FR)|_M(RL)|_M(RR), 0,
22
- MATRIX(1.0, 1.0, 1.0, 1.0));
23
+ MATRIX(1.0, 1.0, 0.0, 0.0));
24
+ test_mix(1, _M(MONO), 4, _M(FL)|_M(FR)|_M(RL)|_M(RR), CHANNELMIX_OPTION_UPMIX,
25
+ MATRIX(1.0, 1.0, 0.0, 0.0));
26
test_mix(1, _M(MONO), 12, 0, 0,
27
MATRIX(1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
28
1.0, 1.0, 1.0, 1.0, 1.0, 1.0));
29
30
test_mix(1, _M(FC), 1, _M(FC), 0,
31
MATRIX(1.0));
32
test_mix(2, _M(FL)|_M(FR), 1, _M(MONO), 0,
33
- MATRIX(0.707107, 0.707107));
34
+ MATRIX(0.5, 0.5));
35
test_mix(12, 0, 1, _M(MONO), 0,
36
MATRIX(0.083333, 0.083333, 0.083333, 0.083333, 0.083333, 0.083333,
37
0.083333, 0.083333, 0.083333, 0.083333, 0.083333, 0.0833333));
38
}
39
40
+static void test_2_N(void)
41
+{
42
+ test_mix(2, _M(FL)|_M(FR), 1, _M(MONO), 0, MATRIX(0.5, 0.5));
43
+ test_mix(2, _M(FL)|_M(FR), 1, 0, 0, MATRIX(0.5, 0.5));
44
+ test_mix(2, _M(FL)|_M(FR), 2, 0, 0, MATRIX(1.0, 0.0, 0.0, 1.0));
45
+ test_mix(2, _M(FL)|_M(FR), 2, _M(MONO), 0, MATRIX(1.0, 0.0, 0.0, 1.0));
46
+ test_mix(2, _M(FL)|_M(FR), 2, _M(FL)|_M(FR), 0, MATRIX(1.0, 0.0, 0.0, 1.0));
47
+ test_mix(2, _M(FL)|_M(FR), 4, _M(FL)|_M(FR)|_M(LFE)|_M(FC), 0,
48
+ MATRIX(1.0, 0.0,
49
+ 0.0, 1.0,
50
+ 0.0, 0.0,
51
+ 0.0, 0.0));
52
+ test_mix(2, _M(FL)|_M(FR), 4, _M(FL)|_M(FR)|_M(LFE)|_M(FC), CHANNELMIX_OPTION_UPMIX,
53
+ MATRIX(1.0, 0.0,
54
+ 0.0, 1.0,
55
+ 0.707107, 0.707107,
56
+ 0.5, 0.5));
57
+ test_mix(2, _M(FL)|_M(FR), 6, _M(FL)|_M(FR)|_M(LFE)|_M(FC)|_M(SL)|_M(SR), 0,
58
+ MATRIX(1.0, 0.0,
59
+ 0.0, 1.0,
60
+ 0.0, 0.0,
61
+ 0.0, 0.0,
62
+ 0.0, 0.0,
63
+ 0.0, 0.0));
64
+ test_mix(2, _M(FL)|_M(FR), 6, _M(FL)|_M(FR)|_M(LFE)|_M(FC)|_M(SL)|_M(SR), CHANNELMIX_OPTION_UPMIX,
65
+ MATRIX(1.0, 0.0,
66
+ 0.0, 1.0,
67
+ 0.707107, 0.707107,
68
+ 0.5, 0.5,
69
+ 0.0, 0.0,
70
+ 0.0, 0.0));
71
+}
72
+
73
static void test_3p1_N(void)
74
{
75
test_mix(4, _M(FL)|_M(FR)|_M(LFE)|_M(FC), 1, _M(MONO), 0,
76
- MATRIX(0.707107, 0.707107, 1.0, 0.0));
77
+ MATRIX(0.333333, 0.333333, 0.333333, 0.0));
78
test_mix(4, _M(FL)|_M(FR)|_M(LFE)|_M(FC), 2, _M(FL)|_M(FR), 0,
79
MATRIX(1.0, 0.0, 0.707107, 0.0,
80
0.0, 1.0, 0.707107, 0.0 ));
81
82
static void test_4_N(void)
83
{
84
test_mix(4, _M(FL)|_M(FR)|_M(RL)|_M(RR), 1, _M(MONO), 0,
85
- MATRIX(0.707107, 0.707107, 0.5, 0.5));
86
+ MATRIX(0.25, 0.25, 0.25, 0.25));
87
test_mix(4, _M(FL)|_M(FR)|_M(SL)|_M(SR), 1, _M(MONO), 0,
88
- MATRIX(0.707107, 0.707107, 0.5, 0.5));
89
+ MATRIX(0.25, 0.25, 0.25, 0.25));
90
test_mix(4, _M(FL)|_M(FR)|_M(RL)|_M(RR), 2, _M(FL)|_M(FR), 0,
91
MATRIX(1.0, 0.0, 0.707107, 0.0,
92
0.0, 1.0, 0.0, 0.707107));
93
94
MATRIX(1.0, 0.0, 0.707107, 0.0,
95
0.0, 1.0, 0.0, 0.707107,
96
0.707107, 0.707107, 0.0, 0.0,
97
- 0.0, 0.0, 0.0, 0.0));
98
+ 0.5, 0.5, 0.0, 0.0));
99
}
100
101
static void test_5p1_N(void)
102
{
103
test_mix(6, _M(FL)|_M(FR)|_M(LFE)|_M(FC)|_M(SL)|_M(SR), 1, _M(MONO), 0,
104
- MATRIX(0.707107, 0.707107, 1.0, 0.0, 0.5, 0.5));
105
+ MATRIX(0.20, 0.20, 0.20, 0.0, 0.20, 0.20));
106
test_mix(6, _M(FL)|_M(FR)|_M(LFE)|_M(FC)|_M(SL)|_M(SR), 2, _M(FL)|_M(FR), 0,
107
MATRIX(1.0, 0.0, 0.707107, 0.0, 0.707107, 0.0,
108
0.0, 1.0, 0.707107, 0.0, 0.0, 0.707107));
109
110
static void test_6p1_N(void)
111
{
112
test_mix(7, _M(FL)|_M(FR)|_M(LFE)|_M(FC)|_M(RC)|_M(SL)|_M(SR), 1, _M(MONO), 0,
113
- MATRIX(0.707107, 0.707107, 1.0, 0.0, 0.5, 0.5, 0.5));
114
+ MATRIX(0.166667, 0.166667, 0.166667, 0.0, 0.166667, 0.166667, 0.166667));
115
test_mix(7, _M(FL)|_M(FR)|_M(LFE)|_M(FC)|_M(SL)|_M(SR)|_M(RC),
116
6, _M(FL)|_M(FR)|_M(LFE)|_M(FC)|_M(SL)|_M(SR), 0,
117
MATRIX(1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
118
119
static void test_7p1_N(void)
120
{
121
test_mix(8, _M(FL)|_M(FR)|_M(LFE)|_M(FC)|_M(SL)|_M(SR)|_M(RL)|_M(RR), 1, _M(MONO), 0,
122
- MATRIX(0.707107, 0.707107, 1.0, 0.0, 0.5, 0.5, 0.5, 0.5));
123
+ MATRIX(0.142857, 0.142857, 0.142857, 0.0, 0.142857, 0.142857, 0.142857, 0.142857));
124
test_mix(8, _M(FL)|_M(FR)|_M(LFE)|_M(FC)|_M(SL)|_M(SR)|_M(RL)|_M(RR), 2, _M(FL)|_M(FR), 0,
125
MATRIX(1.0, 0.0, 0.707107, 0.0, 0.707107, 0.0, 0.707107, 0.0,
126
0.0, 1.0, 0.707107, 0.0, 0.0, 0.707107, 0.0, 0.707107));
127
128
test_1_N_MONO();
129
test_1_N_FC();
130
test_N_1();
131
+ test_2_N();
132
test_3p1_N();
133
test_4_N();
134
test_5p1_N();
135
pipewire-0.3.65.tar.gz/spa/plugins/bluez5/bluez5-dbus.c -> pipewire-0.3.66.tar.gz/spa/plugins/bluez5/bluez5-dbus.c
Changed
568
1
2
3
/* A reference audio info for A2DP codec configuration. */
4
struct media_codec_audio_info default_audio_info;
5
-
6
- bool le_audio_supported;
7
};
8
9
/* Stream endpoints owned by BlueZ for each device */
10
11
return 0;
12
}
13
14
+static int adapter_media_update_props(struct spa_bt_adapter *adapter,
15
+ DBusMessageIter *props_iter,
16
+ DBusMessageIter *invalidated_iter)
17
+{
18
+ /* Handle org.bluez.Media1 interface properties of .Adapter1 objects */
19
+ struct spa_bt_monitor *monitor = adapter->monitor;
20
+
21
+ while (dbus_message_iter_get_arg_type(props_iter) != DBUS_TYPE_INVALID) {
22
+ DBusMessageIter it2;
23
+ const char *key;
24
+
25
+ dbus_message_iter_recurse(props_iter, &it0);
26
+ dbus_message_iter_get_basic(&it0, &key);
27
+ dbus_message_iter_next(&it0);
28
+ dbus_message_iter_recurse(&it0, &it1);
29
+
30
+ if (spa_streq(key, "SupportedUUIDs")) {
31
+ DBusMessageIter iter;
32
+
33
+ if (!check_iter_signature(&it1, "as"))
34
+ goto next;
35
+
36
+ dbus_message_iter_recurse(&it1, &iter);
37
+
38
+ while (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_INVALID) {
39
+ const char *uuid;
40
+
41
+ dbus_message_iter_get_basic(&iter, &uuid);
42
+
43
+ if (spa_streq(uuid, SPA_BT_UUID_BAP_SINK)) {
44
+ adapter->le_audio_supported = true;
45
+ spa_log_info(monitor->log, "Adapter %s: LE Audio supported",
46
+ adapter->path);
47
+ }
48
+ dbus_message_iter_next(&iter);
49
+ }
50
+ }
51
+ else
52
+ spa_log_debug(monitor->log, "media: unhandled key %s", key);
53
+
54
+next:
55
+ dbus_message_iter_next(props_iter);
56
+ }
57
+ return 0;
58
+}
59
+
60
static void adapter_update_devices(struct spa_bt_adapter *adapter)
61
{
62
struct spa_bt_monitor *monitor = adapter->monitor;
63
64
{
65
struct spa_bt_monitor *monitor = device->monitor;
66
struct spa_bt_remote_endpoint *ep;
67
+ enum spa_bt_profile codec_profile;
68
+ struct spa_bt_transport *t;
69
const struct { enum spa_bluetooth_audio_codec codec; uint32_t mask; } quirks = {
70
{ SPA_BLUETOOTH_AUDIO_CODEC_SBC_XQ, SPA_BT_FEATURE_SBC_XQ },
71
{ SPA_BLUETOOTH_AUDIO_CODEC_FASTSTREAM, SPA_BT_FEATURE_FASTSTREAM },
72
73
if (!is_media_codec_enabled(device->monitor, codec))
74
return false;
75
76
- if (!device->adapter->application_registered) {
77
+ if (!device->adapter->a2dp_application_registered && !codec->bap) {
78
/* Codec switching not supported: only plain SBC allowed */
79
- return (codec->codec_id == A2DP_CODEC_SBC && spa_streq(codec->name, "sbc"));
80
+ return (codec->codec_id == A2DP_CODEC_SBC && spa_streq(codec->name, "sbc") &&
81
+ device->adapter->legacy_endpoints_registered);
82
}
83
+ if (!device->adapter->bap_application_registered && codec->bap)
84
+ return false;
85
86
/* Check codec quirks */
87
for (i = 0; i < SPA_N_ELEMENTS(quirks); ++i) {
88
89
return false;
90
}
91
92
+ if (codec->bap)
93
+ codec_profile = sink ? SPA_BT_PROFILE_BAP_SINK : SPA_BT_PROFILE_BAP_SOURCE;
94
+ else
95
+ codec_profile = sink ? SPA_BT_PROFILE_A2DP_SINK : SPA_BT_PROFILE_A2DP_SOURCE;
96
+
97
spa_list_for_each(ep, &device->remote_endpoint_list, device_link) {
98
const enum spa_bt_profile profile = spa_bt_profile_from_uuid(ep->uuid);
99
- enum spa_bt_profile expected;
100
101
- if (codec->bap)
102
- expected = sink ? SPA_BT_PROFILE_BAP_SINK : SPA_BT_PROFILE_BAP_SOURCE;
103
- else
104
- expected = sink ? SPA_BT_PROFILE_A2DP_SINK : SPA_BT_PROFILE_A2DP_SOURCE;
105
-
106
- if (profile != expected)
107
+ if (profile != codec_profile)
108
continue;
109
110
if (media_codec_check_caps(codec, ep->codec, ep->capabilities, ep->capabilities_len,
111
112
return true;
113
}
114
115
+ /* Codecs on configured transports are always supported.
116
+ *
117
+ * Remote BAP endpoints correspond to capabilities of the remote
118
+ * BAP Server, not to remote BAP Client, and need not be the same.
119
+ * BAP Clients may not have any remote endpoints. In this case we
120
+ * can only know that the currently configured codec is supported.
121
+ */
122
+ spa_list_for_each(t, &device->transport_list, device_link) {
123
+ if (t->profile != codec_profile)
124
+ continue;
125
+
126
+ if (codec == t->media_codec)
127
+ return true;
128
+ }
129
+
130
return false;
131
}
132
133
134
const struct media_codec *preferred_codec = NULL;
135
size_t i, j, num_codecs, num_eps;
136
137
- if (!device->adapter->application_registered) {
138
+ if (!device->adapter->a2dp_application_registered &&
139
+ !device->adapter->bap_application_registered) {
140
/* Codec switching not supported */
141
return -ENOTSUP;
142
}
143
144
return res;
145
}
146
147
-static void bluez_register_endpoint_reply(DBusPendingCall *pending, void *user_data)
148
+static void bluez_register_endpoint_legacy_reply(DBusPendingCall *pending, void *user_data)
149
{
150
- struct spa_bt_monitor *monitor = user_data;
151
+ struct spa_bt_adapter *adapter = user_data;
152
+ struct spa_bt_monitor *monitor = adapter->monitor;
153
DBusMessage *r;
154
155
r = dbus_pending_call_steal_reply(pending);
156
157
goto finish;
158
}
159
160
+ adapter->legacy_endpoints_registered = true;
161
+
162
finish:
163
dbus_message_unref(r);
164
}
165
166
dbus_message_iter_close_container(dict, &dict_entry_it);
167
}
168
169
-static int bluez_register_endpoint(struct spa_bt_monitor *monitor,
170
- const char *path, enum spa_bt_media_direction direction,
171
+static int bluez_register_endpoint_legacy(struct spa_bt_adapter *adapter,
172
+ enum spa_bt_media_direction direction,
173
const char *uuid, const struct media_codec *codec)
174
{
175
+ struct spa_bt_monitor *monitor = adapter->monitor;
176
+ const char *path = adapter->path;
177
char *object_path = NULL;
178
DBusMessage *m;
179
DBusMessageIter object_it, dict_it;
180
181
dbus_message_iter_close_container(&object_it, &dict_it);
182
183
dbus_connection_send_with_reply(monitor->conn, m, &call, -1);
184
- dbus_pending_call_set_notify(call, bluez_register_endpoint_reply, monitor, NULL);
185
+ dbus_pending_call_set_notify(call, bluez_register_endpoint_legacy_reply, adapter, NULL);
186
dbus_message_unref(m);
187
188
free(object_path);
189
190
return ret;
191
}
192
193
-static int adapter_register_endpoints(struct spa_bt_adapter *a)
194
+static int adapter_register_endpoints_legacy(struct spa_bt_adapter *a)
195
{
196
struct spa_bt_monitor *monitor = a->monitor;
197
const struct media_codec * const * const media_codecs = monitor->media_codecs;
198
int i;
199
int err = 0;
200
+ bool registered = false;
201
202
- if (a->endpoints_registered)
203
+ if (a->legacy_endpoints_registered)
204
return err;
205
206
/* The legacy bluez5 api doesn't support codec switching
207
208
* */
209
spa_log_warn(monitor->log,
210
"Using legacy bluez5 API for A2DP - only SBC will be supported. "
211
- "No LE Audio. Please upgrade bluez5.");
212
-
213
- monitor->le_audio_supported = false;
214
+ "Please upgrade bluez5.");
215
216
for (i = 0; media_codecsi; i++) {
217
const struct media_codec *codec = media_codecsi;
218
219
continue;
220
221
if (endpoint_should_be_registered(monitor, codec, SPA_BT_MEDIA_SOURCE)) {
222
- if ((err = bluez_register_endpoint(monitor, a->path,
223
- SPA_BT_MEDIA_SOURCE,
224
+ if ((err = bluez_register_endpoint_legacy(a, SPA_BT_MEDIA_SOURCE,
225
SPA_BT_UUID_A2DP_SOURCE,
226
codec)))
227
goto out;
228
}
229
230
if (endpoint_should_be_registered(monitor, codec, SPA_BT_MEDIA_SINK)) {
231
- if ((err = bluez_register_endpoint(monitor, a->path,
232
- SPA_BT_MEDIA_SINK,
233
+ if ((err = bluez_register_endpoint_legacy(a, SPA_BT_MEDIA_SINK,
234
SPA_BT_UUID_A2DP_SINK,
235
codec)))
236
goto out;
237
}
238
239
- a->endpoints_registered = true;
240
+ registered = true;
241
break;
242
}
243
244
- if (!a->endpoints_registered) {
245
+ if (!registered) {
246
/* Should never happen as SBC support is always enabled */
247
spa_log_error(monitor->log, "Broken PipeWire build - unable to locate SBC codec");
248
err = -ENOSYS;
249
250
dbus_message_iter_close_container(iter, &object);
251
}
252
253
-static DBusHandlerResult object_manager_handler(DBusConnection *c, DBusMessage *m, void *user_data)
254
+static DBusHandlerResult object_manager_handler(DBusConnection *c, DBusMessage *m, void *user_data, bool is_bap)
255
{
256
struct spa_bt_monitor *monitor = user_data;
257
const struct media_codec * const * const media_codecs = monitor->media_codecs;
258
259
int caps_size, ret;
260
uint16_t codec_id = codec->codec_id;
261
262
- if (!is_media_codec_enabled(monitor, codec))
263
+ if (codec->bap != is_bap)
264
continue;
265
266
- if (codec->bap && !monitor->le_audio_supported) {
267
- /* The legacy bluez5 api doesn't support LE Audio
268
- * It doesn't make sense to register unsupported codecs as it prevents
269
- * registration of A2DP codecs
270
- * let's incentivize users to upgrade their bluez5 daemon
271
- * if they want proper media codec support
272
- * */
273
- spa_log_warn(monitor->log, "Trying to use legacy bluez5 API for LE Audio - only A2DP will be supported. "
274
- "Please upgrade bluez5.");
275
+ if (!is_media_codec_enabled(monitor, codec))
276
continue;
277
- }
278
279
if (endpoint_should_be_registered(monitor, codec, SPA_BT_MEDIA_SINK)) {
280
caps_size = codec->fill_caps(codec, MEDIA_CODEC_FLAG_SINK, caps);
281
282
return res;
283
}
284
285
-static void bluez_register_application_reply(DBusPendingCall *pending, void *user_data)
286
+static DBusHandlerResult object_manager_handler_a2dp(DBusConnection *c, DBusMessage *m, void *user_data)
287
+{
288
+ return object_manager_handler(c, m, user_data, false);
289
+}
290
+
291
+static DBusHandlerResult object_manager_handler_bap(DBusConnection *c, DBusMessage *m, void *user_data)
292
+{
293
+ return object_manager_handler(c, m, user_data, true);
294
+}
295
+
296
+static void bluez_register_application_a2dp_reply(DBusPendingCall *pending, void *user_data)
297
{
298
struct spa_bt_adapter *adapter = user_data;
299
struct spa_bt_monitor *monitor = adapter->monitor;
300
301
}
302
303
fallback = false;
304
- adapter->application_registered = true;
305
+ adapter->a2dp_application_registered = true;
306
307
finish:
308
dbus_message_unref(r);
309
310
if (fallback)
311
- adapter_register_endpoints(adapter);
312
+ adapter_register_endpoints_legacy(adapter);
313
+}
314
+
315
+static void bluez_register_application_bap_reply(DBusPendingCall *pending, void *user_data)
316
+{
317
+ struct spa_bt_adapter *adapter = user_data;
318
+ struct spa_bt_monitor *monitor = adapter->monitor;
319
+ DBusMessage *r;
320
+
321
+ r = dbus_pending_call_steal_reply(pending);
322
+ dbus_pending_call_unref(pending);
323
+
324
+ if (r == NULL)
325
+ return;
326
+
327
+ if (dbus_message_get_type(r) == DBUS_MESSAGE_TYPE_ERROR) {
328
+ spa_log_error(monitor->log, "RegisterApplication() failed: %s",
329
+ dbus_message_get_error_name(r));
330
+ goto finish;
331
+ }
332
+
333
+ adapter->bap_application_registered = true;
334
+
335
+finish:
336
+ dbus_message_unref(r);
337
}
338
339
static int register_media_endpoint(struct spa_bt_monitor *monitor,
340
341
if (ret < 0)
342
return ret;
343
344
- spa_log_info(monitor->log, "registering endpoint: %s", object_path);
345
+ spa_log_info(monitor->log, "Registering DBus media endpoint: %s", object_path);
346
347
if (!dbus_connection_register_object_path(monitor->conn,
348
object_path,
349
350
static int register_media_application(struct spa_bt_monitor * monitor)
351
{
352
const struct media_codec * const * const media_codecs = monitor->media_codecs;
353
- const DBusObjectPathVTable vtable_object_manager = {
354
- .message_function = object_manager_handler,
355
+ const DBusObjectPathVTable vtable_object_manager_a2dp = {
356
+ .message_function = object_manager_handler_a2dp,
357
};
358
+ const DBusObjectPathVTable vtable_object_manager_bap = {
359
+ .message_function = object_manager_handler_bap,
360
+ };
361
+
362
+ spa_log_info(monitor->log, "Registering DBus media object manager: %s",
363
+ A2DP_OBJECT_MANAGER_PATH);
364
365
- spa_log_info(monitor->log, "Registering media application object: " MEDIA_OBJECT_MANAGER_PATH);
366
+ if (!dbus_connection_register_object_path(monitor->conn,
367
+ A2DP_OBJECT_MANAGER_PATH,
368
+ &vtable_object_manager_a2dp, monitor))
369
+ return -EIO;
370
+
371
+ spa_log_info(monitor->log, "Registering DBus media object manager: %s",
372
+ BAP_OBJECT_MANAGER_PATH);
373
374
if (!dbus_connection_register_object_path(monitor->conn,
375
- MEDIA_OBJECT_MANAGER_PATH,
376
- &vtable_object_manager, monitor))
377
+ BAP_OBJECT_MANAGER_PATH,
378
+ &vtable_object_manager_bap, monitor))
379
return -EIO;
380
381
for (int i = 0; media_codecsi; i++) {
382
383
unregister_media_endpoint(monitor, codec, SPA_BT_MEDIA_SINK);
384
}
385
386
- dbus_connection_unregister_object_path(monitor->conn, MEDIA_OBJECT_MANAGER_PATH);
387
+ dbus_connection_unregister_object_path(monitor->conn, BAP_OBJECT_MANAGER_PATH);
388
+ dbus_connection_unregister_object_path(monitor->conn, A2DP_OBJECT_MANAGER_PATH);
389
}
390
391
-static int adapter_register_application(struct spa_bt_adapter *a) {
392
- const char *object_manager_path = MEDIA_OBJECT_MANAGER_PATH;
393
+static int adapter_register_application(struct spa_bt_adapter *a, bool bap)
394
+{
395
+ const char *object_manager_path = bap ? BAP_OBJECT_MANAGER_PATH : A2DP_OBJECT_MANAGER_PATH;
396
struct spa_bt_monitor *monitor = a->monitor;
397
DBusMessage *m;
398
DBusMessageIter i, d;
399
DBusPendingCall *call;
400
401
- if (a->application_registered)
402
+ if (bap && a->bap_application_registered)
403
+ return 0;
404
+ if (!bap && a->a2dp_application_registered)
405
return 0;
406
407
- spa_log_debug(monitor->log, "Registering bluez5 media application on adapter %s", a->path);
408
+ if (bap && !a->le_audio_supported) {
409
+ spa_log_info(monitor->log, "Adapter %s indicates LE Audio unsupported: not registering application",
410
+ a->path);
411
+ return -ENOTSUP;
412
+ }
413
+
414
+ spa_log_debug(monitor->log, "Registering bluez5 %s media application on adapter %s",
415
+ (bap ? "LE Audio" : "A2DP"), a->path);
416
417
m = dbus_message_new_method_call(BLUEZ_SERVICE,
418
a->path,
419
420
dbus_message_iter_close_container(&i, &d);
421
422
dbus_connection_send_with_reply(monitor->conn, m, &call, -1);
423
- dbus_pending_call_set_notify(call, bluez_register_application_reply, a, NULL);
424
+ dbus_pending_call_set_notify(call,
425
+ bap ? bluez_register_application_bap_reply : bluez_register_application_a2dp_reply,
426
+ a, NULL);
427
dbus_message_unref(m);
428
429
return 0;
430
431
backend ? backend->name : "none");
432
}
433
434
-static int media_update_props(struct spa_bt_monitor *monitor,
435
- DBusMessageIter *props_iter,
436
- DBusMessageIter *invalidated_iter)
437
-{
438
- while (dbus_message_iter_get_arg_type(props_iter) != DBUS_TYPE_INVALID) {
439
- DBusMessageIter it2;
440
- const char *key;
441
-
442
- dbus_message_iter_recurse(props_iter, &it0);
443
- dbus_message_iter_get_basic(&it0, &key);
444
- dbus_message_iter_next(&it0);
445
- dbus_message_iter_recurse(&it0, &it1);
446
-
447
- if (spa_streq(key, "SupportedUUIDs")) {
448
- DBusMessageIter iter;
449
-
450
- if (!check_iter_signature(&it1, "as"))
451
- goto next;
452
-
453
- dbus_message_iter_recurse(&it1, &iter);
454
-
455
- while (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_INVALID) {
456
- const char *uuid;
457
-
458
- dbus_message_iter_get_basic(&iter, &uuid);
459
-
460
- if (spa_streq(uuid, SPA_BT_UUID_BAP_SINK)) {
461
- monitor->le_audio_supported = true;
462
- spa_log_info(monitor->log, "LE Audio supported");
463
- }
464
- dbus_message_iter_next(&iter);
465
- }
466
- }
467
- else
468
- spa_log_debug(monitor->log, "media: unhandled key %s", key);
469
-
470
-next:
471
- dbus_message_iter_next(props_iter);
472
- }
473
- return 0;
474
-}
475
-
476
static void interface_added(struct spa_bt_monitor *monitor,
477
DBusConnection *conn,
478
const char *object_path,
479
480
{
481
spa_log_debug(monitor->log, "Found object %s, interface %s", object_path, interface_name);
482
483
- if (spa_streq(interface_name, BLUEZ_ADAPTER_INTERFACE)) {
484
+ if (spa_streq(interface_name, BLUEZ_ADAPTER_INTERFACE) ||
485
+ spa_streq(interface_name, BLUEZ_MEDIA_INTERFACE)) {
486
struct spa_bt_adapter *a;
487
488
a = adapter_find(monitor, object_path);
489
490
return;
491
}
492
}
493
- adapter_update_props(a, props_iter, NULL);
494
- adapter_register_application(a);
495
- adapter_register_player(a);
496
- adapter_update_devices(a);
497
+
498
+ if (spa_streq(interface_name, BLUEZ_ADAPTER_INTERFACE)) {
499
+ adapter_update_props(a, props_iter, NULL);
500
+ a->has_adapter1_interface = true;
501
+ } else {
502
+ adapter_media_update_props(a, props_iter, NULL);
503
+ a->has_media1_interface = true;
504
+ }
505
+
506
+ if (a->has_adapter1_interface && a->has_media1_interface) {
507
+ adapter_register_application(a, false);
508
+ adapter_register_application(a, true);
509
+ adapter_register_player(a);
510
+ adapter_update_devices(a);
511
+ }
512
}
513
else if (spa_streq(interface_name, BLUEZ_PROFILE_MANAGER_INTERFACE)) {
514
if (monitor->backendsBACKEND_NATIVE)
515
516
if (d)
517
spa_bt_device_emit_profiles_changed(d, d->profiles, d->connected_profiles);
518
}
519
- else if (spa_streq(interface_name, BLUEZ_MEDIA_INTERFACE)) {
520
- media_update_props(monitor, props_iter, NULL);
521
- }
522
}
523
524
static void interfaces_added(struct spa_bt_monitor *monitor, DBusMessageIter *arg_iter)
525
526
d = spa_bt_device_find(monitor, object_path);
527
if (d != NULL)
528
device_free(d);
529
- } else if (spa_streq(interface_name, BLUEZ_ADAPTER_INTERFACE)) {
530
+ } else if (spa_streq(interface_name, BLUEZ_ADAPTER_INTERFACE) ||
531
+ spa_streq(interface_name, BLUEZ_MEDIA_INTERFACE)) {
532
struct spa_bt_adapter *a;
533
a = adapter_find(monitor, object_path);
534
if (a != NULL)
535
536
dbus_message_iter_next(&it0);
537
dbus_message_iter_recurse(&it0, &it1);
538
539
- if (spa_streq(iface, BLUEZ_ADAPTER_INTERFACE)) {
540
+ if (spa_streq(iface, BLUEZ_ADAPTER_INTERFACE) ||
541
+ spa_streq(iface, BLUEZ_MEDIA_INTERFACE)) {
542
struct spa_bt_adapter *a;
543
544
a = adapter_find(monitor, path);
545
546
}
547
spa_log_debug(monitor->log, "Properties changed in adapter %s", path);
548
549
- adapter_update_props(a, &it1, NULL);
550
+ if (spa_streq(iface, BLUEZ_ADAPTER_INTERFACE))
551
+ adapter_update_props(a, &it1, NULL);
552
+ else
553
+ adapter_media_update_props(a, &it1, NULL);
554
}
555
else if (spa_streq(iface, BLUEZ_DEVICE_INTERFACE)) {
556
struct spa_bt_device *d;
557
558
dbus_bus_add_match(this->conn,
559
"type='signal',sender='" BLUEZ_SERVICE "',"
560
"interface='org.freedesktop.DBus.Properties',member='PropertiesChanged',"
561
+ "arg0='" BLUEZ_MEDIA_INTERFACE "'", &err);
562
+ dbus_bus_add_match(this->conn,
563
+ "type='signal',sender='" BLUEZ_SERVICE "',"
564
+ "interface='org.freedesktop.DBus.Properties',member='PropertiesChanged',"
565
"arg0='" BLUEZ_DEVICE_INTERFACE "'", &err);
566
dbus_bus_add_match(this->conn,
567
"type='signal',sender='" BLUEZ_SERVICE "',"
568
pipewire-0.3.65.tar.gz/spa/plugins/bluez5/bluez5-device.c -> pipewire-0.3.66.tar.gz/spa/plugins/bluez5/bluez5-device.c
Changed
136
1
2
return media_codec;
3
}
4
5
+static bool is_bap_client(struct impl *this)
6
+{
7
+ struct spa_bt_device *device = this->bt_dev;
8
+ struct spa_bt_transport *t;
9
+
10
+ spa_list_for_each(t, &device->transport_list, device_link) {
11
+ if (t->bap_initiator)
12
+ return true;
13
+ }
14
+
15
+ return false;
16
+}
17
+
18
+static bool can_bap_codec_switch(struct impl *this)
19
+{
20
+ if (!is_bap_client(this))
21
+ return false;
22
+
23
+ /* XXX: codec switching for source/duplex is not currently
24
+ * XXX: implemented properly. TODO: fix this
25
+ */
26
+ if (this->bt_dev->connected_profiles & SPA_BT_PROFILE_BAP_SOURCE)
27
+ return false;
28
+
29
+ return true;
30
+}
31
+
32
static unsigned int get_hfp_codec(enum spa_bluetooth_audio_codec id)
33
{
34
switch (id) {
35
36
* A2DP/BAP: ensure there's a transport with the selected codec (0 means any).
37
* Don't try to switch codecs when the device is in the A2DP source role, since
38
* devices do not appear to like that.
39
+ *
40
+ * For BAP, only BAP client can configure the codec.
41
+ *
42
+ * XXX: codec switching also currently does not work in the duplex or
43
+ * XXX: source-only case, as it will only switch the sink, and we only
44
+ * XXX: list the sink codecs here. TODO: fix this
45
*/
46
- if ((profile == DEVICE_PROFILE_A2DP || profile == DEVICE_PROFILE_BAP)
47
- && !(this->bt_dev->connected_profiles & SPA_BT_PROFILE_A2DP_SOURCE)) {
48
+ if ((profile == DEVICE_PROFILE_A2DP || (profile == DEVICE_PROFILE_BAP && can_bap_codec_switch(this)))
49
+ && !(this->bt_dev->connected_profiles & SPA_BT_PROFILE_A2DP_SOURCE)) {
50
int ret;
51
const struct media_codec *codecs64;
52
53
54
if (profile == 0)
55
return NULL;
56
57
- if (!codec) {
58
- errno = EINVAL;
59
- return NULL;
60
- }
61
-
62
if (profile & (SPA_BT_PROFILE_BAP_SINK))
63
n_sink++;
64
if (profile & (SPA_BT_PROFILE_BAP_SOURCE))
65
66
67
name = spa_bt_profile_name(profile);
68
69
- media_codec = get_supported_media_codec(this, codec, &idx);
70
- if (media_codec == NULL) {
71
- errno = EINVAL;
72
+ /* If we can't codec switch, emit codecless profile */
73
+ if (current && !can_bap_codec_switch(this)) {
74
+ codec = 0;
75
+ index = get_index_from_profile(this, profile_index, codec);
76
+ } else if ((codec != 0) != can_bap_codec_switch(this)) {
77
+ errno = -EINVAL;
78
return NULL;
79
}
80
- name_and_codec = spa_aprintf("%s-%s", name, media_codec->name);
81
- name = name_and_codec;
82
- switch (profile) {
83
- case SPA_BT_PROFILE_BAP_SINK:
84
- desc_and_codec = spa_aprintf(_("High Fidelity Playback (BAP Sink, codec %s)"),
85
- media_codec->description);
86
- break;
87
- case SPA_BT_PROFILE_BAP_SOURCE:
88
- desc_and_codec = spa_aprintf(_("High Fidelity Input (BAP Source, codec %s)"),
89
- media_codec->description);
90
- break;
91
- default:
92
- desc_and_codec = spa_aprintf(_("High Fidelity Duplex (BAP Source/Sink, codec %s)"),
93
- media_codec->description);
94
+
95
+ if (codec) {
96
+ media_codec = get_supported_media_codec(this, codec, &idx);
97
+ if (media_codec == NULL) {
98
+ errno = EINVAL;
99
+ return NULL;
100
+ }
101
+ name_and_codec = spa_aprintf("%s-%s", name, media_codec->name);
102
+ name = name_and_codec;
103
+ switch (profile) {
104
+ case SPA_BT_PROFILE_BAP_SINK:
105
+ desc_and_codec = spa_aprintf(_("High Fidelity Playback (BAP Sink, codec %s)"),
106
+ media_codec->description);
107
+ break;
108
+ case SPA_BT_PROFILE_BAP_SOURCE:
109
+ desc_and_codec = spa_aprintf(_("High Fidelity Input (BAP Source, codec %s)"),
110
+ media_codec->description);
111
+ break;
112
+ default:
113
+ desc_and_codec = spa_aprintf(_("High Fidelity Duplex (BAP Source/Sink, codec %s)"),
114
+ media_codec->description);
115
+ }
116
+ desc = desc_and_codec;
117
+ priority = 128 + this->supported_codec_count - idx; /* order as in codec list */
118
+ } else {
119
+ switch (profile) {
120
+ case SPA_BT_PROFILE_BAP_SINK:
121
+ desc = _("High Fidelity Playback (BAP Sink)");
122
+ break;
123
+ case SPA_BT_PROFILE_BAP_SOURCE:
124
+ desc = _("High Fidelity Input (BAP Source)");
125
+ break;
126
+ default:
127
+ desc = _("High Fidelity Duplex (BAP Source/Sink)");
128
+ }
129
+ priority = 128;
130
}
131
- desc = desc_and_codec;
132
- priority = 128 + this->supported_codec_count - idx; /* order as in codec list */
133
break;
134
}
135
case DEVICE_PROFILE_HSP_HFP:
136
pipewire-0.3.65.tar.gz/spa/plugins/bluez5/defs.h -> pipewire-0.3.66.tar.gz/spa/plugins/bluez5/defs.h
Changed
38
1
2
#define HFP_AUDIO_CODEC_CVSD 0x01
3
#define HFP_AUDIO_CODEC_MSBC 0x02
4
5
-#define MEDIA_OBJECT_MANAGER_PATH "/MediaEndpoint"
6
-#define A2DP_SINK_ENDPOINT MEDIA_OBJECT_MANAGER_PATH "/A2DPSink"
7
-#define A2DP_SOURCE_ENDPOINT MEDIA_OBJECT_MANAGER_PATH "/A2DPSource"
8
+#define A2DP_OBJECT_MANAGER_PATH "/MediaEndpoint"
9
+#define A2DP_SINK_ENDPOINT A2DP_OBJECT_MANAGER_PATH "/A2DPSink"
10
+#define A2DP_SOURCE_ENDPOINT A2DP_OBJECT_MANAGER_PATH "/A2DPSource"
11
12
-#define BAP_SINK_ENDPOINT MEDIA_OBJECT_MANAGER_PATH "/BAPSink"
13
-#define BAP_SOURCE_ENDPOINT MEDIA_OBJECT_MANAGER_PATH "/BAPSource"
14
+#define BAP_OBJECT_MANAGER_PATH "/MediaEndpointLE"
15
+#define BAP_SINK_ENDPOINT BAP_OBJECT_MANAGER_PATH "/BAPSink"
16
+#define BAP_SOURCE_ENDPOINT BAP_OBJECT_MANAGER_PATH "/BAPSource"
17
18
#define SPA_BT_UNKNOWN_DELAY 0
19
20
21
int powered;
22
unsigned int has_msbc:1;
23
unsigned int msbc_probed:1;
24
- unsigned int endpoints_registered:1;
25
- unsigned int application_registered:1;
26
+ unsigned int legacy_endpoints_registered:1;
27
+ unsigned int a2dp_application_registered:1;
28
+ unsigned int bap_application_registered:1;
29
unsigned int player_registered:1;
30
unsigned int has_battery_provider:1;
31
unsigned int battery_provider_unavailable:1;
32
+ unsigned int le_audio_supported:1;
33
+ unsigned int has_adapter1_interface:1;
34
+ unsigned int has_media1_interface:1;
35
};
36
37
enum spa_bt_form_factor {
38
pipewire-0.3.65.tar.gz/spa/plugins/bluez5/meson.build -> pipewire-0.3.66.tar.gz/spa/plugins/bluez5/meson.build
Changed
14
1
2
gnome = import('gnome')
3
4
-bluez5_deps = mathlib, dbus_dep, glib2_dep, sbc_dep, bluez_dep, gio_dep, gio_unix_dep
5
-foreach dep: bluez5_deps
6
- if not dep.found()
7
- subdir_done()
8
- endif
9
-endforeach
10
-
11
cdata.set('HAVE_BLUEZ_5_BACKEND_NATIVE',
12
get_option('bluez5-backend-hsp-native').allowed() or
13
get_option('bluez5-backend-hfp-native').allowed())
14
pipewire-0.3.65.tar.gz/spa/plugins/libcamera/libcamera-utils.cpp -> pipewire-0.3.66.tar.gz/spa/plugins/libcamera/libcamera-utils.cpp
Changed
86
1
2
#include <limits.h>
3
4
#include <linux/media.h>
5
+#include <libcamera/control_ids.h>
6
7
int spa_libcamera_open(struct impl *impl)
8
{
9
10
11
}
12
13
+static struct {
14
+ uint32_t id;
15
+ uint32_t spa_id;
16
+} control_map = {
17
+ { libcamera::controls::BRIGHTNESS, SPA_PROP_brightness },
18
+ { libcamera::controls::CONTRAST, SPA_PROP_contrast },
19
+ { libcamera::controls::SATURATION, SPA_PROP_saturation },
20
+ { libcamera::controls::EXPOSURE_TIME, SPA_PROP_exposure },
21
+ { libcamera::controls::ANALOGUE_GAIN, SPA_PROP_gain },
22
+ { libcamera::controls::SHARPNESS, SPA_PROP_sharpness },
23
+};
24
+
25
+static uint32_t control_to_prop_id(struct impl *impl, uint32_t control_id)
26
+{
27
+ SPA_FOR_EACH_ELEMENT_VAR(control_map, c) {
28
+ if (c->id == control_id)
29
+ return c->spa_id;
30
+ }
31
+ return SPA_PROP_START_CUSTOM + control_id;
32
+}
33
+
34
+static uint32_t prop_id_to_control(struct impl *impl, uint32_t prop_id)
35
+{
36
+ SPA_FOR_EACH_ELEMENT_VAR(control_map, c) {
37
+ if (c->spa_id == prop_id)
38
+ return c->id;
39
+ }
40
+ if (prop_id >= SPA_PROP_START_CUSTOM)
41
+ return prop_id - SPA_PROP_START_CUSTOM;
42
+ return SPA_ID_INVALID;
43
+}
44
+
45
static int
46
spa_libcamera_enum_controls(struct impl *impl, struct port *port, int seq,
47
uint32_t start, uint32_t num,
48
49
struct spa_pod_frame f2;
50
struct spa_result_node_params result;
51
struct spa_pod *ctrl;
52
- uint32_t count = 0, skip;
53
+ uint32_t count = 0, skip, id;
54
int res;
55
const ControlId *ctrl_id;
56
ControlInfo ctrl_info;
57
58
ctrl_id = it->first;
59
ctrl_info = it->second;
60
61
+ id = control_to_prop_id(impl, ctrl_id->id());
62
+
63
spa_pod_builder_init(&b, buffer, sizeof(buffer));
64
spa_pod_builder_push_object(&b, &f0, SPA_TYPE_OBJECT_PropInfo, SPA_PARAM_PropInfo);
65
spa_pod_builder_add(&b,
66
- SPA_PROP_INFO_id, SPA_POD_Id(ctrl_id->id()),
67
+ SPA_PROP_INFO_id, SPA_POD_Id(id),
68
SPA_PROP_INFO_description, SPA_POD_String(ctrl_id->name().c_str()),
69
0);
70
71
72
const ControlId *ctrl_id;
73
int res;
74
struct val d;
75
+ uint32_t control_id;
76
+
77
+ control_id = prop_id_to_control(impl, prop->key);
78
+ if (control_id == SPA_ID_INVALID)
79
+ return -ENOENT;
80
81
- auto v = info.idmap().find(prop->key);
82
+ auto v = info.idmap().find(control_id);
83
if (v == info.idmap().end())
84
return -ENOENT;
85
86
pipewire-0.3.65.tar.gz/spa/plugins/libcamera/meson.build -> pipewire-0.3.66.tar.gz/spa/plugins/libcamera/meson.build
Changed
20
1
2
'libcamera-source.cpp'
3
4
5
-libdrm_dep = dependency('libdrm', version : '>= 2.4.98',
6
- required : get_option('libcamera'))
7
-summary({'libdrm': libdrm_dep.found()}, bool_yn: true, section: 'Backend')
8
-if libdrm_dep.found()
9
- libcameralib = shared_library('spa-libcamera',
10
- libcamera_sources,
11
- dependencies : spa_dep, libudev_dep, libcamera_dep, pthread_lib, libdrm_dep ,
12
- install : true,
13
- install_dir : spa_plugindir / 'libcamera')
14
-endif
15
+libcameralib = shared_library('spa-libcamera',
16
+ libcamera_sources,
17
+ dependencies : spa_dep, libudev_dep, libcamera_dep, pthread_lib ,
18
+ install : true,
19
+ install_dir : spa_plugindir / 'libcamera')
20
pipewire-0.3.65.tar.gz/spa/plugins/support/journal.c -> pipewire-0.3.66.tar.gz/spa/plugins/support/journal.c
Changed
20
1
2
* DEALINGS IN THE SOFTWARE.
3
*/
4
5
+#include "config.h"
6
+
7
#include <stddef.h>
8
#include <unistd.h>
9
#include <string.h>
10
11
sd_journal_send_with_location(file_buffer, line_buffer, func,
12
"MESSAGE=%s", message_buffer,
13
"PRIORITY=%i", priority,
14
+#ifdef HAVE_GETTID
15
+ "TID=%jd", (intmax_t) gettid(),
16
+#endif
17
NULL);
18
}
19
20
pipewire-0.3.65.tar.gz/spa/plugins/support/meson.build -> pipewire-0.3.66.tar.gz/spa/plugins/support/meson.build
Changed
18
1
2
spa_support_lib = shared_library('spa-support',
3
spa_support_sources,
4
c_args : simd_cargs ,
5
- dependencies : spa_dep, pthread_lib, epoll_shim_dep ,
6
+ dependencies : spa_dep, pthread_lib, epoll_shim_dep, mathlib ,
7
install : true,
8
install_dir : spa_plugindir / 'support')
9
spa_support_dep = declare_dependency(link_with: spa_support_lib)
10
11
12
spa_journal_lib = shared_library('spa-journal',
13
spa_journal_sources,
14
+ include_directories : configinc ,
15
dependencies : spa_dep, systemd_dep ,
16
install : true,
17
install_dir : spa_plugindir / 'support')
18
pipewire-0.3.65.tar.gz/spa/plugins/support/node-driver.c -> pipewire-0.3.66.tar.gz/spa/plugins/support/node-driver.c
Changed
364
1
2
#include <unistd.h>
3
#include <string.h>
4
#include <stdio.h>
5
+#include <fcntl.h>
6
7
#include <spa/support/plugin.h>
8
#include <spa/support/log.h>
9
10
#include <spa/utils/names.h>
11
#include <spa/utils/result.h>
12
#include <spa/utils/string.h>
13
+#include <spa/utils/dll.h>
14
#include <spa/node/node.h>
15
#include <spa/node/keys.h>
16
#include <spa/node/io.h>
17
18
#define NAME "driver"
19
20
#define DEFAULT_FREEWHEEL false
21
-#define DEFAULT_CLOCK_NAME "clock.system.monotonic"
22
+#define DEFAULT_CLOCK_PREFIX "clock.system"
23
+#define DEFAULT_CLOCK_ID CLOCK_MONOTONIC
24
+
25
+#define CLOCKFD 3
26
+#define FD_TO_CLOCKID(fd) ((~(clockid_t) (fd) << 3) | CLOCKFD)
27
+#define CLOCKID_TO_FD(clk) ((unsigned int) ~((clk) >> 3))
28
+
29
+#define BW_PERIOD (3 * SPA_NSEC_PER_SEC)
30
+#define MAX_ERROR_MS 1
31
32
struct props {
33
bool freewheel;
34
char clock_name64;
35
+ clockid_t clock_id;
36
};
37
38
struct impl {
39
40
41
struct spa_source timer_source;
42
struct itimerspec timerspec;
43
+ int clock_fd;
44
45
bool started;
46
bool following;
47
+ bool tracking;
48
+ clockid_t timer_clockid;
49
uint64_t next_time;
50
+ uint64_t last_time;
51
+ uint64_t base_time;
52
+ struct spa_dll dll;
53
+ double max_error;
54
};
55
56
static void reset_props(struct props *props)
57
{
58
props->freewheel = DEFAULT_FREEWHEEL;
59
- spa_scnprintf(props->clock_name, sizeof(props->clock_name),
60
- "%s", DEFAULT_CLOCK_NAME);
61
+ spa_zero(props->clock_name);
62
+ props->clock_id = CLOCK_MONOTONIC;
63
}
64
65
+static const struct clock_info {
66
+ const char *name;
67
+ clockid_t id;
68
+} clock_info = {
69
+ { "realtime", CLOCK_REALTIME },
70
+ { "tai", CLOCK_TAI },
71
+ { "monotonic", CLOCK_MONOTONIC },
72
+ { "monotonic-raw", CLOCK_MONOTONIC_RAW },
73
+ { "boottime", CLOCK_BOOTTIME },
74
+};
75
+
76
+static bool clock_for_timerfd(clockid_t id)
77
+{
78
+ return id == CLOCK_REALTIME ||
79
+ id == CLOCK_MONOTONIC ||
80
+ id == CLOCK_BOOTTIME;
81
+}
82
+
83
+static clockid_t clock_name_to_id(const char *name)
84
+{
85
+ SPA_FOR_EACH_ELEMENT_VAR(clock_info, i) {
86
+ if (spa_streq(i->name, name))
87
+ return i->id;
88
+ }
89
+ return -1;
90
+}
91
+static const char *clock_id_to_name(clockid_t id)
92
+{
93
+ SPA_FOR_EACH_ELEMENT_VAR(clock_info, i) {
94
+ if (i->id == id)
95
+ return i->name;
96
+ }
97
+ return "custom";
98
+}
99
+
100
+
101
static void set_timeout(struct impl *this, uint64_t next_time)
102
{
103
spa_log_trace(this->log, "set timeout %"PRIu64, next_time);
104
105
this->timer_source.fd, SPA_FD_TIMER_ABSTIME, &this->timerspec, NULL);
106
}
107
108
+static inline uint64_t gettime_nsec(struct impl *this, clockid_t clock_id)
109
+{
110
+ struct timespec now = { 0 };
111
+ uint64_t nsec;
112
+ if (spa_system_clock_gettime(this->data_system, clock_id, &now) < 0)
113
+ return 0;
114
+ nsec = SPA_TIMESPEC_TO_NSEC(&now);
115
+ spa_log_trace(this->log, "%p now:%"PRIu64, this, nsec);
116
+ return nsec;
117
+}
118
+
119
static int set_timers(struct impl *this)
120
{
121
- struct timespec now;
122
- int res;
123
+ this->next_time = gettime_nsec(this, this->timer_clockid);
124
125
- if ((res = spa_system_clock_gettime(this->data_system, CLOCK_MONOTONIC, &now)) < 0)
126
- return res;
127
- this->next_time = SPA_TIMESPEC_TO_NSEC(&now);
128
+ spa_log_debug(this->log, "%p now:%"PRIu64, this, this->next_time);
129
130
if (this->following) {
131
set_timeout(this, 0);
132
133
return 0;
134
}
135
136
+static inline uint64_t scale_u64(uint64_t val, uint32_t num, uint32_t denom)
137
+{
138
+#if 0
139
+ return ((__uint128_t)val * num) / denom;
140
+#else
141
+ return (double)val / denom * num;
142
+#endif
143
+}
144
+
145
static void on_timeout(struct spa_source *source)
146
{
147
struct impl *this = source->data;
148
- uint64_t expirations, nsec, duration;
149
+ uint64_t expirations, nsec, duration, current_time, current_position, position;
150
uint32_t rate;
151
+ double corr = 1.0, err = 0.0;
152
int res;
153
154
- spa_log_trace(this->log, "timeout");
155
-
156
if ((res = spa_system_timerfd_read(this->data_system,
157
this->timer_source.fd, &expirations)) < 0) {
158
if (res != EAGAIN)
159
160
this, spa_strerror(res));
161
return;
162
}
163
-
164
- nsec = this->next_time;
165
-
166
if (SPA_LIKELY(this->position)) {
167
duration = this->position->clock.duration;
168
rate = this->position->clock.rate.denom;
169
170
duration = 1024;
171
rate = 48000;
172
}
173
+ nsec = this->next_time;
174
+
175
+ if (this->tracking)
176
+ /* we are actually following another clock */
177
+ current_time = gettime_nsec(this, this->props.clock_id);
178
+ else
179
+ current_time = nsec;
180
+
181
+ current_position = scale_u64(current_time, rate, SPA_NSEC_PER_SEC);
182
+
183
+ if (SPA_LIKELY(this->clock))
184
+ position = this->clock->position;
185
+ else
186
+ position = current_position;
187
+
188
+ if (this->last_time == 0) {
189
+ spa_dll_set_bw(&this->dll, SPA_DLL_BW_MIN, duration, rate);
190
+ this->max_error = rate * MAX_ERROR_MS / 1000;
191
+ position = current_position;
192
+ }
193
194
- this->next_time = nsec + duration * SPA_NSEC_PER_SEC / rate;
195
+ /* check the elapsed time of the other clock against
196
+ * the graph clock elapsed time, feed this error into the
197
+ * dll and adjust the timeout of our MONOTONIC clock. */
198
+ err = (double)position - (double)current_position;
199
+ if (err > this->max_error)
200
+ err = this->max_error;
201
+ else if (err < -this->max_error)
202
+ err = -this->max_error;
203
+
204
+ position += duration;
205
+ this->last_time = current_time;
206
+
207
+ if (this->tracking) {
208
+ corr = spa_dll_update(&this->dll, err);
209
+ this->next_time = nsec + duration / corr * 1e9 / rate;
210
+ } else {
211
+ corr = 1.0;
212
+ this->next_time = scale_u64(position, SPA_NSEC_PER_SEC, rate);
213
+ }
214
+
215
+ if (SPA_UNLIKELY((this->next_time - this->base_time) > BW_PERIOD)) {
216
+ this->base_time = this->next_time;
217
+ spa_log_debug(this->log, "%p: rate:%f "
218
+ "bw:%f dur:%"PRIu64" max:%f drift:%f",
219
+ this, corr, this->dll.bw, duration,
220
+ this->max_error, err);
221
+ }
222
223
if (SPA_LIKELY(this->clock)) {
224
this->clock->nsec = nsec;
225
- this->clock->position += duration;
226
+ this->clock->position = position;
227
this->clock->duration = duration;
228
this->clock->delay = 0;
229
- this->clock->rate_diff = 1.0;
230
+ this->clock->rate_diff = corr;
231
this->clock->next_nsec = this->next_time;
232
}
233
234
235
this->following = is_following(this);
236
set_timers(this);
237
this->started = true;
238
+ this->last_time = 0;
239
return 0;
240
}
241
242
243
return 0;
244
}
245
246
-static const struct spa_dict_item node_info_items = {
247
- { SPA_KEY_NODE_DRIVER, "true" },
248
-};
249
-
250
static void emit_node_info(struct impl *this, bool full)
251
{
252
uint64_t old = full ? this->info.change_mask : 0;
253
if (full)
254
this->info.change_mask = this->info_all;
255
if (this->info.change_mask) {
256
- this->info.props = &SPA_DICT_INIT_ARRAY(node_info_items);
257
+ struct spa_dict_item items3;
258
+
259
+ items0 = SPA_DICT_ITEM_INIT(SPA_KEY_NODE_DRIVER, "true");
260
+ items1 = SPA_DICT_ITEM_INIT("clock.id", clock_id_to_name(this->props.clock_id));
261
+ items2 = SPA_DICT_ITEM_INIT("clock.name", this->props.clock_name);
262
+
263
+ this->info.props = &SPA_DICT_INIT(items, 3);
264
spa_node_emit_info(&this->hooks, &this->info);
265
this->info.change_mask = old;
266
}
267
268
static int impl_node_process(void *object)
269
{
270
struct impl *this = object;
271
- struct timespec now;
272
273
spa_return_val_if_fail(this != NULL, -EINVAL);
274
spa_log_trace(this->log, "process %d", this->props.freewheel);
275
276
if (this->props.freewheel) {
277
- clock_gettime(CLOCK_MONOTONIC, &now);
278
- this->next_time = SPA_TIMESPEC_TO_NSEC(&now);
279
+ this->next_time = gettime_nsec(this, this->timer_clockid);
280
set_timeout(this, this->next_time);
281
}
282
return SPA_STATUS_HAVE_DATA | SPA_STATUS_NEED_DATA;
283
284
spa_loop_invoke(this->data_loop, do_remove_timer, 0, NULL, 0, true, this);
285
spa_system_close(this->data_system, this->timer_source.fd);
286
287
+ if (this->clock_fd != -1)
288
+ close(this->clock_fd);
289
+
290
return 0;
291
}
292
293
294
this->log = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_Log);
295
this->data_loop = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_DataLoop);
296
this->data_system = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_DataSystem);
297
+ this->clock_fd = -1;
298
+ spa_dll_init(&this->dll);
299
300
if (this->data_loop == NULL) {
301
spa_log_error(this->log, "a data_loop is needed");
302
303
this->info.params = this->params;
304
this->info.n_params = 0;
305
306
- this->timer_source.func = on_timeout;
307
- this->timer_source.data = this;
308
- this->timer_source.fd = spa_system_timerfd_create(this->data_system, CLOCK_MONOTONIC,
309
- SPA_FD_CLOEXEC | SPA_FD_NONBLOCK);
310
- this->timer_source.mask = SPA_IO_IN;
311
- this->timer_source.rmask = 0;
312
- this->timerspec.it_value.tv_sec = 0;
313
- this->timerspec.it_value.tv_nsec = 0;
314
- this->timerspec.it_interval.tv_sec = 0;
315
- this->timerspec.it_interval.tv_nsec = 0;
316
-
317
reset_props(&this->props);
318
319
for (i = 0; info && i < info->n_items; i++) {
320
321
} else if (spa_streq(k, "clock.name")) {
322
spa_scnprintf(this->props.clock_name,
323
sizeof(this->props.clock_name), "%s", s);
324
+ } else if (spa_streq(k, "clock.id")) {
325
+ this->props.clock_id = clock_name_to_id(s);
326
+ if (this->props.clock_id == -1) {
327
+ spa_log_warn(this->log, "unknown clock id '%s'", s);
328
+ this->props.clock_id = DEFAULT_CLOCK_ID;
329
+ }
330
+ } else if (spa_streq(k, "clock.device")) {
331
+ this->clock_fd = open(s, O_RDWR);
332
+ if (this->clock_fd == -1) {
333
+ spa_log_warn(this->log, "failed to open clock device '%s'", s);
334
+ } else {
335
+ this->props.clock_id = FD_TO_CLOCKID(this->clock_fd);
336
+ }
337
}
338
}
339
+ if (this->props.clock_name0 == '\0') {
340
+ spa_scnprintf(this->props.clock_name, sizeof(this->props.clock_name),
341
+ "%s.%s", DEFAULT_CLOCK_PREFIX,
342
+ clock_id_to_name(this->props.clock_id));
343
+ }
344
+
345
+ this->tracking = !clock_for_timerfd(this->props.clock_id);
346
+ this->timer_clockid = this->tracking ? CLOCK_MONOTONIC : this->props.clock_id;
347
+ this->max_error = 128;
348
+
349
+ this->timer_source.func = on_timeout;
350
+ this->timer_source.data = this;
351
+ this->timer_source.fd = spa_system_timerfd_create(this->data_system,
352
+ this->timer_clockid, SPA_FD_CLOEXEC | SPA_FD_NONBLOCK);
353
+
354
+ this->timer_source.mask = SPA_IO_IN;
355
+ this->timer_source.rmask = 0;
356
+ this->timerspec.it_value.tv_sec = 0;
357
+ this->timerspec.it_value.tv_nsec = 0;
358
+ this->timerspec.it_interval.tv_sec = 0;
359
+ this->timerspec.it_interval.tv_nsec = 0;
360
+
361
spa_loop_add_source(this->data_loop, &this->timer_source);
362
363
return 0;
364
pipewire-0.3.65.tar.gz/src/daemon/client-rt.conf.in -> pipewire-0.3.66.tar.gz/src/daemon/client-rt.conf.in
Changed
13
1
2
3
context.modules =
4
#{ name = <module-name>
5
- # args = { <key> = <value> ... }
6
- # flags = ifexists nofail
7
+ # ( args = { <key> = <value> ... } )
8
+ # ( flags = ( ifexists ) ( nofail ) )
9
+ # ( condition = { <key> = <value> ... } ... )
10
#}
11
#
12
# Loads a module with the given parameters.
13
pipewire-0.3.65.tar.gz/src/daemon/client.conf.in -> pipewire-0.3.66.tar.gz/src/daemon/client.conf.in
Changed
13
1
2
3
context.modules =
4
#{ name = <module-name>
5
- # args = { <key> = <value> ... }
6
- # flags = ifexists nofail
7
+ # ( args = { <key> = <value> ... } )
8
+ # ( flags = ( ifexists ) ( nofail ) )
9
+ # ( condition = { <key> = <value> ... } ... )
10
#}
11
#
12
# Loads a module with the given parameters.
13
pipewire-0.3.65.tar.gz/src/daemon/filter-chain.conf.in -> pipewire-0.3.66.tar.gz/src/daemon/filter-chain.conf.in
Changed
13
1
2
3
context.modules =
4
#{ name = <module-name>
5
- # args = { <key> = <value> ... }
6
- # flags = ifexists nofail
7
+ # ( args = { <key> = <value> ... } )
8
+ # ( flags = ( ifexists ) ( nofail ) )
9
+ # ( condition = { <key> = <value> ... } ... )
10
#}
11
#
12
# Loads a module with the given parameters.
13
pipewire-0.3.66.tar.gz/src/daemon/filter-chain/spatializer-7.1.conf
Added
159
1
2
+# Headphone surround sink
3
+#
4
+# Copy this file into a conf.d/ directory such as
5
+# ~/.config/pipewire/filter-chain.conf.d/
6
+#
7
+context.modules =
8
+ { name = libpipewire-module-filter-chain
9
+ args = {
10
+ node.description = "Spatial Sink"
11
+ media.name = "Spatial Sink"
12
+ filter.graph = {
13
+ nodes =
14
+ {
15
+ type = sofa
16
+ label = spatializer
17
+ name = spFL
18
+ config = {
19
+ filename = "~/.config/hrtf-sofa/hrtf b_nh724.sofa"
20
+ }
21
+ control = {
22
+ "Azimuth" = 30.0
23
+ "Elevation" = 0.0
24
+ "Radius" = 3.0
25
+ }
26
+ }
27
+ {
28
+ type = sofa
29
+ label = spatializer
30
+ name = spFR
31
+ config = {
32
+ filename = "~/.config/hrtf-sofa/hrtf b_nh724.sofa"
33
+ }
34
+ control = {
35
+ "Azimuth" = 330.0
36
+ "Elevation" = 0.0
37
+ "Radius" = 3.0
38
+ }
39
+ }
40
+ {
41
+ type = sofa
42
+ label = spatializer
43
+ name = spFC
44
+ config = {
45
+ filename = "~/.config/hrtf-sofa/hrtf b_nh724.sofa"
46
+ }
47
+ control = {
48
+ "Azimuth" = 0.0
49
+ "Elevation" = 0.0
50
+ "Radius" = 3.0
51
+ }
52
+ }
53
+ {
54
+ type = sofa
55
+ label = spatializer
56
+ name = spRL
57
+ config = {
58
+ filename = "~/.config/hrtf-sofa/hrtf b_nh724.sofa"
59
+ }
60
+ control = {
61
+ "Azimuth" = 150.0
62
+ "Elevation" = 0.0
63
+ "Radius" = 3.0
64
+ }
65
+ }
66
+ {
67
+ type = sofa
68
+ label = spatializer
69
+ name = spRR
70
+ config = {
71
+ filename = "~/.config/hrtf-sofa/hrtf b_nh724.sofa"
72
+ }
73
+ control = {
74
+ "Azimuth" = 210.0
75
+ "Elevation" = 0.0
76
+ "Radius" = 3.0
77
+ }
78
+ }
79
+ {
80
+ type = sofa
81
+ label = spatializer
82
+ name = spSL
83
+ config = {
84
+ filename = "~/.config/hrtf-sofa/hrtf b_nh724.sofa"
85
+ }
86
+ control = {
87
+ "Azimuth" = 90.0
88
+ "Elevation" = 0.0
89
+ "Radius" = 3.0
90
+ }
91
+ }
92
+ {
93
+ type = sofa
94
+ label = spatializer
95
+ name = spSR
96
+ config = {
97
+ filename = "~/.config/hrtf-sofa/hrtf b_nh724.sofa"
98
+ }
99
+ control = {
100
+ "Azimuth" = 270.0
101
+ "Elevation" = 0.0
102
+ "Radius" = 3.0
103
+ }
104
+ }
105
+ {
106
+ type = sofa
107
+ label = spatializer
108
+ name = spLFE
109
+ config = {
110
+ filename = "~/.config/hrtf-sofa/hrtf b_nh724.sofa"
111
+ }
112
+ control = {
113
+ "Azimuth" = 0.0
114
+ "Elevation" = -60.0
115
+ "Radius" = 3.0
116
+ }
117
+ }
118
+
119
+ { type = builtin label = mixer name = mixL }
120
+ { type = builtin label = mixer name = mixR }
121
+
122
+ links =
123
+ # output
124
+ { output = "spFL:Out L" input="mixL:In 1" }
125
+ { output = "spFL:Out R" input="mixR:In 1" }
126
+ { output = "spFR:Out L" input="mixL:In 2" }
127
+ { output = "spFR:Out R" input="mixR:In 2" }
128
+ { output = "spFC:Out L" input="mixL:In 3" }
129
+ { output = "spFC:Out R" input="mixR:In 3" }
130
+ { output = "spRL:Out L" input="mixL:In 4" }
131
+ { output = "spRL:Out R" input="mixR:In 4" }
132
+ { output = "spRR:Out L" input="mixL:In 5" }
133
+ { output = "spRR:Out R" input="mixR:In 5" }
134
+ { output = "spSL:Out L" input="mixL:In 6" }
135
+ { output = "spSL:Out R" input="mixR:In 6" }
136
+ { output = "spSR:Out L" input="mixL:In 7" }
137
+ { output = "spSR:Out R" input="mixR:In 7" }
138
+ { output = "spLFE:Out L" input="mixL:In 8" }
139
+ { output = "spLFE:Out R" input="mixR:In 8" }
140
+
141
+ inputs = "spFL:In" "spFR:In" "spFC:In" "spLFE:In" "spRL:In" "spRR:In", "spSL:In", "spSR:In"
142
+ outputs = "mixL:Out" "mixR:Out"
143
+ }
144
+ capture.props = {
145
+ node.name = "effect_input.spatializer"
146
+ media.class = Audio/Sink
147
+ audio.channels = 8
148
+ audio.position = FL FR FC LFE RL RR SL SR
149
+ }
150
+ playback.props = {
151
+ node.name = "effect_output.spatializer"
152
+ node.passive = true
153
+ audio.channels = 2
154
+ audio.position = FL FR
155
+ }
156
+ }
157
+ }
158
+
159
pipewire-0.3.66.tar.gz/src/daemon/filter-chain/spatializer-single.conf
Added
47
1
2
+# A virtual sound source sink
3
+# Useful for testing spatial effects by moving it around with controls
4
+#
5
+# Copy this file into a conf.d/ directory such as
6
+# ~/.config/pipewire/filter-chain.conf.d/
7
+#
8
+context.modules =
9
+ { name = libpipewire-module-filter-chain
10
+ args = {
11
+ node.description = "3D Sink"
12
+ media.name = "3D Sink"
13
+ filter.graph = {
14
+ nodes =
15
+ {
16
+ type = sofa
17
+ label = spatializer
18
+ name = sp
19
+ config = {
20
+ filename = "~/.config/hrtf-sofa/hrtf b_nh724.sofa"
21
+ }
22
+ control = {
23
+ "Azimuth" = 220.0
24
+ "Elevation" = 0.0
25
+ "Radius" = 3.0
26
+ }
27
+ }
28
+
29
+ inputs = "sp:In"
30
+ outputs = "sp:Out L" "sp:Out R"
31
+ }
32
+ capture.props = {
33
+ node.name = "effect_input.3d"
34
+ media.class = Audio/Sink
35
+ audio.channels = 1
36
+ audio.position = FC
37
+ }
38
+ playback.props = {
39
+ node.name = "effect_output.3d"
40
+ node.passive = true
41
+ audio.channels = 2
42
+ audio.position = FL FR
43
+ }
44
+ }
45
+ }
46
+
47
pipewire-0.3.65.tar.gz/src/daemon/jack.conf.in -> pipewire-0.3.66.tar.gz/src/daemon/jack.conf.in
Changed
13
1
2
3
context.modules =
4
#{ name = <module-name>
5
- # args = { <key> = <value> ... }
6
- # flags = ifexists nofail
7
+ # ( args = { <key> = <value> ... } )
8
+ # ( flags = ( ifexists ) ( nofail ) )
9
+ # ( condition = { <key> = <value> ... } ... )
10
#}
11
#
12
# Loads a module with the given parameters.
13
pipewire-0.3.65.tar.gz/src/daemon/meson.build -> pipewire-0.3.66.tar.gz/src/daemon/meson.build
Changed
24
1
2
'minimal.conf',
3
'pipewire-pulse.conf',
4
'pipewire-avb.conf',
5
+ 'pipewire-aes67.conf',
6
7
8
foreach c : conf_files
9
10
dependencies : spa_dep, pipewire_dep, ,
11
)
12
13
+executable('pipewire-aes67',
14
+ pipewire_daemon_sources,
15
+ install: true,
16
+ c_args : pipewire_c_args,
17
+ include_directories : configinc ,
18
+ dependencies : spa_dep, pipewire_dep, ,
19
+)
20
+
21
ln = find_program('ln')
22
23
custom_target('pipewire-uninstalled',
24
pipewire-0.3.65.tar.gz/src/daemon/minimal.conf.in -> pipewire-0.3.66.tar.gz/src/daemon/minimal.conf.in
Changed
37
1
2
3
context.modules =
4
#{ name = <module-name>
5
- # args = { <key> = <value> ... }
6
- # flags = ifexists nofail
7
+ # ( args = { <key> = <value> ... } )
8
+ # ( flags = ( ifexists ) ( nofail ) )
9
+ # ( condition = { <key> = <value> ... } ... )
10
#}
11
#
12
# Loads a module with the given parameters.
13
14
15
context.objects =
16
#{ factory = <factory-name>
17
- # args = { <key> = <value> ... }
18
- # flags = nofail
19
+ # ( args = { <key> = <value> ... } )
20
+ # ( flags = ( nofail ) )
21
+ # ( condition = { <key> = <value> ... } ... )
22
#}
23
#
24
# Creates an object from a PipeWire factory with the given parameters.
25
26
27
28
context.exec =
29
- #{ path = <program-name> args = "<arguments>" }
30
+ #{ path = <program-name>
31
+ # ( args = "<arguments>" )
32
+ # ( condition = { <key> = <value> ... } ... )
33
+ #}
34
#
35
# Execute the given program with arguments.
36
#
37
pipewire-0.3.66.tar.gz/src/daemon/pipewire-aes67.conf.in
Added
54
1
2
+# AES67 config file for PipeWire version @VERSION@ #
3
+#
4
+# Copy and edit this file in @PIPEWIRE_CONFIG_DIR@ for system-wide changes
5
+# or in ~/.config/pipewire for local changes.
6
+#
7
+# It is also possible to place a file with an updated section in
8
+# @PIPEWIRE_CONFIG_DIR@/pipewire-aes67.conf.d/ for system-wide changes or in
9
+# ~/.config/pipewire/pipewire-aes67.conf.d/ for local changes.
10
+#
11
+
12
+context.properties = {
13
+ ## Configure properties in the system.
14
+ #mem.warn-mlock = false
15
+ #mem.allow-mlock = true
16
+ #mem.mlock-all = false
17
+ #log.level = 2
18
+
19
+ #default.clock.quantum-limit = 8192
20
+}
21
+
22
+#context.spa-libs = {
23
+# audio.convert.* = audioconvert/libspa-audioconvert
24
+# support.* = support/libspa-support
25
+#}
26
+
27
+context.modules =
28
+ { name = libpipewire-module-rt
29
+ args = {
30
+ nice.level = -11
31
+ #rt.prio = 88
32
+ #rt.time.soft = -1
33
+ #rt.time.hard = -1
34
+ }
35
+ flags = ifexists nofail
36
+ }
37
+ { name = libpipewire-module-protocol-native }
38
+ { name = libpipewire-module-client-node }
39
+ { name = libpipewire-module-adapter }
40
+ { name = libpipewire-module-rtp-source
41
+ args = {
42
+ sap.ip = 239.255.255.255
43
+ sap.port = 9875
44
+ sess.latency.msec = 10
45
+ local.ifname = eth0
46
+ stream.props = {
47
+ media.class = "Audio/Source"
48
+ node.virtual = false
49
+ device.api = aes67
50
+ }
51
+ }
52
+ }
53
+
54
pipewire-0.3.65.tar.gz/src/daemon/pipewire-pulse.conf.in -> pipewire-0.3.66.tar.gz/src/daemon/pipewire-pulse.conf.in
Changed
15
1
2
# Extra commands can be executed here.
3
# load-module : loads a module with args and flags
4
# args = "<module-name> <module-args>"
5
-# flags = "no-fail"
6
+# ( flags = nofail )
7
pulse.cmd =
8
{ cmd = "load-module" args = "module-always-sink" flags = }
9
#{ cmd = "load-module" args = "module-switch-on-connect" }
10
- #{ cmd = "load-module" args = "module-gsettings" flags = "nofail" }
11
+ #{ cmd = "load-module" args = "module-gsettings" flags = nofail }
12
13
14
stream.properties = {
15
pipewire-0.3.65.tar.gz/src/daemon/pipewire.conf.in -> pipewire-0.3.66.tar.gz/src/daemon/pipewire.conf.in
Changed
109
1
2
#default.clock.rate = 48000
3
#default.clock.allowed-rates = 48000
4
#default.clock.quantum = 1024
5
- default.clock.min-quantum = 16
6
+ #default.clock.min-quantum = 32
7
#default.clock.max-quantum = 2048
8
#default.clock.quantum-limit = 8192
9
#default.video.width = 640
10
11
vm.overrides = {
12
default.clock.min-quantum = 1024
13
}
14
+
15
+ # keys checked below to disable module loading
16
+ module.x11.bell = true
17
}
18
19
context.spa-libs = {
20
21
22
context.modules =
23
#{ name = <module-name>
24
- # args = { <key> = <value> ... }
25
- # flags = ifexists nofail
26
+ # ( args = { <key> = <value> ... } )
27
+ # ( flags = ( ifexists ) ( nofail ) )
28
+ # ( condition = { <key> = <value> ... } ... )
29
#}
30
#
31
# Loads a module with the given parameters.
32
# If ifexists is given, the module is ignored when it is not found.
33
# If nofail is given, module initialization failures are ignored.
34
+ # If condition is given, the module is loaded only when the context
35
+ # properties all match the match rules.
36
#
37
38
# Uses realtime scheduling to boost the audio thread priorities. This uses
39
40
#x11.xauthority = null
41
}
42
flags = ifexists nofail
43
+ condition = { module.x11.bell = true }
44
}
45
46
47
context.objects =
48
#{ factory = <factory-name>
49
- # args = { <key> = <value> ... }
50
- # flags = nofail
51
+ # ( args = { <key> = <value> ... } )
52
+ # ( flags = ( nofail ) )
53
+ # ( condition = { <key> = <value> ... } ... )
54
#}
55
#
56
# Creates an object from a PipeWire factory with the given parameters.
57
# If nofail is given, errors are ignored (and no object is created).
58
+ # If condition is given, the object is created only when the context properties
59
+ # all match the match rules.
60
#
61
#{ factory = spa-node-factory args = { factory.name = videotestsrc node.name = videotestsrc Spa:Pod:Object:Param:Props:patternType = 1 } }
62
#{ factory = spa-device-factory args = { factory.name = api.jack.device foo=bar } flags = nofail }
63
64
node.name = Dummy-Driver
65
node.group = pipewire.dummy
66
priority.driver = 20000
67
+ #clock.id = monotonic # realtime | tai | monotonic-raw | boottime
68
+ #clock.name = "clock.system.monotonic"
69
}
70
}
71
{ factory = spa-node-factory
72
73
node.freewheel = true
74
}
75
}
76
+ # An example clock reading from /dev/ptp0. Another option is to sync the
77
+ # ptp clock to CLOCK_TAI and then set clock.id = tai.
78
+ #{ factory = spa-node-factory
79
+ # args = {
80
+ # factory.name = support.node.driver
81
+ # node.name = PTP0-Driver
82
+ # node.group = pipewire.ptp0
83
+ # priority.driver = 30000
84
+ # clock.name = "clock.system.ptp0"
85
+ # #clock.id = tai
86
+ # clock.device = "/dev/ptp0"
87
+ # }
88
+ #}
89
+
90
# This creates a new Source node. It will have input ports
91
# that you can link, to provide audio for this source.
92
#{ factory = adapter
93
94
95
96
context.exec =
97
- #{ path = <program-name> args = "<arguments>" }
98
+ #{ path = <program-name>
99
+ # ( args = "<arguments>" )
100
+ # ( condition = { <key> = <value> ... } ... )
101
+ #}
102
#
103
# Execute the given program with arguments.
104
+ # If condition is given, the program is executed only when the context
105
+ # properties all match the match rules.
106
#
107
# You can optionally start the session manager here,
108
# but it is better to start it as a systemd service.
109
pipewire-0.3.65.tar.gz/src/gst/gstpipewirepool.c -> pipewire-0.3.66.tar.gz/src/gst/gstpipewirepool.c
Changed
69
1
2
gst_buffer_insert_memory (buf, i, gmem);
3
}
4
5
+ if (pool->add_metavideo) {
6
+ gst_buffer_add_video_meta_full (buf, GST_VIDEO_FRAME_FLAG_NONE,
7
+ GST_VIDEO_INFO_FORMAT (&pool->video_info),
8
+ GST_VIDEO_INFO_WIDTH (&pool->video_info),
9
+ GST_VIDEO_INFO_HEIGHT (&pool->video_info),
10
+ GST_VIDEO_INFO_N_PLANES (&pool->video_info),
11
+ pool->video_info.offset,
12
+ pool->video_info.stride);
13
+ }
14
+
15
data->pool = gst_object_ref (pool);
16
data->owner = NULL;
17
data->header = spa_buffer_find_meta_data (b->buffer, SPA_META_Header, sizeof(*data->header));
18
19
}
20
}
21
22
+static const gchar **
23
+get_options (GstBufferPool * pool)
24
+{
25
+ static const gchar *options = { GST_BUFFER_POOL_OPTION_VIDEO_META, NULL };
26
+ return options;
27
+}
28
+
29
+static gboolean
30
+set_config (GstBufferPool * pool, GstStructure * config)
31
+{
32
+ GstPipeWirePool *p = GST_PIPEWIRE_POOL (pool);
33
+ GstCaps *caps;
34
+ guint size, min_buffers, max_buffers;
35
+ gboolean has_video;
36
+
37
+ if (!gst_buffer_pool_config_get_params (config, &caps, &size, &min_buffers, &max_buffers)) {
38
+ GST_WARNING_OBJECT (pool, "invalid config");
39
+ return FALSE;
40
+ }
41
+
42
+ if (caps == NULL) {
43
+ GST_WARNING_OBJECT (pool, "no caps in config");
44
+ return FALSE;
45
+ }
46
+
47
+ has_video = gst_video_info_from_caps (&p->video_info, caps);
48
+
49
+ p->add_metavideo = has_video && gst_buffer_pool_config_has_option (config,
50
+ GST_BUFFER_POOL_OPTION_VIDEO_META);
51
+
52
+ gst_buffer_pool_config_set_params (config, caps, p->video_info.size, min_buffers, max_buffers);
53
+
54
+ return GST_BUFFER_POOL_CLASS (gst_pipewire_pool_parent_class)->set_config (pool, config);
55
+}
56
+
57
static void
58
flush_start (GstBufferPool * pool)
59
{
60
61
62
gobject_class->finalize = gst_pipewire_pool_finalize;
63
64
+ bufferpool_class->get_options = get_options;
65
+ bufferpool_class->set_config = set_config;
66
bufferpool_class->start = do_start;
67
bufferpool_class->flush_start = flush_start;
68
bufferpool_class->acquire_buffer = acquire_buffer;
69
pipewire-0.3.65.tar.gz/src/gst/gstpipewirepool.h -> pipewire-0.3.66.tar.gz/src/gst/gstpipewirepool.h
Changed
20
1
2
3
#include <gst/gst.h>
4
5
+#include <gst/video/video.h>
6
+
7
#include <pipewire/pipewire.h>
8
9
G_BEGIN_DECLS
10
11
struct pw_stream *stream;
12
struct pw_type *t;
13
14
+ gboolean add_metavideo;
15
+ GstVideoInfo video_info;
16
+
17
GstAllocator *fd_allocator;
18
GstAllocator *dmabuf_allocator;
19
20
pipewire-0.3.65.tar.gz/src/gst/gstpipewiresink.c -> pipewire-0.3.66.tar.gz/src/gst/gstpipewiresink.c
Changed
32
1
2
GstPipeWireSink *pwsink = GST_PIPEWIRE_SINK (bsink);
3
4
gst_query_add_allocation_pool (query, GST_BUFFER_POOL_CAST (pwsink->pool), 0, 0, 0);
5
+ gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
6
return TRUE;
7
}
8
9
10
d->chunk->stride = 0;
11
}
12
13
+ GstVideoMeta *meta = gst_buffer_get_video_meta (buffer);
14
+ if (meta) {
15
+ if (meta->n_planes == b->n_datas) {
16
+ gsize video_size = 0;
17
+ for (i = 0; i < meta->n_planes; i++) {
18
+ struct spa_data *d = &b->datasi;
19
+ d->chunk->offset += meta->offseti - video_size;
20
+ d->chunk->stride = meta->stridei;
21
+
22
+ video_size += d->chunk->size;
23
+ }
24
+ } else {
25
+ GST_ERROR ("plane num not matching, meta:%u buffer:%u", meta->n_planes, b->n_datas);
26
+ }
27
+ }
28
+
29
if ((res = pw_stream_queue_buffer (pwsink->stream, data->b)) < 0) {
30
g_warning ("can't send buffer %s", spa_strerror(res));
31
}
32
pipewire-0.3.65.tar.gz/src/gst/gstpipewiresrc.c -> pipewire-0.3.66.tar.gz/src/gst/gstpipewiresrc.c
Changed
48
1
2
}
3
}
4
5
+ if (pwsrc->is_video) {
6
+ gsize video_size = 0;
7
+ GstVideoInfo *info = &pwsrc->video_info;
8
+ GstVideoMeta *meta = gst_buffer_add_video_meta_full (buf, GST_VIDEO_FRAME_FLAG_NONE,
9
+ GST_VIDEO_INFO_FORMAT (info),
10
+ GST_VIDEO_INFO_WIDTH (info),
11
+ GST_VIDEO_INFO_HEIGHT (info),
12
+ GST_VIDEO_INFO_N_PLANES (info),
13
+ info->offset,
14
+ info->stride);
15
+
16
+ meta->n_planes = MIN(meta->n_planes, b->buffer->n_datas);
17
+ for (i = 0; i < meta->n_planes; i++) {
18
+ struct spa_data *d = &b->buffer->datasi;
19
+ meta->offseti = video_size;
20
+ meta->stridei = d->chunk->stride;
21
+
22
+ video_size += d->chunk->size;
23
+ }
24
+ }
25
+
26
for (i = 0; i < b->buffer->n_datas; i++) {
27
struct spa_data *d = &b->buffer->datasi;
28
GstMemory *pmem = gst_buffer_peek_memory (data->buf, i);
29
30
case PW_STREAM_STATE_STREAMING:
31
break;
32
case PW_STREAM_STATE_ERROR:
33
+ pw_stream_set_error (pwsrc->stream, -EPIPE, "%s", error);
34
GST_ELEMENT_ERROR (pwsrc, RESOURCE, FAILED,
35
("stream error: %s", error), (NULL));
36
break;
37
38
gst_caps_unref(pwsrc->caps);
39
pwsrc->caps = gst_caps_from_format (param);
40
41
+ pwsrc->is_video = pwsrc->caps != NULL
42
+ ? gst_video_info_from_caps (&pwsrc->video_info, pwsrc->caps)
43
+ : FALSE;
44
+
45
pwsrc->negotiated = pwsrc->caps != NULL;
46
47
if (pwsrc->negotiated) {
48
pipewire-0.3.65.tar.gz/src/gst/gstpipewiresrc.h -> pipewire-0.3.66.tar.gz/src/gst/gstpipewiresrc.h
Changed
20
1
2
#include <gst/gst.h>
3
#include <gst/base/gstpushsrc.h>
4
5
+#include <gst/video/video.h>
6
+
7
#include <pipewire/pipewire.h>
8
#include <gst/gstpipewirepool.h>
9
#include <gst/gstpipewirecore.h>
10
11
12
GstCaps *caps;
13
14
+ gboolean is_video;
15
+ GstVideoInfo video_info;
16
+
17
gboolean negotiated;
18
gboolean flushing;
19
gboolean started;
20
pipewire-0.3.65.tar.gz/src/modules/meson.build -> pipewire-0.3.66.tar.gz/src/modules/meson.build
Changed
282
1
2
+subdir('module-rt')
3
subdir('spa')
4
5
# The list of "main" source files for modules, the ones that have the
6
7
'module-filter-chain/biquad.c',
8
'module-filter-chain/ladspa_plugin.c',
9
'module-filter-chain/builtin_plugin.c',
10
+ 'module-filter-chain/sofa_plugin.c',
11
'module-filter-chain/convolver.c'
12
13
filter_chain_dependencies =
14
- mathlib, dl_lib, pipewire_dep, sndfile_dep, audioconvert_dep
15
+ mathlib, dl_lib, pipewire_dep, sndfile_dep, audioconvert_dep, libmysofa_dep
16
17
18
if lilv_lib.found()
19
20
pipewire_module_combine_stream = shared_library('pipewire-module-combine-stream',
21
'module-combine-stream.c' ,
22
include_directories : configinc,
23
- install : false,
24
+ install : true,
25
install_dir : modules_install_dir,
26
install_rpath: modules_install_dir,
27
dependencies : spa_dep, dl_lib, pipewire_dep,
28
29
30
build_module_rtkit = dbus_dep.found() and (get_option('legacy-rtkit') == true)
31
if build_module_rtkit
32
-# TODO: This serves as a temporary alias to prevent breaking existing setups
33
-# while `module-rtkit` is being migrated to `module-rt`
34
-pipewire_module_rtkit = shared_library('pipewire-module-rtkit', 'module-rt.c' ,
35
- include_directories : configinc,
36
- install : true,
37
- install_dir : modules_install_dir,
38
- install_rpath: modules_install_dir,
39
- dependencies : dbus_dep, mathlib, dl_lib, pipewire_dep,
40
-)
41
+ pipewire_module_rtkit = shared_library('pipewire-module-rtkit', 'module-rt.c' ,
42
+ include_directories : configinc,
43
+ install : true,
44
+ install_dir : modules_install_dir,
45
+ install_rpath: modules_install_dir,
46
+ dependencies : dbus_dep, mathlib, dl_lib, pipewire_dep,
47
+ )
48
endif
49
summary({'rt': '@0@ RTKit'.format(build_module_rtkit ? 'with' : 'without')}, section: 'Optional Modules')
50
51
build_module_portal = dbus_dep.found()
52
if build_module_portal
53
-pipewire_module_portal = shared_library('pipewire-module-portal', 'module-portal.c' ,
54
- include_directories : configinc,
55
- install : true,
56
- install_dir : modules_install_dir,
57
- install_rpath: modules_install_dir,
58
- dependencies : dbus_dep, mathlib, dl_lib, pipewire_dep,
59
-)
60
+ pipewire_module_portal = shared_library('pipewire-module-portal', 'module-portal.c' ,
61
+ include_directories : configinc,
62
+ install : true,
63
+ install_dir : modules_install_dir,
64
+ install_rpath: modules_install_dir,
65
+ dependencies : dbus_dep, mathlib, dl_lib, pipewire_dep,
66
+ )
67
endif
68
summary({'portal': build_module_portal}, bool_yn: true, section: 'Optional Modules')
69
70
71
)
72
73
build_module_pulse_tunnel = pulseaudio_dep.found()
74
-if build_module_pulse_tunnel
75
- pipewire_module_pulse_tunnel = shared_library('pipewire-module-pulse-tunnel',
76
- 'module-pulse-tunnel.c',
77
- 'module-protocol-pulse/format.c' ,
78
- include_directories : configinc,
79
- install : true,
80
- install_dir : modules_install_dir,
81
- install_rpath: modules_install_dir,
82
- dependencies : mathlib, dl_lib, pipewire_dep, pulseaudio_dep,
83
-)
84
+ if build_module_pulse_tunnel
85
+ pipewire_module_pulse_tunnel = shared_library('pipewire-module-pulse-tunnel',
86
+ 'module-pulse-tunnel.c',
87
+ 'module-protocol-pulse/format.c' ,
88
+ include_directories : configinc,
89
+ install : true,
90
+ install_dir : modules_install_dir,
91
+ install_rpath: modules_install_dir,
92
+ dependencies : mathlib, dl_lib, pipewire_dep, pulseaudio_dep,
93
+ )
94
endif
95
summary({'pulse-tunnel': build_module_pulse_tunnel}, bool_yn: true, section: 'Optional Modules')
96
97
98
99
build_module_zeroconf_discover = avahi_dep.found()
100
if build_module_zeroconf_discover
101
-pipewire_module_zeroconf_discover = shared_library('pipewire-module-zeroconf-discover',
102
- 'module-zeroconf-discover.c',
103
- 'module-protocol-pulse/format.c',
104
- 'module-zeroconf-discover/avahi-poll.c' ,
105
- include_directories : configinc,
106
- install : true,
107
- install_dir : modules_install_dir,
108
- install_rpath: modules_install_dir,
109
- dependencies : mathlib, dl_lib, rt_lib, pipewire_dep, avahi_dep,
110
-)
111
+ pipewire_module_zeroconf_discover = shared_library('pipewire-module-zeroconf-discover',
112
+ 'module-zeroconf-discover.c',
113
+ 'module-protocol-pulse/format.c',
114
+ 'module-zeroconf-discover/avahi-poll.c' ,
115
+ include_directories : configinc,
116
+ install : true,
117
+ install_dir : modules_install_dir,
118
+ install_rpath: modules_install_dir,
119
+ dependencies : mathlib, dl_lib, rt_lib, pipewire_dep, avahi_dep,
120
+ )
121
endif
122
summary({'zeroconf-discover': build_module_zeroconf_discover}, bool_yn: true, section: 'Optional Modules')
123
124
build_module_raop_discover = avahi_dep.found()
125
if build_module_raop_discover
126
-pipewire_module_raop_discover = shared_library('pipewire-module-raop-discover',
127
- 'module-raop-discover.c',
128
- 'module-zeroconf-discover/avahi-poll.c' ,
129
- include_directories : configinc,
130
- install : true,
131
- install_dir : modules_install_dir,
132
- install_rpath: modules_install_dir,
133
- dependencies : mathlib, dl_lib, rt_lib, pipewire_dep, avahi_dep,
134
-)
135
+ pipewire_module_raop_discover = shared_library('pipewire-module-raop-discover',
136
+ 'module-raop-discover.c',
137
+ 'module-zeroconf-discover/avahi-poll.c' ,
138
+ include_directories : configinc,
139
+ install : true,
140
+ install_dir : modules_install_dir,
141
+ install_rpath: modules_install_dir,
142
+ dependencies : mathlib, dl_lib, rt_lib, pipewire_dep, avahi_dep,
143
+ )
144
endif
145
summary({'raop-discover (needs Avahi)': build_module_raop_discover}, bool_yn: true, section: 'Optional Modules')
146
147
build_module_raop = openssl_lib.found()
148
if build_module_raop
149
-pipewire_module_raop_sink = shared_library('pipewire-module-raop-sink',
150
- 'module-raop-sink.c',
151
- 'module-raop/rtsp-client.c' ,
152
- include_directories : configinc,
153
- install : true,
154
- install_dir : modules_install_dir,
155
- install_rpath: modules_install_dir,
156
- dependencies : mathlib, dl_lib, rt_lib, pipewire_dep, openssl_lib,
157
-)
158
+ pipewire_module_raop_sink = shared_library('pipewire-module-raop-sink',
159
+ 'module-raop-sink.c',
160
+ 'module-raop/rtsp-client.c' ,
161
+ include_directories : configinc,
162
+ install : true,
163
+ install_dir : modules_install_dir,
164
+ install_rpath: modules_install_dir,
165
+ dependencies : mathlib, dl_lib, rt_lib, pipewire_dep, openssl_lib,
166
+ )
167
endif
168
summary({'raop-sink (requires OpenSSL)': build_module_raop}, bool_yn: true, section: 'Optional Modules')
169
170
171
172
build_module_roc = roc_dep.found()
173
if build_module_roc
174
-pipewire_module_roc_sink = shared_library('pipewire-module-roc-sink',
175
- 'module-roc-sink.c' ,
176
- include_directories : configinc,
177
- install : true,
178
- install_dir : modules_install_dir,
179
- install_rpath: modules_install_dir,
180
- dependencies : mathlib, dl_lib, rt_lib, pipewire_dep, roc_dep,
181
-)
182
+ pipewire_module_roc_sink = shared_library('pipewire-module-roc-sink',
183
+ 'module-roc-sink.c' ,
184
+ include_directories : configinc,
185
+ install : true,
186
+ install_dir : modules_install_dir,
187
+ install_rpath: modules_install_dir,
188
+ dependencies : mathlib, dl_lib, rt_lib, pipewire_dep, roc_dep,
189
+ )
190
191
-pipewire_module_roc_source = shared_library('pipewire-module-roc-source',
192
- 'module-roc-source.c' ,
193
- include_directories : configinc,
194
- install : true,
195
- install_dir : modules_install_dir,
196
- install_rpath: modules_install_dir,
197
- dependencies : mathlib, dl_lib, rt_lib, pipewire_dep, roc_dep,
198
-)
199
+ pipewire_module_roc_source = shared_library('pipewire-module-roc-source',
200
+ 'module-roc-source.c' ,
201
+ include_directories : configinc,
202
+ install : true,
203
+ install_dir : modules_install_dir,
204
+ install_rpath: modules_install_dir,
205
+ dependencies : mathlib, dl_lib, rt_lib, pipewire_dep, roc_dep,
206
+ )
207
endif
208
summary({'roc-sink': build_module_roc}, bool_yn: true, section: 'Optional Modules')
209
summary({'roc-source': build_module_roc}, bool_yn: true, section: 'Optional Modules')
210
211
build_module_x11_bell = x11_dep.found() and canberra_dep.found()
212
if build_module_x11_bell
213
-pipewire_module_x11_bell = shared_library('pipewire-module-x11-bell',
214
- 'module-x11-bell.c' ,
215
- include_directories : configinc,
216
- install : true,
217
- install_dir : modules_install_dir,
218
- install_rpath: modules_install_dir,
219
- dependencies : mathlib, dl_lib, rt_lib, pipewire_dep, x11_dep, xfixes_dep, canberra_dep,
220
-)
221
+ pipewire_module_x11_bell = shared_library('pipewire-module-x11-bell',
222
+ 'module-x11-bell.c' ,
223
+ include_directories : configinc,
224
+ install : true,
225
+ install_dir : modules_install_dir,
226
+ install_rpath: modules_install_dir,
227
+ dependencies : mathlib, dl_lib, rt_lib, pipewire_dep, x11_dep, xfixes_dep, canberra_dep,
228
+ )
229
endif
230
summary({'x11-bell': build_module_x11_bell}, bool_yn: true, section: 'Optional Modules')
231
232
233
234
build_module_avb = get_option('avb').require(host_machine.system() == 'linux', error_message: 'AVB support is only available on Linux').allowed()
235
if build_module_avb
236
-pipewire_module_avb = shared_library('pipewire-module-avb',
237
- 'module-avb.c',
238
- 'module-avb/avb.c',
239
- 'module-avb/adp.c',
240
- 'module-avb/acmp.c',
241
- 'module-avb/aecp.c',
242
- 'module-avb/aecp-aem.c',
243
- 'module-avb/avdecc.c',
244
- 'module-avb/maap.c',
245
- 'module-avb/mmrp.c',
246
- 'module-avb/mrp.c',
247
- 'module-avb/msrp.c',
248
- 'module-avb/mvrp.c',
249
- 'module-avb/srp.c',
250
- 'module-avb/stream.c'
251
- ,
252
- include_directories : configinc,
253
- install : true,
254
- install_dir : modules_install_dir,
255
- install_rpath: modules_install_dir,
256
- dependencies : mathlib, dl_lib, rt_lib, pipewire_dep,
257
-)
258
+ pipewire_module_avb = shared_library('pipewire-module-avb',
259
+ 'module-avb.c',
260
+ 'module-avb/avb.c',
261
+ 'module-avb/adp.c',
262
+ 'module-avb/acmp.c',
263
+ 'module-avb/aecp.c',
264
+ 'module-avb/aecp-aem.c',
265
+ 'module-avb/avdecc.c',
266
+ 'module-avb/maap.c',
267
+ 'module-avb/mmrp.c',
268
+ 'module-avb/mrp.c',
269
+ 'module-avb/msrp.c',
270
+ 'module-avb/mvrp.c',
271
+ 'module-avb/srp.c',
272
+ 'module-avb/stream.c'
273
+ ,
274
+ include_directories : configinc,
275
+ install : true,
276
+ install_dir : modules_install_dir,
277
+ install_rpath: modules_install_dir,
278
+ dependencies : mathlib, dl_lib, rt_lib, pipewire_dep,
279
+ )
280
endif
281
summary({'avb': build_module_avb}, bool_yn: true, section: 'Optional Modules')
282
pipewire-0.3.65.tar.gz/src/modules/module-combine-stream.c -> pipewire-0.3.66.tar.gz/src/modules/module-combine-stream.c
Changed
9
1
2
}
3
4
static const struct pw_proxy_events core_proxy_events = {
5
+ PW_VERSION_PROXY_EVENTS,
6
.removed = core_removed,
7
};
8
9
pipewire-0.3.65.tar.gz/src/modules/module-filter-chain.c -> pipewire-0.3.66.tar.gz/src/modules/module-filter-chain.c
Changed
130
1
2
* - `max-delay` the maximum delay in seconds. The "Delay (s)" parameter will
3
* be clamped to this value.
4
*
5
+ * ### Invert
6
+ *
7
+ * The invert plugin can be used to invert the phase of the signal.
8
+ *
9
+ * It has an input port "In" and an output port "Out".
10
+ *
11
* ## General options
12
*
13
* Options with well-known behavior. Most options can be added to the global
14
15
struct plugin {
16
struct spa_list link;
17
int ref;
18
- char type64;
19
+ char type256;
20
char pathPATH_MAX;
21
22
struct fc_plugin *plugin;
23
24
unsigned int n_deps;
25
unsigned int visited:1;
26
unsigned int disabled:1;
27
+ unsigned int control_changed:1;
28
};
29
30
struct link {
31
32
old = port->control_data;
33
port->control_data = value ? *value : desc->default_controlport->idx;
34
pw_log_info("control %d ('%s') from %f to %f", port->idx, name, old, port->control_data);
35
- return old == port->control_data ? 0 : 1;
36
+ node->control_changed = old != port->control_data;
37
+ return node->control_changed ? 1 : 0;
38
}
39
40
static int parse_params(struct graph *graph, const struct spa_pod *pod)
41
42
d->activate(*hndl->hndl);
43
}
44
}
45
+
46
+static void node_control_changed(struct node *node)
47
+{
48
+ const struct fc_descriptor *d = node->desc->desc;
49
+ uint32_t i;
50
+
51
+ if (!node->control_changed)
52
+ return;
53
+
54
+ for (i = 0; i < node->n_hndl; i++) {
55
+ if (node->hndli == NULL)
56
+ continue;
57
+ if (d->control_changed)
58
+ d->control_changed(node->hndli);
59
+ }
60
+ node->control_changed = false;
61
+}
62
+
63
static void param_props_changed(struct impl *impl, const struct spa_pod *param)
64
{
65
struct spa_pod_object *obj = (struct spa_pod_object *) param;
66
67
uint8_t buffer1024;
68
struct spa_pod_dynamic_builder b;
69
const struct spa_pod *params1;
70
+ struct node *node;
71
+
72
+ spa_list_for_each(node, &graph->node_list, link)
73
+ node_control_changed(node);
74
75
spa_pod_dynamic_builder_init(&b, buffer, sizeof(buffer), 4096);
76
params0 = get_props_param(graph, &b.b);
77
78
if (spa_streq(type, "builtin")) {
79
pl = load_builtin_plugin(support, n_support, &impl->dsp, path, NULL);
80
}
81
+ else if (spa_streq(type, "sofa")) {
82
+ pl = load_sofa_plugin(support, n_support, &impl->dsp, path, NULL);
83
+ }
84
else if (spa_streq(type, "ladspa")) {
85
pl = load_ladspa_plugin(support, n_support, &impl->dsp, path, NULL);
86
}
87
88
free(node->output_port);
89
free(node->control_port);
90
free(node->notify_port);
91
+ free(node->config);
92
free(node);
93
}
94
95
96
}
97
if (d->activate)
98
d->activate(node->hndli);
99
+ if (node->control_changed && d->control_changed)
100
+ d->control_changed(node->hndli);
101
}
102
}
103
return 0;
104
105
pw_log_error("input port %s not found", v);
106
goto error;
107
} else {
108
+ bool disabled = false;
109
+
110
desc = port->node->desc;
111
d = desc->desc;
112
if (i == 0 && port->external != SPA_ID_INVALID) {
113
114
gp->hndl = &peer->node->hndli;
115
gp->port = peer->p;
116
gp->next = true;
117
+ disabled = true;
118
}
119
if (gp != NULL)
120
gp->next = false;
121
}
122
- port->node->disabled = true;
123
- } else {
124
+ port->node->disabled = disabled;
125
+ }
126
+ if (!disabled) {
127
pw_log_info("input port %s%d:%s",
128
port->node->name, i, d->portsport->p.name);
129
port->external = graph->n_input;
130
pipewire-0.3.65.tar.gz/src/modules/module-filter-chain/builtin_plugin.c -> pipewire-0.3.66.tar.gz/src/modules/module-filter-chain/builtin_plugin.c
Changed
49
1
2
.cleanup = delay_cleanup,
3
};
4
5
+static void invert_run(void * Instance, unsigned long SampleCount)
6
+{
7
+ struct builtin *impl = Instance;
8
+ float *in = impl->port1, *out = impl->port0;
9
+ unsigned long n;
10
+ for (n = 0; n < SampleCount; n++)
11
+ outn = -inn;
12
+}
13
+
14
+static struct fc_port invert_ports = {
15
+ { .index = 0,
16
+ .name = "Out",
17
+ .flags = FC_PORT_OUTPUT | FC_PORT_AUDIO,
18
+ },
19
+ { .index = 1,
20
+ .name = "In",
21
+ .flags = FC_PORT_INPUT | FC_PORT_AUDIO,
22
+ },
23
+};
24
+
25
+static const struct fc_descriptor invert_desc = {
26
+ .name = "invert",
27
+
28
+ .n_ports = 2,
29
+ .ports = invert_ports,
30
+
31
+ .instantiate = builtin_instantiate,
32
+ .connect_port = builtin_connect_port,
33
+ .run = invert_run,
34
+ .cleanup = builtin_cleanup,
35
+};
36
+
37
static const struct fc_descriptor * builtin_descriptor(unsigned long Index)
38
{
39
switch(Index) {
40
41
return &convolve_desc;
42
case 11:
43
return &delay_desc;
44
+ case 12:
45
+ return &invert_desc;
46
}
47
return NULL;
48
}
49
pipewire-0.3.65.tar.gz/src/modules/module-filter-chain/plugin.h -> pipewire-0.3.66.tar.gz/src/modules/module-filter-chain/plugin.h
Changed
17
1
2
void (*cleanup) (void *instance);
3
4
void (*connect_port) (void *instance, unsigned long port, float *data);
5
+ void (*control_changed) (void *instance);
6
7
void (*activate) (void *instance);
8
void (*deactivate) (void *instance);
9
10
struct dsp_ops *dsp, const char *path, const char *config);
11
struct fc_plugin *load_builtin_plugin(const struct spa_support *support, uint32_t n_support,
12
struct dsp_ops *dsp, const char *path, const char *config);
13
+struct fc_plugin *load_sofa_plugin(const struct spa_support *support, uint32_t n_support,
14
+ struct dsp_ops *dsp, const char *path, const char *config);
15
16
#endif /* PLUGIN_H */
17
pipewire-0.3.66.tar.gz/src/modules/module-filter-chain/sofa_plugin.c
Added
377
1
2
+#include "config.h"
3
+
4
+#include <spa/utils/json.h>
5
+#include <spa/support/loop.h>
6
+
7
+#include <pipewire/log.h>
8
+#include "plugin.h"
9
+#include "convolver.h"
10
+#include "dsp-ops.h"
11
+#include "pffft.h"
12
+
13
+#ifdef HAVE_LIBMYSOFA
14
+#include <mysofa.h>
15
+
16
+#define MAX_SAMPLES 8192u
17
+#endif
18
+
19
+static struct dsp_ops *dsp_ops;
20
+static struct spa_loop *data_loop;
21
+static struct spa_loop *main_loop;
22
+
23
+struct spatializer_impl {
24
+ unsigned long rate;
25
+ float *port6;
26
+ int n_samples, blocksize, tailsize;
27
+ float *tmp2;
28
+
29
+#ifdef HAVE_LIBMYSOFA
30
+ struct MYSOFA_EASY *sofa;
31
+#endif
32
+ unsigned int interpolate:1;
33
+ struct convolver *l_conv3;
34
+ struct convolver *r_conv3;
35
+};
36
+
37
+static void * spatializer_instantiate(const struct fc_descriptor * Descriptor,
38
+ unsigned long SampleRate, int index, const char *config)
39
+{
40
+#ifdef HAVE_LIBMYSOFA
41
+ struct spatializer_impl *impl;
42
+ struct spa_json it2;
43
+ const char *val;
44
+ char key256;
45
+ char filenamePATH_MAX = "";
46
+
47
+ errno = EINVAL;
48
+ if (config == NULL)
49
+ return NULL;
50
+
51
+ spa_json_init(&it0, config, strlen(config));
52
+ if (spa_json_enter_object(&it0, &it1) <= 0)
53
+ return NULL;
54
+
55
+ impl = calloc(1, sizeof(*impl));
56
+ if (impl == NULL) {
57
+ errno = ENOMEM;
58
+ return NULL;
59
+ }
60
+
61
+ while (spa_json_get_string(&it1, key, sizeof(key)) > 0) {
62
+ if (spa_streq(key, "blocksize")) {
63
+ if (spa_json_get_int(&it1, &impl->blocksize) <= 0) {
64
+ pw_log_error("spatializer:blocksize requires a number");
65
+ errno = EINVAL;
66
+ goto error;
67
+ }
68
+ }
69
+ else if (spa_streq(key, "tailsize")) {
70
+ if (spa_json_get_int(&it1, &impl->tailsize) <= 0) {
71
+ pw_log_error("spatializer:tailsize requires a number");
72
+ errno = EINVAL;
73
+ goto error;
74
+ }
75
+ }
76
+ else if (spa_streq(key, "filename")) {
77
+ if (spa_json_get_string(&it1, filename, sizeof(filename)) <= 0) {
78
+ pw_log_error("spatializer:filename requires a string");
79
+ errno = EINVAL;
80
+ goto error;
81
+ }
82
+ }
83
+ else if (spa_json_next(&it1, &val) < 0)
84
+ break;
85
+ }
86
+ if (!filename0) {
87
+ pw_log_error("spatializer:filename was not given");
88
+ errno = EINVAL;
89
+ goto error;
90
+ }
91
+
92
+ int ret = MYSOFA_OK;
93
+
94
+ impl->sofa = mysofa_open_cached(filename, SampleRate, &impl->n_samples, &ret);
95
+
96
+ if (ret != MYSOFA_OK) {
97
+ pw_log_error("Unable to load HRTF from %s: %d", filename, ret);
98
+ errno = ENOENT;
99
+ goto error;
100
+ }
101
+
102
+ if (impl->blocksize <= 0)
103
+ impl->blocksize = SPA_CLAMP(impl->n_samples, 64, 256);
104
+ if (impl->tailsize <= 0)
105
+ impl->tailsize = SPA_CLAMP(4096, impl->blocksize, 32768);
106
+
107
+ pw_log_info("using n_samples:%u %d:%d blocksize sofa:%s", impl->n_samples,
108
+ impl->blocksize, impl->tailsize, filename);
109
+
110
+ impl->tmp0 = calloc(MAX_SAMPLES, sizeof(float));
111
+ impl->tmp1 = calloc(MAX_SAMPLES, sizeof(float));
112
+ impl->rate = SampleRate;
113
+ return impl;
114
+error:
115
+ if (impl->sofa)
116
+ mysofa_close_cached(impl->sofa);
117
+ free(impl);
118
+ return NULL;
119
+#else
120
+ pw_log_error("libmysofa is required for spatializer, but disabled at compile time");
121
+ errno = EINVAL;
122
+ return NULL;
123
+#endif
124
+}
125
+
126
+#ifdef HAVE_LIBMYSOFA
127
+static int
128
+do_switch(struct spa_loop *loop, bool async, uint32_t seq, const void *data,
129
+ size_t size, void *user_data)
130
+{
131
+ struct spatializer_impl *impl = user_data;
132
+
133
+ if (impl->l_conv0 == NULL) {
134
+ SPA_SWAP(impl->l_conv0, impl->l_conv2);
135
+ SPA_SWAP(impl->r_conv0, impl->r_conv2);
136
+ } else {
137
+ SPA_SWAP(impl->l_conv1, impl->l_conv2);
138
+ SPA_SWAP(impl->r_conv1, impl->r_conv2);
139
+ }
140
+ impl->interpolate = impl->l_conv0 && impl->l_conv1;
141
+
142
+ return 0;
143
+}
144
+
145
+static void spatializer_reload(void * Instance)
146
+{
147
+ struct spatializer_impl *impl = Instance;
148
+ float *left_ir = calloc(impl->n_samples, sizeof(float));
149
+ float *right_ir = calloc(impl->n_samples, sizeof(float));
150
+ float left_delay;
151
+ float right_delay;
152
+ float coords3;
153
+
154
+ for (uint8_t i = 0; i < 3; i++)
155
+ coordsi = impl->port3 + i0;
156
+
157
+ mysofa_s2c(coords);
158
+ mysofa_getfilter_float(
159
+ impl->sofa,
160
+ coords0,
161
+ coords1,
162
+ coords2,
163
+ left_ir,
164
+ right_ir,
165
+ &left_delay,
166
+ &right_delay
167
+ );
168
+
169
+ // TODO: make use of delay
170
+ if ((left_delay || right_delay) && (!isnan(left_delay) || !isnan(right_delay))) {
171
+ pw_log_warn("delay dropped l: %f, r: %f", left_delay, right_delay);
172
+ }
173
+
174
+ if (impl->l_conv2)
175
+ convolver_free(impl->l_conv2);
176
+ if (impl->r_conv2)
177
+ convolver_free(impl->r_conv2);
178
+
179
+ impl->l_conv2 = convolver_new(dsp_ops, impl->blocksize, impl->tailsize,
180
+ left_ir, impl->n_samples);
181
+ impl->r_conv2 = convolver_new(dsp_ops, impl->blocksize, impl->tailsize,
182
+ right_ir, impl->n_samples);
183
+
184
+ free(left_ir);
185
+ free(right_ir);
186
+
187
+ if (impl->l_conv2 == NULL || impl->r_conv2 == NULL) {
188
+ pw_log_error("reloading left or right convolver failed");
189
+ return;
190
+ }
191
+ spa_loop_invoke(data_loop, do_switch, 1, NULL, 0, true, impl);
192
+}
193
+
194
+struct free_data {
195
+ void *item2;
196
+};
197
+
198
+static int
199
+do_free(struct spa_loop *loop, bool async, uint32_t seq, const void *data,
200
+ size_t size, void *user_data)
201
+{
202
+ const struct free_data *fd = data;
203
+ if (fd->item0)
204
+ convolver_free(fd->item0);
205
+ if (fd->item1)
206
+ convolver_free(fd->item1);
207
+ return 0;
208
+}
209
+#endif
210
+
211
+static void spatializer_run(void * Instance, unsigned long SampleCount)
212
+{
213
+#ifdef HAVE_LIBMYSOFA
214
+ struct spatializer_impl *impl = Instance;
215
+
216
+ if (impl->interpolate) {
217
+ uint32_t len = SPA_MIN(SampleCount, MAX_SAMPLES);
218
+ struct free_data free_data;
219
+ float *l = impl->tmp0, *r = impl->tmp1;
220
+
221
+ convolver_run(impl->l_conv0, impl->port2, impl->port0, len);
222
+ convolver_run(impl->l_conv1, impl->port2, l, len);
223
+ convolver_run(impl->r_conv0, impl->port2, impl->port1, len);
224
+ convolver_run(impl->r_conv1, impl->port2, r, len);
225
+
226
+ for (uint32_t i = 0; i < SampleCount; i++) {
227
+ float t = (float)i / SampleCount;
228
+ impl->port0i = impl->port0i * (1.0f - t) + li * t;
229
+ impl->port1i = impl->port1i * (1.0f - t) + ri * t;
230
+ }
231
+ free_data.item0 = impl->l_conv0;
232
+ free_data.item1 = impl->r_conv0;
233
+ impl->l_conv0 = impl->l_conv1;
234
+ impl->r_conv0 = impl->r_conv1;
235
+ impl->l_conv1 = impl->r_conv1 = NULL;
236
+ impl->interpolate = false;
237
+
238
+ spa_loop_invoke(main_loop, do_free, 1, &free_data, sizeof(free_data), false, impl);
239
+ } else if (impl->l_conv0 && impl->r_conv0) {
240
+ convolver_run(impl->l_conv0, impl->port2, impl->port0, SampleCount);
241
+ convolver_run(impl->r_conv0, impl->port2, impl->port1, SampleCount);
242
+ }
243
+#endif
244
+}
245
+
246
+static void spatializer_connect_port(void * Instance, unsigned long Port,
247
+ float * DataLocation)
248
+{
249
+ struct spatializer_impl *impl = Instance;
250
+ if (Port > 5)
251
+ return;
252
+ impl->portPort = DataLocation;
253
+}
254
+
255
+static void spatializer_cleanup(void * Instance)
256
+{
257
+ struct spatializer_impl *impl = Instance;
258
+
259
+ for (uint8_t i = 0; i < 3; i++) {
260
+ if (impl->l_convi)
261
+ convolver_free(impl->l_convi);
262
+ if (impl->r_convi)
263
+ convolver_free(impl->r_convi);
264
+ }
265
+#ifdef HAVE_LIBMYSOFA
266
+ if (impl->sofa)
267
+ mysofa_close_cached(impl->sofa);
268
+#endif
269
+ free(impl->tmp0);
270
+ free(impl->tmp1);
271
+
272
+ free(impl);
273
+}
274
+
275
+static void spatializer_control_changed(void * Instance)
276
+{
277
+#ifdef HAVE_LIBMYSOFA
278
+ pw_log_info("control changed");
279
+ spatializer_reload(Instance);
280
+#endif
281
+}
282
+
283
+static void spatializer_deactivate(void * Instance)
284
+{
285
+ struct spatializer_impl *impl = Instance;
286
+ if (impl->l_conv0)
287
+ convolver_reset(impl->l_conv0);
288
+ if (impl->r_conv0)
289
+ convolver_reset(impl->r_conv0);
290
+ impl->interpolate = false;
291
+}
292
+
293
+static struct fc_port spatializer_ports = {
294
+ { .index = 0,
295
+ .name = "Out L",
296
+ .flags = FC_PORT_OUTPUT | FC_PORT_AUDIO,
297
+ },
298
+ { .index = 1,
299
+ .name = "Out R",
300
+ .flags = FC_PORT_OUTPUT | FC_PORT_AUDIO,
301
+ },
302
+ { .index = 2,
303
+ .name = "In",
304
+ .flags = FC_PORT_INPUT | FC_PORT_AUDIO,
305
+ },
306
+
307
+ { .index = 3,
308
+ .name = "Azimuth",
309
+ .flags = FC_PORT_INPUT | FC_PORT_CONTROL,
310
+ .def = 0.0f, .min = 0.0f, .max = 360.0f
311
+ },
312
+ { .index = 4,
313
+ .name = "Elevation",
314
+ .flags = FC_PORT_INPUT | FC_PORT_CONTROL,
315
+ .def = 0.0f, .min = -90.0f, .max = 90.0f
316
+ },
317
+ { .index = 5,
318
+ .name = "Radius",
319
+ .flags = FC_PORT_INPUT | FC_PORT_CONTROL,
320
+ .def = 1.0f, .min = 0.0f, .max = 100.0f
321
+ },
322
+};
323
+
324
+static const struct fc_descriptor spatializer_desc = {
325
+ .name = "spatializer",
326
+
327
+ .n_ports = 6,
328
+ .ports = spatializer_ports,
329
+
330
+ .instantiate = spatializer_instantiate,
331
+ .connect_port = spatializer_connect_port,
332
+ .control_changed = spatializer_control_changed,
333
+ .deactivate = spatializer_deactivate,
334
+ .run = spatializer_run,
335
+ .cleanup = spatializer_cleanup,
336
+};
337
+
338
+static const struct fc_descriptor * sofa_descriptor(unsigned long Index)
339
+{
340
+ switch(Index) {
341
+ case 0:
342
+ return &spatializer_desc;
343
+ }
344
+ return NULL;
345
+}
346
+
347
+
348
+static const struct fc_descriptor *sofa_make_desc(struct fc_plugin *plugin, const char *name)
349
+{
350
+ unsigned long i;
351
+ for (i = 0; ;i++) {
352
+ const struct fc_descriptor *d = sofa_descriptor(i);
353
+ if (d == NULL)
354
+ break;
355
+ if (spa_streq(d->name, name))
356
+ return d;
357
+ }
358
+ return NULL;
359
+}
360
+
361
+static struct fc_plugin builtin_plugin = {
362
+ .make_desc = sofa_make_desc
363
+};
364
+
365
+struct fc_plugin *load_sofa_plugin(const struct spa_support *support, uint32_t n_support,
366
+ struct dsp_ops *dsp, const char *plugin, const char *config)
367
+{
368
+ dsp_ops = dsp;
369
+ pffft_select_cpu(dsp->cpu_flags);
370
+
371
+ data_loop = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_DataLoop);
372
+ main_loop = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_Loop);
373
+
374
+ return &builtin_plugin;
375
+}
376
+
377
pipewire-0.3.65.tar.gz/src/modules/module-loopback.c -> pipewire-0.3.66.tar.gz/src/modules/module-loopback.c
Changed
34
1
2
*
3
*\endcode
4
*
5
+ * ## Example configuration of a virtual source
6
+ *
7
+ * This Virtual source routes the front-left channel of a multi-channel input to a mono channel.
8
+ * This is useful for splitting up multi-channel inputs from USB audio interfaces that are not yet fully supported by alsa.
9
+ *
10
+ *\code{.unparsed}
11
+ * context.modules =
12
+ * { name = libpipewire-module-loopback
13
+ * args = {
14
+ * node.description = "Scarlett Focusrite Line 1"
15
+ * capture.props = {
16
+ * audio.position = FL
17
+ * stream.dont-remix = true
18
+ * node.target = "alsa_input.usb-Focusrite_Scarlett_Solo_USB_Y7ZD17C24495BC-00.analog-stereo"
19
+ * node.passive = true
20
+ * }
21
+ * playback.props = {
22
+ * node.name = "SF_mono_in_1"
23
+ * media.class = "Audio/Source"
24
+ * audio.position = MONO
25
+ * }
26
+ * }
27
+ * }
28
+ *
29
+ *\endcode
30
+ *
31
* ## See also
32
*
33
* `pw-loopback` : a tool that loads the loopback module with given parameters.
34
pipewire-0.3.65.tar.gz/src/modules/module-protocol-pulse/cmd.c -> pipewire-0.3.66.tar.gz/src/modules/module-protocol-pulse/cmd.c
Changed
13
1
2
3
/*
4
* pulse.cmd =
5
- * { cmd = <command> args = "<arguments>" }
6
+ * { cmd = <command>
7
+ * ( args = "<arguments>" )
8
+ * ( flags = ( nofail ) )
9
+ * }
10
* ...
11
*
12
*/
13
pipewire-0.3.66.tar.gz/src/modules/module-rt
Added
2
1
+(directory)
2
pipewire-0.3.66.tar.gz/src/modules/module-rt/20-pw-defaults.conf.in
Added
22
1
2
+# This file was installed by PipeWire project for buffer locking to always work
3
+
4
+# Required to memlock audio buffers for all client types
5
+#
6
+# This will match all PAM users i.e. those going through the login procedure but
7
+# it should not get applied to system daemons, since they are run bypassing PAM.
8
+#
9
+# While at first glance this might appear very relevant, in fact abusing this
10
+# can at most allow for either more rapid OOM or enhance malicious system memory
11
+# thrashing while evading systemd-oomd limits that are based on the requirement
12
+# that swap utilization must be high before issues arise. As such it's perfectly
13
+# reasonable to just set a limit where each client can lock a few megabytes with
14
+# nearly no impact on regular systems. Meanwhile malicious attackers can OOM
15
+# just as they could. And instead tooling for OOM and resource abuse should be
16
+# improved, if such denial of service attacks are a serious consideration at all.
17
+#
18
+# Starting with Linux 5.16 or systemd v253 the default is 8192 which is plenty
19
+# good enough and this file should not be installed on such systems.
20
+#
21
+* - memlock @PAM_MEMLOCK@
22
pipewire-0.3.66.tar.gz/src/modules/module-rt/25-pw-rlimits.conf.in
Added
10
1
2
+# This file was installed by PipeWire project for its libpipewire-module-rt.so
3
+
4
+# It's believed to be acceptable to have match rules that will never be true
5
+# i.e. a group that does not exist.
6
+#
7
+@MATCH@ - rtprio @RTPRIO@
8
+@MATCH@ - nice @NICE@
9
+@MATCH@ - memlock @MEMLOCK@
10
pipewire-0.3.66.tar.gz/src/modules/module-rt/meson.build
Added
25
1
2
+rlimits_install = get_option('rlimits-install')
3
+rlimits_data = configuration_data()
4
+rlimits_data.set('MATCH', get_option('rlimits-match'))
5
+rlimits_data.set('RTPRIO', get_option('rlimits-rtprio'))
6
+rlimits_data.set('NICE', get_option('rlimits-nice'))
7
+rlimits_data.set('MEMLOCK', get_option('rlimits-memlock'))
8
+configure_file(input: '25-pw-rlimits.conf.in',
9
+ output: '25-pw-rlimits.conf',
10
+ install: rlimits_install,
11
+ install_dir: get_option('sysconfdir') / 'security' / 'limits.d',
12
+ configuration: rlimits_data)
13
+summary({'RLIMITs': '@0@ limits.d file affecting matching PAM users'.format(rlimits_install ? 'with' : 'without')})
14
+
15
+# The pam-defaults-install related code can be removed once all Linux <5.16 kernels are EOL (projected Dec, 2026)
16
+pam_defaults_install = get_option('pam-defaults-install')
17
+pam_defaults_data = configuration_data()
18
+pam_defaults_data.set('PAM_MEMLOCK', get_option('pam-memlock-default'))
19
+configure_file(input: '20-pw-defaults.conf.in',
20
+ output: '20-pw-defaults.conf',
21
+ install: pam_defaults_install,
22
+ install_dir: get_option('sysconfdir') / 'security' / 'limits.d',
23
+ configuration: pam_defaults_data)
24
+summary({'PAM defaults': '@0@ limits.d file affecting all PAM users (not needed with modern systemd or kernel)'.format(pam_defaults_install ? 'with' : 'without')})
25
pipewire-0.3.65.tar.gz/src/modules/module-rtp-sink.c -> pipewire-0.3.66.tar.gz/src/modules/module-rtp-sink.c
Changed
351
1
2
* - `sess.min-ptime = <int>`: minimum packet time in milliseconds, default 2
3
* - `sess.max-ptime = <int>`: maximum packet time in milliseconds, default 20
4
* - `sess.name = <str>`: a session name
5
+ * - `sess.ts-offset = <int>`: an offset to apply to the timestamp, default -1 = random offset
6
+ * - `sess.ts-refclk = <string>`: the name of a reference clock
7
* - `stream.props = {}`: properties to be passed to the stream
8
*
9
* ## General options
10
11
12
#define DEFAULT_MIN_PTIME 2
13
#define DEFAULT_MAX_PTIME 20
14
+#define DEFAULT_TS_OFFSET -1
15
16
#define USAGE "sap.ip=<SAP IP address to send announce, default:"DEFAULT_SAP_IP"> " \
17
"sap.port=<SAP port to send on, default:"SPA_STRINGIFY(DEFAULT_SAP_PORT)"> " \
18
19
struct pw_stream *stream;
20
struct spa_hook stream_listener;
21
22
+ struct spa_io_position *io_position;
23
+
24
unsigned int do_disconnect:1;
25
26
char *ifname;
27
28
int mtu;
29
bool ttl;
30
bool mcast_loop;
31
- uint32_t min_ptime;
32
- uint32_t max_ptime;
33
- uint32_t pbytes;
34
+ float min_ptime;
35
+ float max_ptime;
36
+ uint32_t psamples;
37
38
struct sockaddr_storage src_addr;
39
socklen_t src_len;
40
41
42
struct spa_audio_info_raw info;
43
const struct format_info *format_info;
44
- uint32_t frame_size;
45
+ uint32_t stride;
46
int payload;
47
uint16_t seq;
48
- uint32_t timestamp;
49
uint32_t ssrc;
50
+ uint32_t ts_offset;
51
+ char ts_refclk64;
52
53
struct spa_ringbuffer ring;
54
uint8_t bufferBUFFER_SIZE;
55
56
int rtp_fd;
57
int sap_fd;
58
+
59
+ unsigned sync:1;
60
};
61
62
63
64
static void flush_packets(struct impl *impl)
65
{
66
int32_t avail;
67
- uint32_t index;
68
+ uint32_t stride, timestamp;
69
struct iovec iov3;
70
struct msghdr msg;
71
ssize_t n;
72
struct rtp_header header;
73
int32_t tosend;
74
75
- avail = spa_ringbuffer_get_read_index(&impl->ring, &index);
76
-
77
- tosend = impl->pbytes;
78
+ avail = spa_ringbuffer_get_read_index(&impl->ring, ×tamp);
79
+ tosend = impl->psamples;
80
81
if (avail < tosend)
82
return;
83
84
+ stride = impl->stride;
85
+
86
spa_zero(header);
87
header.v = 2;
88
header.pt = impl->payload;
89
90
91
while (avail >= tosend) {
92
header.sequence_number = htons(impl->seq);
93
- header.timestamp = htonl(impl->timestamp);
94
+ header.timestamp = htonl(impl->ts_offset + timestamp);
95
96
set_iovec(&impl->ring,
97
impl->buffer, BUFFER_SIZE,
98
- index & BUFFER_MASK,
99
- &iov1, tosend);
100
+ (timestamp * stride) & BUFFER_MASK,
101
+ &iov1, tosend * stride);
102
103
+ pw_log_trace("sending %d timestamp:%d", tosend, timestamp);
104
n = sendmsg(impl->rtp_fd, &msg, MSG_NOSIGNAL);
105
if (n < 0) {
106
switch (errno) {
107
108
pw_log_debug("remote end not listening");
109
break;
110
default:
111
- pw_log_warn("sendmsg() failed: %m");
112
+ pw_log_warn("sendmsg() failed, seq:%u dropped: %m",
113
+ impl->seq);
114
break;
115
}
116
}
117
118
impl->seq++;
119
- impl->timestamp += tosend / impl->frame_size;
120
121
- index += tosend;
122
+ timestamp += tosend;
123
avail -= tosend;
124
}
125
- spa_ringbuffer_read_update(&impl->ring, index);
126
+ spa_ringbuffer_read_update(&impl->ring, timestamp);
127
}
128
129
static void stream_process(void *data)
130
131
struct impl *impl = data;
132
struct pw_buffer *buf;
133
struct spa_data *d;
134
- uint32_t index;
135
- int32_t filled, wanted;
136
+ uint32_t offs, size, timestamp, expected_timestamp, stride;
137
+ int32_t filled, wanted;
138
139
if ((buf = pw_stream_dequeue_buffer(impl->stream)) == NULL) {
140
pw_log_debug("Out of stream buffers: %m");
141
142
}
143
d = buf->buffer->datas;
144
145
- wanted = d0.chunk->size;
146
+ offs = SPA_MIN(d0.chunk->offset, d0.maxsize);
147
+ size = SPA_MIN(d0.chunk->size, d0.maxsize - offs);
148
+ stride = impl->stride;
149
+ wanted = size / stride;
150
+
151
+ filled = spa_ringbuffer_get_write_index(&impl->ring, &expected_timestamp);
152
+ if (SPA_LIKELY(impl->io_position))
153
+ timestamp = impl->io_position->clock.position;
154
+ else
155
+ timestamp = expected_timestamp;
156
+
157
+ if (impl->sync) {
158
+ if (expected_timestamp != timestamp) {
159
+ pw_log_warn("expected %u != timestamp %u", expected_timestamp, timestamp);
160
+ impl->sync = false;
161
+ } else if (filled + wanted > (int32_t)(BUFFER_SIZE / stride)) {
162
+ pw_log_warn("overrun %u + %u > %u", filled, wanted, BUFFER_SIZE / stride);
163
+ impl->sync = false;
164
+ }
165
+ }
166
+ if (!impl->sync) {
167
+ pw_log_info("sync to timestamp %u", timestamp);
168
+ impl->ring.readindex = impl->ring.writeindex = timestamp;
169
+ memset(impl->buffer, 0, BUFFER_SIZE);
170
+ impl->sync = true;
171
+ }
172
173
- filled = spa_ringbuffer_get_write_index(&impl->ring, &index);
174
+ spa_ringbuffer_write_data(&impl->ring,
175
+ impl->buffer,
176
+ BUFFER_SIZE,
177
+ (timestamp * stride) & BUFFER_MASK,
178
+ SPA_PTROFF(d0.data, offs, void), wanted * stride);
179
+ timestamp += wanted;
180
+ spa_ringbuffer_write_update(&impl->ring, timestamp);
181
182
- if (filled + wanted > (int32_t)BUFFER_SIZE) {
183
- pw_log_warn("overrun %u + %u > %u", filled, wanted, BUFFER_SIZE);
184
- } else {
185
- spa_ringbuffer_write_data(&impl->ring,
186
- impl->buffer,
187
- BUFFER_SIZE,
188
- index & BUFFER_MASK,
189
- d0.data, wanted);
190
-
191
- index += wanted;
192
- spa_ringbuffer_write_update(&impl->ring, index);
193
- }
194
pw_stream_queue_buffer(impl->stream, buf);
195
196
flush_packets(impl);
197
}
198
199
+static void stream_io_changed(void *data, uint32_t id, void *area, uint32_t size)
200
+{
201
+ struct impl *impl = data;
202
+ switch (id) {
203
+ case SPA_IO_Position:
204
+ impl->io_position = area;
205
+ break;
206
+ }
207
+}
208
+
209
static void on_stream_state_changed(void *d, enum pw_stream_state old,
210
enum pw_stream_state state, const char *error)
211
{
212
213
case PW_STREAM_STATE_ERROR:
214
pw_log_error("stream error: %s", error);
215
break;
216
+ case PW_STREAM_STATE_PAUSED:
217
+ impl->sync = false;
218
+ break;
219
default:
220
break;
221
}
222
223
static const struct pw_stream_events in_stream_events = {
224
PW_VERSION_STREAM_EVENTS,
225
.destroy = stream_destroy,
226
+ .io_changed = stream_io_changed,
227
.state_changed = on_stream_state_changed,
228
.process = stream_process
229
};
230
231
if (setsockopt(fd, SOL_SOCKET, SO_PRIORITY, &val, sizeof(val)) < 0)
232
pw_log_warn("setsockopt(SO_PRIORITY) failed: %m");
233
#endif
234
+ /* FIXME AES67 wants IPTOS_DSCP_AF41 */
235
val = IPTOS_LOWDELAY;
236
if (setsockopt(fd, IPPROTO_IP, IP_TOS, &val, sizeof(val)) < 0)
237
pw_log_warn("setsockopt(IP_TOS) failed: %m");
238
239
240
if (pw_properties_get(props, PW_KEY_NODE_LATENCY) == NULL) {
241
pw_properties_setf(props, PW_KEY_NODE_LATENCY,
242
- "%d/%d", impl->pbytes / impl->frame_size,
243
- impl->info.rate);
244
+ "%d/%d", impl->psamples, impl->info.rate);
245
}
246
pw_properties_setf(props, PW_KEY_NODE_RATE, "1/%d", impl->info.rate);
247
248
249
struct sap_header header;
250
struct iovec iov4;
251
struct msghdr msg;
252
+ struct spa_strbuf buf;
253
254
spa_zero(header);
255
header.v = 1;
256
257
if (is_multicast((struct sockaddr*)&impl->dst_addr, impl->dst_len))
258
snprintf(dst_ttl, sizeof(dst_ttl), "/%d", impl->ttl);
259
260
- snprintf(buffer, sizeof(buffer),
261
+ spa_strbuf_init(&buf, buffer, sizeof(buffer));
262
+ spa_strbuf_append(&buf,
263
"v=0\n"
264
"o=%s %u 0 IN %s %s\n"
265
"s=%s\n"
266
267
impl->port, impl->payload,
268
impl->payload, impl->format_info->mime,
269
impl->info.rate, impl->info.channels,
270
- (impl->pbytes / impl->frame_size) * 1000 / impl->info.rate);
271
+ impl->psamples * 1000 / impl->info.rate);
272
+
273
+ if (impl->ts_refclk0 != '\0') {
274
+ spa_strbuf_append(&buf,
275
+ "a=ts-refclk:%s\n"
276
+ "a=mediaclk:direct=%u\n",
277
+ impl->ts_refclk,
278
+ impl->ts_offset);
279
+ } else {
280
+ spa_strbuf_append(&buf, "a=mediaclk:sender\n");
281
+ }
282
283
iov3.iov_base = buffer;
284
iov3.iov_len = strlen(buffer);
285
286
struct impl *impl;
287
struct pw_properties *props = NULL, *stream_props = NULL;
288
uint32_t id = pw_global_get_id(pw_impl_module_get_global(module));
289
- uint32_t pid = getpid(), port, min_bytes, max_bytes;
290
+ uint32_t pid = getpid(), port, min_samples, max_samples;
291
+ int64_t ts_offset;
292
char addr64;
293
const char *str;
294
int res = 0;
295
296
res = -EINVAL;
297
goto out;
298
}
299
- impl->frame_size = impl->format_info->size * impl->info.channels;
300
+ impl->stride = impl->format_info->size * impl->info.channels;
301
impl->msg_id_hash = rand();
302
impl->ntp = (uint32_t) time(NULL) + 2208988800U;
303
304
impl->payload = 127;
305
impl->seq = rand();
306
- impl->timestamp = rand();
307
impl->ssrc = rand();
308
309
str = pw_properties_get(props, "local.ifname");
310
311
impl->ttl = pw_properties_get_uint32(props, "net.ttl", DEFAULT_TTL);
312
impl->mcast_loop = pw_properties_get_bool(props, "net.loop", DEFAULT_LOOP);
313
314
- impl->min_ptime = pw_properties_get_uint32(props, "sess.min-ptime", DEFAULT_MIN_PTIME);
315
- impl->max_ptime = pw_properties_get_uint32(props, "sess.max-ptime", DEFAULT_MAX_PTIME);
316
+ ts_offset = pw_properties_get_int64(props, "sess.ts-offset", DEFAULT_TS_OFFSET);
317
+ impl->ts_offset = ts_offset < 0 ? rand() : ts_offset;
318
+
319
+ str = pw_properties_get(props, "sess.ts-refclk");
320
+ if (str != NULL)
321
+ snprintf(impl->ts_refclk, sizeof(impl->ts_refclk), "%s", str);
322
+
323
+ str = pw_properties_get(props, "sess.min-ptime");
324
+ if (!spa_atof(str, &impl->min_ptime))
325
+ impl->min_ptime = DEFAULT_MIN_PTIME;
326
+ str = pw_properties_get(props, "sess.max-ptime");
327
+ if (!spa_atof(str, &impl->max_ptime))
328
+ impl->max_ptime = DEFAULT_MAX_PTIME;
329
330
- min_bytes = (impl->min_ptime * impl->info.rate / 1000) * impl->frame_size;
331
- max_bytes = (impl->max_ptime * impl->info.rate / 1000) * impl->frame_size;
332
+ min_samples = impl->min_ptime * impl->info.rate / 1000;
333
+ max_samples = impl->max_ptime * impl->info.rate / 1000;
334
335
- impl->pbytes = SPA_ROUND_DOWN(impl->mtu, impl->frame_size);
336
- impl->pbytes = SPA_CLAMP(impl->pbytes, min_bytes, max_bytes);
337
+ impl->psamples = impl->mtu / impl->stride;
338
+ impl->psamples = SPA_CLAMP(impl->psamples, min_samples, max_samples);
339
340
if ((str = pw_properties_get(props, "sess.name")) == NULL)
341
pw_properties_setf(props, "sess.name", "PipeWire RTP Stream on %s",
342
343
pw_properties_setf(stream_props, "rtp.mtu", "%u", impl->mtu);
344
pw_properties_setf(stream_props, "rtp.ttl", "%u", impl->ttl);
345
pw_properties_setf(stream_props, "rtp.ptime", "%u",
346
- (impl->pbytes / impl->frame_size) * 1000 / impl->info.rate);
347
+ impl->psamples * 1000 / impl->info.rate);
348
349
impl->core = pw_context_get_object(impl->module_context, PW_TYPE_INTERFACE_Core);
350
if (impl->core == NULL) {
351
pipewire-0.3.65.tar.gz/src/modules/module-rtp-source.c -> pipewire-0.3.66.tar.gz/src/modules/module-rtp-source.c
Changed
643
1
2
#include "config.h"
3
4
#include <limits.h>
5
+#include <string.h>
6
#include <unistd.h>
7
#include <sys/stat.h>
8
#include <sys/socket.h>
9
10
* #sap.port = 9875
11
* #local.ifname = eth0
12
* sess.latency.msec = 100
13
+ * #node.always-process = false # true to receive even when not running
14
* stream.props = {
15
* #media.class = "Audio/Source"
16
* #node.name = "rtp-source"
17
18
* #rtp.payload = "127"
19
* #rtp.fmt = "L16/48000/2"
20
* #rtp.session = "PipeWire RTP Stream on fedora"
21
+ * #rtp.ts-offset = 0
22
+ * #rtp.ts-refclk = "private"
23
* }
24
*
25
* actions = {
26
* create-stream = {
27
* #sess.latency.msec = 100
28
+ * #sess.ts-direct = false
29
* #target.object = ""
30
* }
31
* }
32
33
34
char *ifname;
35
char *sap_ip;
36
+ bool always_process;
37
int sap_port;
38
int sess_latency_msec;
39
uint32_t cleanup_interval;
40
41
42
char origin128;
43
char session256;
44
+ char channelmap512;
45
46
struct sockaddr_storage sa;
47
socklen_t salen;
48
49
const struct format_info *format_info;
50
struct spa_audio_info_raw info;
51
uint32_t stride;
52
+
53
+ uint32_t ts_offset;
54
+ char refclk64;
55
};
56
57
struct session {
58
59
uint8_t bufferBUFFER_SIZE;
60
61
struct spa_io_rate_match *rate_match;
62
+ struct spa_io_position *position;
63
struct spa_dll dll;
64
uint32_t target_buffer;
65
- uint32_t last_packet_size;
66
float max_error;
67
- unsigned buffering:1;
68
unsigned first:1;
69
+ unsigned receiving:1;
70
+ unsigned direct_timestamp:1;
71
};
72
73
static void stream_destroy(void *d)
74
75
struct session *sess = data;
76
struct pw_buffer *buf;
77
struct spa_data *d;
78
- uint32_t index, target_buffer;
79
- int32_t avail, wanted;
80
+ uint32_t wanted, timestamp, target_buffer, stride, maxsize;
81
+ int32_t avail;
82
83
if ((buf = pw_stream_dequeue_buffer(sess->stream)) == NULL) {
84
pw_log_debug("Out of stream buffers: %m");
85
86
}
87
d = buf->buffer->datas;
88
89
- wanted = buf->requested ?
90
- SPA_MIN(buf->requested * sess->info.stride, d0.maxsize)
91
- : d0.maxsize;
92
+ stride = sess->info.stride;
93
94
- avail = spa_ringbuffer_get_read_index(&sess->ring, &index);
95
+ maxsize = d0.maxsize / stride;
96
+ wanted = buf->requested ? SPA_MIN(buf->requested, maxsize) : maxsize;
97
98
- target_buffer = sess->target_buffer + sess->last_packet_size / 2;
99
+ if (sess->position && sess->direct_timestamp) {
100
+ /* in direct mode, read directly from the timestamp index,
101
+ * because sender and receiver are in sync, this would keep
102
+ * target_buffer of bytes available. */
103
+ spa_ringbuffer_read_update(&sess->ring,
104
+ sess->position->clock.position);
105
+ }
106
+ avail = spa_ringbuffer_get_read_index(&sess->ring, ×tamp);
107
108
- if (avail < wanted || sess->buffering) {
109
- memset(d0.data, 0, wanted);
110
- if (!sess->buffering && sess->have_sync) {
111
- pw_log_debug("underrun %u/%u < %u, buffering...",
112
- avail, target_buffer, wanted);
113
- sess->buffering = true;
114
+ target_buffer = sess->target_buffer;
115
+
116
+ if (avail < (int32_t)wanted) {
117
+ enum spa_log_level level;
118
+ memset(d0.data, 0, wanted * stride);
119
+ if (sess->have_sync) {
120
+ sess->have_sync = false;
121
+ level = SPA_LOG_LEVEL_WARN;
122
+ } else {
123
+ level = SPA_LOG_LEVEL_DEBUG;
124
}
125
+ pw_log(level, "underrun %d/%u < %u",
126
+ avail, target_buffer, wanted);
127
} else {
128
float error, corr;
129
- if (avail > (int32_t)SPA_MIN(target_buffer * 8, BUFFER_SIZE)) {
130
+ if (avail > (int32_t)SPA_MIN(target_buffer * 8, BUFFER_SIZE / stride)) {
131
pw_log_warn("overrun %u > %u", avail, target_buffer * 8);
132
- index += avail - target_buffer;
133
+ timestamp += avail - target_buffer;
134
avail = target_buffer;
135
- } else {
136
- if (sess->first) {
137
- if ((uint32_t)avail > target_buffer) {
138
- uint32_t skip = avail - target_buffer;
139
- pw_log_debug("first: avail:%d skip:%u target:%u",
140
+ } else if (sess->first) {
141
+ if ((uint32_t)avail > target_buffer) {
142
+ uint32_t skip = avail - target_buffer;
143
+ pw_log_debug("first: avail:%d skip:%u target:%u",
144
avail, skip, target_buffer);
145
- index += skip;
146
- avail = target_buffer;
147
- }
148
- sess->first = false;
149
+ timestamp += skip;
150
+ avail = target_buffer;
151
}
152
+ sess->first = false;
153
+ }
154
+ if (!sess->direct_timestamp) {
155
+ /* when not using direct timestamp and clocks are not
156
+ * in sync, try to adjust our playback rate to keep the
157
+ * requested target_buffer bytes in the ringbuffer */
158
error = (float)target_buffer - (float)avail;
159
error = SPA_CLAMP(error, -sess->max_error, sess->max_error);
160
161
162
target_buffer, error, corr);
163
164
if (sess->rate_match) {
165
- SPA_FLAG_SET(sess->rate_match->flags, SPA_IO_RATE_MATCH_FLAG_ACTIVE);
166
+ SPA_FLAG_SET(sess->rate_match->flags,
167
+ SPA_IO_RATE_MATCH_FLAG_ACTIVE);
168
sess->rate_match->rate = 1.0f / corr;
169
}
170
}
171
spa_ringbuffer_read_data(&sess->ring,
172
sess->buffer,
173
BUFFER_SIZE,
174
- index & BUFFER_MASK,
175
- d0.data, wanted);
176
+ (timestamp * stride) & BUFFER_MASK,
177
+ d0.data, wanted * stride);
178
179
- index += wanted;
180
- spa_ringbuffer_read_update(&sess->ring, index);
181
+ timestamp += wanted;
182
+ spa_ringbuffer_read_update(&sess->ring, timestamp);
183
}
184
- d0.chunk->size = wanted;
185
- d0.chunk->stride = sess->info.stride;
186
+ d0.chunk->size = wanted * stride;
187
+ d0.chunk->stride = stride;
188
d0.chunk->offset = 0;
189
- buf->size = wanted / sess->info.stride;
190
+ buf->size = wanted;
191
192
pw_stream_queue_buffer(sess->stream, buf);
193
}
194
195
-static void on_stream_state_changed(void *d, enum pw_stream_state old,
196
- enum pw_stream_state state, const char *error)
197
-{
198
- struct session *sess = d;
199
- struct impl *impl = sess->impl;
200
-
201
- switch (state) {
202
- case PW_STREAM_STATE_UNCONNECTED:
203
- pw_log_info("stream disconnected, unloading");
204
- pw_impl_module_schedule_destroy(impl->module);
205
- break;
206
- case PW_STREAM_STATE_ERROR:
207
- pw_log_error("stream error: %s", error);
208
- break;
209
- default:
210
- break;
211
- }
212
-}
213
-
214
static void stream_io_changed(void *data, uint32_t id, void *area, uint32_t size)
215
{
216
struct session *sess = data;
217
218
case SPA_IO_RateMatch:
219
sess->rate_match = area;
220
break;
221
+ case SPA_IO_Position:
222
+ sess->position = area;
223
+ break;
224
}
225
}
226
227
-static const struct pw_stream_events out_stream_events = {
228
- PW_VERSION_STREAM_EVENTS,
229
- .destroy = stream_destroy,
230
- .state_changed = on_stream_state_changed,
231
- .io_changed = stream_io_changed,
232
- .process = stream_process
233
-};
234
+static void session_touch(struct session *sess)
235
+{
236
+ struct timespec ts;
237
+ clock_gettime(CLOCK_MONOTONIC, &ts);
238
+ sess->timestamp = SPA_TIMESPEC_TO_NSEC(&ts);
239
+}
240
241
static void
242
on_rtp_io(void *data, int fd, uint32_t mask)
243
244
uint8_t buffer2048, *payload;
245
246
if (mask & SPA_IO_IN) {
247
- uint32_t index, expected_index, timestamp;
248
+ uint32_t stride, read, timestamp, expected_timestamp, samples;
249
uint16_t seq;
250
int32_t filled;
251
252
253
254
seq = ntohs(hdr->sequence_number);
255
if (sess->have_seq && sess->expected_seq != seq) {
256
- pw_log_warn("unexpected seq (%d != %d)", seq, sess->expected_seq);
257
+ pw_log_info("unexpected seq (%d != %d)", seq, sess->expected_seq);
258
+ sess->have_sync = false;
259
}
260
sess->expected_seq = seq + 1;
261
sess->have_seq = true;
262
263
- len = SPA_ROUND_DOWN(len - hlen, sess->info.stride);
264
+ stride = sess->info.stride;
265
+ samples = (len - hlen) / stride;
266
payload = &bufferhlen;
267
268
- filled = spa_ringbuffer_get_write_index(&sess->ring, &index);
269
+ filled = spa_ringbuffer_get_write_index(&sess->ring, &expected_timestamp);
270
271
- timestamp = ntohl(hdr->timestamp);
272
- expected_index = timestamp * sess->info.stride;
273
+ read = ntohl(hdr->timestamp) - sess->info.ts_offset;
274
+ /* we always write to timestamp + delay */
275
+ timestamp = read + sess->target_buffer;
276
277
if (!sess->have_sync) {
278
- pw_log_trace("got rtp, no sync");
279
- sess->ring.readindex = sess->ring.writeindex =
280
- index = expected_index;
281
- filled = 0;
282
- sess->have_sync = true;
283
- sess->buffering = true;
284
- pw_log_debug("sync to timestamp %u", index);
285
+ pw_log_info("sync to timestamp %u", read);
286
+ /* we read from timestamp, keeping target_buffer of data
287
+ * in the ringbuffer. */
288
+ sess->ring.readindex = read;
289
+ sess->ring.writeindex = timestamp;
290
+ filled = sess->target_buffer;
291
292
spa_dll_init(&sess->dll);
293
spa_dll_set_bw(&sess->dll, SPA_DLL_BW_MIN, 128, sess->info.info.rate);
294
-
295
- } else if (expected_index != index) {
296
- pw_log_trace("got rtp, wrong timestamp");
297
+ memset(sess->buffer, 0, BUFFER_SIZE);
298
+ sess->have_sync = true;
299
+ } else if (expected_timestamp != timestamp) {
300
pw_log_debug("unexpected timestamp (%u != %u)",
301
- index / sess->info.stride,
302
- expected_index / sess->info.stride);
303
- index = expected_index;
304
- filled = 0;
305
+ timestamp, expected_timestamp);
306
}
307
308
- if (filled + len > BUFFER_SIZE) {
309
- pw_log_debug("got rtp, capture overrun %u %zd", filled, len);
310
+ if (filled + samples > BUFFER_SIZE / stride) {
311
+ pw_log_debug("capture overrun %u + %u > %u", filled, samples,
312
+ BUFFER_SIZE / stride);
313
sess->have_sync = false;
314
} else {
315
- uint32_t target_buffer;
316
-
317
- pw_log_trace("got rtp packet len:%zd", len);
318
+ pw_log_trace("got samples:%u", samples);
319
spa_ringbuffer_write_data(&sess->ring,
320
sess->buffer,
321
BUFFER_SIZE,
322
- index & BUFFER_MASK,
323
- payload, len);
324
- index += len;
325
- filled += len;
326
- spa_ringbuffer_write_update(&sess->ring, index);
327
-
328
- sess->last_packet_size = len;
329
- target_buffer = sess->target_buffer + len/2;
330
-
331
- if (sess->buffering && (uint32_t)filled > target_buffer) {
332
- sess->buffering = false;
333
- pw_log_debug("buffering done %u > %u",
334
- filled, target_buffer);
335
- }
336
+ (timestamp * stride) & BUFFER_MASK,
337
+ payload, (samples * stride));
338
+ timestamp += samples;
339
+ spa_ringbuffer_write_update(&sess->ring, timestamp);
340
}
341
+ sess->receiving = true;
342
}
343
return;
344
345
346
return res;
347
}
348
349
-static uint32_t msec_to_bytes(struct sdp_info *info, uint32_t msec)
350
-{
351
- return msec * info->stride * info->info.rate / 1000;
352
-}
353
-
354
-static void session_touch(struct session *sess)
355
+static uint32_t msec_to_samples(struct sdp_info *info, uint32_t msec)
356
{
357
- struct timespec ts;
358
- clock_gettime(CLOCK_MONOTONIC, &ts);
359
- sess->timestamp = SPA_TIMESPEC_TO_NSEC(&ts);
360
+ return msec * info->info.rate / 1000;
361
}
362
363
static void session_free(struct session *sess)
364
365
return res;
366
}
367
368
+static int session_start(struct impl *impl, struct session *session) {
369
+ int fd;
370
+ if (session->source)
371
+ return 0;
372
+
373
+ pw_log_info("starting RTP listener");
374
+
375
+ if ((fd = make_socket((const struct sockaddr *)&session->info.sa,
376
+ session->info.salen, impl->ifname)) < 0) {
377
+ pw_log_error("failed to create socket: %m");
378
+ return fd;
379
+ }
380
+
381
+ session->source = pw_loop_add_io(impl->data_loop, fd,
382
+ SPA_IO_IN, true, on_rtp_io, session);
383
+ if (session->source == NULL) {
384
+ pw_log_error("can't create io source: %m");
385
+ close(fd);
386
+ return -errno;
387
+ }
388
+ return 0;
389
+}
390
+
391
+static void session_stop(struct impl *impl, struct session *session) {
392
+ if (!session->source)
393
+ return;
394
+
395
+ pw_log_info("stopping RTP listener");
396
+
397
+ pw_loop_destroy_source(
398
+ session->impl->data_loop,
399
+ session->source
400
+ );
401
+
402
+ session->source = NULL;
403
+}
404
+
405
+static void on_stream_state_changed(void *d, enum pw_stream_state old,
406
+ enum pw_stream_state state, const char *error)
407
+{
408
+ struct session *sess = d;
409
+ struct impl *impl = sess->impl;
410
+
411
+ switch (state) {
412
+ case PW_STREAM_STATE_UNCONNECTED:
413
+ pw_log_info("stream disconnected, unloading");
414
+ pw_impl_module_schedule_destroy(impl->module);
415
+ break;
416
+ case PW_STREAM_STATE_ERROR:
417
+ pw_log_error("stream error: %s", error);
418
+ break;
419
+ case PW_STREAM_STATE_STREAMING:
420
+ if ((errno = -session_start(impl, sess)) < 0)
421
+ pw_log_error("failed to start RTP stream: %m");
422
+ break;
423
+ case PW_STREAM_STATE_PAUSED:
424
+ if (!impl->always_process)
425
+ session_stop(impl, sess);
426
+ break;
427
+ default:
428
+ break;
429
+ }
430
+}
431
+
432
+static const struct pw_stream_events out_stream_events = {
433
+ PW_VERSION_STREAM_EVENTS,
434
+ .destroy = stream_destroy,
435
+ .state_changed = on_stream_state_changed,
436
+ .io_changed = stream_io_changed,
437
+ .process = stream_process
438
+};
439
+
440
static int session_new(struct impl *impl, struct sdp_info *info)
441
{
442
struct session *session;
443
444
uint32_t n_params;
445
uint8_t buffer1024;
446
struct pw_properties *props;
447
- int res, fd, sess_latency_msec;
448
+ int res, sess_latency_msec;
449
const char *str;
450
451
if (impl->n_sessions >= MAX_SESSIONS) {
452
453
} else {
454
pw_properties_set(props, PW_KEY_MEDIA_NAME, "RTP Stream");
455
}
456
+ pw_properties_setf(props, "rtp.ts-offset", "%u", info->ts_offset);
457
+ pw_properties_set(props, "rtp.ts-refclk", info->refclk);
458
459
if ((str = pw_properties_get(impl->props, "stream.rules")) != NULL) {
460
struct session_info sinfo = {
461
462
goto error;
463
}
464
}
465
+ session->direct_timestamp = pw_properties_get_bool(props, "sess.ts-direct", false);
466
467
- pw_log_info("new session %s %s", info->origin, info->session);
468
+ pw_log_info("new session %s %s direct:%d", info->origin, info->session,
469
+ session->direct_timestamp);
470
471
sess_latency_msec = pw_properties_get_uint32(props,
472
"sess.latency.msec", impl->sess_latency_msec);
473
474
- session->target_buffer = msec_to_bytes(info, sess_latency_msec);
475
- session->max_error = msec_to_bytes(info, ERROR_MSEC);
476
+ session->target_buffer = msec_to_samples(info, sess_latency_msec);
477
+ session->max_error = msec_to_samples(info, ERROR_MSEC);
478
479
pw_properties_setf(props, PW_KEY_NODE_RATE, "1/%d", info->info.rate);
480
pw_properties_setf(props, PW_KEY_NODE_LATENCY, "%d/%d",
481
- session->target_buffer / (2 * info->stride), info->info.rate);
482
+ session->target_buffer / 2, info->info.rate);
483
484
spa_dll_init(&session->dll);
485
spa_dll_set_bw(&session->dll, SPA_DLL_BW_MIN, 128, session->info.info.rate);
486
487
+ if (info->channelmap0) {
488
+ pw_properties_set(props, PW_KEY_NODE_CHANNELNAMES, info->channelmap);
489
+ pw_log_info("channelmap: %s", info->channelmap);
490
+ }
491
+
492
session->stream = pw_stream_new(impl->core,
493
"rtp-source playback", props);
494
if (session->stream == NULL) {
495
496
goto error;
497
}
498
499
- if ((fd = make_socket((const struct sockaddr *)&info->sa,
500
- info->salen, impl->ifname)) < 0) {
501
- res = fd;
502
+ if (impl->always_process &&
503
+ (res = session_start(impl, session)) < 0)
504
goto error;
505
- }
506
507
- session->source = pw_loop_add_io(impl->data_loop, fd,
508
- SPA_IO_IN, true, on_rtp_io, session);
509
- if (session->source == NULL) {
510
- res = -errno;
511
- pw_log_error("can't create io source: %m");
512
- goto error;
513
- }
514
-
515
- pw_log_info("starting RTP listener");
516
session_touch(session);
517
518
session->impl = impl;
519
520
return 0;
521
}
522
523
-static int parse_sdp_a(struct impl *impl, char *c, struct sdp_info *info)
524
+// some AES67 devices have channelmap encoded in i=*
525
+// if `i` record is found, it matches the template
526
+// and channel count matches, name the channels respectively
527
+// `i=2 channels: 01, 08` is the format
528
+static int parse_sdp_i(struct impl *impl, char *c, struct sdp_info *info)
529
+{
530
+ if (!strstr(c, " channels: ")) {
531
+ return 0;
532
+ }
533
+
534
+ c += strlen("i=");
535
+ cstrcspn(c, " ") = '\0';
536
+
537
+ uint32_t channels;
538
+ if (sscanf(c, "%u", &channels) != 1 || channels <= 0 || channels > SPA_AUDIO_MAX_CHANNELS)
539
+ return 0;
540
+
541
+ c += strcspn(c, "\0");
542
+ c += strlen(" channels: ");
543
+
544
+ strncpy(info->channelmap, c, sizeof(info->channelmap) - 1);
545
+
546
+ return 0;
547
+}
548
+
549
+static int parse_sdp_a_rtpmap(struct impl *impl, char *c, struct sdp_info *info)
550
{
551
int payload, len, rate, channels;
552
553
554
if (sscanf(c, "%u/%u", &rate, &channels) == 2) {
555
info->info.rate = rate;
556
info->info.channels = channels;
557
+ pw_log_debug("rate: %d, ch: %d", rate, channels);
558
if (channels == 2) {
559
info->info.position0 = SPA_AUDIO_CHANNEL_FL;
560
info->info.position1 = SPA_AUDIO_CHANNEL_FR;
561
562
return 0;
563
}
564
565
+static int parse_sdp_a_mediaclk(struct impl *impl, char *c, struct sdp_info *info)
566
+{
567
+ if (!spa_strstartswith(c, "a=mediaclk:"))
568
+ return 0;
569
+
570
+ c += strlen("a=mediaclk:");
571
+
572
+ if (spa_strstartswith(c, "direct=")) {
573
+ int offset;
574
+ c += strlen("direct=");
575
+ if (sscanf(c, "%i", &offset) != 1)
576
+ return -EINVAL;
577
+ info->ts_offset = offset;
578
+ } else if (spa_strstartswith(c, "sender")) {
579
+ info->ts_offset = 0;
580
+ }
581
+ return 0;
582
+}
583
+
584
+static int parse_sdp_a_ts_refclk(struct impl *impl, char *c, struct sdp_info *info)
585
+{
586
+ if (!spa_strstartswith(c, "a=ts-refclk:"))
587
+ return 0;
588
+
589
+ c += strlen("a=ts-refclk:");
590
+ snprintf(info->refclk, sizeof(info->refclk), "%s", c);
591
+ return 0;
592
+}
593
+
594
static int parse_sdp(struct impl *impl, char *sdp, struct sdp_info *info)
595
{
596
char *s = sdp;
597
598
res = parse_sdp_c(impl, s, info);
599
else if (spa_strstartswith(s, "m="))
600
res = parse_sdp_m(impl, s, info);
601
- else if (spa_strstartswith(s, "a="))
602
- res = parse_sdp_a(impl, s, info);
603
+ else if (spa_strstartswith(s, "a=rtpmap:"))
604
+ res = parse_sdp_a_rtpmap(impl, s, info);
605
+ else if (spa_strstartswith(s, "a=mediaclk:"))
606
+ res = parse_sdp_a_mediaclk(impl, s, info);
607
+ else if (spa_strstartswith(s, "a=ts-refclk:"))
608
+ res = parse_sdp_a_ts_refclk(impl, s, info);
609
+ else if (spa_strstartswith(s, "i="))
610
+ res = parse_sdp_i(impl, s, info);
611
612
if (res < 0)
613
goto error;
614
615
616
spa_list_for_each_safe(sess, tmp, &impl->sessions, link) {
617
if (sess->timestamp + interval < timestamp) {
618
- pw_log_debug("More than %lu elapsed from last advertisement at %lu", interval, sess->timestamp);
619
- pw_log_info("No advertisement packets found for timeout, closing RTP source");
620
- session_free(sess);
621
+ pw_log_debug("More than %lu elapsed from last advertisement at %lu",
622
+ interval, sess->timestamp);
623
+ if (!sess->receiving) {
624
+ pw_log_info("SAP timeout, closing inactive RTP source");
625
+ session_free(sess);
626
+ } else {
627
+ pw_log_info("SAP timeout, keeping active RTP source");
628
+ }
629
}
630
+ sess->receiving = false;
631
}
632
}
633
634
635
str = pw_properties_get(impl->props, "local.ifname");
636
impl->ifname = str ? strdup(str) : NULL;
637
638
+ impl->always_process = pw_properties_get_bool(impl->props, PW_KEY_NODE_ALWAYS_PROCESS, false);
639
+
640
str = pw_properties_get(impl->props, "sap.ip");
641
impl->sap_ip = strdup(str ? str : DEFAULT_SAP_IP);
642
impl->sap_port = pw_properties_get_uint32(impl->props,
643
pipewire-0.3.65.tar.gz/src/pipewire/conf.c -> pipewire-0.3.66.tar.gz/src/pipewire/conf.c
Changed
266
1
2
}
3
4
/*
5
+ * {
6
+ * # all keys must match the value. ~ in value starts regex.
7
+ * <key> = <value>
8
+ * ...
9
+ * }
10
+ */
11
+static bool find_match(struct spa_json *arr, const struct spa_dict *props)
12
+{
13
+ struct spa_json it1;
14
+
15
+ while (spa_json_enter_object(arr, &it0) > 0) {
16
+ char key256, val1024;
17
+ const char *str, *value;
18
+ int match = 0, fail = 0;
19
+ int len;
20
+
21
+ while (spa_json_get_string(&it0, key, sizeof(key)) > 0) {
22
+ bool success = false;
23
+
24
+ if ((len = spa_json_next(&it0, &value)) <= 0)
25
+ break;
26
+
27
+ str = spa_dict_lookup(props, key);
28
+
29
+ if (spa_json_is_null(value, len)) {
30
+ success = str == NULL;
31
+ } else {
32
+ if (spa_json_parse_stringn(value, len, val, sizeof(val)) < 0)
33
+ continue;
34
+ value = val;
35
+ len = strlen(val);
36
+ }
37
+ if (str != NULL) {
38
+ if (value0 == '~') {
39
+ regex_t preg;
40
+ if (regcomp(&preg, value+1, REG_EXTENDED | REG_NOSUB) == 0) {
41
+ if (regexec(&preg, str, 0, NULL, 0) == 0)
42
+ success = true;
43
+ regfree(&preg);
44
+ }
45
+ } else if (strncmp(str, value, len) == 0 &&
46
+ strlen(str) == (size_t)len) {
47
+ success = true;
48
+ }
49
+ }
50
+ if (success) {
51
+ match++;
52
+ pw_log_debug("'%s' match '%s' < > '%.*s'", key, str, len, value);
53
+ }
54
+ else
55
+ fail++;
56
+ }
57
+ if (match > 0 && fail == 0)
58
+ return true;
59
+ }
60
+ return false;
61
+}
62
+
63
+/*
64
* context.modules =
65
* { name = <module-name>
66
- * args = { <key> = <value> ... }
67
- * flags = ifexists nofail
68
+ * ( args = { <key> = <value> ... } )
69
+ * ( flags = ( ifexists ) ( nofail )
70
+ * ( condition = { key = value, .. } .. )
71
* }
72
*
73
*/
74
75
{
76
struct data *d = user_data;
77
struct pw_context *context = d->context;
78
- struct spa_json it3;
79
+ struct spa_json it4;
80
char key512, *s;
81
int res = 0;
82
83
84
85
while (spa_json_enter_object(&it1, &it2) > 0) {
86
char *name = NULL, *args = NULL, *flags = NULL;
87
+ bool have_match = true;
88
89
while (spa_json_get_string(&it2, key, sizeof(key)) > 0) {
90
const char *val;
91
92
len = spa_json_container_len(&it2, val, len);
93
flags = (char*)val;
94
spa_json_parse_stringn(val, len, flags, len+1);
95
+ } else if (spa_streq(key, "condition")) {
96
+ if (!spa_json_is_array(val, len))
97
+ break;
98
+ spa_json_enter(&it2, &it3);
99
+ have_match = find_match(&it3, &context->properties->dict);
100
}
101
}
102
+ if (!have_match)
103
+ continue;
104
+
105
if (name != NULL)
106
res = load_module(context, name, args, flags);
107
108
109
/*
110
* context.objects =
111
* { factory = <factory-name>
112
- * args = { <key> = <value> ... }
113
- * flags = nofail
114
+ * ( args = { <key> = <value> ... } )
115
+ * ( flags = ( nofail ) )
116
+ * ( condition = { key = value, .. } .. )
117
* }
118
*
119
*/
120
121
{
122
struct data *d = user_data;
123
struct pw_context *context = d->context;
124
- struct spa_json it3;
125
+ struct spa_json it4;
126
char key512, *s;
127
int res = 0;
128
129
130
131
while (spa_json_enter_object(&it1, &it2) > 0) {
132
char *factory = NULL, *args = NULL, *flags = NULL;
133
+ bool have_match = true;
134
135
while (spa_json_get_string(&it2, key, sizeof(key)) > 0) {
136
const char *val;
137
138
139
flags = (char*)val;
140
spa_json_parse_stringn(val, len, flags, len+1);
141
+ } else if (spa_streq(key, "condition")) {
142
+ if (!spa_json_is_array(val, len))
143
+ break;
144
+ spa_json_enter(&it2, &it3);
145
+ have_match = find_match(&it3, &context->properties->dict);
146
}
147
}
148
+ if (!have_match)
149
+ continue;
150
+
151
if (factory != NULL)
152
res = create_object(context, factory, args, flags);
153
154
155
156
/*
157
* context.exec =
158
- * { path = <program-name>
159
- * args = "<arguments>"
160
+ * { path = <program-name>
161
+ * ( args = "<arguments>" )
162
+ * ( condition = { key = value, .. } .. )
163
* }
164
*
165
*/
166
167
{
168
struct data *d = user_data;
169
struct pw_context *context = d->context;
170
- struct spa_json it3;
171
+ struct spa_json it4;
172
char key512, *s;
173
int res = 0;
174
175
176
177
while (spa_json_enter_object(&it1, &it2) > 0) {
178
char *path = NULL, *args = NULL;
179
+ bool have_match = true;
180
181
while (spa_json_get_string(&it2, key, sizeof(key)) > 0) {
182
const char *val;
183
184
} else if (spa_streq(key, "args")) {
185
args = (char*)val;
186
spa_json_parse_stringn(val, len, args, len+1);
187
+ } else if (spa_streq(key, "condition")) {
188
+ if (!spa_json_is_array(val, len))
189
+ break;
190
+ spa_json_enter(&it2, &it3);
191
+ have_match = find_match(&it3, &context->properties->dict);
192
}
193
}
194
+ if (!have_match)
195
+ continue;
196
+
197
if (path != NULL)
198
res = do_exec(context, path, args);
199
200
201
}
202
203
204
-/*
205
- * {
206
- * # all keys must match the value. ~ in value starts regex.
207
- * <key> = <value>
208
- * ...
209
- * }
210
- */
211
-static bool find_match(struct spa_json *arr, const struct spa_dict *props)
212
-{
213
- struct spa_json it1;
214
-
215
- while (spa_json_enter_object(arr, &it0) > 0) {
216
- char key256, val1024;
217
- const char *str, *value;
218
- int match = 0, fail = 0;
219
- int len;
220
-
221
- while (spa_json_get_string(&it0, key, sizeof(key)) > 0) {
222
- bool success = false;
223
-
224
- if ((len = spa_json_next(&it0, &value)) <= 0)
225
- break;
226
-
227
- str = spa_dict_lookup(props, key);
228
-
229
- if (spa_json_is_null(value, len)) {
230
- success = str == NULL;
231
- } else {
232
- if (spa_json_parse_stringn(value, len, val, sizeof(val)) < 0)
233
- continue;
234
- value = val;
235
- len = strlen(val);
236
- }
237
- if (str != NULL) {
238
- if (value0 == '~') {
239
- regex_t preg;
240
- if (regcomp(&preg, value+1, REG_EXTENDED | REG_NOSUB) == 0) {
241
- if (regexec(&preg, str, 0, NULL, 0) == 0)
242
- success = true;
243
- regfree(&preg);
244
- }
245
- } else if (strncmp(str, value, len) == 0 &&
246
- strlen(str) == (size_t)len) {
247
- success = true;
248
- }
249
- }
250
- if (success) {
251
- match++;
252
- pw_log_debug("'%s' match '%s' < > '%.*s'", key, str, len, value);
253
- }
254
- else
255
- fail++;
256
- }
257
- if (match > 0 && fail == 0)
258
- return true;
259
- }
260
- return false;
261
-}
262
-
263
/**
264
*
265
* {
266
pipewire-0.3.65.tar.gz/src/pipewire/context.c -> pipewire-0.3.66.tar.gz/src/pipewire/context.c
Changed
136
1
2
return fa < fb ? -1 : (fa > fb ? 1 : 0);
3
}
4
5
-static uint32_t find_best_rate(const uint32_t *rates, uint32_t n_rates, uint32_t rate, uint32_t best)
6
+static inline uint32_t calc_gcd(uint32_t a, uint32_t b)
7
{
8
- uint32_t i;
9
+ while (b != 0) {
10
+ uint32_t temp = a;
11
+ a = b;
12
+ b = temp % b;
13
+ }
14
+ return a;
15
+}
16
+
17
+struct rate_info {
18
+ uint32_t rate;
19
+ uint32_t gcd;
20
+ uint32_t diff;
21
+};
22
+
23
+static inline void update_highest_rate(struct rate_info *best, struct rate_info *current)
24
+{
25
+ /* find highest rate */
26
+ if (best->rate == 0 || best->rate < current->rate)
27
+ *best = *current;
28
+}
29
+
30
+static inline void update_nearest_gcd(struct rate_info *best, struct rate_info *current)
31
+{
32
+ /* find nearest GCD */
33
+ if (best->rate == 0 ||
34
+ (best->gcd < current->gcd) ||
35
+ (best->gcd == current->gcd && best->diff > current->diff))
36
+ *best = *current;
37
+}
38
+static inline void update_nearest_rate(struct rate_info *best, struct rate_info *current)
39
+{
40
+ /* find nearest rate */
41
+ if (best->rate == 0 || best->diff > current->diff)
42
+ *best = *current;
43
+}
44
+
45
+static uint32_t find_best_rate(const uint32_t *rates, uint32_t n_rates, uint32_t rate, uint32_t def)
46
+{
47
+ uint32_t i, limit;
48
+ struct rate_info best;
49
+ struct rate_info infon_rates;
50
+
51
+ for (i = 0; i < n_rates; i++) {
52
+ infoi.rate = ratesi;
53
+ infoi.gcd = calc_gcd(rate, ratesi);
54
+ infoi.diff = SPA_ABS((int32_t)rate - (int32_t)ratesi);
55
+ }
56
+
57
+ /* first find higher nearest GCD. This tries to find next bigest rate that
58
+ * requires the least amount of resample filter banks. Usually these are
59
+ * rates that are multiples of eachother or multiples of a common rate.
60
+ *
61
+ * 44100 and 32000 56000 88200 96000 -> 88200
62
+ * 48000 and 32000 56000 88200 96000 -> 96000
63
+ * 88200 and 44100 48000 96000 192000 -> 96000
64
+ * 32000 and 44100 192000 -> 44100
65
+ * 8000 and 44100 48000 -> 48000
66
+ * 8000 and 44100 192000 -> 44100
67
+ * 11025 and 44100 48000 -> 44100
68
+ * 44100 and 48000 176400 -> 48000
69
+ */
70
+ spa_zero(best);
71
+ /* Don't try to do excessive upsampling by limiting the max rate
72
+ * for desired < default to default*2. For other rates allow
73
+ * a x3 upsample rate max */
74
+ limit = rate < def ? def*2 : rate*3;
75
+ for (i = 0; i < n_rates; i++) {
76
+ if (infoi.rate >= rate && infoi.rate <= limit)
77
+ update_nearest_gcd(&best, &infoi);
78
+ }
79
+ if (best.rate != 0)
80
+ return best.rate;
81
+
82
+ /* we would need excessive upsampling, pick a nearest higher rate */
83
+ spa_zero(best);
84
+ for (i = 0; i < n_rates; i++) {
85
+ if (infoi.rate >= rate)
86
+ update_nearest_rate(&best, &infoi);
87
+ }
88
+ if (best.rate != 0)
89
+ return best.rate;
90
+
91
+ /* There is nothing above the rate, we need to downsample. Try to downsample
92
+ * but only to something that is from a common rate family. Also don't
93
+ * try to downsample to something that will sound worse (< 44100).
94
+ *
95
+ * 88200 and 22050 44100 48000 -> 44100
96
+ * 88200 and 22050 48000 -> 48000
97
+ */
98
+ spa_zero(best);
99
for (i = 0; i < n_rates; i++) {
100
- if (SPA_ABS((int32_t)rate - (int32_t)ratesi) <
101
- SPA_ABS((int32_t)rate - (int32_t)best))
102
- best = ratesi;
103
+ if (infoi.rate >= 44100)
104
+ update_nearest_gcd(&best, &infoi);
105
}
106
- return best;
107
+ if (best.rate != 0)
108
+ return best.rate;
109
+
110
+ /* There is nothing to downsample above our threshold. Downsample to whatever
111
+ * is the highest rate then. */
112
+ spa_zero(best);
113
+ for (i = 0; i < n_rates; i++)
114
+ update_highest_rate(&best, &infoi);
115
+ if (best.rate != 0)
116
+ return best.rate;
117
+
118
+ return def;
119
}
120
121
/* here we evaluate the complete state of the graph.
122
123
running = true;
124
125
current_rate = n->current_rate.denom;
126
- if (lock_rate || n->reconfigure ||
127
+ if (lock_rate || n->reconfigure || !running ||
128
(!force_rate &&
129
(n->info.state > PW_NODE_STATE_IDLE)))
130
/* when someone wants us to lock the rate of this driver or
131
+ * when we are in the process of reconfiguring the driver or
132
+ * when we are not running any followers or
133
* when the driver is busy and we don't need to force a rate,
134
* keep the current rate */
135
target_rate = current_rate;
136
pipewire-0.3.65.tar.gz/src/pipewire/filter.c -> pipewire-0.3.66.tar.gz/src/pipewire/filter.c
Changed
264
1
2
3
struct pw_properties *props;
4
5
- uint32_t change_mask_all;
6
+ uint64_t change_mask_all;
7
struct spa_port_info info;
8
struct spa_list param_list;
9
-#define IDX_EnumFormat 0
10
-#define IDX_Meta 1
11
-#define IDX_IO 2
12
-#define IDX_Format 3
13
-#define IDX_Buffers 4
14
-#define IDX_Latency 5
15
+#define PORT_EnumFormat 0
16
+#define PORT_Meta 1
17
+#define PORT_IO 2
18
+#define PORT_Format 3
19
+#define PORT_Buffers 4
20
+#define PORT_Latency 5
21
#define N_PORT_PARAMS 6
22
struct spa_param_info paramsN_PORT_PARAMS;
23
24
25
struct spa_node impl_node;
26
struct spa_hook_list hooks;
27
struct spa_callbacks callbacks;
28
+ struct spa_io_clock *clock;
29
struct spa_io_position *position;
30
31
struct {
32
33
struct spa_list port_list;
34
struct pw_map ports2;
35
36
- uint32_t change_mask_all;
37
+ uint64_t change_mask_all;
38
struct spa_node_info info;
39
struct spa_list param_list;
40
-#define IDX_PropInfo 0
41
-#define IDX_Props 1
42
-#define IDX_ProcessLatency 2
43
+#define NODE_PropInfo 0
44
+#define NODE_Props 1
45
+#define NODE_ProcessLatency 2
46
#define N_NODE_PARAMS 3
47
struct spa_param_info paramsN_NODE_PARAMS;
48
49
50
unsigned int allow_mlock:1;
51
unsigned int warn_mlock:1;
52
unsigned int process_rt:1;
53
+ unsigned int driving:1;
54
};
55
56
static int get_param_index(uint32_t id)
57
{
58
switch (id) {
59
case SPA_PARAM_PropInfo:
60
- return IDX_PropInfo;
61
+ return NODE_PropInfo;
62
case SPA_PARAM_Props:
63
- return IDX_Props;
64
+ return NODE_Props;
65
case SPA_PARAM_ProcessLatency:
66
- return IDX_ProcessLatency;
67
+ return NODE_ProcessLatency;
68
default:
69
return -1;
70
}
71
72
{
73
switch (id) {
74
case SPA_PARAM_EnumFormat:
75
- return IDX_EnumFormat;
76
+ return PORT_EnumFormat;
77
case SPA_PARAM_Meta:
78
- return IDX_Meta;
79
+ return PORT_Meta;
80
case SPA_PARAM_IO:
81
- return IDX_IO;
82
+ return PORT_IO;
83
case SPA_PARAM_Format:
84
- return IDX_Format;
85
+ return PORT_Format;
86
case SPA_PARAM_Buffers:
87
- return IDX_Buffers;
88
+ return PORT_Buffers;
89
case SPA_PARAM_Latency:
90
- return IDX_Latency;
91
+ return PORT_Latency;
92
default:
93
return -1;
94
}
95
96
pw_log_debug("%p: io %d %p/%zd", impl, id, data, size);
97
98
switch(id) {
99
+ case SPA_IO_Clock:
100
+ if (data && size >= sizeof(struct spa_io_clock))
101
+ impl->clock = data;
102
+ else
103
+ impl->clock = NULL;
104
+ break;
105
case SPA_IO_Position:
106
if (data && size >= sizeof(struct spa_io_position))
107
impl->position = data;
108
109
do_set_position, 1, NULL, 0, true, impl);
110
break;
111
}
112
+ impl->driving = impl->clock && impl->position && impl->position->clock.id == impl->clock->id;
113
pw_filter_emit_io_changed(&impl->this, NULL, id, data, size);
114
115
return 0;
116
117
impl->info.max_output_ports = UINT32_MAX;
118
impl->info.flags = impl->process_rt ? SPA_NODE_FLAG_RT : 0;
119
impl->info.props = &filter->properties->dict;
120
- impl->paramsIDX_PropInfo = SPA_PARAM_INFO(SPA_PARAM_PropInfo, 0);
121
- impl->paramsIDX_Props = SPA_PARAM_INFO(SPA_PARAM_Props, SPA_PARAM_INFO_WRITE);
122
- impl->paramsIDX_ProcessLatency = SPA_PARAM_INFO(SPA_PARAM_ProcessLatency, 0);
123
+ impl->paramsNODE_PropInfo = SPA_PARAM_INFO(SPA_PARAM_PropInfo, 0);
124
+ impl->paramsNODE_Props = SPA_PARAM_INFO(SPA_PARAM_Props, SPA_PARAM_INFO_WRITE);
125
+ impl->paramsNODE_ProcessLatency = SPA_PARAM_INFO(SPA_PARAM_ProcessLatency, 0);
126
impl->info.params = impl->params;
127
impl->info.n_params = N_NODE_PARAMS;
128
impl->info.change_mask = impl->change_mask_all;
129
130
p->info.flags |= SPA_PORT_FLAG_CAN_ALLOC_BUFFERS;
131
p->info.props = &p->props->dict;
132
p->change_mask_all |= SPA_PORT_CHANGE_MASK_PARAMS;
133
- p->paramsIDX_EnumFormat = SPA_PARAM_INFO(SPA_PARAM_EnumFormat, 0);
134
- p->paramsIDX_Meta = SPA_PARAM_INFO(SPA_PARAM_Meta, 0);
135
- p->paramsIDX_IO = SPA_PARAM_INFO(SPA_PARAM_IO, 0);
136
- p->paramsIDX_Format = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE);
137
- p->paramsIDX_Buffers = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0);
138
- p->paramsIDX_Latency = SPA_PARAM_INFO(SPA_PARAM_Latency, SPA_PARAM_INFO_WRITE);
139
+ p->paramsPORT_EnumFormat = SPA_PARAM_INFO(SPA_PARAM_EnumFormat, 0);
140
+ p->paramsPORT_Meta = SPA_PARAM_INFO(SPA_PARAM_Meta, 0);
141
+ p->paramsPORT_IO = SPA_PARAM_INFO(SPA_PARAM_IO, 0);
142
+ p->paramsPORT_Format = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE);
143
+ p->paramsPORT_Buffers = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0);
144
+ p->paramsPORT_Latency = SPA_PARAM_INFO(SPA_PARAM_Latency, SPA_PARAM_INFO_WRITE);
145
p->info.params = p->params;
146
p->info.n_params = N_PORT_PARAMS;
147
148
149
return NULL;
150
}
151
152
-SPA_EXPORT
153
-int pw_filter_remove_port(void *port_data)
154
+static inline void free_port(struct filter *impl, struct port *port)
155
{
156
- struct port *port = SPA_CONTAINER_OF(port_data, struct port, user_data);
157
- struct filter *impl = port->filter;
158
-
159
- spa_node_emit_port_info(&impl->hooks, port->direction, port->id, NULL);
160
-
161
spa_list_remove(&port->link);
162
+ spa_node_emit_port_info(&impl->hooks, port->direction, port->id, NULL);
163
pw_map_remove(&impl->portsport->direction, port->id);
164
-
165
clear_buffers(port);
166
clear_params(impl, port, SPA_ID_INVALID);
167
pw_properties_free(port->props);
168
free(port);
169
+}
170
171
+SPA_EXPORT
172
+int pw_filter_remove_port(void *port_data)
173
+{
174
+ struct port *port = SPA_CONTAINER_OF(port_data, struct port, user_data);
175
+ struct filter *impl = port->filter;
176
+ free_port(impl, port);
177
return 0;
178
}
179
180
181
return 0;
182
}
183
184
-static int
185
-do_process(struct spa_loop *loop,
186
- bool async, uint32_t seq, const void *data, size_t size, void *user_data)
187
-{
188
- struct filter *impl = user_data;
189
- int res = impl_node_process(impl);
190
- return spa_node_call_ready(&impl->callbacks, res);
191
-}
192
-
193
-static inline int call_trigger(struct filter *impl)
194
-{
195
- int res = 0;
196
- if (SPA_FLAG_IS_SET(impl->flags, PW_FILTER_FLAG_DRIVER)) {
197
- res = pw_loop_invoke(impl->context->data_loop,
198
- do_process, 1, NULL, 0, false, impl);
199
- }
200
- return res;
201
-}
202
-
203
SPA_EXPORT
204
struct pw_buffer *pw_filter_dequeue_buffer(void *port_data)
205
{
206
207
if ((res = push_queue(p, &p->queued, b)) < 0)
208
return res;
209
210
- return call_trigger(impl);
211
+ return res;
212
}
213
214
SPA_EXPORT
215
216
drain ? do_drain : do_flush, 1, NULL, 0, true, impl);
217
return 0;
218
}
219
+
220
+SPA_EXPORT
221
+bool pw_filter_is_driving(struct pw_filter *filter)
222
+{
223
+ struct filter *impl = SPA_CONTAINER_OF(filter, struct filter, this);
224
+ return impl->driving;
225
+}
226
+
227
+static int
228
+do_trigger_process(struct spa_loop *loop,
229
+ bool async, uint32_t seq, const void *data, size_t size, void *user_data)
230
+{
231
+ struct filter *impl = user_data;
232
+ int res = impl_node_process(impl);
233
+ return spa_node_call_ready(&impl->callbacks, res);
234
+}
235
+
236
+static int trigger_request_process(struct filter *impl)
237
+{
238
+ uint8_t buffer1024;
239
+ struct spa_pod_builder b = { 0 };
240
+
241
+ spa_pod_builder_init(&b, buffer, sizeof(buffer));
242
+ spa_node_emit_event(&impl->hooks,
243
+ spa_pod_builder_add_object(&b,
244
+ SPA_TYPE_EVENT_Node, SPA_NODE_EVENT_RequestProcess));
245
+ return 0;
246
+}
247
+
248
+SPA_EXPORT
249
+int pw_filter_trigger_process(struct pw_filter *filter)
250
+{
251
+ struct filter *impl = SPA_CONTAINER_OF(filter, struct filter, this);
252
+ int res = 0;
253
+
254
+ pw_log_trace_fp("%p", impl);
255
+
256
+ if (!impl->driving) {
257
+ res = trigger_request_process(impl);
258
+ } else {
259
+ res = pw_loop_invoke(impl->context->data_loop,
260
+ do_trigger_process, 1, NULL, 0, false, impl);
261
+ }
262
+ return res;
263
+}
264
pipewire-0.3.65.tar.gz/src/pipewire/filter.h -> pipewire-0.3.66.tar.gz/src/pipewire/filter.h
Changed
18
1
2
* be called when all data is played or recorded */
3
int pw_filter_flush(struct pw_filter *filter, bool drain);
4
5
+/** Check if the filter is driving. The filter needs to have the
6
+ * PW_FILTER_FLAG_DRIVER set. When the filter is driving,
7
+ * pw_filter_trigger_process() needs to be called when data is
8
+ * available (output) or needed (input). Since 0.3.66 */
9
+bool pw_filter_is_driving(struct pw_filter *filter);
10
+
11
+/** Trigger a push/pull on the filter. One iteration of the graph will
12
+ * be scheduled and process() will be called. Since 0.3.66 */
13
+int pw_filter_trigger_process(struct pw_filter *filter);
14
+
15
/**
16
* \}
17
*/
18
pipewire-0.3.65.tar.gz/src/pipewire/impl-core.c -> pipewire-0.3.66.tar.gz/src/pipewire/impl-core.c
Changed
10
1
2
if (obj == NULL)
3
goto error_create_failed;
4
5
- return 0;
6
+ return obj;
7
8
error_no_factory:
9
res = -ENOENT;
10
pipewire-0.3.65.tar.gz/src/pipewire/keys.h -> pipewire-0.3.66.tar.gz/src/pipewire/keys.h
Changed
17
1
2
* and object name or object.serial */
3
4
#ifndef PW_REMOVE_DEPRECATED
5
-#define PW_KEY_PRIORITY_MASTER PW_DEPRECATED("priority.master") /**< deprecated, use priority.driver */
6
-#define PW_KEY_NODE_TARGET PW_DEPRECATED("node.target") /**< deprecated since 0.3.64, use target.object. */
7
+# ifdef PW_ENABLE_DEPRECATED
8
+# define PW_KEY_PRIORITY_MASTER "priority.master" /**< deprecated, use priority.driver */
9
+# define PW_KEY_NODE_TARGET "node.target" /**< deprecated since 0.3.64, use target.object. */
10
+# else
11
+# define PW_KEY_PRIORITY_MASTER PW_DEPRECATED("priority.master")
12
+# define PW_KEY_NODE_TARGET PW_DEPRECATED("node.target")
13
+# endif /* PW_ENABLE_DEPRECATED */
14
#endif /* PW_REMOVE_DEPRECATED */
15
16
/** \}
17
pipewire-0.3.65.tar.gz/src/pipewire/log.c -> pipewire-0.3.66.tar.gz/src/pipewire/log.c
Changed
29
1
2
3
#include <spa/pod/pod.h>
4
#include <spa/debug/types.h>
5
+#include <spa/debug/format.h>
6
#include <spa/pod/iter.h>
7
#include <spa/utils/list.h>
8
9
10
{
11
struct spa_debug_log_ctx ctx = SPA_LOGF_DEBUG_INIT(global_log, level,
12
topic, file, line, func );
13
- if (flags & PW_LOG_OBJECT_POD) {
14
+ if (object == NULL) {
15
+ pw_log_logt(level, topic, file, line, func, "NULL");
16
+ } else {
17
const struct spa_pod *pod = object;
18
- if (pod == NULL) {
19
- pw_log_logt(level, topic, file, line, func, "NULL");
20
- } else {
21
+ if (flags & PW_LOG_OBJECT_POD)
22
spa_debugc_pod(&ctx.ctx, 0, SPA_TYPE_ROOT, pod);
23
- }
24
+ else if (flags & PW_LOG_OBJECT_FORMAT)
25
+ spa_debugc_format(&ctx.ctx, 0, NULL, pod);
26
}
27
}
28
29
pipewire-0.3.65.tar.gz/src/pipewire/mem.c -> pipewire-0.3.66.tar.gz/src/pipewire/mem.c
Changed
33
1
2
#include <unistd.h>
3
#include <stdlib.h>
4
#include <sys/syscall.h>
5
+#include <sys/stat.h>
6
7
#include <spa/utils/list.h>
8
#include <spa/buffer/buffer.h>
9
10
struct mapping *m;
11
struct memmap *mm;
12
struct pw_map_range range;
13
+ struct stat sb;
14
+
15
+ if (fstat(b->this.fd, &sb) != 0)
16
+ return NULL;
17
+
18
+ const bool valid = (int64_t) offset + size <= (int64_t) sb.st_size;
19
+ pw_log(valid ? SPA_LOG_LEVEL_DEBUG : SPA_LOG_LEVEL_ERROR,
20
+ "%p: block %p%u mapping %" PRIu32 "+%" PRIu32 " of file=%d/%" PRIu64 ":%" PRIu64 " with size=%" PRId64,
21
+ block->pool, block, block->id,
22
+ offset, size,
23
+ block->fd, (uint64_t) sb.st_dev, (uint64_t) sb.st_ino,
24
+ (int64_t) sb.st_size);
25
+
26
+ if (!valid) {
27
+ errno = -EINVAL;
28
+ return NULL;
29
+ }
30
31
pw_map_range_init(&range, offset, size, p->pagesize);
32
33
pipewire-0.3.65.tar.gz/src/pipewire/private.h -> pipewire-0.3.66.tar.gz/src/pipewire/private.h
Changed
18
1
2
void pw_impl_client_unref(struct pw_impl_client *client);
3
4
#define PW_LOG_OBJECT_POD (1<<0)
5
+#define PW_LOG_OBJECT_FORMAT (1<<1)
6
void pw_log_log_object(enum spa_log_level level, const struct spa_log_topic *topic,
7
const char *file, int line, const char *func, uint32_t flags,
8
const void *object);
9
10
})
11
12
#define pw_log_pod(lev,pod) pw_log_object(lev,PW_LOG_TOPIC_DEFAULT,PW_LOG_OBJECT_POD,pod)
13
-#define pw_log_format(lev,pod) pw_log_object(lev,PW_LOG_TOPIC_DEFAULT,PW_LOG_OBJECT_POD,pod)
14
+#define pw_log_format(lev,pod) pw_log_object(lev,PW_LOG_TOPIC_DEFAULT,PW_LOG_OBJECT_FORMAT,pod)
15
16
bool pw_log_is_default(void);
17
18
pipewire-0.3.65.tar.gz/src/pipewire/stream.c -> pipewire-0.3.66.tar.gz/src/pipewire/stream.c
Changed
19
1
2
struct spa_io_position *position;
3
} rt;
4
5
- uint32_t port_change_mask_all;
6
+ uint64_t port_change_mask_all;
7
struct spa_port_info port_info;
8
struct pw_properties *port_props;
9
#define PORT_EnumFormat 0
10
11
12
struct spa_list param_list;
13
14
- uint32_t change_mask_all;
15
+ uint64_t change_mask_all;
16
struct spa_node_info info;
17
#define NODE_PropInfo 0
18
#define NODE_Props 1
19
pipewire-0.3.65.tar.gz/src/pipewire/thread-loop.c -> pipewire-0.3.66.tar.gz/src/pipewire/thread-loop.c
Changed
10
1
2
*
3
*/
4
SPA_EXPORT
5
-int pw_thread_loop_timed_wait_full(struct pw_thread_loop *loop, struct timespec *abstime)
6
+int pw_thread_loop_timed_wait_full(struct pw_thread_loop *loop, const struct timespec *abstime)
7
{
8
int ret;
9
loop->n_waiting++;
10
pipewire-0.3.65.tar.gz/src/pipewire/thread-loop.h -> pipewire-0.3.66.tar.gz/src/pipewire/thread-loop.h
Changed
10
1
2
/** Release the lock and wait up to \a abstime until some thread calls
3
* \ref pw_thread_loop_signal. Use \ref pw_thread_loop_get_time to make a timeout.
4
* Since: 0.3.7 */
5
-int pw_thread_loop_timed_wait_full(struct pw_thread_loop *loop, struct timespec *abstime);
6
+int pw_thread_loop_timed_wait_full(struct pw_thread_loop *loop, const struct timespec *abstime);
7
8
/** Signal all threads waiting with \ref pw_thread_loop_wait */
9
void pw_thread_loop_signal(struct pw_thread_loop *loop, bool wait_for_accept);
10
pipewire-0.3.65.tar.gz/src/tools/pw-cat.c -> pipewire-0.3.66.tar.gz/src/tools/pw-cat.c
Changed
58
1
2
static int encoded_playback_fill(struct data *d, void *dest, unsigned int n_frames)
3
{
4
int ret, size = 0;
5
- uint8_t buffer16384 = { 0 };
6
+ uint8_t buffer16384;
7
8
- ret = fread(buffer, 1, 16384, d->encoded_file);
9
+ ret = fread(buffer, 1, SPA_MIN(n_frames, sizeof(buffer)), d->encoded_file);
10
if (ret > 0) {
11
memcpy(dest, buffer, ret);
12
size = ret;
13
}
14
-
15
return (int)size;
16
}
17
18
19
n_frames = d->maxsize / data->stride;
20
n_frames = SPA_MIN(n_frames, (int)b->requested);
21
22
-#ifdef HAVE_PW_CAT_FFMPEG_INTEGRATION
23
- n_fill_frames = data->fill(data, p, n_frames);
24
-
25
- if (n_fill_frames > 0 || n_frames == 0) {
26
- d->chunk->offset = 0;
27
- if (data->data_type == TYPE_ENCODED) {
28
- d->chunk->stride = 0;
29
- // encoded_playback_fill returns number of bytes
30
- // read and not number of frames like other
31
- // functions for raw audio.
32
- d->chunk->size = n_fill_frames;
33
- b->size = n_fill_frames;
34
- } else {
35
- d->chunk->stride = data->stride;
36
- d->chunk->size = n_fill_frames * data->stride;
37
- b->size = n_frames;
38
- }
39
- have_data = true;
40
- } else if (n_fill_frames < 0) {
41
- fprintf(stderr, "fill error %d\n", n_fill_frames);
42
- } else {
43
- if (data->verbose)
44
- printf("drain start\n");
45
- }
46
-#else
47
n_fill_frames = data->fill(data, p, n_frames);
48
49
if (n_fill_frames > 0 || n_frames == 0) {
50
51
if (data->verbose)
52
printf("drain start\n");
53
}
54
-#endif
55
} else {
56
offset = SPA_MIN(d->chunk->offset, d->maxsize);
57
size = SPA_MIN(d->chunk->size, d->maxsize - offset);
58
pipewire-0.3.66.tar.gz/subprojects/libcamera.wrap
Added
5
1
2
+wrap-git
3
+url = https://git.libcamera.org/libcamera/libcamera.git
4
+revision = head
5
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 2 years ago
New upstream release
zaitor accepted request about 2 years ago
Xin