Overview
pipewire-aptx.changes
Changed
x
1
2
-------------------------------------------------------------------
3
+Sun May 14 10:53:41 UTC 2023 - Bjørn Lie <zaitor@opensuse.org>
4
+
5
+- Update to version 0.3.70
6
+
7
+-------------------------------------------------------------------
8
Fri Apr 14 13:35:34 UTC 2023 - Bjørn Lie <zaitor@opensuse.org>
9
10
- Update to version 0.3.69
11
pipewire-aptx.spec
Changed
10
1
2
%define soversion 0_2
3
4
Name: pipewire-aptx
5
-Version: 0.3.69
6
+Version: 0.3.70
7
Release: 0
8
Summary: PipeWire Bluetooth aptX codec plugin
9
License: MIT
10
pipewire-0.3.69.tar.gz/.gitlab-ci.yml -> pipewire-0.3.70.tar.gz/.gitlab-ci.yml
Changed
111
1
2
.fedora:
3
variables:
4
# Update this tag when you want to trigger a rebuild
5
- FDO_DISTRIBUTION_TAG: '2023-03-09.0'
6
- FDO_DISTRIBUTION_VERSION: '35'
7
+ FDO_DISTRIBUTION_TAG: '2023-04-18.0'
8
+ FDO_DISTRIBUTION_VERSION: '37'
9
FDO_DISTRIBUTION_PACKAGES: >-
10
alsa-lib-devel
11
avahi-devel
12
13
libmysofa-devel
14
libsndfile-devel
15
libubsan
16
- libusb-devel
17
+ libusb1-devel
18
lilv-devel
19
libv4l-devel
20
libva-devel
21
libX11-devel
22
ModemManager-devel
23
+ meson
24
openssl-devel
25
pulseaudio-libs-devel
26
python3-docutils
27
+ python3-pip
28
sbc-devel
29
ShellCheck
30
SDL2-devel
31
32
valgrind
33
ninja-build
34
pkgconf
35
- python3-pip
36
pulseaudio-utils
37
openal-soft
38
readline-devel
39
- FDO_DISTRIBUTION_EXEC: >-
40
- pip3 install meson
41
+# Uncommenting the following two lines and disabling the meson entry above
42
+# will re-enable use of Meson via pip but please consider using a newer distro
43
+# image first or making the build system compatible instead! This is because
44
+# using pip or another 3rd party repo defeats the point testing the particular
45
+# distro for regressions.
46
+# NOTE: If you do end up using pip3 for meson, be sure to also update the
47
+# build_meson_prerelease and build_meson_exact_release build instructions
48
+# to uninstall the pip3 version again and probably to not call dnf remove
49
+# FDO_DISTRIBUTION_EXEC: >-
50
+# pip3 install meson
51
52
.ubuntu:
53
variables:
54
# Update this tag when you want to trigger a rebuild
55
- FDO_DISTRIBUTION_TAG: '2023-02-16.0'
56
- FDO_DISTRIBUTION_VERSION: '20.04'
57
+ FDO_DISTRIBUTION_TAG: '2023-04-18.0'
58
+ FDO_DISTRIBUTION_VERSION: '22.04'
59
FDO_DISTRIBUTION_PACKAGES: >-
60
debhelper-compat
61
findutils
62
63
libva-dev
64
libv4l-dev
65
libx11-dev
66
+ meson
67
ninja-build
68
pkg-config
69
python3-docutils
70
systemd
71
- python3-pip
72
- FDO_DISTRIBUTION_EXEC: >-
73
- pip3 install meson
74
+# Uncommenting the following three lines and disabling the meson entry above
75
+# will re-enable use of Meson via pip but please consider using a newer distro
76
+# image first or making the build system compatible instead! This is because
77
+# using pip or another 3rd party repo defeats the point testing the particular
78
+# distro for regressions.
79
+# python3-pip
80
+# FDO_DISTRIBUTION_EXEC: >-
81
+# pip3 install meson
82
83
.alpine:
84
variables:
85
# Update this tag when you want to trigger a rebuild
86
- FDO_DISTRIBUTION_TAG: '2022-09-07.0'
87
- FDO_DISTRIBUTION_VERSION: '3.15'
88
+ FDO_DISTRIBUTION_TAG: '2023-04-17.0'
89
+ FDO_DISTRIBUTION_VERSION: '3.17'
90
FDO_DISTRIBUTION_PACKAGES: >-
91
alsa-lib-dev
92
avahi-dev
93
94
extends:
95
- .build_on_fedora
96
script:
97
+ - dnf remove --assumeyes meson
98
- pip3 install --upgrade --pre meson
99
- echo "Building with meson options $MESON_OPTIONS"
100
- meson setup "$BUILD_DIR" --prefix="$PREFIX" $MESON_OPTIONS
101
102
- meson_version=$(head -n 5 meson.build | grep 'meson_version' | sed -e 's/.*\(0-9\+\.0-9\+\.0-9\+\).*/\1/')
103
- echo "Requiring meson version $meson_version"
104
- test -n "$meson_version" || (echo "Meson version parser failed" && exit 1)
105
- - pip3 uninstall --yes meson
106
+ - dnf remove --assumeyes meson
107
+# - pip3 uninstall --yes meson
108
- pip3 install "meson==$meson_version"
109
- echo "Building with meson options $MESON_OPTIONS"
110
- meson setup "$BUILD_DIR" --prefix="$PREFIX" $MESON_OPTIONS
111
pipewire-0.3.69.tar.gz/NEWS -> pipewire-0.3.70.tar.gz/NEWS
Changed
82
1
2
+# PipeWire 0.3.70 (2023-04-20)
3
+
4
+This is a quick bugfix release that is API and ABI compatible with previous
5
+0.3.x releases.
6
+
7
+## Highlights
8
+ - Fix a regression in the scheduler that could keep some nodes IDLE.
9
+ - Fix a regression in the biquad filters in filter-chain.
10
+ - Fix a regression and potential crash in the ALSA mixer probing.
11
+ - Fix a regression in pipewiresrc with timestamps that could cause cheese
12
+ to record video with wrong timestamps.
13
+ - Beamforming support was enabled in the echo-canceler.
14
+ - pulse-tunnel and raop-sink will now proxy local volume changes to the
15
+ remote end.
16
+ - More bugfixes and improvements.
17
+
18
+
19
+## PipeWire
20
+ - Fix a bug in the graph scheduler where some nodes might stay IDLE in
21
+ some cases (like when connecting the source of the echo-canceler to the
22
+ sink).
23
+ - pw-metadata can now be created from the factory with initial values for
24
+ the metadata. (#3076)
25
+ - Conditions were added to the pipewire config file to make it possible to
26
+ configure the access module and the exec sections.
27
+ - Support was added in pw-stream to intercept and override properties for
28
+ the adapter. This can be used to implement custom volume control, for
29
+ example.
30
+
31
+## Tools
32
+ - pw-metadata can now list all available metadata objects with the -l
33
+ option.
34
+ - A new pw-config tool was added to debug configuration file loading and
35
+ parsing.
36
+
37
+## Modules
38
+ - The webrtc echo canceler now supports beamforming. You can provide the
39
+ coordinates of the microphones and let webrtc perform beamforming on
40
+ the captured samples to improve quality and remove noise.
41
+ - Fix a regression in the filter-chain with biquad filters. (#3161) and
42
+ improve error reporting.
43
+ - The pulse-tunnel will now proxy the volume changes to the remote end.
44
+ - The RAOP sink will now send volume parameters to control the volume
45
+ remotely. (#2061)
46
+
47
+## SPA
48
+ - One ALSA commit was not correctly reverted and might cause crashes.
49
+ - The ALSA sink and source now calculate the ALSA ringbuffer memory
50
+ location more correctly wich might improve compatibility with some
51
+ hardware.
52
+ - v4l2 now sets the values of the controls in the Props param.
53
+
54
+## Pulse-server
55
+ - The echo-canceler aec_args are now parsed like they would be under
56
+ pulseaudio.
57
+
58
+## Bluetooth
59
+ - More work on synchronizing BAP devices.
60
+
61
+## GStreamer
62
+ - The GStreamer source can now renegotiate the format when it changes.
63
+ - The GStreamer source now uses the BaseSrc clocking code to implement
64
+ the clock and timing code.
65
+
66
+
67
+Older versions:
68
+
69
# PipeWire 0.3.69 (2023-04-13)
70
71
This is a quick bugfix release that is API and ABI compatible with previous
72
73
## GStreamer
74
- Fix the GStreamer clock to make cheese video recording work again. (#3149)
75
76
-
77
-Older versions:
78
-
79
# PipeWire 0.3.68 (2023-04-06)
80
81
This is a bugfix release that is API and ABI compatible with previous
82
pipewire-0.3.69.tar.gz/doc/pipewire-daemon.dox -> pipewire-0.3.70.tar.gz/doc/pipewire-daemon.dox
Changed
12
1
2
3
The first configuration file found is loaded as the base configuration.
4
5
-Next, configuration sections are collected in the directories in this
6
-order:
7
+Next, configuration sections (from files ending with a .conf extension) are collected
8
+in the directories in this order:
9
10
- `$datadir/pipewire/pipewire.conf.d/` (usually `/usr/share/pipewire/pipewire.conf.d/`)
11
- `$sysconfdir/pipewire/pipewire.conf.d/` (usually `/etc/pipewire/pipewire.conf.d/`)
12
pipewire-0.3.69.tar.gz/man/meson.build -> pipewire-0.3.70.tar.gz/man/meson.build
Changed
9
1
2
'pipewire.conf.5.rst.in',
3
'pw-cat.1.rst.in',
4
'pw-cli.1.rst.in',
5
+ 'pw-config.1.rst.in',
6
'pw-dot.1.rst.in',
7
'pw-link.1.rst.in',
8
'pw-metadata.1.rst.in',
9
pipewire-0.3.70.tar.gz/man/pw-config.1.rst.in
Added
112
1
2
+pw-config
3
+#########
4
+
5
+-----------------------------
6
+Debug PipeWire Config parsing
7
+-----------------------------
8
+
9
+:Manual section: 1
10
+:Manual group: General Commands Manual
11
+
12
+SYNOPSIS
13
+========
14
+
15
+| **pw-config** *options* paths
16
+
17
+| **pw-config** *options* list *SECTION*
18
+
19
+| **pw-config** *options* merge *SECTION*
20
+
21
+DESCRIPTION
22
+===========
23
+
24
+List config paths and config sections and display the parsed
25
+output.
26
+
27
+This tool can be used to get an overview of the config file that will be
28
+parsed by the PipeWire server and clients.
29
+
30
+COMMON OPTIONS
31
+==============
32
+
33
+-h | --help
34
+ Show help.
35
+
36
+--version
37
+ Show version information.
38
+
39
+-n | --name=NAME
40
+ Config Name (default 'pipewire.conf')
41
+
42
+-p | --prefix=PREFIX
43
+ Config Prefix (default '')
44
+
45
+-L | --no-newline
46
+ Omit newlines after values
47
+
48
+-r | --recurse
49
+ Reformat config sections recursively
50
+
51
+-N | --no-colors
52
+ Disable color output
53
+
54
+-C | --color=WHEN
55
+ whether to enable color support. WHEN is `never`, `always`, or `auto`
56
+
57
+LISTING PATHS
58
+=============
59
+
60
+Specify the paths command. It will display all the config files that will
61
+be parsed and in what order.
62
+
63
+LISTING CONFIG SECTIONS
64
+=======================
65
+
66
+Specify the list command with an optional *SECTION* to list the configuration
67
+fragments used for *SECTION*. Without a *SECTION*, all sections will be
68
+listed.
69
+
70
+Use the -r options to reformat the sections.
71
+
72
+MERGING A CONFIG SECTION
73
+========================
74
+
75
+With the merge option and a *SECTION*, pw-config will merge all config files into
76
+a merged config section and dump the results. This will be the section used by
77
+the client or server.
78
+
79
+Use the -r options to reformat the sections.
80
+
81
+EXAMPLES
82
+========
83
+
84
+**pw-config**
85
+ List all config files that will be used
86
+
87
+**pw-config** -n pipewire-pulse.conf
88
+ List all config files that will be used by the PipeWire pulseaudio server.
89
+
90
+**pw-config** -n pipewire-pulse.conf list
91
+ List all config sections used by the PipeWire pulseaudio server
92
+
93
+**pw-config** -n jack.conf list context.properties
94
+ List the context.properties fragments used by the JACK clients
95
+
96
+**pw-config** -n jack.conf merge context.properties
97
+ List the merged context.properties used by the JACK clients
98
+
99
+**pw-config** -n pipewire.conf -r merge context.modules
100
+ List the merged context.modules used by the PipeWire server and reformat
101
+
102
+AUTHORS
103
+=======
104
+
105
+The PipeWire Developers <@PACKAGE_BUGREPORT@>; PipeWire is available from @PACKAGE_URL@
106
+
107
+SEE ALSO
108
+========
109
+
110
+``pipewire(1)``,
111
+``pw-dump(1)``,
112
pipewire-0.3.69.tar.gz/man/pw-metadata.1.rst.in -> pipewire-0.3.70.tar.gz/man/pw-metadata.1.rst.in
Changed
11
1
2
--version
3
Show version information.
4
5
+-l | --list
6
+ List available metadata objects
7
+
8
-m | --monitor
9
Keeps running and log the changes to the metadata.
10
11
pipewire-0.3.69.tar.gz/meson.build -> pipewire-0.3.70.tar.gz/meson.build
Changed
8
1
2
project('pipewire', 'c' ,
3
- version : '0.3.69',
4
+ version : '0.3.70',
5
license : 'MIT', 'LGPL-2.1-or-later', 'GPL-2.0-only' ,
6
meson_version : '>= 0.61.1',
7
default_options : 'warning_level=3',
8
pipewire-0.3.69.tar.gz/spa/examples/adapter-control.c -> pipewire-0.3.70.tar.gz/spa/examples/adapter-control.c
Changed
11
1
2
int main(int argc, char *argv)
3
{
4
struct data data = { 0 };
5
- int res = 0;
6
- char c;
7
+ int res = 0, c;
8
9
/* default values*/
10
data.volume_ramp_samples = DEFAULT_RAMP_SAMPLES;
11
pipewire-0.3.69.tar.gz/spa/plugins/aec/aec-webrtc.cpp -> pipewire-0.3.70.tar.gz/spa/plugins/aec/aec-webrtc.cpp
Changed
117
1
2
#include <spa/support/log.h>
3
#include <spa/utils/string.h>
4
#include <spa/utils/names.h>
5
+#include <spa/utils/json.h>
6
#include <spa/support/plugin.h>
7
8
#include <webrtc/modules/audio_processing/include/audio_processing.h>
9
10
return default_value;
11
}
12
13
+
14
+/* f0 f1 f2 */
15
+static int parse_point(struct spa_json *it, float (&f)3)
16
+{
17
+ struct spa_json arr;
18
+ int i, res;
19
+
20
+ if (spa_json_enter_array(it, &arr) <= 0)
21
+ return -EINVAL;
22
+
23
+ for (i = 0; i < 3; i++) {
24
+ if ((res = spa_json_get_float(&arr, &fi)) <= 0)
25
+ return -EINVAL;
26
+ }
27
+ return 0;
28
+}
29
+
30
+/* point1 point2 ... */
31
+static int parse_mic_geometry(struct impl_data *impl, const char *mic_geometry,
32
+ std::vector<webrtc::Point>& geometry)
33
+{
34
+ int res;
35
+ size_t i;
36
+ struct spa_json it2;
37
+
38
+ spa_json_init(&it0, mic_geometry, strlen(mic_geometry));
39
+ if (spa_json_enter_array(&it0, &it1) <= 0) {
40
+ spa_log_error(impl->log, "Error: webrtc.mic-geometry expects an array");
41
+ return -EINVAL;
42
+ }
43
+
44
+ for (i = 0; i < geometry.size(); i++) {
45
+ float f3;
46
+
47
+ if ((res = parse_point(&it1, f)) < 0) {
48
+ spa_log_error(impl->log, "Error: can't parse webrtc.mic-geometry points: %d", res);
49
+ return res;
50
+ }
51
+
52
+ spa_log_info(impl->log, "mic %zd position: (%g %g %g)", i, f0, f1, f2);
53
+ geometryi.c0 = f0;
54
+ geometryi.c1 = f1;
55
+ geometryi.c2 = f2;
56
+ }
57
+ return 0;
58
+}
59
+
60
static int webrtc_init2(void *object, const struct spa_dict *args,
61
struct spa_audio_info_raw *rec_info, struct spa_audio_info_raw *out_info,
62
struct spa_audio_info_raw *play_info)
63
64
bool experimental_agc = webrtc_get_spa_bool(args, "webrtc.experimental_agc", false);
65
bool experimental_ns = webrtc_get_spa_bool(args, "webrtc.experimental_ns", false);
66
67
+ bool beamforming = webrtc_get_spa_bool(args, "webrtc.beamforming", false);
68
+
69
// FIXME: Intelligibility enhancer is not currently supported
70
// This filter will modify playback buffer (when calling ProcessReverseStream), but now
71
// playback buffer modifications are discarded.
72
73
config.Set<webrtc::ExperimentalAgc>(new webrtc::ExperimentalAgc(experimental_agc));
74
config.Set<webrtc::ExperimentalNs>(new webrtc::ExperimentalNs(experimental_ns));
75
76
+ if (beamforming) {
77
+ std::vector<webrtc::Point> geometry(rec_info->channels);
78
+ const char *mic_geometry, *target_direction;
79
+
80
+ /* The beamformer gives a single mono channel */
81
+ out_info->channels = 1;
82
+ out_info->position0 = SPA_AUDIO_CHANNEL_MONO;
83
+
84
+ if ((mic_geometry = spa_dict_lookup(args, "webrtc.mic-geometry")) == NULL) {
85
+ spa_log_error(impl->log, "Error: webrtc.beamforming requires webrtc.mic-geometry");
86
+ return -EINVAL;
87
+ }
88
+
89
+ if ((res = parse_mic_geometry(impl, mic_geometry, geometry)) < 0)
90
+ return res;
91
+
92
+ if ((target_direction = spa_dict_lookup(args, "webrtc.target-direction")) != NULL) {
93
+ webrtc::SphericalPointf direction(0.0f, 0.0f, 0.0f);
94
+ struct spa_json it;
95
+ float f3;
96
+
97
+ spa_json_init(&it, target_direction, strlen(target_direction));
98
+ if (parse_point(&it, f) < 0) {
99
+ spa_log_error(impl->log, "Error: can't parse target-direction %s",
100
+ target_direction);
101
+ return -EINVAL;
102
+ }
103
+
104
+ direction.s0 = f0;
105
+ direction.s1 = f1;
106
+ direction.s2 = f2;
107
+
108
+ config.Set<webrtc::Beamforming>(new webrtc::Beamforming(true, geometry, direction));
109
+ } else {
110
+ config.Set<webrtc::Beamforming>(new webrtc::Beamforming(true, geometry));
111
+ }
112
+ }
113
+
114
webrtc::ProcessingConfig pconfig = {{
115
webrtc::StreamConfig(rec_info->rate, rec_info->channels, false), /* input stream */
116
webrtc::StreamConfig(out_info->rate, out_info->channels, false), /* output stream */
117
pipewire-0.3.69.tar.gz/spa/plugins/alsa/acp/alsa-util.c -> pipewire-0.3.70.tar.gz/spa/plugins/alsa/acp/alsa-util.c
Changed
26
1
2
} else if (mask & SND_CTL_EVENT_MASK_ADD) {
3
snd_ctl_elem_iface_t iface = snd_hctl_elem_get_interface(helem);
4
if (iface == SND_CTL_ELEM_IFACE_CARD || iface == SND_CTL_ELEM_IFACE_PCM) {
5
- snd_mixer_t *mixer = snd_mixer_class_get_mixer(class);
6
- snd_ctl_elem_iface_t iface = snd_hctl_elem_get_interface(helem);
7
- const char *name = snd_hctl_elem_get_name(helem);
8
- const int index = snd_hctl_elem_get_index(helem);
9
- const int device = snd_hctl_elem_get_device(helem);
10
snd_mixer_elem_t *new_melem;
11
12
- new_melem = pa_alsa_mixer_find(mixer, iface, name, index, device);
13
- if (!new_melem) {
14
- /* Put the hctl pointer as our private data - it will be useful for callbacks */
15
- if ((err = snd_mixer_elem_new(&new_melem, SND_MIXER_ELEM_PULSEAUDIO, 0, helem, NULL)) < 0) {
16
- pa_log_warn("snd_mixer_elem_new failed: %s", pa_alsa_strerror(err));
17
- return 0;
18
- }
19
+ /* Put the hctl pointer as our private data - it will be useful for callbacks */
20
+ if ((err = snd_mixer_elem_new(&new_melem, SND_MIXER_ELEM_PULSEAUDIO, 0, helem, NULL)) < 0) {
21
+ pa_log_warn("snd_mixer_elem_new failed: %s", pa_alsa_strerror(err));
22
+ return 0;
23
}
24
25
if ((err = snd_mixer_elem_attach(new_melem, helem)) < 0) {
26
pipewire-0.3.69.tar.gz/spa/plugins/alsa/alsa-pcm.c -> pipewire-0.3.70.tar.gz/spa/plugins/alsa/alsa-pcm.c
Changed
24
1
2
3
if (SPA_LIKELY(state->use_mmap)) {
4
for (i = 0; i < b->buf->n_datas; i++) {
5
- spa_memcpy(SPA_PTROFF(my_areasi.addr, off * frame_size, void),
6
+ spa_memcpy(channel_area_addr(&my_areasi, off),
7
SPA_PTROFF(di.data, offs, void), n_bytes);
8
}
9
} else {
10
11
12
for (i = 0; i < b->buf->n_datas; i++) {
13
spa_memcpy(di.data,
14
- SPA_PTROFF(my_areasi.addr, offset * frame_size, void),
15
+ channel_area_addr(&my_areasi, offset),
16
l0);
17
if (SPA_UNLIKELY(l1 > 0))
18
spa_memcpy(SPA_PTROFF(di.data, l0, void),
19
- my_areasi.addr,
20
+ channel_area_addr(&my_areasi, 0),
21
l1);
22
di.chunk->offset = 0;
23
di.chunk->size = n_bytes;
24
pipewire-0.3.69.tar.gz/spa/plugins/alsa/alsa-pcm.h -> pipewire-0.3.70.tar.gz/spa/plugins/alsa/alsa-pcm.h
Changed
22
1
2
#include <math.h>
3
4
#include <alsa/asoundlib.h>
5
+#include <alsa/version.h>
6
#include <alsa/use-case.h>
7
8
#include <spa/support/plugin.h>
9
10
return missed;
11
}
12
13
+/* This function is also as snd_pcm_channel_area_addr() since 1.2.6 which is not yet
14
+ * in ubuntu and I can't figure out how to do the ALSA version check. */
15
+static inline void *channel_area_addr(const snd_pcm_channel_area_t *area, snd_pcm_uframes_t offset)
16
+{
17
+ return (char *)area->addr + (area->first + area->step * offset) / 8;
18
+}
19
20
#ifdef __cplusplus
21
} /* extern "C" */
22
pipewire-0.3.69.tar.gz/spa/plugins/audioconvert/audioadapter.c -> pipewire-0.3.70.tar.gz/spa/plugins/audioconvert/audioadapter.c
Changed
29
1
2
uint64_t follower_flags;
3
struct spa_audio_info follower_current_format;
4
struct spa_audio_info default_format;
5
+ int in_set_param;
6
7
struct spa_handle *hnd_convert;
8
struct spa_node *convert;
9
10
}
11
12
case SPA_PARAM_Props:
13
- if (this->target != this->follower)
14
- res = spa_node_set_param(this->target, id, flags, param);
15
- res2 = spa_node_set_param(this->follower, id, flags, param);
16
+ {
17
+ int in_set_param = ++this->in_set_param;
18
+ res = spa_node_set_param(this->follower, id, flags, param);
19
+ if (this->target != this->follower && this->in_set_param == in_set_param)
20
+ res2 = spa_node_set_param(this->target, id, flags, param);
21
if (res < 0 && res2 < 0)
22
return res;
23
res = 0;
24
break;
25
+ }
26
case SPA_PARAM_ProcessLatency:
27
res = spa_node_set_param(this->follower, id, flags, param);
28
break;
29
pipewire-0.3.69.tar.gz/spa/plugins/bluez5/bluez5-dbus.c -> pipewire-0.3.70.tar.gz/spa/plugins/bluez5/bluez5-dbus.c
Changed
120
1
2
else if (spa_streq(key, "State")) {
3
enum spa_bt_transport_state state = spa_bt_transport_state_from_string(value);
4
5
- /* Emit transition to active only for transports with
6
- * acquired fd. If the acquire completes after prop
7
- * update, we set the state in acquire completion. BlueZ
8
- * currently sends events in the order where this never
9
- * happens, but let's not rely on that.
10
- */
11
- if (state != SPA_BT_TRANSPORT_STATE_ACTIVE || transport->fd >= 0)
12
+ /* Transition to active emitted only from acquire callback. */
13
+ if (state != SPA_BT_TRANSPORT_STATE_ACTIVE)
14
spa_bt_transport_set_state(transport, state);
15
}
16
else if (spa_streq(key, "Device")) {
17
18
{
19
struct spa_bt_monitor *monitor = transport->monitor;
20
struct spa_bt_transport *t;
21
- bool sink = (transport->profile & SPA_BT_PROFILE_BAP_SINK) != 0;
22
23
if (!(transport->profile & (SPA_BT_PROFILE_BAP_SINK | SPA_BT_PROFILE_BAP_SOURCE)))
24
return 0;
25
26
if (t->iso_io) {
27
spa_log_debug(monitor->log, "transport %p: attach ISO IO to %p",
28
transport, t);
29
- transport->iso_io = spa_bt_iso_io_attach(t->iso_io, transport->fd, sink);
30
+ transport->iso_io = spa_bt_iso_io_attach(t->iso_io, transport);
31
+ if (transport->iso_io == NULL)
32
+ return -errno;
33
return 0;
34
}
35
}
36
37
spa_log_debug(monitor->log, "transport %p: new ISO IO", transport);
38
- transport->iso_io = spa_bt_iso_io_create(transport->fd, sink,
39
- transport->bap_cig, transport->bap_interval,
40
- monitor->log, monitor->data_loop, monitor->data_system);
41
+ transport->iso_io = spa_bt_iso_io_create(transport, monitor->log, monitor->data_loop, monitor->data_system);
42
if (transport->iso_io == NULL)
43
return -errno;
44
45
return 0;
46
}
47
48
+static bool transport_in_same_cig(struct spa_bt_transport *transport, struct spa_bt_transport *other)
49
+{
50
+ return (other->profile & (SPA_BT_PROFILE_BAP_SINK | SPA_BT_PROFILE_BAP_SOURCE)) &&
51
+ other->bap_cig == transport->bap_cig &&
52
+ other->bap_initiator;
53
+}
54
+
55
static void transport_acquire_reply(DBusPendingCall *pending, void *user_data)
56
{
57
struct spa_bt_transport *transport = user_data;
58
59
int ret = 0;
60
DBusError err;
61
DBusMessage *r;
62
- struct spa_bt_transport *t_linked;
63
+ struct spa_bt_transport *t, *t_linked;
64
65
r = dbus_pending_call_steal_reply(pending);
66
67
68
spa_log_error(monitor->log, "transport %p: transport_create_iso_io failed",
69
transport);
70
71
- spa_bt_transport_set_state(transport, SPA_BT_TRANSPORT_STATE_ACTIVE);
72
+ if (!transport->bap_initiator)
73
+ spa_bt_transport_set_state(transport, SPA_BT_TRANSPORT_STATE_ACTIVE);
74
}
75
76
/* For LE Audio, multiple transport from the same device may share the same
77
78
spa_log_error(monitor->log, "transport %p: transport_create_iso_io failed",
79
t_linked);
80
81
- spa_bt_transport_set_state(t_linked, SPA_BT_TRANSPORT_STATE_ACTIVE);
82
+ if (!transport->bap_initiator)
83
+ spa_bt_transport_set_state(t_linked, SPA_BT_TRANSPORT_STATE_ACTIVE);
84
+ }
85
+
86
+ /*
87
+ * Transports in same CIG emit state change events at the same time,
88
+ * after all pending acquires complete.
89
+ */
90
+ if (transport->bap_initiator) {
91
+ spa_list_for_each(t, &monitor->transport_list, link) {
92
+ if (!transport_in_same_cig(transport, t))
93
+ continue;
94
+ if (t->acquire_call)
95
+ return;
96
+ }
97
+ spa_list_for_each(t, &monitor->transport_list, link) {
98
+ if (!transport_in_same_cig(transport, t))
99
+ continue;
100
+ if (t->fd >= 0)
101
+ spa_bt_transport_set_state(t, SPA_BT_TRANSPORT_STATE_ACTIVE);
102
+ }
103
}
104
}
105
106
107
return 0;
108
}
109
110
-static bool transport_in_same_cig(struct spa_bt_transport *transport, struct spa_bt_transport *other)
111
-{
112
- return (other->profile & (SPA_BT_PROFILE_BAP_SINK | SPA_BT_PROFILE_BAP_SOURCE)) &&
113
- other->bap_cig == transport->bap_cig &&
114
- other->bap_initiator;
115
-}
116
-
117
static bool another_cig_transport_active(struct spa_bt_transport *transport)
118
{
119
struct spa_bt_monitor *monitor = transport->monitor;
120
pipewire-0.3.69.tar.gz/spa/plugins/bluez5/dbus-monitor.c -> pipewire-0.3.70.tar.gz/spa/plugins/bluez5/dbus-monitor.c
Changed
10
1
2
monitor, g_dbus_object_get_object_path(object), name ? name : "<null>");
3
4
if (g_object_get_data(G_OBJECT(iface), "dbus-monitor-signals-connected")) {
5
- g_object_disconnect(G_OBJECT(iface), "g-properties-changed",
6
+ g_object_disconnect(G_OBJECT(iface), "any_signal",
7
G_CALLBACK(on_g_properties_changed),
8
monitor, NULL);
9
g_object_set_data(G_OBJECT(iface), "dbus-monitor-signals-connected", NULL);
10
pipewire-0.3.69.tar.gz/spa/plugins/bluez5/iso-io.c -> pipewire-0.3.70.tar.gz/spa/plugins/bluez5/iso-io.c
Changed
331
1
2
#include "config.h"
3
#include "iso-io.h"
4
5
+#include "media-codecs.h"
6
+#include "defs.h"
7
+
8
static struct spa_log_topic log_topic = SPA_LOG_TOPIC(0, "spa.bluez5.iso");
9
#undef SPA_LOG_TOPIC_DEFAULT
10
#define SPA_LOG_TOPIC_DEFAULT &log_topic
11
12
-#define IDLE_TIME (200 * SPA_NSEC_PER_MSEC)
13
+#define IDLE_TIME (500 * SPA_NSEC_PER_MSEC)
14
+#define EMPTY_BUF_SIZE 65536
15
16
struct group {
17
struct spa_log *log;
18
19
uint64_t next;
20
uint64_t duration;
21
uint32_t paused;
22
+ bool started;
23
};
24
25
struct stream {
26
27
bool idle;
28
29
spa_bt_iso_io_pull_t pull;
30
+
31
+ const struct media_codec *codec;
32
+ uint32_t block_size;
33
};
34
35
struct modify_info
36
37
spa_assert_se(res == 0);
38
}
39
40
+static int stream_silence(struct stream *stream)
41
+{
42
+ static uint8_t emptyEMPTY_BUF_SIZE = {0};
43
+ const size_t max_size = sizeof(stream->this.buf);
44
+ int res, used, need_flush;
45
+ size_t encoded;
46
+
47
+ stream->idle = true;
48
+
49
+ res = used = stream->codec->start_encode(stream->this.codec_data, stream->this.buf, max_size, 0, 0);
50
+ if (res < 0)
51
+ return res;
52
+
53
+ res = stream->codec->encode(stream->this.codec_data, empty, stream->block_size,
54
+ SPA_PTROFF(stream->this.buf, used, void), max_size - used, &encoded, &need_flush);
55
+ if (res < 0)
56
+ return res;
57
+
58
+ used += encoded;
59
+
60
+ if (!need_flush)
61
+ return -EINVAL;
62
+
63
+ stream->this.size = used;
64
+ return 0;
65
+}
66
+
67
static int set_timeout(struct group *group, uint64_t time)
68
{
69
struct itimerspec ts;
70
71
{
72
struct group *group = source->data;
73
struct stream *stream;
74
+ bool resync = false;
75
+ bool fail = false;
76
uint64_t exp;
77
int res;
78
- bool active = false;
79
80
if ((res = spa_system_timerfd_read(group->data_system, group->timerfd, &exp)) < 0) {
81
if (res != -EAGAIN)
82
83
}
84
85
/*
86
- * If an idle stream activates when another stream is already active,
87
- * pause output of all streams for a while to avoid desynchronization.
88
+ * If a stream failed, pause output of all streams for a while to avoid
89
+ * desynchronization.
90
*/
91
spa_list_for_each(stream, &group->streams, link) {
92
if (!stream->sink)
93
continue;
94
- if (!stream->idle) {
95
- active = true;
96
- break;
97
- }
98
- }
99
100
- spa_list_for_each(stream, &group->streams, link) {
101
- if (!stream->sink)
102
- continue;
103
-
104
- if (stream->idle && stream->this.size > 0 && active && !group->paused)
105
- group->paused = 1u + IDLE_TIME / group->duration;
106
+ if (stream->this.need_resync) {
107
+ resync = true;
108
+ stream->this.need_resync = false;
109
+ }
110
111
- stream->idle = (stream->this.size == 0);
112
+ if (!group->started && !stream->idle && stream->this.size > 0)
113
+ group->started = true;
114
}
115
116
if (group->paused) {
117
118
119
if (!stream->sink)
120
continue;
121
- if (stream->idle || group->paused) {
122
+ if (group->paused || !group->started) {
123
stream->this.resync = true;
124
stream->this.size = 0;
125
continue;
126
}
127
+ if (stream->this.size == 0) {
128
+ spa_log_debug(group->log, "%p: ISO group:%u miss fd:%d",
129
+ group, group->cig, stream->fd);
130
+ if (stream_silence(stream) < 0) {
131
+ fail = true;
132
+ continue;
133
+ }
134
+ }
135
136
res = send(stream->fd, stream->this.buf, stream->this.size, MSG_DONTWAIT | MSG_NOSIGNAL);
137
- if (res < 0)
138
+ if (res < 0) {
139
res = -errno;
140
+ fail = true;
141
+ }
142
143
- spa_log_trace(group->log, "%p: ISO group:%u sent fd:%d size:%u ts:%u res:%d",
144
+ spa_log_trace(group->log, "%p: ISO group:%u sent fd:%d size:%u ts:%u idle:%d res:%d",
145
group, group->cig, stream->fd, (unsigned)stream->this.size,
146
- (unsigned)stream->this.timestamp, res);
147
+ (unsigned)stream->this.timestamp, stream->idle, res);
148
149
stream->this.size = 0;
150
}
151
152
+ if (fail)
153
+ group->paused = 1u + IDLE_TIME / group->duration;
154
+
155
/* Pull data for the next interval */
156
group->next += exp * group->duration;
157
158
159
if (!stream->sink)
160
continue;
161
162
+ if (resync)
163
+ stream->this.resync = true;
164
+
165
if (stream->pull) {
166
+ stream->idle = false;
167
stream->this.now = group->next;
168
stream->pull(&stream->this);
169
} else {
170
- stream->this.size = 0;
171
+ stream_silence(stream);
172
}
173
}
174
175
set_timeout(group, group->next);
176
}
177
178
-static struct group *group_create(uint8_t cig, uint32_t interval,
179
+static struct group *group_create(struct spa_bt_transport *t,
180
struct spa_log *log, struct spa_loop *data_loop, struct spa_system *data_system)
181
{
182
struct group *group;
183
184
- if (interval <= 5000) {
185
+ if (t->bap_interval <= 5000) {
186
errno = EINVAL;
187
return NULL;
188
}
189
190
191
spa_log_topic_init(log, &log_topic);
192
193
- group->cig = cig;
194
+ group->cig = t->bap_cig;
195
group->log = log;
196
group->data_loop = data_loop;
197
group->data_system = data_system;
198
- group->duration = interval * SPA_NSEC_PER_USEC;
199
+ group->duration = t->bap_interval * SPA_NSEC_PER_USEC;
200
201
spa_list_init(&group->streams);
202
203
204
free(group);
205
}
206
207
-struct stream *stream_create(int fd, bool sink, struct group *group)
208
+struct stream *stream_create(struct spa_bt_transport *t, struct group *group)
209
{
210
struct stream *stream;
211
+ void *codec_data = NULL;
212
+ int block_size = 0;
213
+ struct spa_audio_info format = { 0 };
214
+ int res;
215
+ bool sink = (t->profile & SPA_BT_PROFILE_BAP_SINK) != 0;
216
+
217
+ if (!t->media_codec->bap) {
218
+ res = -EINVAL;
219
+ goto fail;
220
+ }
221
+
222
+ if (sink) {
223
+ res = t->media_codec->validate_config(t->media_codec, 0, t->configuration, t->configuration_len, &format);
224
+ if (res < 0)
225
+ goto fail;
226
+
227
+ codec_data = t->media_codec->init(t->media_codec, 0, t->configuration, t->configuration_len,
228
+ &format, NULL, t->write_mtu);
229
+ if (!codec_data) {
230
+ res = -EINVAL;
231
+ goto fail;
232
+ }
233
+
234
+ block_size = t->media_codec->get_block_size(codec_data);
235
+ if (block_size < 0 || block_size > EMPTY_BUF_SIZE) {
236
+ res = -EINVAL;
237
+ goto fail;
238
+ }
239
+ }
240
241
stream = calloc(1, sizeof(struct stream));
242
if (stream == NULL)
243
- return NULL;
244
+ goto fail_errno;
245
246
- stream->fd = fd;
247
+ stream->fd = t->fd;
248
stream->sink = sink;
249
stream->group = group;
250
- stream->idle = true;
251
stream->this.duration = group->duration;
252
253
+ stream->codec = t->media_codec;
254
+ stream->this.codec_data = codec_data;
255
+ stream->this.format = format;
256
+ stream->block_size = block_size;
257
+
258
+ if (sink)
259
+ stream_silence(stream);
260
+
261
stream_link(group, stream);
262
263
return stream;
264
+
265
+fail_errno:
266
+ res = -errno;
267
+fail:
268
+ if (codec_data)
269
+ t->media_codec->deinit(codec_data);
270
+ errno = -res;
271
+ return NULL;
272
}
273
274
-struct spa_bt_iso_io *spa_bt_iso_io_create(int fd, bool sink, uint8_t cig, uint32_t interval,
275
+struct spa_bt_iso_io *spa_bt_iso_io_create(struct spa_bt_transport *t,
276
struct spa_log *log, struct spa_loop *data_loop, struct spa_system *data_system)
277
{
278
struct stream *stream;
279
struct group *group;
280
281
- group = group_create(cig, interval, log, data_loop, data_system);
282
+ group = group_create(t, log, data_loop, data_system);
283
if (group == NULL)
284
return NULL;
285
286
- stream = stream_create(fd, sink, group);
287
+ stream = stream_create(t, group);
288
if (stream == NULL) {
289
int err = errno;
290
group_destroy(group);
291
292
return &stream->this;
293
}
294
295
-struct spa_bt_iso_io *spa_bt_iso_io_attach(struct spa_bt_iso_io *this, int fd, bool sink)
296
+struct spa_bt_iso_io *spa_bt_iso_io_attach(struct spa_bt_iso_io *this, struct spa_bt_transport *t)
297
{
298
struct stream *stream = SPA_CONTAINER_OF(this, struct stream, this);
299
300
- stream = stream_create(fd, sink, stream->group);
301
+ stream = stream_create(t, stream->group);
302
if (stream == NULL)
303
return NULL;
304
305
306
if (spa_list_is_empty(&stream->group->streams))
307
group_destroy(stream->group);
308
309
+ if (stream->this.codec_data)
310
+ stream->codec->deinit(stream->this.codec_data);
311
+ stream->this.codec_data = NULL;
312
+
313
free(stream);
314
}
315
316
317
318
enabled = group_is_enabled(stream->group);
319
320
- if (!enabled && was_enabled)
321
+ if (!enabled && was_enabled) {
322
+ stream->group->started = false;
323
set_timeout(stream->group, 0);
324
- else if (enabled && !was_enabled)
325
+ } else if (enabled && !was_enabled) {
326
set_timers(stream->group);
327
+ }
328
329
stream->idle = true;
330
stream->this.resync = true;
331
pipewire-0.3.69.tar.gz/spa/plugins/bluez5/iso-io.h -> pipewire-0.3.70.tar.gz/spa/plugins/bluez5/iso-io.h
Changed
33
1
2
#include <spa/support/loop.h>
3
#include <spa/support/log.h>
4
#include <spa/node/io.h>
5
+#include <spa/param/audio/format.h>
6
+
7
+struct spa_bt_transport;
8
9
/**
10
* ISO I/O.
11
12
uint32_t timestamp; /**< Packet timestamp (set by pull callback) */
13
uint8_t buf4096; /**< Packet data (set by pull callback) */
14
size_t size; /**< Packet size (set by pull callback) */
15
+ bool need_resync; /**< Resync requested (set by pull callback) */
16
+
17
+ struct spa_audio_info format; /**< Audio format */
18
+ void *codec_data; /**< Codec data */
19
20
void *user_data;
21
};
22
23
typedef void (*spa_bt_iso_io_pull_t)(struct spa_bt_iso_io *io);
24
25
-struct spa_bt_iso_io *spa_bt_iso_io_create(int fd, bool sink, uint8_t cig, uint32_t interval,
26
+struct spa_bt_iso_io *spa_bt_iso_io_create(struct spa_bt_transport *t,
27
struct spa_log *log, struct spa_loop *data_loop, struct spa_system *data_system);
28
-struct spa_bt_iso_io *spa_bt_iso_io_attach(struct spa_bt_iso_io *io, int fd, bool sink);
29
+struct spa_bt_iso_io *spa_bt_iso_io_attach(struct spa_bt_iso_io *io, struct spa_bt_transport *t);
30
void spa_bt_iso_io_destroy(struct spa_bt_iso_io *io);
31
void spa_bt_iso_io_set_cb(struct spa_bt_iso_io *io, spa_bt_iso_io_pull_t pull, void *user_data);
32
33
pipewire-0.3.69.tar.gz/spa/plugins/bluez5/media-sink.c -> pipewire-0.3.70.tar.gz/spa/plugins/bluez5/media-sink.c
Changed
110
1
2
unsigned int is_output:1;
3
unsigned int flush_pending:1;
4
unsigned int iso_pending:1;
5
+ unsigned int own_codec_data:1;
6
7
unsigned int is_duplex:1;
8
unsigned int is_internal:1;
9
10
err = value - target;
11
max_err = iso_io->duration;
12
13
- if (err > max_err || (iso_io->resync && err > 0)) {
14
+ if (iso_io->resync && err >= 0) {
15
unsigned int req = err * port->current_format.info.raw.rate / SPA_NSEC_PER_SEC;
16
17
if (req > 0) {
18
spa_bt_rate_control_init(&port->ratectl, 0);
19
drop_frames(this, req);
20
- spa_log_debug(this->log, "%p: ISO sync skip frames:%u resync:%d",
21
- this, req, iso_io->resync);
22
}
23
- } else if (-err > max_err || (iso_io->resync && -err > 0)) {
24
+ spa_log_debug(this->log, "%p: ISO sync skip frames:%u", this, req);
25
+ } else if (iso_io->resync && -err >= 0) {
26
unsigned int req = -err * port->current_format.info.raw.rate / SPA_NSEC_PER_SEC;
27
static const uint8_t empty8192 = {0};
28
29
30
spa_bt_rate_control_init(&port->ratectl, 0);
31
req = SPA_MIN(req, sizeof(empty) / port->frame_size);
32
add_data(this, empty, req * port->frame_size);
33
- spa_log_debug(this->log, "%p: ISO sync pad frames:%u resync:%d",
34
- this, req, iso_io->resync);
35
}
36
+ spa_log_debug(this->log, "%p: ISO sync pad frames:%u", this, req);
37
+ } else if (err > max_err || -err > max_err) {
38
+ iso_io->need_resync = true;
39
+ spa_log_debug(this->log, "%p: ISO sync need resync err:%+.3f",
40
+ this, err / SPA_NSEC_PER_MSEC);
41
} else {
42
spa_bt_rate_control_update(&port->ratectl, err, 0,
43
iso_io->duration, period, RATE_CTL_DIFF_MAX);
44
45
46
flags = this->is_duplex ? MEDIA_CODEC_FLAG_SINK : 0;
47
48
- this->codec_data = this->codec->init(this->codec,
49
- flags,
50
- this->transport->configuration,
51
- this->transport->configuration_len,
52
- &port->current_format,
53
- this->codec_props,
54
- this->transport->write_mtu);
55
- if (this->codec_data == NULL)
56
- return -EIO;
57
+ if (!this->transport->iso_io) {
58
+ this->own_codec_data = true;
59
+ this->codec_data = this->codec->init(this->codec,
60
+ flags,
61
+ this->transport->configuration,
62
+ this->transport->configuration_len,
63
+ &port->current_format,
64
+ this->codec_props,
65
+ this->transport->write_mtu);
66
+ if (this->codec_data == NULL)
67
+ return -EIO;
68
+ } else {
69
+ this->own_codec_data = false;
70
+ this->codec_data = this->transport->iso_io->codec_data;
71
+ this->codec_props_changed = true;
72
+ }
73
74
spa_log_info(this->log, "%p: using %s codec %s, delay:%"PRIi64" ms", this,
75
this->codec->bap ? "BAP" : "A2DP", this->codec->description,
76
77
78
spa_loop_invoke(this->data_loop, do_remove_transport_source, 0, NULL, 0, true, this);
79
80
- if (this->codec_data)
81
+ if (this->codec_data && this->own_codec_data)
82
this->codec->deinit(this->codec_data);
83
this->codec_data = NULL;
84
}
85
86
info.info.raw.channels > SPA_AUDIO_MAX_CHANNELS)
87
return -EINVAL;
88
89
+ if (this->transport && this->transport->iso_io) {
90
+ if (memcmp(&info.info.raw, &this->transport->iso_io->format.info.raw,
91
+ sizeof(info.info.raw))) {
92
+ spa_log_error(this->log, "unexpected incompatible "
93
+ "BAP audio format");
94
+ return -EINVAL;
95
+ }
96
+ }
97
+
98
port->frame_size = info.info.raw.channels;
99
switch (info.info.raw.format) {
100
case SPA_AUDIO_FORMAT_S16:
101
102
else
103
transport_stop(this);
104
105
- if (state < SPA_BT_TRANSPORT_STATE_ACTIVE && was_started) {
106
+ if (state < SPA_BT_TRANSPORT_STATE_ACTIVE && was_started && !this->is_duplex && this->is_output) {
107
/*
108
* If establishing connection fails due to remote end not activating
109
* the transport, we won't get a write error, but instead see a transport
110
pipewire-0.3.69.tar.gz/spa/plugins/bluez5/media-source.c -> pipewire-0.3.70.tar.gz/spa/plugins/bluez5/media-source.c
Changed
10
1
2
io->buffer_id = SPA_ID_INVALID;
3
}
4
5
- if (!this->source.loop) {
6
+ if (this->transport_started && !this->source.loop) {
7
io->status = -EIO;
8
return SPA_STATUS_STOPPED;
9
}
10
pipewire-0.3.69.tar.gz/spa/plugins/support/logger.c -> pipewire-0.3.70.tar.gz/spa/plugins/support/logger.c
Changed
58
1
2
{
3
struct impl *this;
4
struct spa_loop *loop = NULL;
5
- const char *str;
6
+ const char *str, *dest = "";
7
+ bool linebuf = false;
8
9
spa_return_val_if_fail(factory != NULL, -EINVAL);
10
spa_return_val_if_fail(handle != NULL, -EINVAL);
11
12
if ((str = spa_dict_lookup(info, SPA_KEY_LOG_LEVEL)) != NULL)
13
this->log.level = atoi(str);
14
if ((str = spa_dict_lookup(info, SPA_KEY_LOG_FILE)) != NULL) {
15
- this->file = fopen(str, "we");
16
- if (this->file == NULL)
17
- fprintf(stderr, "Warning: failed to open file %s: (%m)", str);
18
- else
19
- this->close_file = true;
20
+ dest = str;
21
+ if (spa_streq(str, "stderr"))
22
+ this->file = stderr;
23
+ else if (spa_streq(str, "stdout"))
24
+ this->file = stdout;
25
+ else {
26
+ this->file = fopen(str, "we");
27
+ if (this->file == NULL)
28
+ fprintf(stderr, "Warning: failed to open file %s: (%m)", str);
29
+ else
30
+ this->close_file = true;
31
+ }
32
}
33
if ((str = spa_dict_lookup(info, SPA_KEY_LOG_PATTERNS)) != NULL)
34
support_log_parse_patterns(&this->patterns, str);
35
}
36
- if (this->file == NULL)
37
+ if (this->file == NULL) {
38
this->file = stderr;
39
+ dest = "stderr";
40
+ } else {
41
+ linebuf = true;
42
+ }
43
+ if (linebuf)
44
+ setlinebuf(this->file);
45
+
46
if (!isatty(fileno(this->file)))
47
this->colors = false;
48
49
spa_ringbuffer_init(&this->trace_rb);
50
51
- spa_log_debug(&this->log, NAME " %p: initialized", this);
52
-
53
- setlinebuf(this->file);
54
+ spa_log_debug(&this->log, NAME " %p: initialized to %s linebuf:%u", this, dest, linebuf);
55
56
return 0;
57
}
58
pipewire-0.3.69.tar.gz/spa/plugins/v4l2/v4l2-source.c -> pipewire-0.3.70.tar.gz/spa/plugins/v4l2/v4l2-source.c
Changed
142
1
2
struct control {
3
uint32_t id;
4
uint32_t ctrl_id;
5
- double value;
6
+ uint32_t type;
7
+ int32_t value;
8
};
9
10
struct port {
11
12
13
#include "v4l2-utils.c"
14
15
+static const struct spa_dict_item info_items = {
16
+ { SPA_KEY_DEVICE_API, "v4l2" },
17
+ { SPA_KEY_MEDIA_CLASS, "Video/Source" },
18
+ { SPA_KEY_MEDIA_ROLE, "Camera" },
19
+ { SPA_KEY_NODE_DRIVER, "true" },
20
+};
21
+
22
+static void emit_node_info(struct impl *this, bool full)
23
+{
24
+ uint64_t old = full ? this->info.change_mask : 0;
25
+ if (full)
26
+ this->info.change_mask = this->info_all;
27
+ if (this->info.change_mask) {
28
+ this->info.props = &SPA_DICT_INIT_ARRAY(info_items);
29
+ spa_node_emit_info(&this->hooks, &this->info);
30
+ this->info.change_mask = old;
31
+ }
32
+}
33
+
34
+static void emit_port_info(struct impl *this, struct port *port, bool full)
35
+{
36
+ uint64_t old = full ? port->info.change_mask : 0;
37
+ if (full)
38
+ port->info.change_mask = port->info_all;
39
+ if (port->info.change_mask) {
40
+ spa_node_emit_port_info(&this->hooks,
41
+ SPA_DIRECTION_OUTPUT, 0, &port->info);
42
+ port->info.change_mask = old;
43
+ }
44
+}
45
+
46
static int port_get_format(struct port *port,
47
uint32_t index,
48
const struct spa_pod *filter,
49
50
case SPA_PARAM_Props:
51
{
52
struct props *p = &this->props;
53
+ struct spa_pod_frame f;
54
+ struct port *port = &this->out_ports0;
55
+ uint32_t i;
56
+
57
+ if ((res = spa_v4l2_update_controls(this)) < 0) {
58
+ spa_log_error(this->log, "error: %s", spa_strerror(res));
59
+ return res;
60
+ }
61
62
switch (result.index) {
63
case 0:
64
- param = spa_pod_builder_add_object(&b,
65
- SPA_TYPE_OBJECT_Props, id,
66
+ spa_pod_builder_push_object(&b, &f, SPA_TYPE_OBJECT_Props, id);
67
+ spa_pod_builder_add(&b,
68
SPA_PROP_device, SPA_POD_String(p->device),
69
SPA_PROP_deviceName, SPA_POD_String(p->device_name),
70
- SPA_PROP_deviceFd, SPA_POD_Int(p->device_fd));
71
+ SPA_PROP_deviceFd, SPA_POD_Int(p->device_fd),
72
+ 0);
73
+ for (i = 0; i < port->n_controls; i++) {
74
+ struct control *c = &port->controlsi;
75
+
76
+ spa_pod_builder_prop(&b, c->id, 0);
77
+ switch (c->type) {
78
+ case SPA_TYPE_Int:
79
+ spa_pod_builder_int(&b, c->value);
80
+ break;
81
+ case SPA_TYPE_Bool:
82
+ spa_pod_builder_bool(&b, c->value);
83
+ break;
84
+ default:
85
+ spa_pod_builder_int(&b, c->value);
86
+ break;
87
+ }
88
+ }
89
+ param = spa_pod_builder_pop(&b, &f);
90
break;
91
default:
92
return 0;
93
94
break;
95
}
96
}
97
-
98
+ this->info.change_mask |= SPA_NODE_CHANGE_MASK_PARAMS;
99
+ this->paramsNODE_Props.flags ^= SPA_PARAM_INFO_SERIAL;
100
+ emit_node_info(this, true);
101
break;
102
}
103
default:
104
105
return 0;
106
}
107
108
-static const struct spa_dict_item info_items = {
109
- { SPA_KEY_DEVICE_API, "v4l2" },
110
- { SPA_KEY_MEDIA_CLASS, "Video/Source" },
111
- { SPA_KEY_MEDIA_ROLE, "Camera" },
112
- { SPA_KEY_NODE_DRIVER, "true" },
113
-};
114
-
115
-static void emit_node_info(struct impl *this, bool full)
116
-{
117
- uint64_t old = full ? this->info.change_mask : 0;
118
- if (full)
119
- this->info.change_mask = this->info_all;
120
- if (this->info.change_mask) {
121
- this->info.props = &SPA_DICT_INIT_ARRAY(info_items);
122
- spa_node_emit_info(&this->hooks, &this->info);
123
- this->info.change_mask = old;
124
- }
125
-}
126
-
127
-static void emit_port_info(struct impl *this, struct port *port, bool full)
128
-{
129
- uint64_t old = full ? port->info.change_mask : 0;
130
- if (full)
131
- port->info.change_mask = port->info_all;
132
- if (port->info.change_mask) {
133
- spa_node_emit_port_info(&this->hooks,
134
- SPA_DIRECTION_OUTPUT, 0, &port->info);
135
- port->info.change_mask = old;
136
- }
137
-}
138
-
139
static int
140
impl_node_add_listener(void *object,
141
struct spa_hook *listener,
142
pipewire-0.3.69.tar.gz/spa/plugins/v4l2/v4l2-utils.c -> pipewire-0.3.70.tar.gz/spa/plugins/v4l2/v4l2-utils.c
Changed
75
1
2
3
spa_log_debug(this->log, "Control '%s' %d %d", queryctrl.name, prop_id, ctrl_id);
4
5
- port->n_controls++;
6
-
7
switch (queryctrl.type) {
8
case V4L2_CTRL_TYPE_INTEGER:
9
+ port->controlsport->n_controls.type = SPA_TYPE_Int;
10
param = spa_pod_builder_add_object(&b,
11
SPA_TYPE_OBJECT_PropInfo, SPA_PARAM_PropInfo,
12
SPA_PROP_INFO_id, SPA_POD_Id(prop_id),
13
14
SPA_PROP_INFO_description, SPA_POD_String(queryctrl.name));
15
break;
16
case V4L2_CTRL_TYPE_BOOLEAN:
17
+ port->controlsport->n_controls.type = SPA_TYPE_Bool;
18
param = spa_pod_builder_add_object(&b,
19
SPA_TYPE_OBJECT_PropInfo, SPA_PARAM_PropInfo,
20
SPA_PROP_INFO_id, SPA_POD_Id(prop_id),
21
22
struct v4l2_querymenu querymenu;
23
struct spa_pod_builder_state state;
24
25
+ port->controlsport->n_controls.type = SPA_TYPE_Int;
26
spa_pod_builder_push_object(&b, &f0, SPA_TYPE_OBJECT_PropInfo, SPA_PARAM_PropInfo);
27
spa_pod_builder_add(&b,
28
SPA_PROP_INFO_id, SPA_POD_Id(prop_id),
29
30
goto next;
31
32
}
33
+
34
+ port->n_controls++;
35
+
36
if (spa_pod_filter(&b, &result.param, param, filter) < 0)
37
goto next;
38
39
40
}
41
42
static int
43
+spa_v4l2_update_controls(struct impl *this)
44
+{
45
+ struct port *port = &this->out_ports0;
46
+ struct spa_v4l2_device *dev = &port->dev;
47
+ int res;
48
+ uint32_t i;
49
+
50
+ if ((res = spa_v4l2_open(dev, this->props.device)) < 0)
51
+ return res;
52
+
53
+ for (i = 0; i < port->n_controls; i++) {
54
+ struct control *c = &port->controlsi;
55
+ struct v4l2_control control;
56
+
57
+ spa_zero(control);
58
+ control.id = c->ctrl_id;
59
+ if (xioctl(dev->fd, VIDIOC_G_CTRL, &control) < 0) {
60
+ res = -errno;
61
+ goto done;
62
+ }
63
+ c->value = control.value;
64
+ }
65
+ res = 0;
66
+done:
67
+ spa_v4l2_close(dev);
68
+ return res;
69
+}
70
+
71
+static int
72
spa_v4l2_set_control(struct impl *this, uint32_t id,
73
const struct spa_pod_prop *prop)
74
{
75
pipewire-0.3.69.tar.gz/src/daemon/minimal.conf.in -> pipewire-0.3.70.tar.gz/src/daemon/minimal.conf.in
Changed
18
1
2
#{ factory = spa-node-factory args = { factory.name = api.vulkan.compute.source node.name = my-compute-source } }
3
4
# Make a default metadata store
5
- { factory = metadata args = { metadata.name = default } }
6
+ { factory = metadata
7
+ args = {
8
+ metadata.name = default
9
+ # metadata.values =
10
+ # { key = default.audio.sink value = { name = somesink } }
11
+ # { key = default.audio.source value = { name = somesource } }
12
+ #
13
+ }
14
+ }
15
16
# A default dummy driver. This handles nodes marked with the "node.always-driver"
17
# property when no other driver is currently active. JACK clients need this.
18
pipewire-0.3.69.tar.gz/src/daemon/pipewire.conf.in -> pipewire-0.3.70.tar.gz/src/daemon/pipewire.conf.in
Changed
54
1
2
3
# keys checked below to disable module loading
4
module.x11.bell = true
5
+ # enables autoloading of access module, when disabled an alternative
6
+ # access module needs to be loaded.
7
+ module.access = true
8
}
9
10
context.spa-libs = {
11
12
# access.force permission.
13
#access.force = flatpak
14
}
15
+ condition = { module.access = true }
16
}
17
18
# Makes a factory for wrapping nodes in an adapter with a
19
20
# audio.position = "FL,FR"
21
# }
22
#}
23
+
24
+ # Use the metadata factory to create metadata and some default values.
25
+ #{ factory = metadata
26
+ # args = {
27
+ # metadata.name = my-metadata
28
+ # metadata.values =
29
+ # { key = default.audio.sink value = { name = somesink } }
30
+ # { key = default.audio.source value = { name = somesource } }
31
+ #
32
+ # }
33
+ #}
34
35
36
context.exec =
37
38
# but it is better to start it as a systemd service.
39
# Run the session manager with -h for options.
40
#
41
- @sm_comment@{ path = "@session_manager_path@" args = "@session_manager_args@" }
42
+ @sm_comment@{ path = "@session_manager_path@" args = "@session_manager_args@"
43
+ @sm_comment@ condition = { exec.session-manager = null } { exec.session-manager = true } }
44
#
45
# You can optionally start the pulseaudio-server here as well
46
# but it is better to start it as a systemd service.
47
# It can be interesting to start another daemon here that listens
48
# on another address with the -a option (eg. -a tcp:4713).
49
#
50
- @pulse_comment@{ path = "@pipewire_path@" args = "-c pipewire-pulse.conf" }
51
+ @pulse_comment@{ path = "@pipewire_path@" args = "-c pipewire-pulse.conf"
52
+ @pulse_comment@ condition = { exec.pipewire-pulse = null } { exec.pipewire-pulse = true } }
53
54
pipewire-0.3.69.tar.gz/src/gst/gstpipewiresrc.c -> pipewire-0.3.70.tar.gz/src/gst/gstpipewiresrc.c
Changed
138
1
2
static gboolean gst_pipewire_src_stop (GstBaseSrc * basesrc);
3
static gboolean gst_pipewire_src_event (GstBaseSrc * src, GstEvent * event);
4
static gboolean gst_pipewire_src_query (GstBaseSrc * src, GstQuery * query);
5
+static void gst_pipewire_src_get_times (GstBaseSrc * basesrc, GstBuffer * buffer,
6
+ GstClockTime * start, GstClockTime * end);
7
8
static void
9
gst_pipewire_src_set_property (GObject * object, guint prop_id,
10
11
gstbasesrc_class->stop = gst_pipewire_src_stop;
12
gstbasesrc_class->event = gst_pipewire_src_event;
13
gstbasesrc_class->query = gst_pipewire_src_query;
14
+ gstbasesrc_class->get_times = gst_pipewire_src_get_times;
15
gstpushsrc_class->create = gst_pipewire_src_create;
16
17
GST_DEBUG_CATEGORY_INIT (pipewire_src_debug, "pipewiresrc", 0,
18
19
GST_LOG_OBJECT (pwsrc, "pts %" G_GUINT64_FORMAT ", dts_offset %" G_GUINT64_FORMAT, h->pts, h->dts_offset);
20
21
if (GST_CLOCK_TIME_IS_VALID (h->pts)) {
22
- GST_BUFFER_PTS (buf) = h->pts + GST_PIPEWIRE_CLOCK (pwsrc->clock)->time_offset;
23
+ GST_BUFFER_PTS (buf) = h->pts;
24
if (GST_BUFFER_PTS (buf) + h->dts_offset > 0)
25
GST_BUFFER_DTS (buf) = GST_BUFFER_PTS (buf) + h->dts_offset;
26
}
27
28
return res;
29
}
30
31
+static void
32
+gst_pipewire_src_get_times (GstBaseSrc * basesrc, GstBuffer * buffer,
33
+ GstClockTime * start, GstClockTime * end)
34
+{
35
+ GstPipeWireSrc *pwsrc = GST_PIPEWIRE_SRC (basesrc);
36
+
37
+ /* for live sources, sync on the timestamp of the buffer */
38
+ if (gst_base_src_is_live (basesrc)) {
39
+ GstClockTime timestamp = GST_BUFFER_PTS (buffer);
40
+
41
+ if (GST_CLOCK_TIME_IS_VALID (timestamp)) {
42
+ /* get duration to calculate end time */
43
+ GstClockTime duration = GST_BUFFER_DURATION (buffer);
44
+
45
+ if (GST_CLOCK_TIME_IS_VALID (duration)) {
46
+ *end = timestamp + duration;
47
+ }
48
+ *start = timestamp;
49
+ }
50
+ } else {
51
+ *start = GST_CLOCK_TIME_NONE;
52
+ *end = GST_CLOCK_TIME_NONE;
53
+ }
54
+
55
+ GST_LOG_OBJECT (pwsrc, "start %" GST_TIME_FORMAT " (%" G_GUINT64_FORMAT
56
+ "), end %" GST_TIME_FORMAT " (%" G_GUINT64_FORMAT ")",
57
+ GST_TIME_ARGS (*start), *start, GST_TIME_ARGS (*end), *end);
58
+}
59
+
60
static GstFlowReturn
61
gst_pipewire_src_create (GstPushSrc * psrc, GstBuffer ** buffer)
62
{
63
GstPipeWireSrc *pwsrc;
64
- GstClockTime pts, dts, base_time;
65
const char *error = NULL;
66
GstBuffer *buf;
67
gboolean update_time = FALSE, timeout = FALSE;
68
+ GstCaps *caps = NULL;
69
70
pwsrc = GST_PIPEWIRE_SRC (psrc);
71
72
73
if (state != PW_STREAM_STATE_STREAMING)
74
goto streaming_stopped;
75
76
+ if ((caps = pwsrc->caps) != NULL) {
77
+ pwsrc->caps = NULL;
78
+ pw_thread_loop_unlock (pwsrc->core->loop);
79
+
80
+ GST_DEBUG_OBJECT (pwsrc, "set format %" GST_PTR_FORMAT, caps);
81
+ gst_base_src_set_caps (GST_BASE_SRC (pwsrc), caps);
82
+ gst_caps_unref (caps);
83
+
84
+ pw_thread_loop_lock (pwsrc->core->loop);
85
+ continue;
86
+ }
87
+
88
if (pwsrc->eos) {
89
if (pwsrc->last_buffer == NULL)
90
goto streaming_eos;
91
92
93
*buffer = buf;
94
95
- if (pwsrc->is_live)
96
- base_time = GST_ELEMENT_CAST (psrc)->base_time;
97
- else
98
- base_time = 0;
99
-
100
if (update_time) {
101
- GstClock *clock = gst_element_get_clock (GST_ELEMENT_CAST (pwsrc));
102
+ GstClock *clock;
103
+ GstClockTime pts, dts;
104
+
105
+ clock = gst_element_get_clock (GST_ELEMENT_CAST (pwsrc));
106
if (clock != NULL) {
107
pts = dts = gst_clock_get_time (clock);
108
gst_object_unref (clock);
109
} else {
110
pts = dts = GST_CLOCK_TIME_NONE;
111
}
112
- } else {
113
- pts = GST_BUFFER_PTS (*buffer);
114
- dts = GST_BUFFER_DTS (*buffer);
115
- }
116
-
117
- if (GST_CLOCK_TIME_IS_VALID (pts))
118
- pts = (pts >= base_time ? pts - base_time : 0);
119
- if (GST_CLOCK_TIME_IS_VALID (dts))
120
- dts = (dts >= base_time ? dts - base_time : 0);
121
122
- GST_LOG_OBJECT (pwsrc,
123
- "pts %" G_GUINT64_FORMAT ", dts %" G_GUINT64_FORMAT
124
- ", base-time %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT ", %" GST_TIME_FORMAT,
125
- GST_BUFFER_PTS (*buffer), GST_BUFFER_DTS (*buffer), GST_TIME_ARGS (base_time),
126
- GST_TIME_ARGS (pts), GST_TIME_ARGS (dts));
127
+ GST_BUFFER_PTS (*buffer) = pts;
128
+ GST_BUFFER_DTS (*buffer) = dts;
129
130
- GST_BUFFER_PTS (*buffer) = pts;
131
- GST_BUFFER_DTS (*buffer) = dts;
132
+ GST_LOG_OBJECT (pwsrc, "Sending keepalive buffer pts/dts: %" GST_TIME_FORMAT
133
+ " (%" G_GUINT64_FORMAT ")", GST_TIME_ARGS (pts), pts);
134
+ }
135
136
return GST_FLOW_OK;
137
138
pipewire-0.3.69.tar.gz/src/modules/module-filter-chain/builtin_plugin.c -> pipewire-0.3.70.tar.gz/src/modules/module-filter-chain/builtin_plugin.c
Changed
116
1
2
impl->rate = SampleRate;
3
impl->b0 = impl->a0 = 1.0f;
4
impl->type = bq_type_from_name(Descriptor->name);
5
+ if (impl->type != BQ_NONE)
6
+ return impl;
7
8
- if (config == NULL)
9
+ if (config == NULL) {
10
+ pw_log_error("biquads:bq_raw requires a config section");
11
goto error;
12
+ }
13
14
spa_json_init(&it0, config, strlen(config));
15
- if (spa_json_enter_object(&it0, &it1) <= 0)
16
+ if (spa_json_enter_object(&it0, &it1) <= 0) {
17
+ pw_log_error("biquads:config section must be an object");
18
goto error;
19
+ }
20
21
while (spa_json_get_string(&it1, key, sizeof(key)) > 0) {
22
if (spa_streq(key, "coefficients")) {
23
24
goto error;
25
}
26
}
27
- else if (spa_json_next(&it1, &val) < 0)
28
- break;
29
+ else {
30
+ pw_log_warn("biquads: ignoring coefficients key: '%s'", key);
31
+ if (spa_json_next(&it3, &val) < 0)
32
+ break;
33
+ }
34
}
35
if (labs((long)rate - (long)SampleRate) <
36
labs((long)best_rate - (long)SampleRate)) {
37
38
}
39
}
40
}
41
- else if (spa_json_next(&it1, &val) < 0)
42
- break;
43
+ else {
44
+ pw_log_warn("biquads: ignoring config key: '%s'", key);
45
+ if (spa_json_next(&it1, &val) < 0)
46
+ break;
47
+ }
48
}
49
50
return impl;
51
52
unsigned long rate;
53
54
errno = EINVAL;
55
- if (config == NULL)
56
+ if (config == NULL) {
57
+ pw_log_error("convolver: requires a config section");
58
return NULL;
59
+ }
60
61
spa_json_init(&it0, config, strlen(config));
62
- if (spa_json_enter_object(&it0, &it1) <= 0)
63
+ if (spa_json_enter_object(&it0, &it1) <= 0) {
64
+ pw_log_error("convolver:config must be an object");
65
return NULL;
66
+ }
67
68
while (spa_json_get_string(&it1, key, sizeof(key)) > 0) {
69
if (spa_streq(key, "blocksize")) {
70
71
return NULL;
72
}
73
}
74
- else if (spa_json_next(&it1, &val) < 0)
75
- break;
76
+ else {
77
+ pw_log_warn("convolver: ignoring config key: '%s'", key);
78
+ if (spa_json_next(&it1, &val) < 0)
79
+ break;
80
+ }
81
}
82
if (filenames0 == NULL) {
83
pw_log_error("convolver:filename was not given");
84
85
float max_delay = 1.0f;
86
87
if (config == NULL) {
88
+ pw_log_error("delay: requires a config section");
89
errno = EINVAL;
90
return NULL;
91
}
92
93
spa_json_init(&it0, config, strlen(config));
94
- if (spa_json_enter_object(&it0, &it1) <= 0)
95
+ if (spa_json_enter_object(&it0, &it1) <= 0) {
96
+ pw_log_error("delay:config must be an object");
97
return NULL;
98
+ }
99
100
while (spa_json_get_string(&it1, key, sizeof(key)) > 0) {
101
if (spa_streq(key, "max-delay")) {
102
103
pw_log_error("delay:max-delay requires a number");
104
return NULL;
105
}
106
+ } else {
107
+ pw_log_warn("delay: ignoring config key: '%s'", key);
108
+ if (spa_json_next(&it1, &val) < 0)
109
+ break;
110
}
111
- else if (spa_json_next(&it1, &val) < 0)
112
- break;
113
}
114
if (max_delay <= 0.0f)
115
max_delay = 1.0f;
116
pipewire-0.3.69.tar.gz/src/modules/module-metadata.c -> pipewire-0.3.70.tar.gz/src/modules/module-metadata.c
Changed
135
1
2
#include "config.h"
3
4
#include <spa/utils/result.h>
5
+#include <spa/utils/json.h>
6
7
#include <pipewire/impl.h>
8
#include <pipewire/extensions/metadata.h>
9
10
11
#define NAME "metadata"
12
13
+#define FACTORY_USAGE "("PW_KEY_METADATA_NAME" = <name> ) " \
14
+ "("PW_KEY_METADATA_VALUES" = " \
15
+ " { ( id = <int> ) key = <string> ( type = <string> ) value = <json> } " \
16
+ " ..." \
17
+ " )"
18
+
19
PW_LOG_TOPIC_STATIC(mod_topic, "mod." NAME);
20
#define PW_LOG_TOPIC_DEFAULT mod_topic
21
22
23
};
24
25
26
-void * pw_metadata_new(struct pw_context *context, struct pw_resource *resource,
27
+struct pw_metadata *pw_metadata_new(struct pw_context *context, struct pw_resource *resource,
28
struct pw_properties *properties);
29
30
struct pw_proxy *pw_core_metadata_export(struct pw_core *core,
31
32
struct pw_export_type export_metadata;
33
};
34
35
+/*
36
+ *
37
+ * { ( "id" = <int>, ) "key" = <string> ("type" = <string>) "value" = <json> }
38
+ * ....
39
+ *
40
+ */
41
+static int fill_metadata(struct pw_metadata *metadata, const char *str)
42
+{
43
+ struct spa_json it3;
44
+
45
+ spa_json_init(&it0, str, strlen(str));
46
+ if (spa_json_enter_array(&it0, &it1) <= 0)
47
+ return -EINVAL;
48
+
49
+ while (spa_json_enter_object(&it1, &it2) > 0) {
50
+ char key256, *k = NULL, *v = NULL, *t = NULL;
51
+ int id = 0;
52
+
53
+ while (spa_json_get_string(&it2, key, sizeof(key)) > 0) {
54
+ int len;
55
+ const char *val;
56
+
57
+ if ((len = spa_json_next(&it2, &val)) <= 0)
58
+ return -EINVAL;
59
+
60
+ if (spa_streq(key, "id")) {
61
+ if (spa_json_parse_int(val, len, &id) <= 0)
62
+ return -EINVAL;
63
+ } else if (spa_streq(key, "key")) {
64
+ if ((k = malloc(len+1)) != NULL)
65
+ spa_json_parse_stringn(val, len, k, len+1);
66
+ } else if (spa_streq(key, "type")) {
67
+ if ((t = malloc(len+1)) != NULL)
68
+ spa_json_parse_stringn(val, len, t, len+1);
69
+ } else if (spa_streq(key, "value")) {
70
+ if (spa_json_is_container(val, len))
71
+ len = spa_json_container_len(&it2, val, len);
72
+ if ((v = malloc(len+1)) != NULL)
73
+ spa_json_parse_stringn(val, len, v, len+1);
74
+ }
75
+ }
76
+ if (k != NULL && v != NULL)
77
+ pw_metadata_set_property(metadata, id, k, t, v);
78
+ free(k);
79
+ free(v);
80
+ free(t);
81
+ }
82
+ return 0;
83
+}
84
+
85
static void *create_object(void *_data,
86
struct pw_resource *resource,
87
const char *type,
88
89
{
90
struct factory_data *data = _data;
91
struct pw_context *context = pw_impl_module_get_context(data->module);
92
- void *result;
93
+ struct pw_metadata *result;
94
struct pw_resource *metadata_resource = NULL;
95
struct pw_impl_client *client = resource ? pw_resource_get_client(resource) : NULL;
96
+ const char *str;
97
int res;
98
99
if (properties == NULL)
100
101
goto error_node;
102
}
103
} else {
104
- result = pw_context_create_metadata(context, NULL, properties, 0);
105
- if (result == NULL) {
106
+ struct pw_impl_metadata *impl;
107
+
108
+ impl = pw_context_create_metadata(context, NULL, properties, 0);
109
+ if (impl == NULL) {
110
properties = NULL;
111
res = -errno;
112
goto error_node;
113
}
114
- pw_impl_metadata_register(result, NULL);
115
+ pw_impl_metadata_register(impl, NULL);
116
+ result = pw_impl_metadata_get_implementation(impl);
117
}
118
+ if ((str = pw_properties_get(properties, PW_KEY_METADATA_VALUES)) != NULL)
119
+ fill_metadata(result, str);
120
+
121
return result;
122
123
error_resource:
124
125
"metadata",
126
PW_TYPE_INTERFACE_Metadata,
127
PW_VERSION_METADATA,
128
- NULL,
129
+ pw_properties_new(
130
+ PW_KEY_FACTORY_USAGE, FACTORY_USAGE,
131
+ NULL),
132
sizeof(*data));
133
if (factory == NULL)
134
return -errno;
135
pipewire-0.3.69.tar.gz/src/modules/module-metadata/metadata.c -> pipewire-0.3.70.tar.gz/src/modules/module-metadata/metadata.c
Changed
17
1
2
.destroy = global_resource_destroy,
3
};
4
5
-void *
6
+struct pw_metadata *
7
pw_metadata_new(struct pw_context *context, struct pw_resource *resource,
8
struct pw_properties *properties)
9
{
10
11
&impl->resource_listener,
12
&global_resource_events, impl);
13
14
- return impl;
15
+ return impl->metadata;
16
}
17
pipewire-0.3.69.tar.gz/src/modules/module-protocol-pulse/modules/module-echo-cancel.c -> pipewire-0.3.70.tar.gz/src/modules/module-protocol-pulse/modules/module-echo-cancel.c
Changed
151
1
2
3
static int module_echo_cancel_load(struct module *module)
4
{
5
+ struct pw_properties * const props = module->props;
6
struct module_echo_cancel_data *data = module->user_data;
7
+ const char *method;
8
FILE *f;
9
- const char *str;
10
char *args;
11
size_t size;
12
uint32_t i;
13
14
return -errno;
15
16
fprintf(f, "{");
17
- /* Can't just serialise this dict because the "null" method gets
18
- * interpreted as a JSON null */
19
- if ((str = pw_properties_get(data->props, "aec.method")))
20
- fprintf(f, " aec.method = \"%s\"", str);
21
- if ((str = pw_properties_get(data->props, "aec.args")))
22
- fprintf(f, " aec.args = \"%s\"", str);
23
+ if ((method = pw_properties_get(props, "aec_method")) == NULL)
24
+ method = "webrtc";
25
+
26
+ fprintf(f, " library.name = \"aec/libspa-aec-%s\"", method);
27
+
28
+ fprintf(f, " aec.args = {");
29
+ pw_properties_serialize_dict(f, &data->props->dict, 0);
30
+ fprintf(f, " }");
31
if (data->info.rate != 0)
32
fprintf(f, " audio.rate = %u", data->info.rate);
33
if (data->info.channels != 0) {
34
35
{ PW_KEY_MODULE_VERSION, PACKAGE_VERSION },
36
};
37
38
+static void rename_bool_prop(struct pw_properties *props, const char *pa_key, const char *pw_key)
39
+{
40
+ const char *str;
41
+ if ((str = pw_properties_get(props, pa_key)) != NULL) {
42
+ pw_properties_set(props, pw_key, module_args_parse_bool(str) ? "true" : "false");
43
+ pw_properties_set(props, pa_key, NULL);
44
+ }
45
+}
46
+static int parse_point(const char **point, float f3)
47
+{
48
+ int length;
49
+ if (sscanf(*point, "%g,%g,%g%n", &f0, &f1, &f2, &length) != 3)
50
+ return -EINVAL;
51
+ return length;
52
+}
53
+
54
+static int rename_geometry(struct pw_properties *props, const char *pa_key, const char *pw_key)
55
+{
56
+ const char *str;
57
+ int len;
58
+ char *args;
59
+ size_t size;
60
+ FILE *f;
61
+
62
+ if ((str = pw_properties_get(props, pa_key)) == NULL)
63
+ return 0;
64
+
65
+ pw_log_info("geometry: %s", str);
66
+
67
+ if ((f = open_memstream(&args, &size)) == NULL)
68
+ return -errno;
69
+
70
+ fprintf(f, " ");
71
+ while (true) {
72
+ float p3;
73
+ if ((len = parse_point(&str, p)) < 0)
74
+ break;
75
+
76
+ fprintf(f, " %f %f %f ", p0, p1, p2);
77
+ str += len;
78
+ if (*str != ',')
79
+ break;
80
+ str++;
81
+ }
82
+ fprintf(f, "");
83
+ fclose(f);
84
+
85
+ pw_properties_set(props, pw_key, args);
86
+ free(args);
87
+
88
+ pw_properties_set(props, pa_key, NULL);
89
+ return 0;
90
+}
91
+
92
+static int rename_direction(struct pw_properties *props, const char *pa_key, const char *pw_key)
93
+{
94
+ const char *str;
95
+ int res;
96
+ float f3;
97
+
98
+ if ((str = pw_properties_get(props, pa_key)) == NULL)
99
+ return 0;
100
+
101
+ pw_log_info("direction: %s", str);
102
+
103
+ if ((res = parse_point(&str, f)) < 0)
104
+ return res;
105
+
106
+ pw_properties_setf(props, pw_key, " %f %f %f ", f0, f1, f2);
107
+ pw_properties_set(props, pa_key, NULL);
108
+ return 0;
109
+}
110
+
111
static int module_echo_cancel_prepare(struct module * const module)
112
{
113
struct module_echo_cancel_data * const d = module->user_data;
114
struct pw_properties * const props = module->props;
115
struct pw_properties *aec_props = NULL, *sink_props = NULL, *source_props = NULL;
116
struct pw_properties *playback_props = NULL, *capture_props = NULL;
117
- const char *str;
118
+ const char *str, *method;
119
struct spa_audio_info_raw info = { 0 };
120
int res;
121
122
123
pw_properties_set(props, "sink_properties", NULL);
124
}
125
126
- if ((str = pw_properties_get(props, "aec_method")) != NULL) {
127
- pw_properties_set(aec_props, "aec.method", str);
128
- pw_properties_set(props, "aec_method", NULL);
129
- }
130
+ if ((method = pw_properties_get(props, "aec_method")) == NULL)
131
+ method = "webrtc";
132
133
if ((str = pw_properties_get(props, "aec_args")) != NULL) {
134
- pw_properties_set(aec_props, "aec.args", str);
135
+ module_args_add_props(aec_props, str);
136
+ if (spa_streq(method, "webrtc")) {
137
+ rename_bool_prop(aec_props, "high_pass_filter", "webrtc.high_pass_filter");
138
+ rename_bool_prop(aec_props, "noise_suppression", "webrtc.noise_suppression");
139
+ rename_bool_prop(aec_props, "analog_gain_control", "webrtc.gain_control");
140
+ rename_bool_prop(aec_props, "digital_gain_control", "webrtc.gain_control");
141
+ rename_bool_prop(aec_props, "voice_detection", "webrtc.voice_detection");
142
+ rename_bool_prop(aec_props, "extended_filter", "webrtc.extended_filter");
143
+ rename_bool_prop(aec_props, "experimental_agc", "webrtc.experimental_agc");
144
+ rename_bool_prop(aec_props, "beamforming", "webrtc.beamforming");
145
+ rename_geometry(aec_props, "mic_geometry", "webrtc.mic-geometry");
146
+ rename_direction(aec_props, "target_direction", "webrtc.target-direction");
147
+ }
148
pw_properties_set(props, "aec_args", NULL);
149
}
150
151
pipewire-0.3.69.tar.gz/src/modules/module-pulse-tunnel.c -> pipewire-0.3.70.tar.gz/src/modules/module-pulse-tunnel.c
Changed
227
1
2
void *buffer;
3
uint8_t empty8192;
4
5
+ bool mute;
6
+ pa_cvolume volume;
7
+
8
pa_threaded_mainloop *pa_mainloop;
9
pa_context *pa_context;
10
pa_stream *pa_stream;
11
+ uint32_t pa_index;
12
13
struct ratelimit rate_limit;
14
15
16
}
17
}
18
19
+static void stream_param_changed(void *d, uint32_t id, const struct spa_pod *param)
20
+{
21
+ struct impl *impl = d;
22
+ char buf1024;
23
+ struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buf, sizeof(buf));
24
+ struct spa_pod_frame f1;
25
+ struct spa_pod_object *obj = (struct spa_pod_object *) param;
26
+ struct spa_pod_prop *prop;
27
+
28
+ if (param == NULL || id != SPA_PARAM_Props)
29
+ return;
30
+
31
+ spa_pod_builder_push_object(&b, &f0, SPA_TYPE_OBJECT_Props, SPA_PARAM_Props);
32
+
33
+ SPA_POD_OBJECT_FOREACH(obj, prop) {
34
+ switch (prop->key) {
35
+ case SPA_PROP_mute:
36
+ {
37
+ bool mute;
38
+ if (spa_pod_get_bool(&prop->value, &mute) == 0) {
39
+ pa_threaded_mainloop_lock(impl->pa_mainloop);
40
+ if (impl->mode == MODE_SOURCE) {
41
+ pa_context_set_source_output_mute(impl->pa_context,
42
+ impl->pa_index, mute,
43
+ NULL, impl);
44
+ } else {
45
+ pa_context_set_sink_input_mute(impl->pa_context,
46
+ impl->pa_index, mute,
47
+ NULL, impl);
48
+ }
49
+ pa_threaded_mainloop_unlock(impl->pa_mainloop);
50
+ }
51
+ break;
52
+ }
53
+ case SPA_PROP_channelVolumes:
54
+ {
55
+ struct pa_cvolume volume;
56
+ uint32_t n;
57
+ float volsSPA_AUDIO_MAX_CHANNELS;
58
+
59
+ if ((n = spa_pod_copy_array(&prop->value, SPA_TYPE_Float,
60
+ vols, SPA_AUDIO_MAX_CHANNELS)) > 0) {
61
+ volume.channels = n;
62
+ for (n = 0; n < volume.channels; n++)
63
+ volume.valuesn = pa_sw_volume_from_linear(volsn);
64
+
65
+ pa_threaded_mainloop_lock(impl->pa_mainloop);
66
+ if (impl->mode == MODE_SOURCE) {
67
+ pa_context_set_source_output_volume(impl->pa_context,
68
+ impl->pa_index, &volume,
69
+ NULL, impl);
70
+ } else {
71
+ pa_context_set_sink_input_volume(impl->pa_context,
72
+ impl->pa_index, &volume,
73
+ NULL, impl);
74
+ }
75
+ pa_threaded_mainloop_unlock(impl->pa_mainloop);
76
+ }
77
+ break;
78
+ }
79
+ case SPA_PROP_softVolumes:
80
+ case SPA_PROP_softMute:
81
+ break;
82
+ default:
83
+ spa_pod_builder_raw_padded(&b, prop, SPA_POD_PROP_SIZE(prop));
84
+ break;
85
+ }
86
+ }
87
+ param = spa_pod_builder_pop(&b, &f0);
88
+
89
+ pw_stream_set_param(impl->stream, id, param);
90
+}
91
+
92
static void update_rate(struct impl *impl, uint32_t filled)
93
{
94
float error, corr;
95
96
.destroy = stream_destroy,
97
.state_changed = stream_state_changed,
98
.io_changed = stream_io_changed,
99
+ .param_changed = stream_param_changed,
100
.process = playback_stream_process
101
};
102
103
104
.destroy = stream_destroy,
105
.state_changed = stream_state_changed,
106
.io_changed = stream_io_changed,
107
+ .param_changed = stream_param_changed,
108
.process = capture_stream_process
109
};
110
111
112
do_destroy = true;
113
SPA_FALLTHROUGH;
114
case PA_STREAM_READY:
115
+ impl->pa_index = pa_stream_get_index(impl->pa_stream);
116
pa_threaded_mainloop_signal(impl->pa_mainloop, 0);
117
break;
118
case PA_STREAM_UNCONNECTED:
119
120
pa_threaded_mainloop_signal(impl->pa_mainloop, 0);
121
}
122
123
+static int
124
+do_stream_sync_volumes(struct spa_loop *loop,
125
+ bool async, uint32_t seq, const void *data, size_t size, void *user_data)
126
+{
127
+ struct impl *impl = user_data;
128
+ char buf1024;
129
+ struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buf, sizeof(buf));
130
+ struct spa_pod_frame f1;
131
+ struct spa_pod *param;
132
+ uint32_t i;
133
+ float volsSPA_AUDIO_MAX_CHANNELS;
134
+ float soft_volsSPA_AUDIO_MAX_CHANNELS;
135
+
136
+ for (i = 0; i < impl->volume.channels; i++) {
137
+ volsi = pa_sw_volume_to_linear(impl->volume.valuesi);
138
+ soft_volsi = 1.0f;
139
+ }
140
+
141
+ spa_pod_builder_push_object(&b, &f0, SPA_TYPE_OBJECT_Props, SPA_PARAM_Props);
142
+ spa_pod_builder_prop(&b, SPA_PROP_softMute, 0);
143
+ spa_pod_builder_bool(&b, impl->mute);
144
+ spa_pod_builder_prop(&b, SPA_PROP_mute, 0);
145
+ spa_pod_builder_bool(&b, impl->mute);
146
+
147
+ spa_pod_builder_prop(&b, SPA_PROP_channelVolumes, 0);
148
+ spa_pod_builder_array(&b, sizeof(float), SPA_TYPE_Float,
149
+ impl->volume.channels, vols);
150
+ spa_pod_builder_prop(&b, SPA_PROP_softVolumes, 0);
151
+ spa_pod_builder_array(&b, sizeof(float), SPA_TYPE_Float,
152
+ impl->volume.channels, soft_vols);
153
+ param = spa_pod_builder_pop(&b, &f0);
154
+
155
+ pw_stream_set_param(impl->stream, SPA_PARAM_Props, param);
156
+ return 0;
157
+}
158
+
159
+static void stream_sync_volumes(struct impl *impl, const struct pa_cvolume *volume, bool mute)
160
+{
161
+ impl->mute = mute;
162
+ impl->volume = *volume;
163
+ pw_loop_invoke(impl->main_loop, do_stream_sync_volumes, 1, NULL, 0, false, impl);
164
+}
165
+
166
+static void source_output_info_cb(pa_context *c, const pa_source_output_info *i, int eol, void *userdata)
167
+{
168
+ struct impl *impl = userdata;
169
+ if (i != NULL)
170
+ stream_sync_volumes(impl, &i->volume, i->mute);
171
+}
172
+
173
+static void sink_input_info_cb(pa_context *c, const pa_sink_input_info *i, int eol, void *userdata)
174
+{
175
+ struct impl *impl = userdata;
176
+ if (i != NULL)
177
+ stream_sync_volumes(impl, &i->volume, i->mute);
178
+}
179
+
180
+static void context_subscribe_cb(pa_context *c, pa_subscription_event_type_t t,
181
+ uint32_t idx, void *userdata)
182
+{
183
+ struct impl *impl = userdata;
184
+ if (idx != impl->pa_index)
185
+ return;
186
+
187
+ if (impl->mode == MODE_SOURCE)
188
+ pa_context_get_source_output_info(impl->pa_context,
189
+ idx, source_output_info_cb, impl);
190
+ else
191
+ pa_context_get_sink_input_info(impl->pa_context,
192
+ idx, sink_input_info_cb, impl);
193
+}
194
+
195
static pa_proplist* tunnel_new_proplist(struct impl *impl)
196
{
197
pa_proplist *proplist = pa_proplist_new();
198
199
200
pa_threaded_mainloop_lock(impl->pa_mainloop);
201
202
+ pa_context_set_subscribe_callback(impl->pa_context, context_subscribe_cb, impl);
203
+
204
if (pa_threaded_mainloop_start(impl->pa_mainloop) < 0)
205
goto error_unlock;
206
207
208
if (impl->mode == MODE_SOURCE) {
209
bufferattr.fragsize = latency_bytes / 2;
210
211
+ pa_context_subscribe(impl->pa_context,
212
+ PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT, NULL, impl);
213
+
214
res = pa_stream_connect_record(impl->pa_stream,
215
remote_node_target, &bufferattr,
216
PA_STREAM_DONT_MOVE |
217
218
bufferattr.minreq = bufferattr.tlength / 4;
219
bufferattr.prebuf = bufferattr.tlength;
220
221
+ pa_context_subscribe(impl->pa_context,
222
+ PA_SUBSCRIPTION_MASK_SINK_INPUT, NULL, impl);
223
+
224
res = pa_stream_connect_playback(impl->pa_stream,
225
remote_node_target, &bufferattr,
226
PA_STREAM_DONT_MOVE |
227
pipewire-0.3.69.tar.gz/src/modules/module-raop-sink.c -> pipewire-0.3.70.tar.gz/src/modules/module-raop-sink.c
Changed
103
1
2
3
#define DEFAULT_LATENCY 22050
4
5
+#define VOLUME_MAX 0.0
6
+#define VOLUME_DEF -30.0
7
+#define VOLUME_MIN -144.0
8
+
9
#define MODULE_USAGE "( raop.ip=<ip address of host> ) " \
10
"( raop.port=<remote port> ) " \
11
"( raop.name=<name of host> ) " \
12
13
unsigned int ready:1;
14
unsigned int recording:1;
15
16
+ bool mute;
17
+ float volume;
18
+
19
uint8_t bufferFRAMES_PER_TCP_PACKET * 4;
20
uint32_t filled;
21
};
22
23
return rtsp_send(impl, "TEARDOWN", NULL, NULL, rtsp_teardown_reply);
24
}
25
26
+static void stream_props_changed(struct impl *impl, uint32_t id, const struct spa_pod *param)
27
+{
28
+ char buf1024;
29
+ struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buf, sizeof(buf));
30
+ struct spa_pod_frame f1;
31
+ struct spa_pod_object *obj = (struct spa_pod_object *) param;
32
+ struct spa_pod_prop *prop;
33
+
34
+ spa_pod_builder_push_object(&b, &f0, SPA_TYPE_OBJECT_Props, SPA_PARAM_Props);
35
+
36
+ SPA_POD_OBJECT_FOREACH(obj, prop) {
37
+ switch (prop->key) {
38
+ case SPA_PROP_mute:
39
+ {
40
+ bool mute;
41
+ if (spa_pod_get_bool(&prop->value, &mute) == 0) {
42
+ impl->mute = mute;
43
+ }
44
+ spa_pod_builder_prop(&b, SPA_PROP_softMute, 0);
45
+ spa_pod_builder_bool(&b, impl->mute);
46
+ spa_pod_builder_raw_padded(&b, prop, SPA_POD_PROP_SIZE(prop));
47
+ break;
48
+ }
49
+ case SPA_PROP_channelVolumes:
50
+ {
51
+ uint32_t i, n_vols;
52
+ float volsSPA_AUDIO_MAX_CHANNELS, volume;
53
+ float soft_volsSPA_AUDIO_MAX_CHANNELS;
54
+ char header128, volstr64;
55
+
56
+ if ((n_vols = spa_pod_copy_array(&prop->value, SPA_TYPE_Float,
57
+ vols, SPA_AUDIO_MAX_CHANNELS)) > 0) {
58
+ volume = 0.0f;
59
+ for (i = 0; i < n_vols; i++) {
60
+ volume += volsi;
61
+ soft_volsi = 1.0f;
62
+ }
63
+ volume /= n_vols;
64
+ volume = SPA_CLAMPF(20.0 * log10(volume), VOLUME_MIN, VOLUME_MAX);
65
+ impl->volume = volume;
66
+
67
+ snprintf(header, sizeof(header), "volume: %s\r\n",
68
+ spa_dtoa(volstr, sizeof(volstr), volume));
69
+ rtsp_send(impl, "SET_PARAMETER", "text/parameters", header, NULL);
70
+ }
71
+ spa_pod_builder_prop(&b, SPA_PROP_softVolumes, 0);
72
+ spa_pod_builder_array(&b, sizeof(float), SPA_TYPE_Float,
73
+ n_vols, soft_vols);
74
+ spa_pod_builder_raw_padded(&b, prop, SPA_POD_PROP_SIZE(prop));
75
+ break;
76
+ }
77
+ case SPA_PROP_softVolumes:
78
+ case SPA_PROP_softMute:
79
+ break;
80
+ default:
81
+ spa_pod_builder_raw_padded(&b, prop, SPA_POD_PROP_SIZE(prop));
82
+ break;
83
+ }
84
+ }
85
+ param = spa_pod_builder_pop(&b, &f0);
86
+
87
+ pw_stream_set_param(impl->stream, id, param);
88
+}
89
+
90
static void stream_param_changed(void *data, uint32_t id, const struct spa_pod *param)
91
{
92
struct impl *impl = data;
93
94
else
95
rtsp_do_connect(impl);
96
break;
97
+ case SPA_PARAM_Props:
98
+ if (param != NULL)
99
+ stream_props_changed(impl, id, param);
100
default:
101
break;
102
}
103
pipewire-0.3.69.tar.gz/src/modules/module-rtp-session.c -> pipewire-0.3.70.tar.gz/src/modules/module-rtp-session.c
Changed
39
1
2
{
3
ssize_t n;
4
n = sendmsg(fd, msg, MSG_NOSIGNAL);
5
- if (n < 0) {
6
- switch (errno) {
7
- case ECONNREFUSED:
8
- case ECONNRESET:
9
- pw_log_debug("remote end not listening");
10
- break;
11
- default:
12
- pw_log_debug("sendmsg() failed: %m");
13
- break;
14
- }
15
- }
16
+ if (n < 0)
17
+ pw_log_debug("sendmsg() failed: %m");
18
return n;
19
}
20
21
22
latency = t3 - t1;
23
offset = ((t3 + t1) / 2) - t2;
24
25
- pw_log_info("latency:%f offset:%f", latency / 1e5, offset / 1e5);
26
+ pw_log_debug("latency:%f offset:%f", latency / 1e5, offset / 1e5);
27
if (hdr->count >= 2)
28
return;
29
}
30
31
struct session *sess;
32
uint64_t current_time = impl->next_time;
33
34
- pw_log_info("timeout");
35
+ pw_log_debug("timeout");
36
spa_list_for_each(sess, &impl->sessions, link) {
37
if (sess->state != SESSION_STATE_ESTABLISHED)
38
continue;
39
pipewire-0.3.69.tar.gz/src/modules/module-rtp-sink.c -> pipewire-0.3.70.tar.gz/src/modules/module-rtp-sink.c
Changed
21
1
2
msg.msg_flags = 0;
3
4
n = sendmsg(impl->rtp_fd, &msg, MSG_NOSIGNAL);
5
- if (n < 0) {
6
- switch (errno) {
7
- case ECONNREFUSED:
8
- case ECONNRESET:
9
- pw_log_debug("remote end not listening");
10
- break;
11
- default:
12
- pw_log_warn("sendmsg() failed: %m");
13
- break;
14
- }
15
- }
16
+ if (n < 0)
17
+ pw_log_debug("sendmsg() failed: %m");
18
}
19
20
static void stream_state_changed(void *data, bool started, const char *error)
21
pipewire-0.3.69.tar.gz/src/modules/module-x11-bell.c -> pipewire-0.3.70.tar.gz/src/modules/module-x11-bell.c
Changed
12
1
2
unsigned int auto_ctrls, auto_values;
3
4
if (!(impl->display = XOpenDisplay(name))) {
5
- pw_log_error("XOpenDisplay() failed");
6
- return -EIO;
7
+ pw_log_info("XOpenDisplay() failed. Uninstall or disable the module-x11-bell module");
8
+ return -EHOSTDOWN;
9
}
10
11
impl->source = pw_loop_add_io(impl->loop,
12
pipewire-0.3.69.tar.gz/src/pipewire/conf.c -> pipewire-0.3.70.tar.gz/src/pipewire/conf.c
Changed
223
1
2
match++;
3
pw_log_debug("'%s' match '%s' < > '%.*s'", key, str, len, value);
4
}
5
- else
6
+ else {
7
fail++;
8
+ break;
9
+ }
10
}
11
if (match > 0 && fail == 0)
12
return true;
13
14
15
16
SPA_EXPORT
17
-int pw_context_conf_section_for_each(struct pw_context *context, const char *section,
18
+int pw_conf_section_for_each(const struct spa_dict *conf, const char *section,
19
int (*callback) (void *data, const char *location, const char *section,
20
const char *str, size_t len),
21
void *data)
22
{
23
- struct pw_properties *conf = context->conf;
24
const char *path = NULL;
25
const struct spa_dict_item *it;
26
int res = 0;
27
28
- spa_dict_for_each(it, &conf->dict) {
29
+ spa_dict_for_each(it, conf) {
30
if (spa_strendswith(it->key, "config.path")) {
31
path = it->value;
32
continue;
33
34
return res;
35
}
36
37
-SPA_EXPORT
38
-int pw_context_parse_conf_section(struct pw_context *context,
39
- struct pw_properties *conf, const char *section)
40
-{
41
- struct data data = { .context = context };
42
- int res;
43
-
44
- if (spa_streq(section, "context.spa-libs"))
45
- res = pw_context_conf_section_for_each(context, section,
46
- parse_spa_libs, &data);
47
- else if (spa_streq(section, "context.modules"))
48
- res = pw_context_conf_section_for_each(context, section,
49
- parse_modules, &data);
50
- else if (spa_streq(section, "context.objects"))
51
- res = pw_context_conf_section_for_each(context, section,
52
- parse_objects, &data);
53
- else if (spa_streq(section, "context.exec"))
54
- res = pw_context_conf_section_for_each(context, section,
55
- parse_exec, &data);
56
- else
57
- res = -EINVAL;
58
-
59
- return res == 0 ? data.count : res;
60
-}
61
-
62
static int update_props(void *user_data, const char *location, const char *key,
63
const char *val, size_t len)
64
{
65
66
return 0;
67
}
68
69
+SPA_EXPORT
70
+int pw_conf_section_update_props(const struct spa_dict *conf,
71
+ const char *section, struct pw_properties *props)
72
+{
73
+ struct data data = { .props = props };
74
+ int res;
75
+ const char *str;
76
+
77
+ res = pw_conf_section_for_each(conf, section,
78
+ update_props, &data);
79
+
80
+ str = pw_properties_get(props, "config.ext");
81
+ if (res == 0 && str != NULL) {
82
+ char key128;
83
+ snprintf(key, sizeof(key), "%s.%s", section, str);
84
+ res = pw_conf_section_for_each(conf, key,
85
+ update_props, &data);
86
+ }
87
+ return res == 0 ? data.count : res;
88
+}
89
+
90
static int try_load_conf(const char *conf_prefix, const char *conf_name,
91
struct pw_properties *conf)
92
{
93
94
conf_name = getenv("PIPEWIRE_CONFIG_NAME");
95
if ((res = try_load_conf(conf_prefix, conf_name, conf)) < 0) {
96
conf_name = pw_properties_get(props, PW_KEY_CONFIG_NAME);
97
- if ((res = try_load_conf(conf_prefix, conf_name, conf)) < 0) {
98
+ if (conf_name == NULL)
99
conf_name = "client.conf";
100
- if ((res = try_load_conf(conf_prefix, conf_name, conf)) < 0) {
101
- pw_log_error("can't load default config %s: %s",
102
- conf_name, spa_strerror(res));
103
- return res;
104
- }
105
+ if ((res = try_load_conf(conf_prefix, conf_name, conf)) < 0) {
106
+ pw_log_error("can't load config %s: %s",
107
+ conf_name, spa_strerror(res));
108
+ return res;
109
}
110
}
111
112
113
return res;
114
}
115
116
-SPA_EXPORT
117
-int pw_context_conf_update_props(struct pw_context *context,
118
- const char *section, struct pw_properties *props)
119
-{
120
- struct data data = { .context = context, .props = props };
121
- int res;
122
- const char *str = pw_properties_get(props, "config.ext");
123
-
124
- res = pw_context_conf_section_for_each(context, section,
125
- update_props, &data);
126
- if (res == 0 && str != NULL) {
127
- char key128;
128
- snprintf(key, sizeof(key), "%s.%s", section, str);
129
- res = pw_context_conf_section_for_each(context, key,
130
- update_props, &data);
131
- }
132
- return res == 0 ? data.count : res;
133
-}
134
-
135
-
136
/**
137
*
138
* {
139
140
}
141
142
SPA_EXPORT
143
-int pw_context_conf_section_match_rules(struct pw_context *context, const char *section,
144
+int pw_conf_section_match_rules(const struct spa_dict *conf, const char *section,
145
const struct spa_dict *props,
146
int (*callback) (void *data, const char *location, const char *action,
147
const char *str, size_t len),
148
149
.matched = callback,
150
.data = data };
151
int res;
152
- const char *str = spa_dict_lookup(props, "config.ext");
153
+ const char *str;
154
155
- res = pw_context_conf_section_for_each(context, section,
156
+ res = pw_conf_section_for_each(conf, section,
157
match_rules, &match);
158
+
159
+ str = spa_dict_lookup(props, "config.ext");
160
if (res == 0 && str != NULL) {
161
char key128;
162
snprintf(key, sizeof(key), "%s.%s", section, str);
163
- res = pw_context_conf_section_for_each(context, key,
164
+ res = pw_conf_section_for_each(conf, key,
165
match_rules, &match);
166
}
167
return res;
168
}
169
+
170
+SPA_EXPORT
171
+int pw_context_conf_update_props(struct pw_context *context,
172
+ const char *section, struct pw_properties *props)
173
+{
174
+ return pw_conf_section_update_props(&context->conf->dict,
175
+ section, props);
176
+}
177
+
178
+SPA_EXPORT
179
+int pw_context_conf_section_for_each(struct pw_context *context, const char *section,
180
+ int (*callback) (void *data, const char *location, const char *section,
181
+ const char *str, size_t len),
182
+ void *data)
183
+{
184
+ return pw_conf_section_for_each(&context->conf->dict, section, callback, data);
185
+}
186
+
187
+
188
+SPA_EXPORT
189
+int pw_context_parse_conf_section(struct pw_context *context,
190
+ struct pw_properties *conf, const char *section)
191
+{
192
+ struct data data = { .context = context };
193
+ int res;
194
+
195
+ if (spa_streq(section, "context.spa-libs"))
196
+ res = pw_context_conf_section_for_each(context, section,
197
+ parse_spa_libs, &data);
198
+ else if (spa_streq(section, "context.modules"))
199
+ res = pw_context_conf_section_for_each(context, section,
200
+ parse_modules, &data);
201
+ else if (spa_streq(section, "context.objects"))
202
+ res = pw_context_conf_section_for_each(context, section,
203
+ parse_objects, &data);
204
+ else if (spa_streq(section, "context.exec"))
205
+ res = pw_context_conf_section_for_each(context, section,
206
+ parse_exec, &data);
207
+ else
208
+ res = -EINVAL;
209
+
210
+ return res == 0 ? data.count : res;
211
+}
212
+
213
+SPA_EXPORT
214
+int pw_context_conf_section_match_rules(struct pw_context *context, const char *section,
215
+ const struct spa_dict *props,
216
+ int (*callback) (void *data, const char *location, const char *action,
217
+ const char *str, size_t len),
218
+ void *data)
219
+{
220
+ return pw_conf_section_match_rules(&context->conf->dict, section,
221
+ props, callback, data);
222
+}
223
pipewire-0.3.69.tar.gz/src/pipewire/conf.h -> pipewire-0.3.70.tar.gz/src/pipewire/conf.h
Changed
27
1
2
int pw_conf_load_state(const char *prefix, const char *name, struct pw_properties *conf);
3
int pw_conf_save_state(const char *prefix, const char *name, const struct pw_properties *conf);
4
5
+int pw_conf_section_update_props(const struct spa_dict *conf,
6
+ const char *section, struct pw_properties *props);
7
+
8
+int pw_conf_section_for_each(const struct spa_dict *conf, const char *section,
9
+ int (*callback) (void *data, const char *location, const char *section,
10
+ const char *str, size_t len),
11
+ void *data);
12
+
13
int pw_conf_match_rules(const char *str, size_t len, const char *location,
14
const struct spa_dict *props,
15
int (*callback) (void *data, const char *location, const char *action,
16
const char *str, size_t len),
17
void *data);
18
19
+int pw_conf_section_match_rules(const struct spa_dict *conf, const char *section,
20
+ const struct spa_dict *props,
21
+ int (*callback) (void *data, const char *location, const char *action,
22
+ const char *str, size_t len),
23
+ void *data);
24
/**
25
* \}
26
*/
27
pipewire-0.3.69.tar.gz/src/pipewire/context.c -> pipewire-0.3.70.tar.gz/src/pipewire/context.c
Changed
39
1
2
struct pw_impl_port *p;
3
struct pw_impl_link *l;
4
5
- if (!node->runnable)
6
- return 0;
7
-
8
pw_log_debug("node %p: '%s'", node, node->name);
9
10
spa_list_for_each(p, &node->input_ports, link) {
11
12
13
pw_impl_link_prepare(l);
14
15
- if (!l->prepared || (t != n && t->visited))
16
+ if (!l->prepared)
17
continue;
18
19
if (!l->passive)
20
21
22
pw_impl_link_prepare(l);
23
24
- if (!l->prepared || (t != n && t->visited))
25
+ if (!l->prepared)
26
continue;
27
28
if (!l->passive)
29
30
pw_log_debug(" next node %p: '%s' runnable:%u", n, n->name, n->runnable);
31
}
32
spa_list_for_each(n, collect, sort_link)
33
- run_nodes(context, n, collect);
34
+ if (!n->driver && n->runnable)
35
+ run_nodes(context, n, collect);
36
37
return 0;
38
}
39
pipewire-0.3.69.tar.gz/src/pipewire/extensions/metadata.h -> pipewire-0.3.70.tar.gz/src/pipewire/extensions/metadata.h
Changed
9
1
2
#define pw_metadata_clear(c) pw_metadata_method(c,clear,0)
3
4
#define PW_KEY_METADATA_NAME "metadata.name"
5
+#define PW_KEY_METADATA_VALUES "metadata.values"
6
7
/**
8
* \}
9
pipewire-0.3.69.tar.gz/src/pipewire/properties.c -> pipewire-0.3.70.tar.gz/src/pipewire/properties.c
Changed
192
1
2
3
#include <stdio.h>
4
#include <stdarg.h>
5
+
6
+#include <spa/utils/ansi.h>
7
#include <spa/utils/json.h>
8
#include <spa/utils/string.h>
9
10
11
return pw_array_get_unchecked(&impl->items, index, struct spa_dict_item)->key;
12
}
13
14
-static int encode_string(FILE *f, const char *val)
15
+#define NORMAL(c) ((c)->colors ? SPA_ANSI_RESET : "")
16
+#define LITERAL(c) ((c)->colors ? SPA_ANSI_BRIGHT_MAGENTA : "")
17
+#define NUMBER(c) ((c)->colors ? SPA_ANSI_BRIGHT_CYAN : "")
18
+#define STRING(c) ((c)->colors ? SPA_ANSI_BRIGHT_GREEN : "")
19
+#define KEY(c) ((c)->colors ? SPA_ANSI_BRIGHT_BLUE : "")
20
+#define CONTAINER(c) ((c)->colors ? SPA_ANSI_BRIGHT_YELLOW : "")
21
+
22
+struct dump_config {
23
+ FILE *file;
24
+ int indent;
25
+ const char *sep;
26
+ bool colors;
27
+ bool recurse;
28
+};
29
+
30
+static int encode_string(struct dump_config *c, const char *before,
31
+ const char *val, int size, const char *after)
32
{
33
- int len = 0;
34
- len += fprintf(f, "\"");
35
- while (*val) {
36
- switch (*val) {
37
+ FILE *f = c->file;
38
+ int i, len = 0;
39
+ len += fprintf(f, "%s\"", before);
40
+ for (i = 0; i < size; i++) {
41
+ char v = vali;
42
+ switch (v) {
43
case '\n':
44
len += fprintf(f, "\\n");
45
break;
46
47
case '\f':
48
len += fprintf(f, "\\f");
49
break;
50
- case '\\':
51
- case '"':
52
- len += fprintf(f, "\\%c", *val);
53
- break;
54
+ case '\\': case '"':
55
+ len += fprintf(f, "\\%c", v);
56
+ break;
57
default:
58
- if (*val > 0 && *val < 0x20)
59
- len += fprintf(f, "\\u%04x", *val);
60
+ if (v > 0 && v < 0x20)
61
+ len += fprintf(f, "\\u%04x", v);
62
else
63
- len += fprintf(f, "%c", *val);
64
+ len += fprintf(f, "%c", v);
65
break;
66
}
67
- val++;
68
}
69
- len += fprintf(f, "\"");
70
+ len += fprintf(f, "\"%s", after);
71
return len-1;
72
}
73
74
+static int dump(struct dump_config *c, int indent, struct spa_json *it, const char *value, int len)
75
+{
76
+ FILE *file = c->file;
77
+ struct spa_json sub;
78
+ int count = 0;
79
+ char key1024;
80
+
81
+ if (value == NULL || len == 0) {
82
+ fprintf(file, "%snull%s", LITERAL(c), NORMAL(c));
83
+ } else if (spa_json_is_container(value, len) && !c->recurse) {
84
+ len = spa_json_container_len(it, value, len);
85
+ fprintf(file, "%s%.*s%s", CONTAINER(c), len, value, NORMAL(c));
86
+ } else if (spa_json_is_array(value, len)) {
87
+ fprintf(file, "");
88
+ spa_json_enter(it, &sub);
89
+ indent += c->indent;
90
+ while ((len = spa_json_next(&sub, &value)) > 0) {
91
+ fprintf(file, "%s%s%*s", count++ > 0 ? "," : "",
92
+ c->sep, indent, "");
93
+ dump(c, indent, &sub, value, len);
94
+ }
95
+ indent -= c->indent;
96
+ fprintf(file, "%s%*s", count > 0 ? c->sep : "",
97
+ count > 0 ? indent : 0, "");
98
+ } else if (spa_json_is_object(value, len)) {
99
+ fprintf(file, "{");
100
+ spa_json_enter(it, &sub);
101
+ indent += c->indent;
102
+ while (spa_json_get_string(&sub, key, sizeof(key)) > 0) {
103
+ fprintf(file, "%s%s%*s",
104
+ count++ > 0 ? "," : "",
105
+ c->sep, indent, "");
106
+ encode_string(c, KEY(c), key, strlen(key), NORMAL(c));
107
+ fprintf(file, ": ");
108
+ if ((len = spa_json_next(&sub, &value)) <= 0)
109
+ break;
110
+ dump(c, indent, &sub, value, len);
111
+ }
112
+ indent -= c->indent;
113
+ fprintf(file, "%s%*s}", count > 0 ? c->sep : "",
114
+ count > 0 ? indent : 0, "");
115
+ } else if (spa_json_is_null(value, len) ||
116
+ spa_json_is_bool(value, len)) {
117
+ fprintf(file, "%s%.*s%s", LITERAL(c), len, value, NORMAL(c));
118
+ } else if (spa_json_is_int(value, len) ||
119
+ spa_json_is_float(value, len)) {
120
+ fprintf(file, "%s%.*s%s", NUMBER(c), len, value, NORMAL(c));
121
+ } else if (spa_json_is_string(value, len)) {
122
+ fprintf(file, "%s%.*s%s", STRING(c), len, value, NORMAL(c));
123
+ } else {
124
+ encode_string(c, STRING(c), value, len, NORMAL(c));
125
+ }
126
+ return 0;
127
+}
128
+
129
SPA_EXPORT
130
int pw_properties_serialize_dict(FILE *f, const struct spa_dict *dict, uint32_t flags)
131
{
132
const struct spa_dict_item *it;
133
int count = 0;
134
- char key1024;
135
+ struct dump_config cfg = {
136
+ .file = f,
137
+ .indent = flags & PW_PROPERTIES_FLAG_NL ? 2 : 0,
138
+ .sep = flags & PW_PROPERTIES_FLAG_NL ? "\n" : " ",
139
+ .colors = SPA_FLAG_IS_SET(flags, PW_PROPERTIES_FLAG_COLORS),
140
+ .recurse = SPA_FLAG_IS_SET(flags, PW_PROPERTIES_FLAG_RECURSE),
141
+ }, *c = &cfg;
142
+ const char *enc = flags & PW_PROPERTIES_FLAG_ARRAY ? "" : "{}";
143
+
144
+ if (SPA_FLAG_IS_SET(flags, PW_PROPERTIES_FLAG_ENCLOSE))
145
+ fprintf(f, "%c", enc0);
146
147
spa_dict_for_each(it, dict) {
148
- size_t len = it->value ? strlen(it->value) : 0;
149
+ char key1024;
150
+ int len;
151
+ const char *value;
152
+ struct spa_json sub;
153
154
- if (spa_json_encode_string(key, sizeof(key)-1, it->key) >= (int)sizeof(key)-1)
155
- continue;
156
+ fprintf(f, "%s%s%*s", count == 0 ? "" : ",", c->sep, c->indent, "");
157
158
- fprintf(f, "%s%s %s: ",
159
- count == 0 ? "" : ",",
160
- flags & PW_PROPERTIES_FLAG_NL ? "\n" : "",
161
- key);
162
-
163
- if (it->value == NULL) {
164
- fprintf(f, "null");
165
- } else if (spa_json_is_null(it->value, len) ||
166
- spa_json_is_float(it->value, len) ||
167
- spa_json_is_bool(it->value, len) ||
168
- spa_json_is_container(it->value, len) ||
169
- spa_json_is_string(it->value, len)) {
170
- fprintf(f, "%s", it->value);
171
- } else {
172
- encode_string(f, it->value);
173
+ if (!(flags & PW_PROPERTIES_FLAG_ARRAY)) {
174
+ if (spa_json_encode_string(key, sizeof(key)-1, it->key) >= (int)sizeof(key)-1)
175
+ continue;
176
+ fprintf(f, "%s%s%s: ", KEY(c), key, NORMAL(c));
177
}
178
+ value = it->value;
179
+
180
+ len = value ? strlen(value) : 0;
181
+ spa_json_init(&sub, value, len);
182
+ if ((len = spa_json_next(&sub, &value)) < 0)
183
+ break;
184
+
185
+ dump(c, c->indent, &sub, value, len);
186
count++;
187
}
188
+ if (SPA_FLAG_IS_SET(flags, PW_PROPERTIES_FLAG_ENCLOSE))
189
+ fprintf(f, "%s%c", c->sep, enc1);
190
return count;
191
}
192
pipewire-0.3.69.tar.gz/src/pipewire/properties.h -> pipewire-0.3.70.tar.gz/src/pipewire/properties.h
Changed
14
1
2
const char *
3
pw_properties_iterate(const struct pw_properties *properties, void **state);
4
5
-#define PW_PROPERTIES_FLAG_NL (1<<0)
6
+#define PW_PROPERTIES_FLAG_NL (1<<0)
7
+#define PW_PROPERTIES_FLAG_RECURSE (1<<1)
8
+#define PW_PROPERTIES_FLAG_ENCLOSE (1<<2)
9
+#define PW_PROPERTIES_FLAG_ARRAY (1<<3)
10
+#define PW_PROPERTIES_FLAG_COLORS (1<<4)
11
int pw_properties_serialize_dict(FILE *f, const struct spa_dict *dict, uint32_t flags);
12
13
static inline bool pw_properties_parse_bool(const char *value) {
14
pipewire-0.3.69.tar.gz/src/pipewire/stream.c -> pipewire-0.3.70.tar.gz/src/pipewire/stream.c
Changed
58
1
2
unsigned int driving:1;
3
unsigned int using_trigger:1;
4
unsigned int trigger:1;
5
- int in_set_control;
6
+ int in_set_param;
7
};
8
9
static int get_param_index(uint32_t id)
10
11
if (id != SPA_PARAM_Props)
12
return -ENOTSUP;
13
14
- if (impl->in_set_control == 0)
15
+ if (impl->in_set_param == 0)
16
pw_stream_emit_param_changed(stream, id, param);
17
18
return 0;
19
20
return res;
21
}
22
23
+static inline int stream_set_param(struct stream *impl, uint32_t id, const struct spa_pod *param)
24
+{
25
+ int res = 0;
26
+ impl->in_set_param++;
27
+ res = pw_impl_node_set_param(impl->node, id, 0, param);
28
+ impl->in_set_param--;
29
+ return res;
30
+}
31
+
32
+SPA_EXPORT
33
+int pw_stream_set_param(struct pw_stream *stream, uint32_t id, const struct spa_pod *param)
34
+{
35
+ struct stream *impl = SPA_CONTAINER_OF(stream, struct stream, this);
36
+ ensure_loop(impl->context->main_loop, return -EIO);
37
+
38
+ if (impl->node == NULL)
39
+ return -EIO;
40
+
41
+ return stream_set_param(impl, id, param);
42
+}
43
+
44
SPA_EXPORT
45
int pw_stream_set_control(struct pw_stream *stream, uint32_t id, uint32_t n_values, float *values, ...)
46
{
47
48
49
va_end(varargs);
50
51
- impl->in_set_control++;
52
- pw_impl_node_set_param(impl->node, SPA_PARAM_Props, 0, pod);
53
- impl->in_set_control--;
54
+ stream_set_param(impl, SPA_PARAM_Props, pod);
55
56
return 0;
57
}
58
pipewire-0.3.69.tar.gz/src/pipewire/stream.h -> pipewire-0.3.70.tar.gz/src/pipewire/stream.h
Changed
30
1
2
const char *error, /**< an error message */
3
...) SPA_PRINTF_FUNC(3, 4);
4
5
-/** Complete the negotiation process with result code \a res
6
- *
7
- * This function should be called after notification of the format.
8
-
9
- * When \a res indicates success, \a params contain the parameters for the
10
- * allocation state. */
11
+/** Update the param exposed on the stream. */
12
int
13
pw_stream_update_params(struct pw_stream *stream, /**< a \ref pw_stream */
14
const struct spa_pod **params, /**< an array of params. The params should
15
16
* buffer allocation. */
17
uint32_t n_params /**< number of elements in \a params */);
18
19
+/**
20
+ * Set a parameter on the stream. This is like pw_stream_set_control() but with
21
+ * a complete spa_pod param. It can also be called from the param_changed event handler
22
+ * to intercept and modify the param for the adapter. Since 0.3.70 */
23
+int pw_stream_set_param(struct pw_stream *stream, /**< a \ref pw_stream */
24
+ uint32_t id, /**< the id of the param */
25
+ const struct spa_pod *param /**< the params to set */);
26
+
27
/** Get control values */
28
const struct pw_stream_control *pw_stream_get_control(struct pw_stream *stream, uint32_t id);
29
30
pipewire-0.3.69.tar.gz/src/tools/meson.build -> pipewire-0.3.70.tar.gz/src/tools/meson.build
Changed
8
1
2
tools_sources =
3
'pw-mon', 'pw-mon.c' ,
4
+ 'pw-config', 'pw-config.c' ,
5
'pw-dot', 'pw-dot.c' ,
6
'pw-dump', 'pw-dump.c' ,
7
'pw-profiler', 'pw-profiler.c' ,
8
pipewire-0.3.70.tar.gz/src/tools/pw-config.c
Added
256
1
2
+/* PipeWire */
3
+/* SPDX-FileCopyrightText: Copyright © 2023 Wim Taymans */
4
+/* SPDX-License-Identifier: MIT */
5
+
6
+#include "config.h"
7
+
8
+#include <getopt.h>
9
+#include <signal.h>
10
+#include <locale.h>
11
+#include <unistd.h>
12
+
13
+#include <spa/utils/result.h>
14
+#include <spa/utils/json.h>
15
+
16
+#include "pipewire/pipewire.h"
17
+#include "pipewire/log.h"
18
+
19
+#define DEFAULT_NAME "pipewire.conf"
20
+#define DEFAULT_PREFIX ""
21
+
22
+struct data {
23
+ const char *opt_name;
24
+ const char *opt_prefix;
25
+ const char *opt_cmd;
26
+ bool opt_recurse;
27
+ bool opt_newline;
28
+ bool opt_colors;
29
+ struct pw_properties *conf;
30
+ struct pw_properties *assemble;
31
+ int count;
32
+ bool array;
33
+};
34
+
35
+static void print_all_properties(struct data *d, struct pw_properties *props)
36
+{
37
+ pw_properties_serialize_dict(stdout,
38
+ &props->dict,
39
+ (d->opt_newline ? PW_PROPERTIES_FLAG_NL : 0) |
40
+ (d->opt_recurse ? PW_PROPERTIES_FLAG_RECURSE : 0) |
41
+ (d->opt_colors ? PW_PROPERTIES_FLAG_COLORS : 0) |
42
+ (d->array ? PW_PROPERTIES_FLAG_ARRAY : 0) |
43
+ PW_PROPERTIES_FLAG_ENCLOSE);
44
+ fprintf(stdout, "\n");
45
+}
46
+
47
+static void list_paths(struct data *d)
48
+{
49
+ const struct spa_dict_item *it;
50
+
51
+ spa_dict_for_each(it, &d->conf->dict) {
52
+ if (spa_strstartswith(it->key, "config.path")) {
53
+ pw_properties_set(d->assemble, it->key, it->value);
54
+ }
55
+ if (spa_strstartswith(it->key, "override.") &&
56
+ spa_strendswith(it->key, ".config.path")) {
57
+ pw_properties_set(d->assemble, it->key, it->value);
58
+ }
59
+ }
60
+}
61
+
62
+static int do_merge_section(void *data, const char *location, const char *section,
63
+ const char *str, size_t len)
64
+{
65
+ struct data *d = data;
66
+ struct spa_json it2;
67
+ int l;
68
+ const char *value;
69
+
70
+ spa_json_init(&it0, str, len);
71
+ if ((l = spa_json_next(&it0, &value)) <= 0)
72
+ return 0;
73
+
74
+ if (spa_json_is_array(value, l)) {
75
+ char key128;
76
+
77
+ spa_json_enter(&it0, &it1);
78
+ while ((l = spa_json_next(&it1, &value)) > 0) {
79
+ if (spa_json_is_container(value, l))
80
+ l = spa_json_container_len(&it1, value, l);
81
+
82
+ snprintf(key, sizeof(key), "%d-%s", d->count++, location);
83
+ pw_properties_setf(d->assemble, key, "%.*s", l, value);
84
+ }
85
+ d->array = true;
86
+ }
87
+ else if (spa_json_is_object(value, l)) {
88
+ pw_properties_update_string(d->assemble, str, len);
89
+ }
90
+ return 0;
91
+}
92
+
93
+static int do_list_section(void *data, const char *location, const char *section,
94
+ const char *str, size_t len)
95
+{
96
+ struct data *d = data;
97
+ char key128;
98
+ snprintf(key, sizeof(key), "%d-%s", d->count++, location);
99
+ pw_properties_setf(d->assemble, key, "%.*s", (int)len, str);
100
+ return 0;
101
+}
102
+
103
+static void section_for_each(struct data *d, const char *section,
104
+ int (*callback) (void *data, const char *location, const char *section,
105
+ const char *str, size_t len))
106
+{
107
+ const char *str;
108
+ char key128;
109
+
110
+ pw_conf_section_for_each(&d->conf->dict, section, callback, d);
111
+ str = pw_properties_get(d->assemble, "config.ext");
112
+ if (str != NULL) {
113
+ snprintf(key, sizeof(key), "%s.%s", section, str);
114
+ pw_conf_section_for_each(&d->conf->dict, key, callback, d);
115
+ }
116
+}
117
+
118
+static void show_help(const char *name, bool error)
119
+{
120
+ fprintf(error ? stderr : stdout, "%1$s : PipeWire config manager.\n"
121
+ "Usage:\n"
122
+ " %1$s options paths List config paths (default action)\n"
123
+ " %1$s options list SECTION List config section\n"
124
+ " %1$s options merge SECTION Merge a config section\n\n"
125
+ "Options:\n"
126
+ " -h, --help Show this help\n"
127
+ " --version Show version\n"
128
+ " -n, --name Config Name (default '%2$s')\n"
129
+ " -p, --prefix Config Prefix (default '%3$s')\n"
130
+ " -L, --no-newline Omit newlines after values\n"
131
+ " -r, --recurse Reformat config sections recursively\n"
132
+ " -N, --no-colors disable color output\n"
133
+ " -C, --color=WHEN whether to enable color support. WHEN is `never`, `always`, or `auto`\n",
134
+ name, DEFAULT_NAME, DEFAULT_PREFIX);
135
+}
136
+
137
+int main(int argc, char *argv)
138
+{
139
+ struct data d = { 0, };
140
+ struct pw_properties *props = NULL;
141
+ int res = 0, c;
142
+ static const struct option long_options = {
143
+ { "help", no_argument, NULL, 'h' },
144
+ { "version", no_argument, NULL, 'V' },
145
+ { "name", required_argument, NULL, 'n' },
146
+ { "prefix", required_argument, NULL, 'p' },
147
+ { "no-newline", no_argument, NULL, 'L' },
148
+ { "recurse", no_argument, NULL, 'r' },
149
+ { "no-colors", no_argument, NULL, 'N' },
150
+ { "color", optional_argument, NULL, 'C' },
151
+ { NULL, 0, NULL, 0}
152
+ };
153
+
154
+ d.opt_name = DEFAULT_NAME;
155
+ d.opt_prefix = NULL;
156
+ d.opt_recurse = false;
157
+ d.opt_newline = true;
158
+ if (isatty(fileno(stdout)) && getenv("NO_COLOR") == NULL)
159
+ d.opt_colors = true;
160
+ d.opt_cmd = "paths";
161
+
162
+ pw_init(&argc, &argv);
163
+
164
+ while ((c = getopt_long(argc, argv, "hVn:p:LrNC", long_options, NULL)) != -1) {
165
+ switch (c) {
166
+ case 'h':
167
+ show_help(argv0, false);
168
+ return 0;
169
+ case 'V':
170
+ printf("%s\n"
171
+ "Compiled with libpipewire %s\n"
172
+ "Linked with libpipewire %s\n",
173
+ argv0,
174
+ pw_get_headers_version(),
175
+ pw_get_library_version());
176
+ return 0;
177
+ case 'n':
178
+ d.opt_name = optarg;
179
+ break;
180
+ case 'p':
181
+ d.opt_prefix = optarg;
182
+ break;
183
+ case 'L':
184
+ d.opt_newline = false;
185
+ break;
186
+ case 'r':
187
+ d.opt_recurse = true;
188
+ break;
189
+ case 'N' :
190
+ d.opt_colors = false;
191
+ break;
192
+ case 'C' :
193
+ if (optarg == NULL || !strcmp(optarg, "auto"))
194
+ break; /* nothing to do, tty detection was done
195
+ before parsing options */
196
+ else if (!strcmp(optarg, "never"))
197
+ d.opt_colors = false;
198
+ else if (!strcmp(optarg, "always"))
199
+ d.opt_colors = true;
200
+ else {
201
+ fprintf(stderr, "Unknown color: %s\n", optarg);
202
+ show_help(argv0, true);
203
+ return -1;
204
+ }
205
+ break;
206
+ default:
207
+ show_help(argv0, true);
208
+ return -1;
209
+ }
210
+ }
211
+
212
+ if (optind < argc)
213
+ d.opt_cmd = argvoptind++;
214
+
215
+ props = pw_properties_new(
216
+ PW_KEY_CONFIG_NAME, d.opt_name,
217
+ PW_KEY_CONFIG_PREFIX, d.opt_prefix,
218
+ NULL);
219
+
220
+ d.conf = pw_properties_new(NULL, NULL);
221
+ if ((res = pw_conf_load_conf_for_context (props, d.conf)) < 0) {
222
+ fprintf(stderr, "error loading config: %s\n", spa_strerror(res));
223
+ goto done;
224
+ }
225
+
226
+ d.assemble = pw_properties_new(NULL, NULL);
227
+
228
+ if (spa_streq(d.opt_cmd, "paths")) {
229
+ list_paths(&d);
230
+ }
231
+ else if (spa_streq(d.opt_cmd, "list")) {
232
+ if (optind == argc) {
233
+ pw_properties_update(d.assemble, &d.conf->dict);
234
+ } else {
235
+ section_for_each(&d, argvoptind++, do_list_section);
236
+ }
237
+ }
238
+ else if (spa_streq(d.opt_cmd, "merge")) {
239
+ if (optind == argc) {
240
+ fprintf(stderr, "%s requires a section\n", d.opt_cmd);
241
+ res = -EINVAL;
242
+ goto done;
243
+ }
244
+ section_for_each(&d, argvoptind++, do_merge_section);
245
+ }
246
+ print_all_properties(&d, d.assemble);
247
+
248
+done:
249
+ pw_properties_free(d.conf);
250
+ pw_properties_free(d.assemble);
251
+ pw_properties_free(props);
252
+
253
+ pw_deinit();
254
+ return res;
255
+}
256
pipewire-0.3.69.tar.gz/src/tools/pw-metadata.c -> pipewire-0.3.70.tar.gz/src/tools/pw-metadata.c
Changed
92
1
2
3
const char *opt_remote;
4
const char *opt_name;
5
+ bool opt_list;
6
bool opt_monitor;
7
bool opt_delete;
8
uint32_t opt_id;
9
10
{
11
struct data *d = data;
12
13
+ if (d->opt_list)
14
+ return 0;
15
+
16
if ((d->opt_id == SPA_ID_INVALID || d->opt_id == id) &&
17
(d->opt_key == NULL || spa_streq(d->opt_key, key))) {
18
if (key == NULL) {
19
20
const struct spa_dict *props)
21
{
22
struct data *d = data;
23
- const char *str;
24
+ const char *name;
25
26
if (!spa_streq(type, PW_TYPE_INTERFACE_Metadata))
27
return;
28
29
- if (props != NULL &&
30
- (str = spa_dict_lookup(props, PW_KEY_METADATA_NAME)) != NULL &&
31
- !spa_streq(str, d->opt_name))
32
+ if (props == NULL)
33
+ return;
34
+
35
+ name = spa_dict_lookup(props, PW_KEY_METADATA_NAME);
36
+ if (name == NULL)
37
+ return;
38
+
39
+ if (d->opt_name && !spa_streq(name, d->opt_name))
40
return;
41
42
- if (d->metadata != NULL) {
43
+ if (!d->opt_list && d->metadata != NULL) {
44
pw_log_warn("Multiple metadata: ignoring metadata %d", id);
45
return;
46
}
47
48
- printf("Found \"%s\" metadata %d\n", d->opt_name, id);
49
+ printf("Found \"%s\" metadata %d\n", name, id);
50
+ if (d->opt_list)
51
+ return;
52
+
53
d->metadata = pw_registry_bind(d->registry,
54
id, type, PW_VERSION_METADATA, 0);
55
56
57
" -h, --help Show this help\n"
58
" --version Show version\n"
59
" -r, --remote Remote daemon name\n"
60
+ " -l, --list List available metadata\n"
61
" -m, --monitor Monitor metadata\n"
62
" -d, --delete Delete metadata\n"
63
" -n, --name Metadata name (default: \"%s\")\n",
64
65
{ "help", no_argument, NULL, 'h' },
66
{ "version", no_argument, NULL, 'V' },
67
{ "remote", required_argument, NULL, 'r' },
68
+ { "list", no_argument, NULL, 'l' },
69
{ "monitor", no_argument, NULL, 'm' },
70
{ "delete", no_argument, NULL, 'd' },
71
{ "name", required_argument, NULL, 'n' },
72
73
74
data.opt_name = "default";
75
76
- while ((c = getopt_long(argc, argv, "hVr:mdn:", long_options, NULL)) != -1) {
77
+ while ((c = getopt_long(argc, argv, "hVr:lmdn:", long_options, NULL)) != -1) {
78
switch (c) {
79
case 'h':
80
show_help(&data, argv0, false);
81
82
case 'r':
83
data.opt_remote = optarg;
84
break;
85
+ case 'l':
86
+ data.opt_name = NULL;
87
+ data.opt_list = true;
88
+ break;
89
case 'm':
90
data.opt_monitor = true;
91
break;
92
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 almost 2 years ago
New upstream release
zaitor accepted request almost 2 years ago
Xin